1.1 How did the focus pass from one component to its's sibling?
-We could pass the reference of SearchInput's sibling component
Treeview component to the inside of SearchInput
-However, to keep the component self-contained, we shouldn't do it like this
-It's better if we leave an interface for the parent element to pass the eventhandler
[]Solution:
1. We define onKeyDown={handleKeyDown} in < OutlinedInput >,
the innner child of < SearchInput >, because this is where the focus located exactly
-remember the non-bubble property of focus event
2. Inside of handleKeyDown, we pass the event we get, and triger the interface prop
we set in < SearchInput/ >
const handleKeyDown = useCallback(
(event: React.KeyboardEvent< HTMLInputElement >) = > {
if (event.key === 'ArrowDown') {
event.preventDefault();
onArrowDownKeyDown(e);
}
},
[]
)
3. In this case, it's the onArrowDownKeyDown
export default function SearchInput({
onChange,
ref,
onArrowDownKeyDown,
}: {
onChange: (value: string) = > void;
ref?: React.RefObject< HTMLInputElement >;
onArrowDownKeyDown?: (e: React.KeyboardEvent< HTMLInputElement >) = > void;
4. Then in the parent element of SearchInput, in this case,
SearchedTreeView.tsx
-We define the things we want to do through interface prop of < SearchInput >
In this case,in return, we define
< SearchInput onChange={search} onArrowDownKeyDown={focusOnTreeView} / >
//to make the focus changes easier, we define the reference to the parent
div of SearchInput and ControlledTreeView
the handler focusOnTreeView is defined as:
const focusOnTreeView = useCallback(() = > {
const treeView = searchTreeViewRef.current?.children[1];
(treeView?.children[0] as HTMLLIElement)?.focus();
}, []);
Until here, the arrowkeydown event:
change focus from SearchInput to ControlledTreeView is finished
5. Add on to that, we also want to change the focus back to SearchInput when
we are at the first children of TreeView and press up again
-This part is a little hard to understand:
-by checking Treeview API, we found we have onNodeFocus
https://mui.com/material-ui/api/tree-view/
-basically, we check the if the current focus node is the first children
of treeview, if so, we call the onArrowUpkeyDown(), we defined
-and set the focus back to searchInput through parent
-check full commit in https://github.com/Max-ChenFei/VisualProgrammingEditor/commit/fe1358624809fbf43eb17fbaaa9088644574c693
const ref = useRef<HTMLDivElement>(null);
const focusOnNew = useRef<boolean>(false);
const focusOnTop = useRef<boolean>(false);
return (
< TreeView
ref={ref}
onFocus={() => {
focusOnNew.current = false;
}}
onNodeFocus={(e, node) => {
focusOnNew.current = true;
focusOnTop.current =
ref.current?.children[0].id.includes(node) ?? false;
}}
onKeyDown={(e) => {
if (e.key === 'ArrowUp') {
e.preventDefault();
e.stopPropagation();
if (focusOnTop.current && !focusOnNew.current) onArrowUpKeyDown?.();
}
focusOnNew.current = false;
}}
1.1 How did the focus pass from one component to its's sibling? -We could pass the reference of SearchInput's sibling component Treeview component to the inside of SearchInput -However, to keep the component self-contained, we shouldn't do it like this
[]Solution: