Fix command menu selection (#10248)
- Created a state `hasUserSelectedCommandState` : This state is set to `true` when the user selects an element in the command menu list. It is set to false upon redirection or when the command menu is closed. - Modified `CommandMenuDefaultSelectionEffect` to have the expected selection behavior for the command menu
This commit is contained in:
@ -1,3 +1,4 @@
|
|||||||
|
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
@ -13,10 +14,13 @@ export const CommandMenuDefaultSelectionEffect = ({
|
|||||||
|
|
||||||
const selectedItemId = useRecoilValue(selectedItemIdState);
|
const selectedItemId = useRecoilValue(selectedItemIdState);
|
||||||
|
|
||||||
|
const hasUserSelectedCommand = useRecoilValue(hasUserSelectedCommandState);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
isDefined(selectedItemId) &&
|
isDefined(selectedItemId) &&
|
||||||
selectableItemIds.includes(selectedItemId)
|
selectableItemIds.includes(selectedItemId) &&
|
||||||
|
hasUserSelectedCommand
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -24,7 +28,12 @@ export const CommandMenuDefaultSelectionEffect = ({
|
|||||||
if (selectableItemIds.length > 0) {
|
if (selectableItemIds.length > 0) {
|
||||||
setSelectedItemId(selectableItemIds[0]);
|
setSelectedItemId(selectableItemIds[0]);
|
||||||
}
|
}
|
||||||
}, [selectableItemIds, selectedItemId, setSelectedItemId]);
|
}, [
|
||||||
|
hasUserSelectedCommand,
|
||||||
|
selectableItemIds,
|
||||||
|
selectedItemId,
|
||||||
|
setSelectedItemId,
|
||||||
|
]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,11 +7,13 @@ import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/Comman
|
|||||||
import { RESET_CONTEXT_TO_SELECTION } from '@/command-menu/constants/ResetContextToSelection';
|
import { RESET_CONTEXT_TO_SELECTION } from '@/command-menu/constants/ResetContextToSelection';
|
||||||
import { useCommandMenuOnItemClick } from '@/command-menu/hooks/useCommandMenuOnItemClick';
|
import { useCommandMenuOnItemClick } from '@/command-menu/hooks/useCommandMenuOnItemClick';
|
||||||
import { useResetPreviousCommandMenuContext } from '@/command-menu/hooks/useResetPreviousCommandMenuContext';
|
import { useResetPreviousCommandMenuContext } from '@/command-menu/hooks/useResetPreviousCommandMenuContext';
|
||||||
|
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||||
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
|
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import { MOBILE_VIEWPORT } from 'twenty-ui';
|
import { MOBILE_VIEWPORT } from 'twenty-ui';
|
||||||
|
|
||||||
@ -75,6 +77,10 @@ export const CommandMenuList = ({
|
|||||||
const { resetPreviousCommandMenuContext } =
|
const { resetPreviousCommandMenuContext } =
|
||||||
useResetPreviousCommandMenuContext();
|
useResetPreviousCommandMenuContext();
|
||||||
|
|
||||||
|
const setHasUserSelectedCommand = useSetRecoilState(
|
||||||
|
hasUserSelectedCommandState,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CommandMenuDefaultSelectionEffect
|
<CommandMenuDefaultSelectionEffect
|
||||||
@ -109,6 +115,9 @@ export const CommandMenuList = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
onSelect={() => {
|
||||||
|
setHasUserSelectedCommand(true);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
{commandGroups.map(({ heading, items }) =>
|
{commandGroups.map(({ heading, items }) =>
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import {
|
|||||||
} from '@/command-menu/states/commandMenuNavigationStackState';
|
} from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageTitle';
|
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageTitle';
|
||||||
|
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||||
@ -60,6 +61,7 @@ export const useCommandMenu = () => {
|
|||||||
|
|
||||||
set(isCommandMenuOpenedState, true);
|
set(isCommandMenuOpenedState, true);
|
||||||
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenuOpen);
|
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenuOpen);
|
||||||
|
set(hasUserSelectedCommandState, false);
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
copyContextStoreStates,
|
copyContextStoreStates,
|
||||||
@ -89,6 +91,7 @@ export const useCommandMenu = () => {
|
|||||||
set(commandMenuSearchState, '');
|
set(commandMenuSearchState, '');
|
||||||
set(commandMenuNavigationStackState, []);
|
set(commandMenuNavigationStackState, []);
|
||||||
resetSelectedItem();
|
resetSelectedItem();
|
||||||
|
set(hasUserSelectedCommandState, false);
|
||||||
goBackToPreviousHotkeyScope();
|
goBackToPreviousHotkeyScope();
|
||||||
|
|
||||||
emitRightDrawerCloseEvent();
|
emitRightDrawerCloseEvent();
|
||||||
@ -173,6 +176,7 @@ export const useCommandMenu = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
set(commandMenuNavigationStackState, newNavigationStack);
|
set(commandMenuNavigationStackState, newNavigationStack);
|
||||||
|
set(hasUserSelectedCommandState, false);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[closeCommandMenu],
|
[closeCommandMenu],
|
||||||
@ -201,6 +205,8 @@ export const useCommandMenu = () => {
|
|||||||
title: newNavigationStackItem?.pageTitle,
|
title: newNavigationStackItem?.pageTitle,
|
||||||
Icon: newNavigationStackItem?.pageIcon,
|
Icon: newNavigationStackItem?.pageIcon,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
set(hasUserSelectedCommandState, false);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -270,6 +276,8 @@ export const useCommandMenu = () => {
|
|||||||
title: undefined,
|
title: undefined,
|
||||||
Icon: undefined,
|
Icon: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
set(hasUserSelectedCommandState, false);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[copyContextStoreStates],
|
[copyContextStoreStates],
|
||||||
|
|||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { createState } from 'twenty-ui';
|
||||||
|
|
||||||
|
export const hasUserSelectedCommandState = createState({
|
||||||
|
key: 'hasUserSelectedCommandState',
|
||||||
|
defaultValue: false,
|
||||||
|
});
|
||||||
@ -23,8 +23,9 @@ export const SelectableList = ({
|
|||||||
selectableItemIdArray,
|
selectableItemIdArray,
|
||||||
selectableItemIdMatrix,
|
selectableItemIdMatrix,
|
||||||
onEnter,
|
onEnter,
|
||||||
|
onSelect,
|
||||||
}: SelectableListProps) => {
|
}: SelectableListProps) => {
|
||||||
useSelectableListHotKeys(selectableListId, hotkeyScope);
|
useSelectableListHotKeys(selectableListId, hotkeyScope, onSelect);
|
||||||
|
|
||||||
const { setSelectableItemIds, setSelectableListOnEnter, setSelectedItemId } =
|
const { setSelectableItemIds, setSelectableListOnEnter, setSelectedItemId } =
|
||||||
useSelectableList(selectableListId);
|
useSelectableList(selectableListId);
|
||||||
|
|||||||
@ -11,6 +11,7 @@ type Direction = 'up' | 'down' | 'left' | 'right';
|
|||||||
export const useSelectableListHotKeys = (
|
export const useSelectableListHotKeys = (
|
||||||
scopeId: string,
|
scopeId: string,
|
||||||
hotkeyScope: string,
|
hotkeyScope: string,
|
||||||
|
onSelect?: (itemId: string) => void,
|
||||||
) => {
|
) => {
|
||||||
const findPosition = (
|
const findPosition = (
|
||||||
selectableItemIds: string[][],
|
selectableItemIds: string[][],
|
||||||
@ -105,6 +106,7 @@ export const useSelectableListHotKeys = (
|
|||||||
if (isNonEmptyString(nextId)) {
|
if (isNonEmptyString(nextId)) {
|
||||||
set(isSelectedItemIdSelector(nextId), true);
|
set(isSelectedItemIdSelector(nextId), true);
|
||||||
set(selectedItemIdState, nextId);
|
set(selectedItemIdState, nextId);
|
||||||
|
onSelect?.(nextId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNonEmptyString(selectedItemId)) {
|
if (isNonEmptyString(selectedItemId)) {
|
||||||
@ -112,7 +114,12 @@ export const useSelectableListHotKeys = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[isSelectedItemIdSelector, selectableItemIdsState, selectedItemIdState],
|
[
|
||||||
|
isSelectedItemIdSelector,
|
||||||
|
onSelect,
|
||||||
|
selectableItemIdsState,
|
||||||
|
selectedItemIdState,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
useScopedHotkeys(Key.ArrowUp, () => handleSelect('up'), hotkeyScope, []);
|
useScopedHotkeys(Key.ArrowUp, () => handleSelect('up'), hotkeyScope, []);
|
||||||
|
|||||||
Reference in New Issue
Block a user