mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-25 01:52:45 +03:00
feat(EditSlates): only show menu selection when the input is focused
This commit is contained in:
parent
324123fce9
commit
04461097e8
@ -25,6 +25,9 @@ const comboboxContext = React.createContext({});
|
|||||||
const useComboboxContext = () => React.useContext(comboboxContext);
|
const useComboboxContext = () => React.useContext(comboboxContext);
|
||||||
|
|
||||||
function ComboboxProvider({ children, isMobile = false, onItemSelect }) {
|
function ComboboxProvider({ children, isMobile = false, onItemSelect }) {
|
||||||
|
const [isInputFocused, setInputFocus] = React.useState(true);
|
||||||
|
const menuSelectionDisabled = isMobile || !isInputFocused;
|
||||||
|
|
||||||
const menuItemsRef = React.useRef({});
|
const menuItemsRef = React.useRef({});
|
||||||
const menuElementRef = React.useRef({});
|
const menuElementRef = React.useRef({});
|
||||||
|
|
||||||
@ -32,24 +35,25 @@ function ComboboxProvider({ children, isMobile = false, onItemSelect }) {
|
|||||||
const [selectedIdx, setSelectedIdx] = React.useState(initialIndex);
|
const [selectedIdx, setSelectedIdx] = React.useState(initialIndex);
|
||||||
|
|
||||||
const registerMenuRef = (node) => {
|
const registerMenuRef = (node) => {
|
||||||
if (isMobile) return;
|
if (menuSelectionDisabled) return;
|
||||||
menuElementRef.current = node;
|
menuElementRef.current = node;
|
||||||
};
|
};
|
||||||
|
|
||||||
const registerMenuItem = ({ index, onSelectRef, ref }) => {
|
const registerMenuItem = ({ index, onSelectRef, ref }) => {
|
||||||
if (isMobile) return;
|
if (menuSelectionDisabled) return;
|
||||||
menuItemsRef.current[index] = { index, onSelectRef, ref };
|
menuItemsRef.current[index] = { index, onSelectRef, ref };
|
||||||
};
|
};
|
||||||
const cleanupMenuItem = (index) => {
|
const cleanupMenuItem = (index) => {
|
||||||
if (isMobile) return;
|
if (menuSelectionDisabled) return;
|
||||||
if (index === selectedIdx) setSelectedIdx(initialIndex);
|
if (index === selectedIdx) setSelectedIdx(initialIndex);
|
||||||
|
|
||||||
delete menuItemsRef.current[index];
|
delete menuItemsRef.current[index];
|
||||||
};
|
};
|
||||||
|
|
||||||
const isNavigatingViaKeyboard = React.useRef(true);
|
const isNavigatingViaKeyboard = React.useRef(true);
|
||||||
const moveSelectionOnArrowUp = () => {
|
const moveSelectionOnArrowUp = () => {
|
||||||
isNavigatingViaKeyboard.current = true;
|
isNavigatingViaKeyboard.current = true;
|
||||||
if (isMobile) return;
|
if (menuSelectionDisabled) return;
|
||||||
const prevIndex = selectedIdx - 1;
|
const prevIndex = selectedIdx - 1;
|
||||||
let prevFocusedIndex = null;
|
let prevFocusedIndex = null;
|
||||||
if (prevIndex >= initialIndex) {
|
if (prevIndex >= initialIndex) {
|
||||||
@ -62,7 +66,7 @@ function ComboboxProvider({ children, isMobile = false, onItemSelect }) {
|
|||||||
|
|
||||||
const moveSelectionOnArrowDown = () => {
|
const moveSelectionOnArrowDown = () => {
|
||||||
isNavigatingViaKeyboard.current = true;
|
isNavigatingViaKeyboard.current = true;
|
||||||
if (isMobile) return;
|
if (menuSelectionDisabled) return;
|
||||||
const nextIndex = selectedIdx + 1;
|
const nextIndex = selectedIdx + 1;
|
||||||
const elementExists = menuItemsRef.current[nextIndex];
|
const elementExists = menuItemsRef.current[nextIndex];
|
||||||
const nextFocusedIndex = elementExists ? nextIndex : initialIndex;
|
const nextFocusedIndex = elementExists ? nextIndex : initialIndex;
|
||||||
@ -80,12 +84,12 @@ function ComboboxProvider({ children, isMobile = false, onItemSelect }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const applySelectedElement = () => {
|
const applySelectedElement = () => {
|
||||||
if (isMobile) return;
|
if (menuSelectionDisabled) return;
|
||||||
menuItemsRef.current[selectedIdx].onSelectRef.current(), onItemSelect?.();
|
menuItemsRef.current[selectedIdx].onSelectRef.current(), onItemSelect?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useLayoutEffect(() => {
|
React.useLayoutEffect(() => {
|
||||||
if (isMobile) return;
|
if (menuSelectionDisabled) return;
|
||||||
|
|
||||||
//NOTE(amine): don't scroll automatically when the user is navigating using a mouse
|
//NOTE(amine): don't scroll automatically when the user is navigating using a mouse
|
||||||
if (!isNavigatingViaKeyboard.current) return;
|
if (!isNavigatingViaKeyboard.current) return;
|
||||||
@ -108,14 +112,16 @@ function ComboboxProvider({ children, isMobile = false, onItemSelect }) {
|
|||||||
top: selectedNodeBottom - menuNode.offsetHeight + selectedNode.offsetHeight,
|
top: selectedNodeBottom - menuNode.offsetHeight + selectedNode.offsetHeight,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [selectedIdx, isMobile]);
|
}, [selectedIdx, menuSelectionDisabled]);
|
||||||
|
|
||||||
const contextValue = React.useMemo(
|
const contextValue = React.useMemo(
|
||||||
() => [
|
() => [
|
||||||
{ selectedIdx, isMobile },
|
{ selectedIdx, menuSelectionDisabled },
|
||||||
{
|
{
|
||||||
onItemSelect,
|
onItemSelect,
|
||||||
|
|
||||||
|
setInputFocus,
|
||||||
|
|
||||||
registerMenuItem,
|
registerMenuItem,
|
||||||
cleanupMenuItem,
|
cleanupMenuItem,
|
||||||
|
|
||||||
@ -127,7 +133,7 @@ function ComboboxProvider({ children, isMobile = false, onItemSelect }) {
|
|||||||
registerMenuRef,
|
registerMenuRef,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[selectedIdx, isMobile]
|
[selectedIdx, menuSelectionDisabled]
|
||||||
);
|
);
|
||||||
|
|
||||||
return <comboboxContext.Provider value={contextValue}>{children}</comboboxContext.Provider>;
|
return <comboboxContext.Provider value={contextValue}>{children}</comboboxContext.Provider>;
|
||||||
@ -135,9 +141,11 @@ function ComboboxProvider({ children, isMobile = false, onItemSelect }) {
|
|||||||
|
|
||||||
/* -----------------------------------------------------------------------------------------------*/
|
/* -----------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
const ComboboxInput = React.forwardRef(({ onKeyDown, ...props }, ref) => {
|
const ComboboxInput = React.forwardRef(({ onKeyDown, onFocus, onBlur, ...props }, ref) => {
|
||||||
const [, { moveSelectionOnArrowUp, moveSelectionOnArrowDown, applySelectedElement }] =
|
const [
|
||||||
useComboboxContext();
|
,
|
||||||
|
{ setInputFocus, moveSelectionOnArrowUp, moveSelectionOnArrowDown, applySelectedElement },
|
||||||
|
] = useComboboxContext();
|
||||||
|
|
||||||
const keyDownHandler = (e) => {
|
const keyDownHandler = (e) => {
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
@ -165,7 +173,15 @@ const ComboboxInput = React.forwardRef(({ onKeyDown, ...props }, ref) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return <System.Input onKeyDown={mergeEvents(keyDownHandler, onKeyDown)} {...props} ref={ref} />;
|
return (
|
||||||
|
<System.Input
|
||||||
|
onFocus={mergeEvents(() => setInputFocus(true), onFocus)}
|
||||||
|
onBlur={mergeEvents(() => setInputFocus(false), onBlur)}
|
||||||
|
onKeyDown={mergeEvents(keyDownHandler, onKeyDown)}
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------------------------*/
|
/* -----------------------------------------------------------------------------------------------*/
|
||||||
@ -239,9 +255,9 @@ const Combobox = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const useCombobox = () => {
|
const useCombobox = () => {
|
||||||
const [{ selectedIdx, isMobile }] = useComboboxContext();
|
const [{ selectedIdx, menuSelectionDisabled }] = useComboboxContext();
|
||||||
const checkIfIndexSelected = (index) => {
|
const checkIfIndexSelected = (index) => {
|
||||||
if (isMobile) return false;
|
if (menuSelectionDisabled) return false;
|
||||||
return selectedIdx === index;
|
return selectedIdx === index;
|
||||||
};
|
};
|
||||||
return { checkIfIndexSelected };
|
return { checkIfIndexSelected };
|
||||||
@ -843,6 +859,7 @@ export function EditSlates({ file, viewer, onClose, ...props }) {
|
|||||||
/* -----------------------------------------------------------------------------------------------*/
|
/* -----------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
export function EditSlatesMobile({ file, viewer, onClose }) {
|
export function EditSlatesMobile({ file, viewer, onClose }) {
|
||||||
|
const memoizedFiles = React.useMemo(() => (Array.isArray(file) ? file : [file]), [file]);
|
||||||
const {
|
const {
|
||||||
slates,
|
slates,
|
||||||
filteredSlates,
|
filteredSlates,
|
||||||
@ -853,7 +870,7 @@ export function EditSlatesMobile({ file, viewer, onClose }) {
|
|||||||
checkIfSlateIsApplied,
|
checkIfSlateIsApplied,
|
||||||
} = useSlates({
|
} = useSlates({
|
||||||
viewer,
|
viewer,
|
||||||
object: file,
|
objects: memoizedFiles,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [value, { handleInputChange, clearInputValue }] = useInput();
|
const [value, { handleInputChange, clearInputValue }] = useInput();
|
||||||
|
Loading…
Reference in New Issue
Block a user