diff --git a/packages/twenty-front/src/modules/activities/components/ActivityRichTextEditor.tsx b/packages/twenty-front/src/modules/activities/components/ActivityRichTextEditor.tsx index a9fa9a3e27..308d3c561a 100644 --- a/packages/twenty-front/src/modules/activities/components/ActivityRichTextEditor.tsx +++ b/packages/twenty-front/src/modules/activities/components/ActivityRichTextEditor.tsx @@ -344,7 +344,9 @@ export const ActivityRichTextEditor = ({ dependencies: [editor], }); - const handleAllKeys = (keyboardEvent: KeyboardEvent) => { + const focusRichTextEditorWhenFocusOnSidePanel = ( + keyboardEvent: KeyboardEvent, + ) => { if (keyboardEvent.key === Key.Escape) { return; } @@ -378,9 +380,9 @@ export const ActivityRichTextEditor = ({ useHotkeysOnFocusedElement({ keys: '*', - callback: handleAllKeys, + callback: focusRichTextEditorWhenFocusOnSidePanel, focusId: SIDE_PANEL_FOCUS_ID, - dependencies: [handleAllKeys], + dependencies: [focusRichTextEditorWhenFocusOnSidePanel], }); const { labelIdentifierFieldMetadataItem } = @@ -431,7 +433,7 @@ export const ActivityRichTextEditor = ({ focusId: activityId, globalHotkeysConfig: { enableGlobalHotkeysConflictingWithKeyboard: false, - enableGlobalHotkeysWithModifiers: false, + enableGlobalHotkeysWithModifiers: true, }, }); }, diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx index 586106b1d1..f34c230b9c 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx @@ -5,12 +5,16 @@ import { CommandMenuTopBarRightCornerIcon } from '@/command-menu/components/Comm import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight'; import { COMMAND_MENU_SEARCH_BAR_HEIGHT_MOBILE } from '@/command-menu/constants/CommandMenuSearchBarHeightMobile'; import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding'; +import { COMMAND_MENU_SEARCH_INPUT_FOCUS_ID } from '@/command-menu/constants/CommandMenuSearchInputFocusId'; import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { useCommandMenuContextChips } from '@/command-menu/hooks/useCommandMenuContextChips'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages'; +import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; +import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; +import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; @@ -100,6 +104,29 @@ export const CommandMenuTopBar = () => { const { contextChips } = useCommandMenuContextChips(); + const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); + const { removeFocusItemFromFocusStackById } = + useRemoveFocusItemFromFocusStackById(); + + const handleInputFocus = () => { + pushFocusItemToFocusStack({ + focusId: COMMAND_MENU_SEARCH_INPUT_FOCUS_ID, + component: { + type: FocusComponentType.TEXT_INPUT, + instanceId: COMMAND_MENU_SEARCH_INPUT_FOCUS_ID, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); + }; + + const handleInputBlur = () => { + removeFocusItemFromFocusStackById({ + focusId: COMMAND_MENU_SEARCH_INPUT_FOCUS_ID, + }); + }; + const canGoBack = commandMenuNavigationStack.length > 1; const shouldShowCloseButton = @@ -148,11 +175,13 @@ export const CommandMenuTopBar = () => { commandMenuPage === CommandMenuPages.SearchRecords) && ( <> diff --git a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx index c2a2855113..256f811f02 100644 --- a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx @@ -20,6 +20,7 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState'; import { CommandMenuRouter } from '@/command-menu/components/CommandMenuRouter'; import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId'; +import { COMMAND_MENU_SEARCH_INPUT_FOCUS_ID } from '@/command-menu/constants/CommandMenuSearchInputFocusId'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages'; @@ -151,7 +152,9 @@ export const LimitedPermissions: Story = { export const MatchingNavigate: Story = { play: async () => { const canvas = within(document.body); - const searchInput = await canvas.findByTestId('command-menu-search-input'); + const searchInput = await canvas.findByTestId( + COMMAND_MENU_SEARCH_INPUT_FOCUS_ID, + ); await sleep(openTimeout); await userEvent.type(searchInput, 'ta'); expect(await canvas.findByText('Go to Tasks')).toBeVisible(); @@ -161,7 +164,9 @@ export const MatchingNavigate: Story = { export const MatchingNavigateShortcuts: Story = { play: async () => { const canvas = within(document.body); - const searchInput = await canvas.findByTestId('command-menu-search-input'); + const searchInput = await canvas.findByTestId( + COMMAND_MENU_SEARCH_INPUT_FOCUS_ID, + ); await sleep(openTimeout); await userEvent.type(searchInput, 'gp'); expect(await canvas.findByText('Go to People')).toBeVisible(); @@ -186,7 +191,9 @@ export const MatchingNavigateShortcuts: Story = { export const NoResultsSearchFallback: Story = { play: async () => { const canvas = within(document.body); - const searchInput = await canvas.findByTestId('command-menu-search-input'); + const searchInput = await canvas.findByTestId( + COMMAND_MENU_SEARCH_INPUT_FOCUS_ID, + ); await sleep(openTimeout); await userEvent.type(searchInput, 'input without results'); expect(await canvas.findByText('No results found')).toBeVisible(); diff --git a/packages/twenty-front/src/modules/command-menu/constants/CommandMenuSearchInputFocusId.ts b/packages/twenty-front/src/modules/command-menu/constants/CommandMenuSearchInputFocusId.ts new file mode 100644 index 0000000000..35ce16675f --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu/constants/CommandMenuSearchInputFocusId.ts @@ -0,0 +1 @@ +export const COMMAND_MENU_SEARCH_INPUT_FOCUS_ID = 'command-menu-search-input'; diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts index 9c0641b252..8ca678d8bd 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts @@ -2,6 +2,7 @@ import { useRecoilCallback } from 'recoil'; import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; +import { COMMAND_MENU_SEARCH_INPUT_FOCUS_ID } from '@/command-menu/constants/CommandMenuSearchInputFocusId'; import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId'; import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu'; import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState'; @@ -33,6 +34,9 @@ export const useCommandMenu = () => { set(isCommandMenuClosingState, true); set(isDragSelectionStartEnabledState, true); closeAnyOpenDropdown(); + removeFocusItemFromFocusStackById({ + focusId: COMMAND_MENU_SEARCH_INPUT_FOCUS_ID, + }); removeFocusItemFromFocusStackById({ focusId: SIDE_PANEL_FOCUS_ID, });