Fix command menu closing and opening (#10497)

Since I introduced AnimatePresence to animate the exit of the command
menu, the command menu wasn't working properly. By adding this
animation, I had to reset the command menu states at the end of the
animation, otherwise, the component inside the command menu would throw
errors. The problem was that, by closing and instantly reopening the
command menu, the `onExitComplete` wasn't triggered and the states
weren't reset before the opening. By introducing a new state
`isCommandMenuClosingState`, I can reset those states at the beginning
of the opening if the animation didn't have the time to finish.
This commit is contained in:
Raphaël Bosi
2025-02-26 16:52:44 +01:00
committed by GitHub
parent f74e4bedc4
commit d47e5ec47d
2 changed files with 63 additions and 32 deletions

View File

@ -19,6 +19,7 @@ import {
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageTitle';
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
@ -48,42 +49,20 @@ export const useCommandMenu = () => {
const { closeDropdown } = useDropdownV2();
const openCommandMenu = useRecoilCallback(
({ snapshot, set }) =>
() => {
const isCommandMenuOpened = snapshot
.getLoadable(isCommandMenuOpenedState)
.getValue();
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenuOpen);
if (isCommandMenuOpened) {
return;
}
copyContextStoreStates({
instanceIdToCopyFrom: MAIN_CONTEXT_STORE_INSTANCE_ID,
instanceIdToCopyTo: COMMAND_MENU_COMPONENT_INSTANCE_ID,
});
set(isCommandMenuOpenedState, true);
set(hasUserSelectedCommandState, false);
},
[copyContextStoreStates, setHotkeyScopeAndMemorizePreviousScope],
);
const closeCommandMenu = useRecoilCallback(
({ set }) =>
() => {
set(isCommandMenuOpenedState, false);
closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID);
set(isCommandMenuClosingState, true);
},
[closeDropdown],
[],
);
const onCommandMenuCloseAnimationComplete = useRecoilCallback(
({ set }) =>
() => {
closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID);
resetContextStoreStates(COMMAND_MENU_COMPONENT_INSTANCE_ID);
resetContextStoreStates(COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID);
@ -101,8 +80,50 @@ export const useCommandMenu = () => {
goBackToPreviousHotkeyScope();
emitRightDrawerCloseEvent();
set(isCommandMenuClosingState, false);
},
[goBackToPreviousHotkeyScope, resetContextStoreStates, resetSelectedItem],
[
closeDropdown,
goBackToPreviousHotkeyScope,
resetContextStoreStates,
resetSelectedItem,
],
);
const openCommandMenu = useRecoilCallback(
({ snapshot, set }) =>
() => {
const isCommandMenuOpened = snapshot
.getLoadable(isCommandMenuOpenedState)
.getValue();
const isCommandMenuClosing = snapshot
.getLoadable(isCommandMenuClosingState)
.getValue();
if (isCommandMenuClosing) {
onCommandMenuCloseAnimationComplete();
}
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenuOpen);
if (isCommandMenuOpened) {
return;
}
copyContextStoreStates({
instanceIdToCopyFrom: MAIN_CONTEXT_STORE_INSTANCE_ID,
instanceIdToCopyTo: COMMAND_MENU_COMPONENT_INSTANCE_ID,
});
set(isCommandMenuOpenedState, true);
set(hasUserSelectedCommandState, false);
},
[
copyContextStoreStates,
onCommandMenuCloseAnimationComplete,
setHotkeyScopeAndMemorizePreviousScope,
],
);
const navigateCommandMenu = useRecoilCallback(
@ -115,17 +136,21 @@ export const useCommandMenu = () => {
}: CommandMenuNavigationStackItem & {
resetNavigationStack?: boolean;
}) => {
closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID);
openCommandMenu();
set(commandMenuPageState, page);
set(commandMenuPageInfoState, {
title: pageTitle,
Icon: pageIcon,
});
const currentNavigationStack = snapshot
.getLoadable(commandMenuNavigationStackState)
const isCommandMenuClosing = snapshot
.getLoadable(isCommandMenuClosingState)
.getValue();
const currentNavigationStack = isCommandMenuClosing
? []
: snapshot.getLoadable(commandMenuNavigationStackState).getValue();
if (resetNavigationStack) {
set(commandMenuNavigationStackState, [{ page, pageTitle, pageIcon }]);
} else {
@ -134,10 +159,9 @@ export const useCommandMenu = () => {
{ page, pageTitle, pageIcon },
]);
}
openCommandMenu();
};
},
[closeDropdown, openCommandMenu],
[openCommandMenu],
);
const openRootCommandMenu = useCallback(() => {
@ -259,6 +283,7 @@ export const useCommandMenu = () => {
? t`New ${capitalizedObjectNameSingular}`
: capitalizedObjectNameSingular,
pageIcon: Icon,
// TODO: remove this once we can store the navigation stack page states
resetNavigationStack: true,
});
};

View File

@ -0,0 +1,6 @@
import { createState } from 'twenty-ui';
export const isCommandMenuClosingState = createState({
key: 'command-menu/isCommandMenuClosingState',
defaultValue: false,
});