Fix command menu focus (#16264)
CommandMenu did not push its own focus item to the focus stack when focused. (See NavigationDrawerInput) --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@@ -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,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@@ -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) && (
|
||||
<>
|
||||
<StyledInput
|
||||
data-testid="command-menu-search-input"
|
||||
data-testid={COMMAND_MENU_SEARCH_INPUT_FOCUS_ID}
|
||||
ref={inputRef}
|
||||
value={commandMenuSearch}
|
||||
placeholder={t`Type anything...`}
|
||||
onChange={handleSearchChange}
|
||||
onFocus={handleInputFocus}
|
||||
onBlur={handleInputBlur}
|
||||
/>
|
||||
<CommandMenuTopBarInputFocusEffect inputRef={inputRef} />
|
||||
</>
|
||||
|
||||
+10
-3
@@ -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();
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
export const COMMAND_MENU_SEARCH_INPUT_FOCUS_ID = 'command-menu-search-input';
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user