Skip to content

Commit 9248a4b

Browse files
committedApr 17, 2025
Merge branch 'release-2.16.1' into release
2 parents 763521a + f85fef2 commit 9248a4b

File tree

8 files changed

+91
-13
lines changed

8 files changed

+91
-13
lines changed
 

‎client/modules/IDE/components/FileNode.jsx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import classNames from 'classnames';
33
import React, { useState, useRef } from 'react';
44
import { connect } from 'react-redux';
55
import { useTranslation } from 'react-i18next';
6+
import { useSelector } from 'react-redux';
67

78
import * as IDEActions from '../actions/ide';
89
import * as FileActions from '../actions/files';
@@ -88,6 +89,24 @@ const FileNode = ({
8889
const [isDeleting, setIsDeleting] = useState(false);
8990
const [updatedName, setUpdatedName] = useState(name);
9091

92+
const files = useSelector((state) => state.files);
93+
94+
const checkDuplicate = (newName) => {
95+
const parentFolder = files.find((f) => f.id === parentId);
96+
if (!parentFolder) return false;
97+
98+
const siblingFiles = parentFolder.children
99+
.map((childId) => files.find((f) => f.id === childId))
100+
.filter(Boolean)
101+
.filter((file) => file.id !== id);
102+
103+
const isDuplicate = siblingFiles.some(
104+
(f) => f.name.trim().toLowerCase() === newName.trim().toLowerCase()
105+
);
106+
107+
return isDuplicate;
108+
};
109+
91110
const { t } = useTranslation();
92111
const fileNameInput = useRef(null);
93112
const fileOptionsRef = useRef(null);
@@ -157,7 +176,7 @@ const FileNode = ({
157176
};
158177

159178
const saveUpdatedFileName = () => {
160-
if (updatedName !== name) {
179+
if (!checkDuplicate(updatedName) && updatedName !== name) {
161180
updateFileName(id, updatedName);
162181
}
163182
};
@@ -198,8 +217,13 @@ const FileNode = ({
198217
};
199218

200219
const handleFileNameBlur = () => {
201-
validateFileName();
202-
hideEditFileName();
220+
if (!checkDuplicate(updatedName)) {
221+
validateFileName();
222+
hideEditFileName();
223+
} else {
224+
setUpdatedName(name);
225+
hideEditFileName();
226+
}
203227
};
204228

205229
const toggleFileOptions = (event) => {
@@ -271,6 +295,7 @@ const FileNode = ({
271295
aria-label={updatedName}
272296
className="sidebar__file-item-name"
273297
onClick={handleFileClick}
298+
onDoubleClick={handleClickRename}
274299
data-testid="file-name"
275300
>
276301
<FileName name={updatedName} />

‎client/modules/IDE/components/FileNode.unit.test.jsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import React from 'react';
2+
import { Provider } from 'react-redux';
3+
import configureStore from 'redux-mock-store';
4+
import thunk from 'redux-thunk';
25

36
import {
47
fireEvent,
@@ -9,6 +12,8 @@ import {
912
} from '../../../test-utils';
1013
import { FileNode } from './FileNode';
1114

15+
const mockStore = configureStore([thunk]);
16+
1217
describe('<FileNode />', () => {
1318
const changeName = (newFileName) => {
1419
const renameButton = screen.getByText(/Rename/i);
@@ -32,6 +37,7 @@ describe('<FileNode />', () => {
3237
fileType,
3338
canEdit: true,
3439
children: [],
40+
parentId: 'parent-folder-id',
3541
authenticated: false,
3642
setSelectedFile: jest.fn(),
3743
deleteFile: jest.fn(),
@@ -45,7 +51,40 @@ describe('<FileNode />', () => {
4551
setProjectName: jest.fn()
4652
};
4753

48-
render(<FileNode {...props} />);
54+
const mockFiles = [
55+
{
56+
id: '0',
57+
name: props.name,
58+
parentId: 'parent-folder-id'
59+
},
60+
{
61+
id: '1',
62+
name: 'sketch.js',
63+
parentId: '0',
64+
isSelectedFile: true
65+
},
66+
{
67+
id: 'parent-folder-id',
68+
name: 'parent',
69+
parentId: null,
70+
children: ['0', 'some-other-file-id']
71+
},
72+
{
73+
id: 'some-other-file-id',
74+
name: 'duplicate.js',
75+
parentId: 'parent-folder-id'
76+
}
77+
];
78+
79+
const store = mockStore({
80+
files: mockFiles
81+
});
82+
83+
render(
84+
<Provider store={store}>
85+
<FileNode {...props} />
86+
</Provider>
87+
);
4988

5089
return props;
5190
};

‎client/modules/IDE/components/Preferences/index.jsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,13 @@ export default function Preferences() {
249249
onClick={() => {
250250
fontSizeInputRef.current?.select();
251251
}}
252+
onKeyDown={(event) => {
253+
if (event.key === 'ArrowUp') {
254+
increaseFontSize();
255+
} else if (event.key === 'ArrowDown') {
256+
decreaseFontSize();
257+
}
258+
}}
252259
/>
253260
</form>
254261
<button

‎client/modules/IDE/components/SketchListRowBase.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import PropTypes from 'prop-types';
22
import slugify from 'slugify';
3-
import React, { useState, useRef, useCallback } from 'react';
3+
import React, { useState, useEffect, useRef, useCallback } from 'react';
44
import { Link } from 'react-router-dom';
55
import { bindActionCreators } from 'redux';
66
import { connect } from 'react-redux';
@@ -31,10 +31,15 @@ const SketchListRowBase = ({
3131
const [renameValue, setRenameValue] = useState(sketch.name);
3232
const renameInput = useRef(null);
3333

34+
useEffect(() => {
35+
if (renameOpen && renameInput.current) {
36+
renameInput.current.focus();
37+
}
38+
}, [renameOpen]);
39+
3440
const openRename = useCallback(() => {
3541
setRenameOpen(true);
3642
setRenameValue(sketch.name);
37-
renameInput.current.focus();
3843
}, [sketch.name]);
3944

4045
const closeRename = () => setRenameOpen(false);

‎client/modules/IDE/hooks/useP5Version.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable func-names */
12
import React, { useContext, useMemo, useState } from 'react';
23
import { useSelector } from 'react-redux';
34
import PropTypes from 'prop-types';
@@ -8,6 +9,7 @@ import PropTypes from 'prop-types';
89
// TODO: use their API for this to grab these at build time?
910
export const p5Versions = [
1011
'2.0.0',
12+
'1.11.5',
1113
'1.11.4',
1214
'1.11.3',
1315
'1.11.2',
@@ -134,7 +136,7 @@ export const p5Versions = [
134136
'0.2.1'
135137
];
136138

137-
export const currentP5Version = '1.11.4'; // Don't update to 2.x until 2026
139+
export const currentP5Version = '1.11.3'; // Don't update to 2.x until 2026
138140

139141
export const p5SoundURLOld = `https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.3/addons/p5.sound.min.js`;
140142
export const p5SoundURL =
@@ -315,7 +317,7 @@ export function P5VersionProvider(props) {
315317
}
316318

317319
P5VersionProvider.propTypes = {
318-
children: PropTypes.element.isRequired
320+
children: PropTypes.node.isRequired
319321
};
320322

321323
export function useP5Version() {

‎package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "p5.js-web-editor",
3-
"version": "2.16.0",
3+
"version": "2.16.1",
44
"description": "The web editor for p5.js.",
55
"scripts": {
66
"clean": "rimraf dist",

‎server/domain-objects/createDefaultFiles.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ function draw() {
99
export const defaultHTML = `<!DOCTYPE html>
1010
<html lang="en">
1111
<head>
12-
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.4/p5.js"></script>
13-
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.4/addons/p5.sound.min.js"></script>
12+
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.3/p5.js"></script>
13+
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.3/addons/p5.sound.min.js"></script>
1414
<link rel="stylesheet" type="text/css" href="style.css">
1515
<meta charset="utf-8" />
1616

0 commit comments

Comments
 (0)