Replace hotkey scopes by focus stack (Part 1 - Dropdowns and Side Panel) (#12673)
This PR is the first part of a refactoring aiming to deprecate the hotkey scopes api in favor of the new focus stack api which is more robust. The refactored components in this PR are the dropdowns and the side panel/command menu. - Replaced `useScopedHotkeys` by `useHotkeysOnFocusedElement` for all dropdown components, selectable lists and the command menu - Introduced `focusId` for all dropdowns and created a common hotkey scope `DropdownHotkeyScope` for backward compatibility - Replaced `setHotkeyScopeAndMemorizePreviousScope` occurrences with `usePushFocusItemToFocusStack` and `goBackToPreviousHotkeyScope` with `removeFocusItemFromFocusStack` Note: Test that the shorcuts and arrow key navigation still work properly when interacting with dropdowns and the command menu. Bugs that I have spotted during the QA but which are already present on main: - Icon picker select with arrow keys doesn’t work inside dropdowns - Some dropdowns are not selectable with arrow keys (no selectable list) - Dropdowns in dropdowns don’t reset the hotkey scope correctly when closing - The table click outside is not triggered after closing a table cell and clicking outside of the table
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||
import { Key } from 'ts-key-enum';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
@ -13,12 +14,13 @@ export const CmdEnterActionButton = ({
|
||||
onClick: () => void;
|
||||
disabled?: boolean;
|
||||
}) => {
|
||||
useScopedHotkeys(
|
||||
[`${Key.Control}+${Key.Enter}`, `${Key.Meta}+${Key.Enter}`],
|
||||
() => onClick(),
|
||||
AppHotkeyScope.CommandMenuOpen,
|
||||
[onClick],
|
||||
);
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: [`${Key.Control}+${Key.Enter}`, `${Key.Meta}+${Key.Enter}`],
|
||||
callback: () => onClick(),
|
||||
focusId: SIDE_PANEL_FOCUS_ID,
|
||||
scope: AppHotkeyScope.CommandMenuOpen,
|
||||
dependencies: [onClick],
|
||||
});
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
||||
@ -2,15 +2,16 @@ import { ActionComponent } from '@/action-menu/actions/display/components/Action
|
||||
import { ActionScope } from '@/action-menu/actions/types/ActionScope';
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { CommandMenuActionMenuDropdownHotkeyScope } from '@/action-menu/types/CommandMenuActionMenuDropdownHotkeyScope';
|
||||
import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId';
|
||||
import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useTheme } from '@emotion/react';
|
||||
@ -25,24 +26,30 @@ export const CommandMenuActionMenuDropdown = () => {
|
||||
ActionMenuComponentInstanceContext,
|
||||
);
|
||||
|
||||
const { toggleDropdown } = useDropdownV2();
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
useScopedHotkeys(
|
||||
['ctrl+o,meta+o'],
|
||||
() => {
|
||||
toggleDropdown(
|
||||
getRightDrawerActionMenuDropdownIdFromActionMenuId(actionMenuId),
|
||||
{
|
||||
scope:
|
||||
CommandMenuActionMenuDropdownHotkeyScope.CommandMenuActionMenuDropdown,
|
||||
},
|
||||
);
|
||||
const dropdownId =
|
||||
getRightDrawerActionMenuDropdownIdFromActionMenuId(actionMenuId);
|
||||
const { toggleDropdown } = useDropdownV2();
|
||||
|
||||
const hotkeysConfig = {
|
||||
keys: ['ctrl+o', 'meta+o'],
|
||||
callback: () => {
|
||||
toggleDropdown(dropdownId);
|
||||
},
|
||||
AppHotkeyScope.CommandMenuOpen,
|
||||
[toggleDropdown],
|
||||
);
|
||||
scope: AppHotkeyScope.CommandMenuOpen,
|
||||
dependencies: [toggleDropdown],
|
||||
};
|
||||
|
||||
useHotkeysOnFocusedElement({
|
||||
...hotkeysConfig,
|
||||
focusId: SIDE_PANEL_FOCUS_ID,
|
||||
});
|
||||
|
||||
useHotkeysOnFocusedElement({
|
||||
...hotkeysConfig,
|
||||
focusId: dropdownId,
|
||||
});
|
||||
|
||||
const recordSelectionActions = actions.filter(
|
||||
(action) => action.scope === ActionScope.RecordSelection,
|
||||
@ -56,19 +63,17 @@ export const CommandMenuActionMenuDropdown = () => {
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={getRightDrawerActionMenuDropdownIdFromActionMenuId(
|
||||
actionMenuId,
|
||||
)}
|
||||
dropdownHotkeyScope={{
|
||||
scope:
|
||||
CommandMenuActionMenuDropdownHotkeyScope.CommandMenuActionMenuDropdown,
|
||||
}}
|
||||
dropdownId={dropdownId}
|
||||
data-select-disable
|
||||
clickableComponent={
|
||||
<Button title="Options" hotkeys={[getOsControlSymbol(), 'O']} />
|
||||
}
|
||||
dropdownPlacement="top-end"
|
||||
dropdownOffset={{ y: parseInt(theme.spacing(2), 10) }}
|
||||
globalHotkeysConfig={{
|
||||
enableGlobalHotkeysWithModifiers: true,
|
||||
enableGlobalHotkeysConflictingWithKeyboard: false,
|
||||
}}
|
||||
onOpen={() => {
|
||||
setSelectedItemId(selectableItemIdArray[0]);
|
||||
}}
|
||||
@ -77,10 +82,9 @@ export const CommandMenuActionMenuDropdown = () => {
|
||||
<DropdownMenuItemsContainer>
|
||||
<SelectableList
|
||||
selectableListInstanceId={actionMenuId}
|
||||
hotkeyScope={
|
||||
CommandMenuActionMenuDropdownHotkeyScope.CommandMenuActionMenuDropdown
|
||||
}
|
||||
focusId={dropdownId}
|
||||
selectableItemIdArray={selectableItemIdArray}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
{recordSelectionActions.map((action) => (
|
||||
<ActionComponent action={action} key={action.key} />
|
||||
|
||||
@ -5,12 +5,12 @@ import { ACTION_MENU_DROPDOWN_CLICK_OUTSIDE_ID } from '@/action-menu/constants/A
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState';
|
||||
import { ActionMenuDropdownHotkeyScope } from '@/action-menu/types/ActionMenuDropdownHotKeyScope';
|
||||
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
@ -72,9 +72,6 @@ export const RecordIndexActionMenuDropdown = () => {
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={dropdownId}
|
||||
dropdownHotkeyScope={{
|
||||
scope: ActionMenuDropdownHotkeyScope.ActionMenuDropdown,
|
||||
}}
|
||||
data-select-disable
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownStrategy="absolute"
|
||||
@ -89,9 +86,10 @@ export const RecordIndexActionMenuDropdown = () => {
|
||||
>
|
||||
<DropdownMenuItemsContainer>
|
||||
<SelectableList
|
||||
hotkeyScope={ActionMenuDropdownHotkeyScope.ActionMenuDropdown}
|
||||
focusId={dropdownId}
|
||||
selectableItemIdArray={selectedItemIdArray}
|
||||
selectableListInstanceId={dropdownId}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
{recordIndexActions.map((action) => (
|
||||
<ActionComponent action={action} key={action.key} />
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId';
|
||||
import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
@ -11,7 +12,7 @@ import { AppPath } from '@/types/AppPath';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||
@ -118,12 +119,13 @@ export const RecordShowRightDrawerOpenRecordButton = ({
|
||||
],
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
['ctrl+Enter,meta+Enter'],
|
||||
handleOpenRecord,
|
||||
AppHotkeyScope.CommandMenuOpen,
|
||||
[handleOpenRecord],
|
||||
);
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: ['ctrl+Enter,meta+Enter'],
|
||||
callback: handleOpenRecord,
|
||||
focusId: SIDE_PANEL_FOCUS_ID,
|
||||
scope: AppHotkeyScope.CommandMenuOpen,
|
||||
dependencies: [handleOpenRecord],
|
||||
});
|
||||
|
||||
if (!isDefined(record)) {
|
||||
return null;
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
export enum ActionMenuDropdownHotkeyScope {
|
||||
ActionMenuDropdown = 'action-menu-dropdown',
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
export enum CommandMenuActionMenuDropdownHotkeyScope {
|
||||
CommandMenuActionMenuDropdown = 'command-menu-action-menu-dropdown',
|
||||
}
|
||||
@ -72,7 +72,6 @@ export const AttachmentDropdown = ({
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -70,6 +70,7 @@ export const ActivityTargetsInlineCell = ({
|
||||
labelWidth: fieldDefinition?.labelWidth,
|
||||
editModeContent: (
|
||||
<MultipleRecordPicker
|
||||
focusId={componentInstanceId}
|
||||
componentInstanceId={componentInstanceId}
|
||||
onClickOutside={() => {
|
||||
closeInlineCell();
|
||||
|
||||
@ -5,8 +5,9 @@ import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-pic
|
||||
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
||||
import { multipleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState';
|
||||
import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState';
|
||||
import { MultipleRecordPickerHotkeyScope } from '@/object-record/record-picker/multiple-record-picker/types/MultipleRecordPickerHotkeyScope';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
type OpenActivityTargetCellEditModeProps = {
|
||||
@ -19,7 +20,7 @@ export const useOpenActivityTargetCellEditMode = () => {
|
||||
const { performSearch: multipleRecordPickerPerformSearch } =
|
||||
useMultipleRecordPickerPerformSearch();
|
||||
|
||||
const { setHotkeyScopeAndMemorizePreviousScope } = usePreviousHotkeyScope();
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
|
||||
const openActivityTargetCellEditMode = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
@ -84,11 +85,19 @@ export const useOpenActivityTargetCellEditMode = () => {
|
||||
),
|
||||
});
|
||||
|
||||
setHotkeyScopeAndMemorizePreviousScope({
|
||||
scope: MultipleRecordPickerHotkeyScope.MultipleRecordPicker,
|
||||
pushFocusItemToFocusStack({
|
||||
focusId: recordPickerInstanceId,
|
||||
component: {
|
||||
type: FocusComponentType.DROPDOWN,
|
||||
instanceId: recordPickerInstanceId,
|
||||
},
|
||||
hotkeyScope: {
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
},
|
||||
memoizeKey: recordPickerInstanceId,
|
||||
});
|
||||
},
|
||||
[multipleRecordPickerPerformSearch, setHotkeyScopeAndMemorizePreviousScope],
|
||||
[multipleRecordPickerPerformSearch, pushFocusItemToFocusStack],
|
||||
);
|
||||
|
||||
return { openActivityTargetCellEditMode };
|
||||
|
||||
@ -3,7 +3,6 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
import {
|
||||
@ -72,9 +71,6 @@ export const CommandMenuContextChipGroups = ({
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{
|
||||
scope: AppHotkeyScope.CommandMenu,
|
||||
}}
|
||||
dropdownId={COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID}
|
||||
dropdownPlacement="bottom-start"
|
||||
></Dropdown>
|
||||
|
||||
@ -4,6 +4,7 @@ import { ActionGroupConfig } from '@/command-menu/components/CommandMenu';
|
||||
import { CommandMenuDefaultSelectionEffect } from '@/command-menu/components/CommandMenuDefaultSelectionEffect';
|
||||
import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight';
|
||||
import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding';
|
||||
import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId';
|
||||
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||
@ -75,8 +76,9 @@ export const CommandMenuList = ({
|
||||
<StyledInnerList>
|
||||
<SelectableList
|
||||
selectableListInstanceId="command-menu-list"
|
||||
hotkeyScope={AppHotkeyScope.CommandMenuOpen}
|
||||
focusId={SIDE_PANEL_FOCUS_ID}
|
||||
selectableItemIdArray={selectableItemIds}
|
||||
hotkeyScope={AppHotkeyScope.CommandMenuOpen}
|
||||
onSelect={() => {
|
||||
setHasUserSelectedCommand(true);
|
||||
}}
|
||||
|
||||
@ -0,0 +1 @@
|
||||
export const SIDE_PANEL_FOCUS_ID = 'command-menu';
|
||||
@ -3,12 +3,13 @@ import { useRecoilCallback } from 'recoil';
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId';
|
||||
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
|
||||
import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown';
|
||||
import { isDragSelectionStartEnabledState } from '@/ui/utilities/drag-select/states/internal/isDragSelectionStartEnabledState';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { useRemoveFocusItemFromFocusStack } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStack';
|
||||
import { useCallback } from 'react';
|
||||
import { IconDotsVertical } from 'twenty-ui/display';
|
||||
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
||||
@ -16,7 +17,8 @@ import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
||||
export const useCommandMenu = () => {
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown();
|
||||
const { goBackToPreviousHotkeyScope } = usePreviousHotkeyScope();
|
||||
|
||||
const { removeFocusItemFromFocusStack } = useRemoveFocusItemFromFocusStack();
|
||||
|
||||
const closeCommandMenu = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
@ -30,10 +32,13 @@ export const useCommandMenu = () => {
|
||||
set(isCommandMenuClosingState, true);
|
||||
set(isDragSelectionStartEnabledState, true);
|
||||
closeAnyOpenDropdown();
|
||||
goBackToPreviousHotkeyScope(COMMAND_MENU_COMPONENT_INSTANCE_ID);
|
||||
removeFocusItemFromFocusStack({
|
||||
focusId: SIDE_PANEL_FOCUS_ID,
|
||||
memoizeKey: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
});
|
||||
}
|
||||
},
|
||||
[closeAnyOpenDropdown, goBackToPreviousHotkeyScope],
|
||||
[closeAnyOpenDropdown, removeFocusItemFromFocusStack],
|
||||
);
|
||||
|
||||
const openCommandMenu = useCallback(() => {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId';
|
||||
import { useCommandMenuCloseAnimationCompleteCleanup } from '@/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup';
|
||||
import { useCopyContextStoreStates } from '@/command-menu/hooks/useCopyContextStoreAndActionMenuStates';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
@ -13,7 +14,8 @@ import { CommandMenuHotkeyScope } from '@/command-menu/types/CommandMenuHotkeySc
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { isDragSelectionStartEnabledState } from '@/ui/utilities/drag-select/states/internal/isDragSelectionStartEnabledState';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { IconComponent } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
@ -27,13 +29,13 @@ export type CommandMenuNavigationStackItem = {
|
||||
};
|
||||
|
||||
export const useNavigateCommandMenu = () => {
|
||||
const { setHotkeyScopeAndMemorizePreviousScope } = usePreviousHotkeyScope();
|
||||
|
||||
const { copyContextStoreStates } = useCopyContextStoreStates();
|
||||
|
||||
const { commandMenuCloseAnimationCompleteCleanup } =
|
||||
useCommandMenuCloseAnimationCompleteCleanup();
|
||||
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
|
||||
const openCommandMenu = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
() => {
|
||||
@ -53,10 +55,17 @@ export const useNavigateCommandMenu = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
setHotkeyScopeAndMemorizePreviousScope({
|
||||
scope: CommandMenuHotkeyScope.CommandMenuFocused,
|
||||
customScopes: {
|
||||
commandMenuOpen: true,
|
||||
pushFocusItemToFocusStack({
|
||||
focusId: SIDE_PANEL_FOCUS_ID,
|
||||
component: {
|
||||
type: FocusComponentType.SIDE_PANEL,
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
},
|
||||
hotkeyScope: {
|
||||
scope: CommandMenuHotkeyScope.CommandMenuFocused,
|
||||
customScopes: {
|
||||
commandMenuOpen: true,
|
||||
},
|
||||
},
|
||||
memoizeKey: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
});
|
||||
@ -73,7 +82,7 @@ export const useNavigateCommandMenu = () => {
|
||||
[
|
||||
copyContextStoreStates,
|
||||
commandMenuCloseAnimationCompleteCleanup,
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
pushFocusItemToFocusStack,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { FavoriteFolderHotkeyScope } from '@/favorites/constants/FavoriteFolderRightIconDropdownHotkeyScope';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
@ -33,9 +32,6 @@ export const FavoriteFolderNavigationDrawerItemDropdown = ({
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={`favorite-folder-edit-${folderId}`}
|
||||
dropdownHotkeyScope={{
|
||||
scope: FavoriteFolderHotkeyScope.FavoriteFolderRightIconDropdown,
|
||||
}}
|
||||
data-select-disable
|
||||
clickableComponent={
|
||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||
|
||||
@ -9,7 +9,8 @@ import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
|
||||
@ -57,22 +58,23 @@ export const FavoriteFolderPicker = ({
|
||||
!favoriteFoldersSearchFilter ||
|
||||
'no folder'.includes(favoriteFoldersSearchFilter.toLowerCase());
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
() => {
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: [Key.Escape],
|
||||
callback: () => {
|
||||
if (isFavoriteFolderCreating) {
|
||||
setIsFavoriteFolderCreating(false);
|
||||
return;
|
||||
}
|
||||
onSubmit?.();
|
||||
},
|
||||
instanceId,
|
||||
[onSubmit, isFavoriteFolderCreating],
|
||||
);
|
||||
focusId: dropdownId,
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
dependencies: [onSubmit, isFavoriteFolderCreating],
|
||||
});
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Enter,
|
||||
() => {
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: [Key.Enter],
|
||||
callback: () => {
|
||||
if (filteredFolders.length === 1 && !showNoFolderOption) {
|
||||
toggleFolderSelection(filteredFolders[0].id);
|
||||
onSubmit?.();
|
||||
@ -85,9 +87,15 @@ export const FavoriteFolderPicker = ({
|
||||
return;
|
||||
}
|
||||
},
|
||||
instanceId,
|
||||
[filteredFolders, showNoFolderOption, toggleFolderSelection, onSubmit],
|
||||
);
|
||||
focusId: instanceId,
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
dependencies: [
|
||||
filteredFolders,
|
||||
showNoFolderOption,
|
||||
toggleFolderSelection,
|
||||
onSubmit,
|
||||
],
|
||||
});
|
||||
|
||||
return (
|
||||
<DropdownContent>
|
||||
|
||||
@ -180,7 +180,6 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
dropdownOffset={{ y: 8, x: 0 }}
|
||||
dropdownPlacement="bottom-start"
|
||||
/>
|
||||
|
||||
@ -22,7 +22,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
type AdvancedFilterDropdownFilterInputProps = {
|
||||
filterDropdownId?: string;
|
||||
filterDropdownId: string;
|
||||
recordFilter: RecordFilter;
|
||||
};
|
||||
|
||||
@ -57,12 +57,15 @@ export const AdvancedFilterDropdownFilterInput = ({
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||
<ObjectFilterDropdownSearchInput />
|
||||
<DropdownMenuSeparator />
|
||||
<ObjectFilterDropdownRecordSelect recordFilterId={recordFilter.id} />
|
||||
<ObjectFilterDropdownRecordSelect
|
||||
recordFilterId={recordFilter.id}
|
||||
dropdownId={filterDropdownId}
|
||||
/>
|
||||
</DropdownContent>
|
||||
)}
|
||||
{filterType === 'ACTOR' &&
|
||||
(isActorSourceCompositeFilter ? (
|
||||
<ObjectFilterDropdownSourceSelect />
|
||||
<ObjectFilterDropdownSourceSelect dropdownId={filterDropdownId} />
|
||||
) : (
|
||||
<ObjectFilterDropdownTextInput />
|
||||
))}
|
||||
@ -70,7 +73,7 @@ export const AdvancedFilterDropdownFilterInput = ({
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||
<ObjectFilterDropdownSearchInput />
|
||||
<DropdownMenuSeparator />
|
||||
<ObjectFilterDropdownOptionSelect />
|
||||
<ObjectFilterDropdownOptionSelect focusId={filterDropdownId} />
|
||||
</DropdownContent>
|
||||
)}
|
||||
{filterType === 'BOOLEAN' && <ObjectFilterDropdownBooleanSelect />}
|
||||
|
||||
@ -34,7 +34,6 @@ export const AdvancedFilterFieldSelectDropdownButton = ({
|
||||
recordFilterId={recordFilterId}
|
||||
/>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: advancedFilterFieldSelectDropdownId }}
|
||||
dropdownOffset={DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET}
|
||||
dropdownPlacement="bottom-start"
|
||||
/>
|
||||
|
||||
@ -23,6 +23,7 @@ import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/uti
|
||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
@ -144,9 +145,10 @@ export const AdvancedFilterFieldSelectMenu = ({
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||
<AdvancedFilterFieldSelectSearchInput />
|
||||
<SelectableList
|
||||
hotkeyScope={advancedFilterFieldSelectDropdownId}
|
||||
focusId={advancedFilterFieldSelectDropdownId}
|
||||
selectableItemIdArray={selectableItemIdArray}
|
||||
selectableListInstanceId={advancedFilterFieldSelectDropdownId}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
{shouldShowVisibleFields && (
|
||||
<>
|
||||
|
||||
@ -65,7 +65,6 @@ export const AdvancedFilterRecordFilterGroupOptionsDropdown = ({
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
dropdownOffset={{ y: 2, x: 0 }}
|
||||
dropdownPlacement="bottom-start"
|
||||
/>
|
||||
|
||||
@ -8,6 +8,7 @@ import { SelectControl } from '@/ui/input/components/SelectControl';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
@ -63,11 +64,12 @@ export const AdvancedFilterRecordFilterOperandSelectContent = ({
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.Narrow}>
|
||||
<DropdownMenuItemsContainer>
|
||||
<SelectableList
|
||||
hotkeyScope={dropdownId}
|
||||
focusId={dropdownId}
|
||||
selectableItemIdArray={operandsForFilterType.map(
|
||||
(operand) => operand,
|
||||
)}
|
||||
selectableListInstanceId={dropdownId}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
{operandsForFilterType.map((filterOperand, index) => (
|
||||
<SelectableListItem
|
||||
@ -90,7 +92,6 @@ export const AdvancedFilterRecordFilterOperandSelectContent = ({
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
dropdownOffset={DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET}
|
||||
dropdownPlacement="bottom-start"
|
||||
/>
|
||||
|
||||
@ -85,7 +85,6 @@ export const AdvancedFilterRecordFilterOptionsDropdown = ({
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
dropdownOffset={DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET}
|
||||
dropdownPlacement="bottom-start"
|
||||
/>
|
||||
|
||||
@ -18,6 +18,7 @@ import { CompositeFieldSubFieldName } from '@/settings/data-model/types/Composit
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
@ -124,9 +125,10 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
||||
</DropdownMenuHeader>
|
||||
<DropdownMenuItemsContainer>
|
||||
<SelectableList
|
||||
hotkeyScope={advancedFilterFieldSelectDropdownId}
|
||||
focusId={advancedFilterFieldSelectDropdownId}
|
||||
selectableItemIdArray={selectableItemIdArray}
|
||||
selectableListInstanceId={advancedFilterFieldSelectDropdownId}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
{compositeFieldTypeIsFilterableByAnySubField && (
|
||||
<SelectableListItem
|
||||
|
||||
@ -104,9 +104,11 @@ export const AdvancedFilterValueInput = ({
|
||||
/>
|
||||
}
|
||||
dropdownComponents={
|
||||
<AdvancedFilterDropdownFilterInput recordFilter={recordFilter} />
|
||||
<AdvancedFilterDropdownFilterInput
|
||||
recordFilter={recordFilter}
|
||||
filterDropdownId={dropdownId}
|
||||
/>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
dropdownOffset={dropdownContentOffset}
|
||||
dropdownPlacement="bottom-start"
|
||||
onClose={handleFilterValueDropdownClose}
|
||||
|
||||
@ -13,10 +13,10 @@ import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { getDefaultSubFieldNameForCompositeFilterableFieldType } from '@/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType';
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { isCompositeTypeNonFilterableByAnySubField } from '@/object-record/record-filter/utils/isCompositeTypeNonFilterableByAnySubField';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
||||
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@ -44,7 +44,7 @@ export const useSelectFieldUsedInAdvancedFilterDropdown = () => {
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
|
||||
const { getFieldMetadataItemById } = useGetFieldMetadataItemById();
|
||||
|
||||
@ -76,7 +76,17 @@ export const useSelectFieldUsedInAdvancedFilterDropdown = () => {
|
||||
fieldMetadataItem.type === 'RELATION' ||
|
||||
fieldMetadataItem.type === 'SELECT'
|
||||
) {
|
||||
setHotkeyScope(SingleRecordPickerHotkeyScope.SingleRecordPicker);
|
||||
pushFocusItemToFocusStack({
|
||||
focusId: fieldMetadataItem.id,
|
||||
component: {
|
||||
type: FocusComponentType.DROPDOWN,
|
||||
instanceId: fieldMetadataItem.id,
|
||||
},
|
||||
hotkeyScope: {
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
},
|
||||
memoizeKey: fieldMetadataItem.id,
|
||||
});
|
||||
}
|
||||
|
||||
const filterType = getFilterTypeFromFieldType(fieldMetadataItem.type);
|
||||
|
||||
@ -3,10 +3,10 @@ import styled from '@emotion/styled';
|
||||
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { BooleanDisplay } from '@/ui/field/display/components/BooleanDisplay';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
@ -57,7 +57,8 @@ export const ObjectFilterDropdownBooleanSelect = () => {
|
||||
<SelectableList
|
||||
selectableListInstanceId="boolean-select"
|
||||
selectableItemIdArray={options.map((option) => option.toString())}
|
||||
hotkeyScope={SingleRecordPickerHotkeyScope.SingleRecordPicker}
|
||||
focusId="boolean-select"
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
{options.map((option) => (
|
||||
|
||||
@ -25,7 +25,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type ObjectFilterDropdownFilterInputProps = {
|
||||
filterDropdownId?: string;
|
||||
filterDropdownId: string;
|
||||
recordFilterId?: string;
|
||||
};
|
||||
|
||||
@ -113,7 +113,10 @@ export const ObjectFilterDropdownFilterInput = ({
|
||||
<>
|
||||
<ObjectFilterDropdownSearchInput />
|
||||
<DropdownMenuSeparator />
|
||||
<ObjectFilterDropdownRecordSelect recordFilterId={recordFilterId} />
|
||||
<ObjectFilterDropdownRecordSelect
|
||||
recordFilterId={recordFilterId}
|
||||
dropdownId={filterDropdownId}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{filterType === 'ACTOR' && <ObjectFilterDropdownTextInput />}
|
||||
@ -123,7 +126,7 @@ export const ObjectFilterDropdownFilterInput = ({
|
||||
<>
|
||||
<ObjectFilterDropdownSearchInput />
|
||||
<DropdownMenuSeparator />
|
||||
<ObjectFilterDropdownOptionSelect />
|
||||
<ObjectFilterDropdownOptionSelect focusId={filterDropdownId} />
|
||||
</>
|
||||
)}
|
||||
{filterType === 'BOOLEAN' && <ObjectFilterDropdownBooleanSelect />}
|
||||
|
||||
@ -3,7 +3,6 @@ import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenu
|
||||
import { ObjectFilterDropdownOperandSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
|
||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { ClickOutsideListenerContext } from '@/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
@ -47,9 +46,6 @@ export const ObjectFilterDropdownOperandDropdown = ({
|
||||
</StyledDropdownMenuHeader>
|
||||
}
|
||||
dropdownComponents={<ObjectFilterDropdownOperandSelect />}
|
||||
dropdownHotkeyScope={{
|
||||
scope: FiltersHotkeyScope.ObjectFilterDropdownOperandDropdown,
|
||||
}}
|
||||
dropdownOffset={{ x: parseInt(theme.spacing(2), 10) }}
|
||||
/>
|
||||
</ClickOutsideListenerContext.Provider>
|
||||
|
||||
@ -14,9 +14,9 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/ob
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
@ -30,7 +30,11 @@ type SelectOptionForFilter = FieldMetadataItemOption & {
|
||||
isSelected: boolean;
|
||||
};
|
||||
|
||||
export const ObjectFilterDropdownOptionSelect = () => {
|
||||
export const ObjectFilterDropdownOptionSelect = ({
|
||||
focusId,
|
||||
}: {
|
||||
focusId: string;
|
||||
}) => {
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
@ -92,15 +96,16 @@ export const ObjectFilterDropdownOptionSelect = () => {
|
||||
}
|
||||
}, [selectedOptions, selectOptions]);
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
() => {
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: [Key.Escape],
|
||||
callback: () => {
|
||||
closeDropdown();
|
||||
resetSelectedItem();
|
||||
},
|
||||
SingleRecordPickerHotkeyScope.SingleRecordPicker,
|
||||
[closeDropdown, resetSelectedItem],
|
||||
);
|
||||
focusId,
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
dependencies: [closeDropdown, resetSelectedItem],
|
||||
});
|
||||
|
||||
const handleMultipleOptionSelectChange = (
|
||||
optionChanged: SelectOptionForFilter,
|
||||
@ -148,7 +153,8 @@ export const ObjectFilterDropdownOptionSelect = () => {
|
||||
<SelectableList
|
||||
selectableListInstanceId={componentInstanceId}
|
||||
selectableItemIdArray={objectRecordsIds}
|
||||
hotkeyScope={SingleRecordPickerHotkeyScope.SingleRecordPicker}
|
||||
focusId={focusId}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
{showNoResult ? (
|
||||
|
||||
@ -8,7 +8,6 @@ import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-recor
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { MultipleSelectDropdown } from '@/object-record/select/components/MultipleSelectDropdown';
|
||||
import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect';
|
||||
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
||||
@ -29,10 +28,12 @@ export const MAX_RECORDS_TO_DISPLAY = 3;
|
||||
|
||||
type ObjectFilterDropdownRecordSelectProps = {
|
||||
recordFilterId?: string;
|
||||
dropdownId: string;
|
||||
};
|
||||
|
||||
export const ObjectFilterDropdownRecordSelect = ({
|
||||
recordFilterId,
|
||||
dropdownId,
|
||||
}: ObjectFilterDropdownRecordSelectProps) => {
|
||||
const fieldMetadataItemUsedInFilterDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
@ -220,7 +221,7 @@ export const ObjectFilterDropdownRecordSelect = ({
|
||||
)}
|
||||
<MultipleSelectDropdown
|
||||
selectableListId="object-filter-record-select-id"
|
||||
hotkeyScope={SingleRecordPickerHotkeyScope.SingleRecordPicker}
|
||||
focusId={dropdownId}
|
||||
itemsToSelect={recordsToSelect}
|
||||
filteredSelectedItems={filteredSelectedRecords}
|
||||
selectedItems={selectedRecords}
|
||||
|
||||
@ -3,7 +3,6 @@ import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-recor
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { getActorSourceMultiSelectOptions } from '@/object-record/object-filter-dropdown/utils/getActorSourceMultiSelectOptions';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { MultipleSelectDropdown } from '@/object-record/select/components/MultipleSelectDropdown';
|
||||
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
@ -15,7 +14,11 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
export const EMPTY_FILTER_VALUE = '[]';
|
||||
export const MAX_ITEMS_TO_DISPLAY = 3;
|
||||
|
||||
export const ObjectFilterDropdownSourceSelect = () => {
|
||||
export const ObjectFilterDropdownSourceSelect = ({
|
||||
dropdownId,
|
||||
}: {
|
||||
dropdownId: string;
|
||||
}) => {
|
||||
const objectFilterDropdownSearchInput = useRecoilComponentValueV2(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
);
|
||||
@ -78,7 +81,7 @@ export const ObjectFilterDropdownSourceSelect = () => {
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||
<MultipleSelectDropdown
|
||||
selectableListId="object-filter-source-select-id"
|
||||
hotkeyScope={SingleRecordPickerHotkeyScope.SingleRecordPicker}
|
||||
focusId={dropdownId}
|
||||
itemsToSelect={sourceTypes.filter(
|
||||
(item) =>
|
||||
!filteredSelectedItems.some((selected) => selected.id === item.id),
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
export enum FiltersHotkeyScope {
|
||||
ObjectFilterDropdownButton = 'filter-dropdown-button',
|
||||
ObjectSortDropdownButton = 'sort-dropdown-button',
|
||||
ObjectFilterDropdownOperandDropdown = 'filter-dropdown-operand-dropdown',
|
||||
}
|
||||
@ -7,7 +7,6 @@ import { ObjectOptionsDropdownContext } from '@/object-record/object-options-dro
|
||||
import { ObjectOptionsContentId } from '@/object-record/object-options-dropdown/types/ObjectOptionsContentId';
|
||||
import { RecordGroupReorderConfirmationModal } from '@/object-record/record-group/components/RecordGroupReorderConfirmationModal';
|
||||
import { useRecordGroupReorderConfirmationModal } from '@/object-record/record-group/hooks/useRecordGroupReorderConfirmationModal';
|
||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
@ -40,7 +39,6 @@ export const ObjectOptionsDropdown = ({
|
||||
<>
|
||||
<Dropdown
|
||||
dropdownId={OBJECT_OPTIONS_DROPDOWN_ID}
|
||||
dropdownHotkeyScope={{ scope: TableOptionsHotkeyScope.Dropdown }}
|
||||
dropdownOffset={{ y: DROPDOWN_OFFSET_Y }}
|
||||
clickableComponent={
|
||||
<StyledHeaderDropdownButton isUnfolded={isDropdownOpen}>
|
||||
|
||||
@ -4,12 +4,12 @@ import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hook
|
||||
import { useSetViewTypeFromLayoutOptionsMenu } from '@/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
@ -108,8 +108,9 @@ export const ObjectOptionsDropdownLayoutContent = () => {
|
||||
{!!currentView && (
|
||||
<SelectableList
|
||||
selectableListInstanceId={OBJECT_OPTIONS_DROPDOWN_ID}
|
||||
hotkeyScope={TableOptionsHotkeyScope.Dropdown}
|
||||
focusId={OBJECT_OPTIONS_DROPDOWN_ID}
|
||||
selectableItemIdArray={selectableItemIdArray}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
<DropdownMenuItemsContainer scrollable={false}>
|
||||
<SelectableListItem
|
||||
|
||||
@ -2,11 +2,11 @@ import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropd
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { useUpdateObjectViewOptions } from '@/object-record/object-options-dropdown/hooks/useUpdateObjectViewOptions';
|
||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
@ -53,8 +53,9 @@ export const ObjectOptionsDropdownLayoutOpenInContent = () => {
|
||||
<DropdownMenuItemsContainer>
|
||||
<SelectableList
|
||||
selectableListInstanceId={OBJECT_OPTIONS_DROPDOWN_ID}
|
||||
hotkeyScope={TableOptionsHotkeyScope.Dropdown}
|
||||
focusId={OBJECT_OPTIONS_DROPDOWN_ID}
|
||||
selectableItemIdArray={selectableItemIdArray}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
<SelectableListItem
|
||||
itemId={ViewOpenRecordInType.SIDE_PANEL}
|
||||
|
||||
@ -1,20 +1,17 @@
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { ObjectOptionsDropdownMenuViewName } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuViewName';
|
||||
import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
|
||||
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
@ -48,14 +45,6 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
||||
(isDefined(currentView?.viewGroups) && currentView.viewGroups.length > 0) ||
|
||||
currentView?.key !== 'INDEX';
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
() => {
|
||||
closeDropdown();
|
||||
},
|
||||
TableOptionsHotkeyScope.Dropdown,
|
||||
);
|
||||
|
||||
const { visibleBoardFields } = useObjectOptionsForBoard({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
recordBoardId: recordIndexId,
|
||||
@ -101,8 +90,9 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
||||
<DropdownMenuSeparator />
|
||||
<SelectableList
|
||||
selectableListInstanceId={OBJECT_OPTIONS_DROPDOWN_ID}
|
||||
hotkeyScope={TableOptionsHotkeyScope.Dropdown}
|
||||
focusId={OBJECT_OPTIONS_DROPDOWN_ID}
|
||||
selectableItemIdArray={selectableItemIdArray}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
<DropdownMenuItemsContainer scrollable={false}>
|
||||
<SelectableListItem
|
||||
|
||||
@ -4,12 +4,13 @@ import { useUpdateObjectViewOptions } from '@/object-record/object-options-dropd
|
||||
import { IconPicker } from '@/ui/input/components/IconPicker';
|
||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { View } from '@/views/types/View';
|
||||
import { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { useUpdateViewFromCurrentState } from '@/views/view-picker/hooks/useUpdateViewFromCurrentState';
|
||||
import { viewPickerIsDirtyComponentState } from '@/views/view-picker/states/viewPickerIsDirtyComponentState';
|
||||
import { viewPickerIsPersistingComponentState } from '@/views/view-picker/states/viewPickerIsPersistingComponentState';
|
||||
@ -75,17 +76,19 @@ export const ObjectOptionsDropdownMenuViewName = ({
|
||||
const { updateViewFromCurrentState } = useUpdateViewFromCurrentState();
|
||||
const [viewName, setViewName] = useState(currentView?.name);
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Enter,
|
||||
async () => {
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: [Key.Enter],
|
||||
callback: async () => {
|
||||
if (viewPickerIsPersisting) {
|
||||
return;
|
||||
}
|
||||
|
||||
await updateViewFromCurrentState();
|
||||
},
|
||||
ViewsHotkeyScope.ListDropdown,
|
||||
);
|
||||
focusId: VIEW_PICKER_DROPDOWN_ID,
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
dependencies: [viewPickerIsPersisting, updateViewFromCurrentState],
|
||||
});
|
||||
|
||||
const handleIconChange = ({ iconKey }: { iconKey: string }) => {
|
||||
setViewPickerIsDirty(true);
|
||||
|
||||
@ -5,11 +5,11 @@ import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hook
|
||||
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
|
||||
import { RecordGroupSort } from '@/object-record/record-group/types/RecordGroupSort';
|
||||
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
|
||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
@ -73,8 +73,9 @@ export const ObjectOptionsDropdownRecordGroupSortContent = () => {
|
||||
<DropdownMenuItemsContainer>
|
||||
<SelectableList
|
||||
selectableListInstanceId={OBJECT_OPTIONS_DROPDOWN_ID}
|
||||
hotkeyScope={TableOptionsHotkeyScope.Dropdown}
|
||||
focusId={OBJECT_OPTIONS_DROPDOWN_ID}
|
||||
selectableItemIdArray={selectableItemIdArray}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
<SelectableListItem
|
||||
itemId={RecordGroupSort.Manual}
|
||||
|
||||
@ -9,12 +9,12 @@ import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-gr
|
||||
import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector';
|
||||
import { recordIndexRecordGroupHideComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordGroupHideComponentFamilyState';
|
||||
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
|
||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
@ -94,6 +94,8 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
'HideEmptyGroups',
|
||||
];
|
||||
|
||||
const hiddenGroupsSelectableListId = `${OBJECT_OPTIONS_DROPDOWN_ID}-hidden-groups`;
|
||||
|
||||
return (
|
||||
<DropdownContent>
|
||||
<DropdownMenuHeader
|
||||
@ -109,8 +111,9 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
<DropdownMenuItemsContainer>
|
||||
<SelectableList
|
||||
selectableListInstanceId={OBJECT_OPTIONS_DROPDOWN_ID}
|
||||
hotkeyScope={TableOptionsHotkeyScope.Dropdown}
|
||||
focusId={OBJECT_OPTIONS_DROPDOWN_ID}
|
||||
selectableItemIdArray={selectableItemIdArray}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
{currentView?.key !== 'INDEX' && (
|
||||
<>
|
||||
@ -175,9 +178,10 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer scrollable={false}>
|
||||
<SelectableList
|
||||
selectableListInstanceId={`${OBJECT_OPTIONS_DROPDOWN_ID}-hidden-groups`}
|
||||
hotkeyScope={TableOptionsHotkeyScope.Dropdown}
|
||||
selectableListInstanceId={hiddenGroupsSelectableListId}
|
||||
focusId={hiddenGroupsSelectableListId}
|
||||
selectableItemIdArray={['HiddenGroups']}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
<SelectableListItem
|
||||
itemId="HiddenGroups"
|
||||
|
||||
@ -6,7 +6,6 @@ import { OBJECT_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/co
|
||||
import { useCloseSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useCloseSortDropdown';
|
||||
import { useResetRecordSortDropdownSearchInput } from '@/object-record/object-sort-dropdown/hooks/useResetRecordSortDropdownSearchInput';
|
||||
import { useResetSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useResetSortDropdown';
|
||||
import { useToggleSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useToggleSortDropdown';
|
||||
import { isRecordSortDirectionDropdownMenuUnfoldedComponentState } from '@/object-record/object-sort-dropdown/states/isRecordSortDirectionDropdownMenuUnfoldedComponentState';
|
||||
import { objectSortDropdownSearchInputComponentState } from '@/object-record/object-sort-dropdown/states/objectSortDropdownSearchInputComponentState';
|
||||
import { selectedRecordSortDirectionComponentState } from '@/object-record/object-sort-dropdown/states/selectedRecordSortDirectionComponentState';
|
||||
@ -25,6 +24,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
||||
import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
@ -86,11 +86,7 @@ export type ObjectSortDropdownButtonProps = {
|
||||
hotkeyScope: HotkeyScope;
|
||||
};
|
||||
|
||||
export const ObjectSortDropdownButton = ({
|
||||
hotkeyScope,
|
||||
}: ObjectSortDropdownButtonProps) => {
|
||||
const { toggleSortDropdown } = useToggleSortDropdown();
|
||||
|
||||
export const ObjectSortDropdownButton = () => {
|
||||
const { resetRecordSortDropdownSearchInput } =
|
||||
useResetRecordSortDropdownSearchInput();
|
||||
|
||||
@ -162,15 +158,16 @@ export const ObjectSortDropdownButton = ({
|
||||
const shouldShowSeparator =
|
||||
visibleFieldMetadataItems.length > 0 && hiddenFieldMetadataItems.length > 0;
|
||||
|
||||
const handleButtonClick = () => {
|
||||
toggleSortDropdown();
|
||||
};
|
||||
|
||||
const handleDropdownButtonClose = () => {
|
||||
resetRecordSortDropdownSearchInput();
|
||||
resetSortDropdown();
|
||||
};
|
||||
|
||||
const handleDropdownOpen = () => {
|
||||
resetSortDropdown();
|
||||
setSelectedItemId(selectableItemIdArray[0]);
|
||||
};
|
||||
|
||||
const { closeSortDropdown } = useCloseSortDropdown();
|
||||
|
||||
const { upsertRecordSort } = useUpsertRecordSort();
|
||||
@ -224,16 +221,10 @@ export const ObjectSortDropdownButton = ({
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={OBJECT_SORT_DROPDOWN_ID}
|
||||
dropdownHotkeyScope={hotkeyScope}
|
||||
dropdownOffset={{ y: 8 }}
|
||||
onOpen={handleDropdownOpen}
|
||||
clickableComponent={
|
||||
<StyledHeaderDropdownButton
|
||||
onClick={() => {
|
||||
handleButtonClick();
|
||||
setSelectedItemId(selectableItemIdArray[0]);
|
||||
}}
|
||||
isUnfolded={isDropdownOpen}
|
||||
>
|
||||
<StyledHeaderDropdownButton isUnfolded={isDropdownOpen}>
|
||||
<Trans>Sort</Trans>
|
||||
</StyledHeaderDropdownButton>
|
||||
}
|
||||
@ -241,8 +232,9 @@ export const ObjectSortDropdownButton = ({
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||
<SelectableList
|
||||
selectableListInstanceId={OBJECT_SORT_DROPDOWN_ID}
|
||||
hotkeyScope={hotkeyScope.scope}
|
||||
selectableItemIdArray={selectableItemIdArray}
|
||||
focusId={OBJECT_SORT_DROPDOWN_ID}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
{isRecordSortDirectionMenuUnfolded && (
|
||||
<StyledSelectedSortDirectionContainer>
|
||||
|
||||
@ -9,7 +9,6 @@ import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/r
|
||||
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
||||
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
||||
|
||||
import { ActionMenuDropdownHotkeyScope } from '@/action-menu/types/ActionMenuDropdownHotKeyScope';
|
||||
import { useActiveRecordBoardCard } from '@/object-record/record-board/hooks/useActiveRecordBoardCard';
|
||||
import { useFocusedRecordBoardCard } from '@/object-record/record-board/hooks/useFocusedRecordBoardCard';
|
||||
import { RecordBoardCardBody } from '@/object-record/record-board/record-board-card/components/RecordBoardCardBody';
|
||||
@ -155,7 +154,8 @@ export const RecordBoardCard = () => {
|
||||
y: event.clientY,
|
||||
});
|
||||
openDropdown(actionMenuDropdownId, {
|
||||
scope: ActionMenuDropdownHotkeyScope.ActionMenuDropdown,
|
||||
enableGlobalHotkeysWithModifiers: true,
|
||||
enableGlobalHotkeysConflictingWithKeyboard: false,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@ import { RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext } from
|
||||
import { RecordBoardColumnHeaderAggregateDropdownButton } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownButton';
|
||||
import { AggregateDropdownContent } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownContent';
|
||||
import { RecordBoardColumnHeaderAggregateDropdownContext } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownContext';
|
||||
import { RecordBoardColumnHotkeyScope } from '@/object-record/record-board/types/BoardColumnHotkeyScope';
|
||||
import { RecordBoardColumnHeaderAggregateContentId } from '@/object-record/record-board/types/RecordBoardColumnHeaderAggregateContentId';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import styled from '@emotion/styled';
|
||||
@ -42,9 +41,6 @@ export const RecordBoardColumnHeaderAggregateDropdown = ({
|
||||
<Dropdown
|
||||
onClose={handleResetContent}
|
||||
dropdownId={dropdownId}
|
||||
dropdownHotkeyScope={{
|
||||
scope: RecordBoardColumnHotkeyScope.ColumnHeader,
|
||||
}}
|
||||
dropdownOffset={{ y: DROPDOWN_OFFSET_Y }}
|
||||
clickableComponent={
|
||||
<RecordBoardColumnHeaderAggregateDropdownButton
|
||||
|
||||
@ -11,6 +11,7 @@ import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldM
|
||||
import { MultiSelectDisplay } from '@/ui/field/display/components/MultiSelectDisplay';
|
||||
import { MultiSelectInput } from '@/ui/field/input/components/MultiSelectInput';
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
|
||||
@ -21,7 +22,6 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { VisibilityHidden } from 'twenty-ui/accessibility';
|
||||
import { IconChevronDown } from 'twenty-ui/display';
|
||||
import { SelectOption } from 'twenty-ui/input';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
|
||||
type FormMultiSelectFieldInputProps = {
|
||||
label?: string;
|
||||
@ -256,7 +256,7 @@ export const FormMultiSelectFieldInput = ({
|
||||
selectableListComponentInstanceId={
|
||||
SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID
|
||||
}
|
||||
hotkeyScope={hotkeyScope}
|
||||
focusId={hotkeyScope}
|
||||
options={options}
|
||||
onCancel={onCancel}
|
||||
onOptionSelected={onOptionSelected}
|
||||
|
||||
@ -10,6 +10,7 @@ import { singleRecordPickerSelectedIdComponentState } from '@/object-record/reco
|
||||
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
|
||||
@ -18,7 +19,6 @@ import styled from '@emotion/styled';
|
||||
import { useCallback, useId } from 'react';
|
||||
import { isDefined, isValidUuid } from 'twenty-shared/utils';
|
||||
import { IconChevronDown, IconForbid } from 'twenty-ui/display';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
|
||||
const StyledFormSelectContainer = styled(FormFieldInputInnerContainer)<{
|
||||
readonly?: boolean;
|
||||
@ -189,6 +189,7 @@ export const FormSingleRecordPicker = ({
|
||||
}
|
||||
dropdownComponents={
|
||||
<SingleRecordPicker
|
||||
focusId={dropdownId}
|
||||
componentInstanceId={dropdownId}
|
||||
EmptyIcon={IconForbid}
|
||||
emptyLabel={'No ' + objectNameSingular}
|
||||
@ -199,7 +200,6 @@ export const FormSingleRecordPicker = ({
|
||||
dropdownWidth={GenericDropdownContentWidth.ExtraLarge}
|
||||
/>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
/>
|
||||
)}
|
||||
{isDefined(VariablePicker) && !disabled && (
|
||||
|
||||
@ -7,6 +7,7 @@ import { getActivityTargetObjectRecords } from '@/activities/utils/getActivityTa
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { useOpenRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useOpenRelationFromManyFieldInput';
|
||||
import { useOpenRelationToOneFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useOpenRelationToOneFieldInput';
|
||||
import { getRelationFromManyFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationFromManyFieldInputInstanceId';
|
||||
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||
import {
|
||||
FieldMetadata,
|
||||
@ -15,11 +16,13 @@ import {
|
||||
} from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { isFieldRelationFromManyObjects } from '@/object-record/record-field/types/guards/isFieldRelationFromManyObjects';
|
||||
import { isFieldRelationToOneObject } from '@/object-record/record-field/types/guards/isFieldRelationToOneObject';
|
||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
||||
import { INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY } from '@/object-record/record-inline-cell/constants/InlineCellHotkeyScopeMemoizeKey';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@ -31,7 +34,7 @@ export const useOpenFieldInputEditMode = () => {
|
||||
const { openActivityTargetCellEditMode } =
|
||||
useOpenActivityTargetCellEditMode();
|
||||
|
||||
const { setHotkeyScopeAndMemorizePreviousScope } = usePreviousHotkeyScope();
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
|
||||
const openFieldInput = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
@ -72,7 +75,10 @@ export const useOpenFieldInputEditMode = () => {
|
||||
});
|
||||
|
||||
openActivityTargetCellEditMode({
|
||||
recordPickerInstanceId: `relation-from-many-field-input-${recordId}`,
|
||||
recordPickerInstanceId: getRelationFromManyFieldInputInstanceId({
|
||||
recordId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
}),
|
||||
activityTargetObjectRecords,
|
||||
});
|
||||
return;
|
||||
@ -103,9 +109,22 @@ export const useOpenFieldInputEditMode = () => {
|
||||
}
|
||||
}
|
||||
|
||||
setHotkeyScopeAndMemorizePreviousScope({
|
||||
scope: DEFAULT_CELL_SCOPE.scope,
|
||||
customScopes: DEFAULT_CELL_SCOPE.customScopes,
|
||||
pushFocusItemToFocusStack({
|
||||
focusId: getFieldInputInstanceId(
|
||||
recordId,
|
||||
fieldDefinition.metadata.fieldName,
|
||||
),
|
||||
component: {
|
||||
type: FocusComponentType.OPEN_FIELD_INPUT,
|
||||
instanceId: getFieldInputInstanceId(
|
||||
recordId,
|
||||
fieldDefinition.metadata.fieldName,
|
||||
),
|
||||
},
|
||||
hotkeyScope: {
|
||||
scope: DEFAULT_CELL_SCOPE.scope,
|
||||
customScopes: DEFAULT_CELL_SCOPE.customScopes,
|
||||
},
|
||||
memoizeKey: INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY,
|
||||
});
|
||||
},
|
||||
@ -113,7 +132,7 @@ export const useOpenFieldInputEditMode = () => {
|
||||
openActivityTargetCellEditMode,
|
||||
openRelationFromManyFieldInput,
|
||||
openRelationToOneFieldInput,
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
pushFocusItemToFocusStack,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@ export const useMultiSelectField = () => {
|
||||
const draftValue = useRecoilValue(getDraftValueSelector());
|
||||
|
||||
return {
|
||||
recordId,
|
||||
fieldDefinition,
|
||||
persistField,
|
||||
fieldValues: fieldMultiSelectValues,
|
||||
|
||||
@ -34,6 +34,7 @@ export const useSelectField = () => {
|
||||
const draftValue = useRecoilValue(getDraftValueSelector());
|
||||
|
||||
return {
|
||||
recordId,
|
||||
fieldDefinition,
|
||||
persistField,
|
||||
fieldValue: fieldSelectValue,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { useMultiSelectField } from '@/object-record/record-field/meta-types/hooks/useMultiSelectField';
|
||||
import { SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID } from '@/object-record/record-field/meta-types/input/constants/SelectFieldInputSelectableListComponentInstanceId';
|
||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
||||
import { MultiSelectInput } from '@/ui/field/input/components/MultiSelectInput';
|
||||
|
||||
type MultiSelectFieldInputProps = {
|
||||
@ -10,14 +10,18 @@ type MultiSelectFieldInputProps = {
|
||||
export const MultiSelectFieldInput = ({
|
||||
onCancel,
|
||||
}: MultiSelectFieldInputProps) => {
|
||||
const { persistField, fieldDefinition, fieldValues } = useMultiSelectField();
|
||||
const { persistField, fieldDefinition, fieldValues, recordId } =
|
||||
useMultiSelectField();
|
||||
|
||||
return (
|
||||
<MultiSelectInput
|
||||
selectableListComponentInstanceId={
|
||||
SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID
|
||||
}
|
||||
hotkeyScope={DEFAULT_CELL_SCOPE.scope}
|
||||
focusId={getFieldInputInstanceId(
|
||||
recordId,
|
||||
fieldDefinition.metadata.fieldName,
|
||||
)}
|
||||
options={fieldDefinition.metadata.options}
|
||||
onCancel={onCancel}
|
||||
onOptionSelected={persistField}
|
||||
|
||||
@ -10,6 +10,7 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext
|
||||
import { useRelationField } from '@/object-record/record-field/meta-types/hooks/useRelationField';
|
||||
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
||||
import { useUpdateRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput';
|
||||
import { getRelationFromManyFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationFromManyFieldInputInstanceId';
|
||||
import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionComponentState';
|
||||
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||
@ -25,7 +26,10 @@ export const RelationFromManyFieldInput = ({
|
||||
onSubmit,
|
||||
}: RelationFromManyFieldInputProps) => {
|
||||
const { fieldDefinition, recordId } = useContext(FieldContext);
|
||||
const recordPickerInstanceId = `relation-from-many-field-input-${recordId}`;
|
||||
const recordPickerInstanceId = getRelationFromManyFieldInputInstanceId({
|
||||
recordId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
});
|
||||
|
||||
const { updateRelation } = useUpdateRelationFromManyFieldInput();
|
||||
const fieldName = fieldDefinition.metadata.fieldName;
|
||||
@ -84,6 +88,7 @@ export const RelationFromManyFieldInput = ({
|
||||
|
||||
return (
|
||||
<MultipleRecordPicker
|
||||
focusId={recordPickerInstanceId}
|
||||
componentInstanceId={recordPickerInstanceId}
|
||||
onSubmit={handleSubmit}
|
||||
onChange={(morphItem) => {
|
||||
|
||||
@ -3,6 +3,7 @@ import { useRelationField } from '../../hooks/useRelationField';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
||||
import { getRelationToOneFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationToOneFieldInputInstanceId';
|
||||
import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionComponentState';
|
||||
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||
@ -25,7 +26,10 @@ export const RelationToOneFieldInput = ({
|
||||
|
||||
const persistField = usePersistField();
|
||||
|
||||
const recordPickerInstanceId = `relation-to-one-field-input-${recordId}-${fieldDefinition.metadata.fieldName}`;
|
||||
const recordPickerInstanceId = getRelationToOneFieldInputInstanceId({
|
||||
recordId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
});
|
||||
|
||||
const handleRecordSelected = (
|
||||
selectedRecord: SingleRecordPickerRecord | null | undefined,
|
||||
@ -64,6 +68,7 @@ export const RelationToOneFieldInput = ({
|
||||
|
||||
return (
|
||||
<SingleRecordPicker
|
||||
focusId={recordPickerInstanceId}
|
||||
componentInstanceId={recordPickerInstanceId}
|
||||
EmptyIcon={IconForbid}
|
||||
emptyLabel={'No ' + fieldDefinition.label}
|
||||
|
||||
@ -2,6 +2,7 @@ import { useClearField } from '@/object-record/record-field/hooks/useClearField'
|
||||
import { useSelectField } from '@/object-record/record-field/meta-types/hooks/useSelectField';
|
||||
import { SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID } from '@/object-record/record-field/meta-types/input/constants/SelectFieldInputSelectableListComponentInstanceId';
|
||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||
import { SelectInput } from '@/ui/field/input/components/SelectInput';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
@ -20,7 +21,8 @@ export const SelectFieldInput = ({
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}: SelectFieldInputProps) => {
|
||||
const { persistField, fieldDefinition, fieldValue } = useSelectField();
|
||||
const { persistField, fieldDefinition, fieldValue, recordId } =
|
||||
useSelectField();
|
||||
|
||||
const [filteredOptions, setFilteredOptions] = useState<SelectOption[]>([]);
|
||||
|
||||
@ -65,7 +67,10 @@ export const SelectFieldInput = ({
|
||||
SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID
|
||||
}
|
||||
selectableItemIdArray={optionIds}
|
||||
hotkeyScope={DEFAULT_CELL_SCOPE.scope}
|
||||
focusId={getFieldInputInstanceId(
|
||||
recordId,
|
||||
fieldDefinition.metadata.fieldName,
|
||||
)}
|
||||
onEnter={(itemId) => {
|
||||
const option = filteredOptions.find(
|
||||
(option) => option.value === itemId,
|
||||
|
||||
@ -18,9 +18,10 @@ import {
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { useOpenFieldInputEditMode } from '@/object-record/record-field/hooks/useOpenFieldInputEditMode';
|
||||
import { getRelationFromManyFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationFromManyFieldInputInstanceId';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||
import { MultipleRecordPickerHotkeyScope } from '@/object-record/record-picker/multiple-record-picker/types/MultipleRecordPickerHotkeyScope';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { RelationType } from '~/generated-metadata/graphql';
|
||||
|
||||
@ -71,7 +72,7 @@ const RelationManyFieldInputWithContext = () => {
|
||||
useEffect(() => {
|
||||
setRecordStoreFieldValue([]);
|
||||
|
||||
setHotKeyScope(MultipleRecordPickerHotkeyScope.MultipleRecordPicker);
|
||||
setHotKeyScope(DropdownHotkeyScope.Dropdown);
|
||||
openFieldInput({
|
||||
fieldDefinition,
|
||||
recordId: 'recordId',
|
||||
@ -87,7 +88,10 @@ const RelationManyFieldInputWithContext = () => {
|
||||
<div>
|
||||
<RecordFieldComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: 'relation-from-many-field-record-id-people',
|
||||
instanceId: getRelationFromManyFieldInputInstanceId({
|
||||
recordId: 'recordId',
|
||||
fieldName: 'people',
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<FieldContext.Provider
|
||||
|
||||
@ -5,7 +5,6 @@ import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
|
||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
@ -17,9 +16,12 @@ import {
|
||||
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { getRelationToOneFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationToOneFieldInputInstanceId';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { getCanvasElementForDropdownTesting } from 'twenty-ui/testing';
|
||||
@ -62,11 +64,30 @@ const RelationToOneFieldInputWithContext = ({
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}: RelationToOneFieldInputWithContextProps) => {
|
||||
const setHotKeyScope = useSetHotkeyScope();
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
|
||||
useEffect(() => {
|
||||
setHotKeyScope(SingleRecordPickerHotkeyScope.SingleRecordPicker);
|
||||
}, [setHotKeyScope]);
|
||||
pushFocusItemToFocusStack({
|
||||
focusId: getRelationToOneFieldInputInstanceId({
|
||||
recordId: '123',
|
||||
fieldName: 'Relation',
|
||||
}),
|
||||
component: {
|
||||
type: FocusComponentType.DROPDOWN,
|
||||
instanceId: getRelationToOneFieldInputInstanceId({
|
||||
recordId: '123',
|
||||
fieldName: 'Relation',
|
||||
}),
|
||||
},
|
||||
hotkeyScope: {
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
},
|
||||
memoizeKey: getRelationToOneFieldInputInstanceId({
|
||||
recordId: '123',
|
||||
fieldName: 'Relation',
|
||||
}),
|
||||
});
|
||||
}, [pushFocusItemToFocusStack]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getRelationFromManyFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationFromManyFieldInputInstanceId';
|
||||
import {
|
||||
FieldRelationFromManyValue,
|
||||
FieldRelationValue,
|
||||
@ -6,17 +7,18 @@ import {
|
||||
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
||||
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
||||
import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState';
|
||||
import { MultipleRecordPickerHotkeyScope } from '@/object-record/record-picker/multiple-record-picker/types/MultipleRecordPickerHotkeyScope';
|
||||
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useOpenRelationFromManyFieldInput = () => {
|
||||
const { performSearch } = useMultipleRecordPickerPerformSearch();
|
||||
|
||||
const { setHotkeyScopeAndMemorizePreviousScope } = usePreviousHotkeyScope();
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
|
||||
const openRelationFromManyFieldInput = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
@ -29,7 +31,10 @@ export const useOpenRelationFromManyFieldInput = () => {
|
||||
objectNameSingular: string;
|
||||
recordId: string;
|
||||
}) => {
|
||||
const recordPickerInstanceId = `relation-from-many-field-input-${recordId}`;
|
||||
const recordPickerInstanceId = getRelationFromManyFieldInputInstanceId({
|
||||
recordId,
|
||||
fieldName,
|
||||
});
|
||||
|
||||
const fieldValue = snapshot
|
||||
.getLoadable<FieldRelationValue<FieldRelationFromManyValue>>(
|
||||
@ -88,11 +93,19 @@ export const useOpenRelationFromManyFieldInput = () => {
|
||||
forcePickableMorphItems: pickableMorphItems,
|
||||
});
|
||||
|
||||
setHotkeyScopeAndMemorizePreviousScope({
|
||||
scope: MultipleRecordPickerHotkeyScope.MultipleRecordPicker,
|
||||
pushFocusItemToFocusStack({
|
||||
focusId: recordPickerInstanceId,
|
||||
component: {
|
||||
type: FocusComponentType.DROPDOWN,
|
||||
instanceId: recordPickerInstanceId,
|
||||
},
|
||||
hotkeyScope: {
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
},
|
||||
memoizeKey: recordPickerInstanceId,
|
||||
});
|
||||
},
|
||||
[performSearch, setHotkeyScopeAndMemorizePreviousScope],
|
||||
[performSearch, pushFocusItemToFocusStack],
|
||||
);
|
||||
|
||||
return { openRelationFromManyFieldInput };
|
||||
|
||||
@ -1,21 +1,26 @@
|
||||
import { getRelationToOneFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationToOneFieldInputInstanceId';
|
||||
import {
|
||||
FieldRelationToOneValue,
|
||||
FieldRelationValue,
|
||||
} from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useOpenRelationToOneFieldInput = () => {
|
||||
const { setHotkeyScopeAndMemorizePreviousScope } = usePreviousHotkeyScope();
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
|
||||
const openRelationToOneFieldInput = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
({ fieldName, recordId }: { fieldName: string; recordId: string }) => {
|
||||
const recordPickerInstanceId = `relation-to-one-field-input-${recordId}-${fieldName}`;
|
||||
const recordPickerInstanceId = getRelationToOneFieldInputInstanceId({
|
||||
recordId,
|
||||
fieldName,
|
||||
});
|
||||
const fieldValue = snapshot
|
||||
.getLoadable<FieldRelationValue<FieldRelationToOneValue>>(
|
||||
recordStoreFamilySelector({
|
||||
@ -34,11 +39,18 @@ export const useOpenRelationToOneFieldInput = () => {
|
||||
);
|
||||
}
|
||||
|
||||
setHotkeyScopeAndMemorizePreviousScope({
|
||||
scope: SingleRecordPickerHotkeyScope.SingleRecordPicker,
|
||||
pushFocusItemToFocusStack({
|
||||
focusId: recordPickerInstanceId,
|
||||
component: {
|
||||
type: FocusComponentType.OPEN_FIELD_INPUT,
|
||||
instanceId: recordPickerInstanceId,
|
||||
},
|
||||
// TODO: Remove this once we've fully migrated away from hotkey scopes
|
||||
hotkeyScope: { scope: DropdownHotkeyScope.Dropdown },
|
||||
memoizeKey: recordPickerInstanceId,
|
||||
});
|
||||
},
|
||||
[setHotkeyScopeAndMemorizePreviousScope],
|
||||
[pushFocusItemToFocusStack],
|
||||
);
|
||||
|
||||
return { openRelationToOneFieldInput };
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
export enum RelationPickerHotkeyScope {
|
||||
AddNew = 'add-new',
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
export const getRelationFromManyFieldInputInstanceId = ({
|
||||
recordId,
|
||||
fieldName,
|
||||
}: {
|
||||
recordId: string;
|
||||
fieldName: string;
|
||||
}): string => {
|
||||
return `relation-from-many-field-input-${recordId}-${fieldName}`;
|
||||
};
|
||||
@ -0,0 +1,9 @@
|
||||
export const getRelationToOneFieldInputInstanceId = ({
|
||||
recordId,
|
||||
fieldName,
|
||||
}: {
|
||||
recordId: string;
|
||||
fieldName: string;
|
||||
}): string => {
|
||||
return `relation-to-one-field-input-${recordId}-${fieldName}`;
|
||||
};
|
||||
@ -0,0 +1,6 @@
|
||||
export const getFieldInputInstanceId = (
|
||||
recordId: string,
|
||||
fieldName: string,
|
||||
) => {
|
||||
return `${recordId}-${fieldName}`;
|
||||
};
|
||||
@ -4,7 +4,6 @@ import { MultipleRecordPickerSearchInput } from '@/object-record/record-picker/m
|
||||
import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext';
|
||||
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
||||
import { multipleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState';
|
||||
import { MultipleRecordPickerHotkeyScope } from '@/object-record/record-picker/multiple-record-picker/types/MultipleRecordPickerHotkeyScope';
|
||||
import { getMultipleRecordPickerSelectableListId } from '@/object-record/record-picker/multiple-record-picker/utils/getMultipleRecordPickerSelectableListId';
|
||||
import { RecordPickerLayoutDirection } from '@/object-record/record-picker/types/RecordPickerLayoutDirection';
|
||||
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
|
||||
@ -12,10 +11,11 @@ import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObj
|
||||
import { CreateNewButton } from '@/ui/input/relation-picker/components/CreateNewButton';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRef } from 'react';
|
||||
@ -36,6 +36,7 @@ type MultipleRecordPickerProps = {
|
||||
layoutDirection?: RecordPickerLayoutDirection;
|
||||
componentInstanceId: string;
|
||||
onClickOutside: () => void;
|
||||
focusId: string;
|
||||
};
|
||||
|
||||
export const MultipleRecordPicker = ({
|
||||
@ -45,6 +46,7 @@ export const MultipleRecordPicker = ({
|
||||
onClickOutside,
|
||||
layoutDirection = 'search-bar-on-bottom',
|
||||
componentInstanceId,
|
||||
focusId,
|
||||
}: MultipleRecordPickerProps) => {
|
||||
const { goBackToPreviousHotkeyScope } = usePreviousHotkeyScope();
|
||||
|
||||
@ -94,14 +96,15 @@ export const MultipleRecordPicker = ({
|
||||
resetState();
|
||||
};
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
() => {
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: [Key.Escape],
|
||||
callback: () => {
|
||||
handleSubmit();
|
||||
},
|
||||
MultipleRecordPickerHotkeyScope.MultipleRecordPicker,
|
||||
[handleSubmit],
|
||||
);
|
||||
focusId,
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
dependencies: [handleSubmit],
|
||||
});
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -140,13 +143,19 @@ export const MultipleRecordPicker = ({
|
||||
{layoutDirection === 'search-bar-on-bottom' && (
|
||||
<>
|
||||
{createNewButtonSection}
|
||||
<MultipleRecordPickerItemsDisplay onChange={onChange} />
|
||||
<MultipleRecordPickerItemsDisplay
|
||||
onChange={onChange}
|
||||
focusId={focusId}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<MultipleRecordPickerSearchInput />
|
||||
{layoutDirection === 'search-bar-on-top' && (
|
||||
<>
|
||||
<MultipleRecordPickerItemsDisplay onChange={onChange} />
|
||||
<MultipleRecordPickerItemsDisplay
|
||||
onChange={onChange}
|
||||
focusId={focusId}
|
||||
/>
|
||||
{createNewButtonSection}
|
||||
</>
|
||||
)}
|
||||
|
||||
@ -10,8 +10,10 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
||||
|
||||
export const MultipleRecordPickerItemsDisplay = ({
|
||||
onChange,
|
||||
focusId,
|
||||
}: {
|
||||
onChange?: (morphItem: RecordPickerPickableMorphItem) => void;
|
||||
focusId: string;
|
||||
}) => {
|
||||
const componentInstanceId = useAvailableComponentInstanceIdOrThrow(
|
||||
MultipleRecordPickerComponentInstanceContext,
|
||||
@ -33,7 +35,7 @@ export const MultipleRecordPickerItemsDisplay = ({
|
||||
{isLoading && itemsLength === 0 ? (
|
||||
<DropdownMenuSkeletonItem />
|
||||
) : (
|
||||
<MultipleRecordPickerMenuItems onChange={onChange} />
|
||||
<MultipleRecordPickerMenuItems onChange={onChange} focusId={focusId} />
|
||||
)}
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
|
||||
@ -6,10 +6,10 @@ import { MultipleRecordPickerMenuItem } from '@/object-record/record-picker/mult
|
||||
import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext';
|
||||
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
||||
import { multipleRecordPickerPickableRecordIdsMatchingSearchComponentSelector } from '@/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPickableRecordIdsMatchingSearchComponentSelector';
|
||||
import { MultipleRecordPickerHotkeyScope } from '@/object-record/record-picker/multiple-record-picker/types/MultipleRecordPickerHotkeyScope';
|
||||
import { getMultipleRecordPickerSelectableListId } from '@/object-record/record-picker/multiple-record-picker/utils/getMultipleRecordPickerSelectableListId';
|
||||
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
@ -25,10 +25,12 @@ export const StyledSelectableItem = styled(SelectableListItem)`
|
||||
|
||||
type MultipleRecordPickerMenuItemsProps = {
|
||||
onChange?: (morphItem: RecordPickerPickableMorphItem) => void;
|
||||
focusId: string;
|
||||
};
|
||||
|
||||
export const MultipleRecordPickerMenuItems = ({
|
||||
onChange,
|
||||
focusId,
|
||||
}: MultipleRecordPickerMenuItemsProps) => {
|
||||
const componentInstanceId = useAvailableComponentInstanceIdOrThrow(
|
||||
MultipleRecordPickerComponentInstanceContext,
|
||||
@ -85,7 +87,8 @@ export const MultipleRecordPickerMenuItems = ({
|
||||
<SelectableList
|
||||
selectableListInstanceId={selectableListComponentInstanceId}
|
||||
selectableItemIdArray={pickableRecordIds}
|
||||
hotkeyScope={MultipleRecordPickerHotkeyScope.MultipleRecordPicker}
|
||||
focusId={focusId}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
{pickableRecordIds.map((recordId) => {
|
||||
return (
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
export enum MultipleRecordPickerHotkeyScope {
|
||||
MultipleRecordPicker = 'multiple-record-picker',
|
||||
}
|
||||
@ -28,6 +28,7 @@ export const SingleRecordPicker = ({
|
||||
componentInstanceId,
|
||||
layoutDirection,
|
||||
dropdownWidth,
|
||||
focusId,
|
||||
}: SingleRecordPickerProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -71,6 +72,7 @@ export const SingleRecordPicker = ({
|
||||
>
|
||||
<DropdownContent ref={containerRef} widthInPixels={dropdownWidth}>
|
||||
<SingleRecordPickerMenuItemsWithSearch
|
||||
focusId={focusId}
|
||||
{...{
|
||||
EmptyIcon,
|
||||
emptyLabel,
|
||||
|
||||
@ -4,16 +4,16 @@ import { Key } from 'ts-key-enum';
|
||||
import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
|
||||
import { SingleRecordPickerMenuItem } from '@/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem';
|
||||
import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext';
|
||||
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
|
||||
import { getSingleRecordPickerSelectableListId } from '@/object-record/record-picker/single-record-picker/utils/getSingleRecordPickerSelectableListId';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
@ -29,7 +29,7 @@ export type SingleRecordPickerMenuItemsProps = {
|
||||
onCancel?: () => void;
|
||||
onRecordSelected: (entity?: SingleRecordPickerRecord) => void;
|
||||
selectedRecord?: SingleRecordPickerRecord;
|
||||
hotkeyScope?: string;
|
||||
focusId: string;
|
||||
};
|
||||
|
||||
export const SingleRecordPickerMenuItems = ({
|
||||
@ -40,7 +40,7 @@ export const SingleRecordPickerMenuItems = ({
|
||||
onCancel,
|
||||
onRecordSelected,
|
||||
selectedRecord,
|
||||
hotkeyScope = SingleRecordPickerHotkeyScope.SingleRecordPicker,
|
||||
focusId,
|
||||
}: SingleRecordPickerMenuItemsProps) => {
|
||||
const selectNone = emptyLabel
|
||||
? {
|
||||
@ -77,15 +77,16 @@ export const SingleRecordPickerMenuItems = ({
|
||||
'select-none',
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
() => {
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: Key.Escape,
|
||||
callback: () => {
|
||||
resetSelectedItem();
|
||||
onCancel?.();
|
||||
},
|
||||
hotkeyScope,
|
||||
[onCancel, resetSelectedItem],
|
||||
);
|
||||
focusId,
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
dependencies: [onCancel, resetSelectedItem],
|
||||
});
|
||||
|
||||
const selectableItemIds = recordsInDropdown.map((entity) => entity.id);
|
||||
const [selectedRecordId, setSelectedRecordId] = useRecoilComponentStateV2(
|
||||
@ -96,7 +97,8 @@ export const SingleRecordPickerMenuItems = ({
|
||||
<SelectableList
|
||||
selectableListInstanceId={selectableListComponentInstanceId}
|
||||
selectableItemIdArray={selectableItemIds}
|
||||
hotkeyScope={hotkeyScope}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
focusId={focusId}
|
||||
>
|
||||
{loading ? (
|
||||
<DropdownMenuSkeletonItem />
|
||||
|
||||
@ -26,6 +26,7 @@ export type SingleRecordPickerMenuItemsWithSearchProps = {
|
||||
objectNameSingular: string;
|
||||
recordPickerInstanceId?: string;
|
||||
layoutDirection?: RecordPickerLayoutDirection;
|
||||
focusId: string;
|
||||
} & Pick<
|
||||
SingleRecordPickerMenuItemsProps,
|
||||
| 'EmptyIcon'
|
||||
@ -44,6 +45,7 @@ export const SingleRecordPickerMenuItemsWithSearch = ({
|
||||
onRecordSelected,
|
||||
objectNameSingular,
|
||||
layoutDirection = 'search-bar-on-top',
|
||||
focusId,
|
||||
}: SingleRecordPickerMenuItemsWithSearchProps) => {
|
||||
const { handleSearchFilterChange } = useSingleRecordPickerSearch();
|
||||
|
||||
@ -96,9 +98,11 @@ export const SingleRecordPickerMenuItemsWithSearch = ({
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
{searchHasNoResults && <RecordPickerNoRecordFoundMenuItem />}
|
||||
<SingleRecordPickerMenuItems
|
||||
focusId={focusId}
|
||||
recordsToSelect={records.recordsToSelect}
|
||||
loading={records.loading}
|
||||
selectedRecord={records.selectedRecords?.[0]}
|
||||
@ -123,6 +127,7 @@ export const SingleRecordPickerMenuItemsWithSearch = ({
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<SingleRecordPickerMenuItems
|
||||
focusId={focusId}
|
||||
recordsToSelect={records.recordsToSelect}
|
||||
loading={records.loading}
|
||||
selectedRecord={records.selectedRecords?.[0]}
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
export enum SingleRecordPickerHotkeyScope {
|
||||
SingleRecordPicker = 'single-record-picker',
|
||||
}
|
||||
@ -285,7 +285,6 @@ export const RecordDetailRelationRecordsListItem = ({
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownScopeId }}
|
||||
/>
|
||||
</DropdownScope>
|
||||
)}
|
||||
|
||||
@ -216,10 +216,10 @@ export const RecordDetailRelationSectionDropdown = ({
|
||||
accent="tertiary"
|
||||
/>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
dropdownComponents={
|
||||
isToOneObject ? (
|
||||
<SingleRecordPicker
|
||||
focusId={dropdownId}
|
||||
componentInstanceId={dropdownId}
|
||||
EmptyIcon={IconForbid}
|
||||
onRecordSelected={handleRelationPickerEntitySelected}
|
||||
@ -235,6 +235,7 @@ export const RecordDetailRelationSectionDropdown = ({
|
||||
/>
|
||||
) : (
|
||||
<MultipleRecordPicker
|
||||
focusId={dropdownId}
|
||||
componentInstanceId={dropdownId}
|
||||
onCreate={() => {
|
||||
closeDropdown();
|
||||
|
||||
@ -8,6 +8,7 @@ import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useC
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { useCloseCurrentTableCellInEditMode } from '@/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode';
|
||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||
import { useResetFocusStack } from '@/ui/utilities/focus/hooks/useResetFocusStack';
|
||||
|
||||
export const useCloseRecordTableCellInGroup = () => {
|
||||
const { recordTableId } = useRecordTableContextOrThrow();
|
||||
@ -22,11 +23,17 @@ export const useCloseRecordTableCellInGroup = () => {
|
||||
const closeCurrentTableCellInEditMode =
|
||||
useCloseCurrentTableCellInEditMode(recordTableId);
|
||||
|
||||
const { resetFocusStack } = useResetFocusStack();
|
||||
|
||||
const closeTableCellInGroup = useRecoilCallback(
|
||||
() => () => {
|
||||
toggleClickOutside(true);
|
||||
setDragSelectionStartEnabled(true);
|
||||
closeCurrentTableCellInEditMode();
|
||||
|
||||
// TODO: Remove this once we've fully migrated away from hotkey scopes
|
||||
resetFocusStack();
|
||||
|
||||
setHotkeyScope(TableHotkeyScope.TableFocus, {
|
||||
goto: true,
|
||||
keyboardShortcutMenu: true,
|
||||
@ -35,6 +42,7 @@ export const useCloseRecordTableCellInGroup = () => {
|
||||
},
|
||||
[
|
||||
closeCurrentTableCellInEditMode,
|
||||
resetFocusStack,
|
||||
setDragSelectionStartEnabled,
|
||||
setHotkeyScope,
|
||||
toggleClickOutside,
|
||||
|
||||
@ -6,6 +6,7 @@ import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useC
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { useCloseCurrentTableCellInEditMode } from '@/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode';
|
||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||
import { useResetFocusStack } from '@/ui/utilities/focus/hooks/useResetFocusStack';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const useCloseRecordTableCellNoGroup = () => {
|
||||
@ -22,10 +23,16 @@ export const useCloseRecordTableCellNoGroup = () => {
|
||||
const closeCurrentTableCellInEditMode =
|
||||
useCloseCurrentTableCellInEditMode(recordTableId);
|
||||
|
||||
const { resetFocusStack } = useResetFocusStack();
|
||||
|
||||
const closeTableCellNoGroup = useCallback(() => {
|
||||
toggleClickOutside(true);
|
||||
setDragSelectionStartEnabled(true);
|
||||
closeCurrentTableCellInEditMode();
|
||||
|
||||
// TODO: Remove this once we've fully migrated away from hotkey scopes
|
||||
resetFocusStack();
|
||||
|
||||
setHotkeyScope(TableHotkeyScope.TableFocus, {
|
||||
goto: true,
|
||||
keyboardShortcutMenu: true,
|
||||
@ -33,6 +40,7 @@ export const useCloseRecordTableCellNoGroup = () => {
|
||||
});
|
||||
}, [
|
||||
closeCurrentTableCellInEditMode,
|
||||
resetFocusStack,
|
||||
setDragSelectionStartEnabled,
|
||||
setHotkeyScope,
|
||||
toggleClickOutside,
|
||||
|
||||
@ -2,7 +2,6 @@ import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState';
|
||||
import { ActionMenuDropdownHotkeyScope } from '@/action-menu/types/ActionMenuDropdownHotKeyScope';
|
||||
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
@ -58,9 +57,7 @@ export const useTriggerActionMenuDropdown = ({
|
||||
|
||||
closeCommandMenu();
|
||||
|
||||
openDropdown({
|
||||
scope: ActionMenuDropdownHotkeyScope.ActionMenuDropdown,
|
||||
});
|
||||
openDropdown();
|
||||
},
|
||||
[
|
||||
recordIndexActionMenuDropdownPositionState,
|
||||
|
||||
@ -76,7 +76,6 @@ export const RecordTableColumnFooterWithDropdown = ({
|
||||
}
|
||||
dropdownOffset={{ x: -1 }}
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -35,7 +35,6 @@ export const RecordTableColumnHeadWithDropdown = ({
|
||||
dropdownComponents={<RecordTableColumnHeadDropdownMenu column={column} />}
|
||||
dropdownOffset={{ x: -1 }}
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownHotkeyScope={{ scope: column.fieldMetadataId + '-header' }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -50,9 +50,6 @@ const StyledDropdownContainer = styled.div`
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const HIDDEN_TABLE_COLUMN_DROPDOWN_HOTKEY_SCOPE_ID =
|
||||
'hidden-table-columns-dropdown-hotkey-scope-id';
|
||||
|
||||
export const RecordTableHeaderLastColumn = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
@ -89,9 +86,6 @@ export const RecordTableHeaderLastColumn = () => {
|
||||
}
|
||||
dropdownComponents={<RecordTableHeaderPlusButtonContent />}
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownHotkeyScope={{
|
||||
scope: HIDDEN_TABLE_COLUMN_DROPDOWN_HOTKEY_SCOPE_ID,
|
||||
}}
|
||||
/>
|
||||
</StyledDropdownContainer>
|
||||
</StyledPlusIconHeaderCell>
|
||||
|
||||
@ -3,19 +3,20 @@ import { Key } from 'ts-key-enum';
|
||||
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
||||
import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { Avatar } from 'twenty-ui/display';
|
||||
import { MenuItem, MenuItemMultiSelectAvatar } from 'twenty-ui/navigation';
|
||||
|
||||
export const MultipleSelectDropdown = ({
|
||||
selectableListId,
|
||||
hotkeyScope,
|
||||
focusId,
|
||||
itemsToSelect,
|
||||
loadingItems,
|
||||
filteredSelectedItems,
|
||||
@ -23,7 +24,7 @@ export const MultipleSelectDropdown = ({
|
||||
searchFilter,
|
||||
}: {
|
||||
selectableListId: string;
|
||||
hotkeyScope: string;
|
||||
focusId: string;
|
||||
itemsToSelect: SelectableItem[];
|
||||
filteredSelectedItems: SelectableItem[];
|
||||
selectedItems: SelectableItem[];
|
||||
@ -61,15 +62,16 @@ export const MultipleSelectDropdown = ({
|
||||
...(itemsToSelect ?? []),
|
||||
];
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
() => {
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: [Key.Escape],
|
||||
callback: () => {
|
||||
closeDropdown();
|
||||
resetSelectedItem();
|
||||
},
|
||||
hotkeyScope,
|
||||
[closeDropdown, resetSelectedItem],
|
||||
);
|
||||
focusId,
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
dependencies: [closeDropdown, resetSelectedItem],
|
||||
});
|
||||
|
||||
const showNoResult =
|
||||
itemsToSelect?.length === 0 &&
|
||||
@ -83,7 +85,8 @@ export const MultipleSelectDropdown = ({
|
||||
<SelectableList
|
||||
selectableListInstanceId={selectableListId}
|
||||
selectableItemIdArray={selectableItemIds}
|
||||
hotkeyScope={hotkeyScope}
|
||||
focusId={focusId}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
{itemsInDropdown?.map((item) => {
|
||||
|
||||
@ -51,7 +51,6 @@ export const SettingsAccountsRowDropdownMenu = ({
|
||||
<Dropdown
|
||||
dropdownId={dropdownId}
|
||||
dropdownPlacement="right-start"
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
clickableComponent={
|
||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ import { Select } from '@/ui/input/components/Select';
|
||||
import { SelectControl } from '@/ui/input/components/SelectControl';
|
||||
import { TextArea } from '@/ui/input/components/TextArea';
|
||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||
import { SelectHotkeyScope } from '@/ui/input/types/SelectHotkeyScope';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
@ -96,7 +95,6 @@ export const ConfigVariableDatabaseInput = ({
|
||||
{options && Array.isArray(options) ? (
|
||||
<Dropdown
|
||||
dropdownId="config-variable-array-dropdown"
|
||||
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownOffset={{
|
||||
y: 8,
|
||||
|
||||
@ -46,7 +46,6 @@ export const ConfigVariableFilterDropdown = ({
|
||||
/>
|
||||
}
|
||||
dropdownId="env-var-options-dropdown"
|
||||
dropdownHotkeyScope={{ scope: 'env-var-options' }}
|
||||
dropdownOffset={{ x: 0, y: 10 }}
|
||||
dropdownComponents={
|
||||
<ConfigVariableOptionsDropdownContent
|
||||
|
||||
@ -130,7 +130,6 @@ export const SettingsDataModelNewFieldBreadcrumbDropDown = () => {
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
|
||||
@ -117,7 +117,6 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
|
||||
<Dropdown
|
||||
dropdownId={SELECT_COLOR_DROPDOWN_ID}
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownHotkeyScope={{ scope: SELECT_COLOR_DROPDOWN_ID }}
|
||||
clickableComponent={<StyledColorSample colorName={option.color} />}
|
||||
dropdownComponents={
|
||||
<DropdownContent>
|
||||
@ -160,7 +159,6 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
|
||||
<Dropdown
|
||||
dropdownId={SELECT_ACTIONS_DROPDOWN_ID}
|
||||
dropdownPlacement="right-start"
|
||||
dropdownHotkeyScope={{ scope: SELECT_ACTIONS_DROPDOWN_ID }}
|
||||
clickableComponent={
|
||||
<StyledLightIconButton accent="tertiary" Icon={IconDotsVertical} />
|
||||
}
|
||||
|
||||
@ -82,7 +82,6 @@ export const SettingsObjectFieldActiveActionDropdown = ({
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -86,9 +86,6 @@ export const SettingsObjectFieldInactiveActionDropdown = ({
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{
|
||||
scope: dropdownId,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -63,7 +63,6 @@ export const SettingsObjectInactiveMenuDropDown = ({
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -54,7 +54,6 @@ export const SettingsIntegrationDatabaseConnectionSummaryCard = ({
|
||||
/>
|
||||
<Dropdown
|
||||
dropdownId={dropdownId}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
clickableComponent={
|
||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||
}
|
||||
|
||||
@ -238,7 +238,6 @@ export const SettingsRoleAssignment = ({
|
||||
<StyledAssignToMemberContainer>
|
||||
<Dropdown
|
||||
dropdownId="role-member-select"
|
||||
dropdownHotkeyScope={{ scope: 'roleAssignment' }}
|
||||
dropdownOffset={{ x: 0, y: 4 }}
|
||||
clickableComponent={
|
||||
<>
|
||||
|
||||
@ -69,7 +69,6 @@ export const SettingsSecuritySSORowDropdownMenu = ({
|
||||
<Dropdown
|
||||
dropdownId={dropdownId}
|
||||
dropdownPlacement="right-start"
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
clickableComponent={
|
||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||
}
|
||||
|
||||
@ -58,7 +58,6 @@ export const SettingsSecurityApprovedAccessDomainRowDropdownMenu = ({
|
||||
<Dropdown
|
||||
dropdownId={dropdownId}
|
||||
dropdownPlacement="right-start"
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
clickableComponent={
|
||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||
}
|
||||
|
||||
@ -131,7 +131,6 @@ export const SettingsServerlessFunctionTabEnvironmentVariableTableRow = ({
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropDownId }}
|
||||
/>
|
||||
</TableCell>
|
||||
</StyledTableRow>
|
||||
|
||||
@ -123,9 +123,6 @@ export const MatchColumnToFieldSelect = ({
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={dropdownId}
|
||||
dropdownHotkeyScope={{
|
||||
scope: dropdownId,
|
||||
}}
|
||||
dropdownPlacement="bottom-start"
|
||||
clickableComponent={
|
||||
<StyledMenuItem
|
||||
|
||||
@ -52,7 +52,6 @@ export const SubMatchingSelectRowRightDropdown = <T extends string>({
|
||||
return (
|
||||
<StyledDropdownContainer>
|
||||
<Dropdown
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
dropdownId={dropdownId}
|
||||
dropdownPlacement="bottom-start"
|
||||
clickableComponent={
|
||||
|
||||
@ -44,7 +44,6 @@ export const SupportDropdown = () => {
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -2,15 +2,17 @@ import { useRef, useState } from 'react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@ -21,7 +23,7 @@ import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmp
|
||||
type MultiSelectInputProps = {
|
||||
selectableListComponentInstanceId: string;
|
||||
values: FieldMultiSelectValue;
|
||||
hotkeyScope: string;
|
||||
focusId: string;
|
||||
onCancel?: () => void;
|
||||
options: SelectOption[];
|
||||
onOptionSelected: (value: FieldMultiSelectValue) => void;
|
||||
@ -32,7 +34,7 @@ export const MultiSelectInput = ({
|
||||
selectableListComponentInstanceId,
|
||||
values,
|
||||
options,
|
||||
hotkeyScope,
|
||||
focusId,
|
||||
onCancel,
|
||||
onOptionSelected,
|
||||
dropdownWidth,
|
||||
@ -69,15 +71,16 @@ export const MultiSelectInput = ({
|
||||
}
|
||||
};
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
() => {
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: Key.Escape,
|
||||
callback: () => {
|
||||
onCancel?.();
|
||||
resetSelectedItem();
|
||||
},
|
||||
hotkeyScope,
|
||||
[onCancel, resetSelectedItem],
|
||||
);
|
||||
focusId,
|
||||
scope: DEFAULT_CELL_SCOPE.scope,
|
||||
dependencies: [onCancel, resetSelectedItem],
|
||||
});
|
||||
|
||||
useListenClickOutside({
|
||||
refs: [containerRef],
|
||||
@ -102,7 +105,8 @@ export const MultiSelectInput = ({
|
||||
<SelectableList
|
||||
selectableListInstanceId={selectableListComponentInstanceId}
|
||||
selectableItemIdArray={optionIds}
|
||||
hotkeyScope={hotkeyScope}
|
||||
focusId={focusId}
|
||||
hotkeyScope={DEFAULT_CELL_SCOPE.scope}
|
||||
>
|
||||
<DropdownContent
|
||||
ref={containerRef}
|
||||
@ -122,17 +126,25 @@ export const MultiSelectInput = ({
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
{filteredOptionsInDropDown.map((option) => {
|
||||
return (
|
||||
<MenuItemMultiSelectTag
|
||||
<SelectableListItem
|
||||
key={option.value}
|
||||
selected={values?.includes(option.value) || false}
|
||||
text={option.label}
|
||||
color={option.color ?? 'transparent'}
|
||||
Icon={option.Icon ?? undefined}
|
||||
onClick={() =>
|
||||
onOptionSelected(formatNewSelectedOptions(option.value))
|
||||
}
|
||||
isKeySelected={selectedItemId === option.value}
|
||||
/>
|
||||
itemId={option.value}
|
||||
onEnter={() => {
|
||||
onOptionSelected(formatNewSelectedOptions(option.value));
|
||||
}}
|
||||
>
|
||||
<MenuItemMultiSelectTag
|
||||
key={option.value}
|
||||
selected={values?.includes(option.value) || false}
|
||||
text={option.label}
|
||||
color={option.color ?? 'transparent'}
|
||||
Icon={option.Icon ?? undefined}
|
||||
onClick={() =>
|
||||
onOptionSelected(formatNewSelectedOptions(option.value))
|
||||
}
|
||||
isKeySelected={selectedItemId === option.value}
|
||||
/>
|
||||
</SelectableListItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuItemsContainer>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||
import { SelectInput as SelectBaseInput } from '@/ui/input/components/SelectInput';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { SelectOption } from 'twenty-ui/input';
|
||||
@ -5,7 +6,7 @@ import { SelectOption } from 'twenty-ui/input';
|
||||
type SelectInputProps = {
|
||||
selectableListComponentInstanceId: string;
|
||||
selectableItemIdArray: string[];
|
||||
hotkeyScope: string;
|
||||
focusId: string;
|
||||
onEnter: (itemId: string) => void;
|
||||
onOptionSelected: (selectedOption: SelectOption) => void;
|
||||
options: SelectOption[];
|
||||
@ -19,7 +20,7 @@ type SelectInputProps = {
|
||||
export const SelectInput = ({
|
||||
selectableListComponentInstanceId,
|
||||
selectableItemIdArray,
|
||||
hotkeyScope,
|
||||
focusId,
|
||||
onOptionSelected,
|
||||
options,
|
||||
onCancel,
|
||||
@ -32,7 +33,8 @@ export const SelectInput = ({
|
||||
<SelectableList
|
||||
selectableListInstanceId={selectableListComponentInstanceId}
|
||||
selectableItemIdArray={selectableItemIdArray}
|
||||
hotkeyScope={hotkeyScope}
|
||||
focusId={focusId}
|
||||
hotkeyScope={DEFAULT_CELL_SCOPE.scope}
|
||||
>
|
||||
<SelectBaseInput
|
||||
onOptionSelected={onOptionSelected}
|
||||
@ -42,7 +44,7 @@ export const SelectInput = ({
|
||||
onFilterChange={onFilterChange}
|
||||
onClear={onClear}
|
||||
clearLabel={clearLabel}
|
||||
hotkeyScope={hotkeyScope}
|
||||
focusId={focusId}
|
||||
/>
|
||||
</SelectableList>
|
||||
);
|
||||
|
||||
@ -12,6 +12,7 @@ import { arrayToChunks } from '~/utils/array/arrayToChunks';
|
||||
|
||||
import { ICON_PICKER_DROPDOWN_CONTENT_WIDTH } from '@/ui/input/components/constants/IconPickerDropdownContentWidth';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { useSelectableListListenToEnterHotkeyOnItem } from '@/ui/layout/selectable-list/hooks/useSelectableListListenToEnterHotkeyOnItem';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
@ -71,9 +72,10 @@ const IconPickerIcon = ({
|
||||
);
|
||||
|
||||
useSelectableListListenToEnterHotkeyOnItem({
|
||||
hotkeyScope: IconPickerHotkeyScope.IconPicker,
|
||||
focusId: iconKey,
|
||||
itemId: iconKey,
|
||||
onEnter: onClick,
|
||||
hotkeyScope: DropdownHotkeyScope.Dropdown,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -184,7 +186,6 @@ export const IconPicker = ({
|
||||
<div className={className}>
|
||||
<Dropdown
|
||||
dropdownId={dropdownId}
|
||||
dropdownHotkeyScope={{ scope: IconPickerHotkeyScope.IconPicker }}
|
||||
clickableComponent={
|
||||
<IconButton
|
||||
ariaLabel={`Click to select icon ${
|
||||
@ -203,7 +204,8 @@ export const IconPicker = ({
|
||||
<SelectableList
|
||||
selectableListInstanceId="icon-list"
|
||||
selectableItemIdMatrix={iconKeys2d}
|
||||
hotkeyScope={IconPickerHotkeyScope.IconPicker}
|
||||
focusId={dropdownId}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
<DropdownMenuSearchInput
|
||||
placeholder={t`Search icon`}
|
||||
|
||||
@ -9,6 +9,7 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
|
||||
import { SelectControl } from '@/ui/input/components/SelectControl';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
@ -19,7 +20,6 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { IconComponent } from 'twenty-ui/display';
|
||||
import { SelectOption } from 'twenty-ui/input';
|
||||
import { MenuItem, MenuItemSelect } from 'twenty-ui/navigation';
|
||||
import { SelectHotkeyScope } from '../types/SelectHotkeyScope';
|
||||
|
||||
export type SelectSizeVariant = 'small' | 'default';
|
||||
|
||||
@ -166,9 +166,10 @@ export const Select = <Value extends SelectValue>({
|
||||
{!!filteredOptions.length && (
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<SelectableList
|
||||
hotkeyScope={SelectHotkeyScope.Select}
|
||||
selectableListInstanceId={dropdownId}
|
||||
focusId={dropdownId}
|
||||
selectableItemIdArray={selectableItemIdArray}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
{filteredOptions.map((option) => (
|
||||
<SelectableListItem
|
||||
@ -211,7 +212,6 @@ export const Select = <Value extends SelectValue>({
|
||||
)}
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
|
||||
/>
|
||||
)}
|
||||
</StyledContainer>
|
||||
|
||||
@ -2,10 +2,13 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { TagColor } from 'twenty-ui/components';
|
||||
import { SelectOption } from 'twenty-ui/input';
|
||||
@ -19,7 +22,7 @@ interface SelectInputProps {
|
||||
onFilterChange?: (filteredOptions: SelectOption[]) => void;
|
||||
onClear?: () => void;
|
||||
clearLabel?: string;
|
||||
hotkeyScope: string;
|
||||
focusId: string;
|
||||
}
|
||||
|
||||
export const SelectInput = ({
|
||||
@ -30,10 +33,19 @@ export const SelectInput = ({
|
||||
onCancel,
|
||||
defaultOption,
|
||||
onFilterChange,
|
||||
hotkeyScope,
|
||||
}: SelectInputProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Get the SelectableList instance id from context
|
||||
const selectableListInstanceId = useAvailableComponentInstanceIdOrThrow(
|
||||
SelectableListComponentInstanceContext,
|
||||
);
|
||||
|
||||
const selectedItemId = useRecoilComponentValueV2(
|
||||
selectedItemIdComponentState,
|
||||
selectableListInstanceId,
|
||||
);
|
||||
|
||||
const [searchFilter, setSearchFilter] = useState('');
|
||||
const [selectedOption, setSelectedOption] = useState<
|
||||
SelectOption | undefined
|
||||
@ -61,6 +73,11 @@ export const SelectInput = ({
|
||||
onOptionSelected(option);
|
||||
};
|
||||
|
||||
const handleClearOption = () => {
|
||||
setSelectedOption(undefined);
|
||||
onClear?.();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
onFilterChange?.(optionsInDropDown);
|
||||
}, [onFilterChange, optionsInDropDown]);
|
||||
@ -81,20 +98,6 @@ export const SelectInput = ({
|
||||
listenerId: 'select-input',
|
||||
});
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Enter,
|
||||
() => {
|
||||
const selectedOption = optionsInDropDown.find((option) =>
|
||||
option.label.toLowerCase().includes(searchFilter.toLowerCase()),
|
||||
);
|
||||
if (isDefined(selectedOption)) {
|
||||
handleOptionChange(selectedOption);
|
||||
}
|
||||
},
|
||||
hotkeyScope,
|
||||
[searchFilter, optionsInDropDown],
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownContent ref={containerRef} selectDisabled>
|
||||
<DropdownMenuSearchInput
|
||||
@ -105,27 +108,37 @@ export const SelectInput = ({
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
{onClear && clearLabel && (
|
||||
<MenuItemSelectTag
|
||||
key={`No ${clearLabel}`}
|
||||
text={`No ${clearLabel}`}
|
||||
color="transparent"
|
||||
variant={'outline'}
|
||||
onClick={() => {
|
||||
setSelectedOption(undefined);
|
||||
onClear();
|
||||
}}
|
||||
/>
|
||||
<SelectableListItem
|
||||
itemId={`No ${clearLabel}`}
|
||||
onEnter={handleClearOption}
|
||||
>
|
||||
<MenuItemSelectTag
|
||||
key={`No ${clearLabel}`}
|
||||
text={`No ${clearLabel}`}
|
||||
color="transparent"
|
||||
variant={'outline'}
|
||||
onClick={handleClearOption}
|
||||
isKeySelected={selectedItemId === `No ${clearLabel}`}
|
||||
/>
|
||||
</SelectableListItem>
|
||||
)}
|
||||
{optionsInDropDown.map((option) => {
|
||||
return (
|
||||
<MenuItemSelectTag
|
||||
<SelectableListItem
|
||||
key={option.value}
|
||||
focused={selectedOption?.value === option.value}
|
||||
text={option.label}
|
||||
color={(option.color as TagColor) ?? 'transparent'}
|
||||
onClick={() => handleOptionChange(option)}
|
||||
LeftIcon={option.Icon}
|
||||
/>
|
||||
itemId={option.value}
|
||||
onEnter={() => handleOptionChange(option)}
|
||||
>
|
||||
<MenuItemSelectTag
|
||||
key={option.value}
|
||||
selected={selectedOption?.value === option.value}
|
||||
text={option.label}
|
||||
color={(option.color as TagColor) ?? 'transparent'}
|
||||
onClick={() => handleOptionChange(option)}
|
||||
LeftIcon={option.Icon}
|
||||
isKeySelected={selectedItemId === option.value}
|
||||
/>
|
||||
</SelectableListItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuItemsContainer>
|
||||
|
||||
@ -70,7 +70,6 @@ export const CurrencyPickerDropdownButton = ({
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId="currency-picker-dropdown-id"
|
||||
dropdownHotkeyScope={{ scope: CurrencyPickerHotkeyScope.CurrencyPicker }}
|
||||
clickableComponent={
|
||||
<StyledDropdownButtonContainer>
|
||||
<StyledIconContainer>
|
||||
|
||||
@ -6,8 +6,6 @@ import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { CountryPickerHotkeyScope } from '../types/CountryPickerHotkeyScope';
|
||||
|
||||
import { PhoneCountryPickerDropdownSelect } from './PhoneCountryPickerDropdownSelect';
|
||||
|
||||
import 'react-phone-number-input/style.css';
|
||||
@ -98,7 +96,6 @@ export const PhoneCountryPickerDropdownButton = ({
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId="country-picker-dropdown-id"
|
||||
dropdownHotkeyScope={{ scope: CountryPickerHotkeyScope.CountryPicker }}
|
||||
clickableComponent={
|
||||
<StyledDropdownButtonContainer isUnfolded={isDropdownOpen}>
|
||||
<StyledIconContainer>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user