Skip to content

Commit 13118cd

Browse files
committed
fix: tree looses focus after renaming item
1 parent 90c1c19 commit 13118cd

File tree

3 files changed

+20
-20
lines changed

3 files changed

+20
-20
lines changed

packages/core/src/controlledEnvironment/useControlledTreeEnvironmentProps.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,16 @@ export const useControlledTreeEnvironmentProps = ({
122122
[onDropProp, updateLinearItems]
123123
);
124124

125+
const focusTree = useCallback((treeId: string) => {
126+
const focusItem = document.querySelector(
127+
`[data-rct-tree="${treeId}"] [data-rct-item-focus="true"]`
128+
);
129+
(focusItem as HTMLElement)?.focus?.();
130+
}, []);
131+
125132
const setActiveTree = useCallback(
126133
(treeIdOrSetStateFunction, autoFocusTree = true) => {
127-
const focusTree = (treeId: string | undefined) => {
134+
const maybeFocusTree = (treeId: string | undefined) => {
128135
if (
129136
autoFocusTree &&
130137
(autoFocus ?? true) &&
@@ -133,10 +140,7 @@ export const useControlledTreeEnvironmentProps = ({
133140
.querySelector(`[data-rct-tree="${treeId}"]`)
134141
?.contains(document.activeElement)
135142
) {
136-
const focusItem = document.querySelector(
137-
`[data-rct-tree="${treeId}"] [data-rct-item-focus="true"]`
138-
);
139-
(focusItem as HTMLElement)?.focus?.();
143+
focusTree(treeId);
140144
}
141145
};
142146

@@ -145,18 +149,18 @@ export const useControlledTreeEnvironmentProps = ({
145149
const treeId = treeIdOrSetStateFunction(oldValue);
146150

147151
if (treeId !== oldValue) {
148-
focusTree(treeId);
152+
maybeFocusTree(treeId);
149153
}
150154

151155
return treeId;
152156
});
153157
} else {
154158
const treeId = treeIdOrSetStateFunction;
155159
setActiveTreeId(treeId);
156-
focusTree(treeId);
160+
maybeFocusTree(treeId);
157161
}
158162
},
159-
[autoFocus]
163+
[autoFocus, focusTree]
160164
);
161165

162166
const renderers = useRenderers(props);

packages/core/src/treeItem/TreeItemRenamingInput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const TreeItemRenamingInput: React.FC<{
2222
const submitButtonRef = useRef<any>(null);
2323
const item = environment.items[props.itemIndex];
2424
const [title, setTitle] = useState(environment.getItemTitle(item));
25-
const callSoon = useCallSoon();
25+
const callSoon = useCallSoon(true);
2626

2727
const abort = () => {
2828
environment.onAbortRenamingItem?.(item, treeInformation.treeId);

packages/core/src/useCallSoon.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,21 @@ import { useCallback, useEffect, useRef } from 'react';
66
*
77
* @returns A function that can be used to schedule a deferred callback.
88
*/
9-
export function useCallSoon(): (callback: () => void) => void {
10-
// list of pending callbacks
9+
export function useCallSoon(dontClean = false): (callback: () => void) => void {
1110
const handleRef = useRef(new Array<number>());
1211

13-
// if the component is unmounted, cancel any pending callbacks
1412
useEffect(() => {
15-
// can't use handleRef.current in the cleanup function, so we have to
16-
// assign it to a new variable here.
13+
if (dontClean) {
14+
return () => {};
15+
}
16+
1717
const handles = handleRef.current;
1818
return () => handles.forEach(handle => cancelAnimationFrame(handle));
19-
}, [handleRef]);
19+
}, [dontClean, handleRef]);
2020

21-
// schedule callback soon and keep handle for later cancellation
22-
const callSoon = useCallback(
21+
return useCallback(
2322
(callback: () => void) => {
2423
const handle = requestAnimationFrame(() => {
25-
// remove the handle from the list of pending callbacks
2624
handleRef.current.splice(handleRef.current.indexOf(handle), 1);
2725

2826
callback();
@@ -32,6 +30,4 @@ export function useCallSoon(): (callback: () => void) => void {
3230
},
3331
[handleRef]
3432
);
35-
36-
return callSoon;
3733
}

0 commit comments

Comments
 (0)