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:
@ -29,7 +29,6 @@ export const AdvancedFilterDropdownButton = () => {
|
||||
dropdownId={ADVANCED_FILTER_DROPDOWN_ID}
|
||||
clickableComponent={<AdvancedFilterChip />}
|
||||
dropdownComponents={<AdvancedFilterRootRecordFilterGroup />}
|
||||
dropdownHotkeyScope={{ scope: ADVANCED_FILTER_DROPDOWN_ID }}
|
||||
dropdownOffset={{ y: 8, x: 0 }}
|
||||
dropdownPlacement="bottom-start"
|
||||
onOpen={handleOpenAdvancedFilterDropdown}
|
||||
|
||||
@ -3,7 +3,6 @@ import { useCallback } from 'react';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { EditableFilterChip } from '@/views/components/EditableFilterChip';
|
||||
|
||||
import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput';
|
||||
@ -13,12 +12,10 @@ import { useSetEditableFilterChipDropdownStates } from '@/views/hooks/useSetEdit
|
||||
|
||||
type EditableFilterDropdownButtonProps = {
|
||||
recordFilter: RecordFilter;
|
||||
hotkeyScope: HotkeyScope;
|
||||
};
|
||||
|
||||
export const EditableFilterDropdownButton = ({
|
||||
recordFilter,
|
||||
hotkeyScope,
|
||||
}: EditableFilterDropdownButtonProps) => {
|
||||
const { closeDropdown } = useDropdown(recordFilter.id);
|
||||
|
||||
@ -59,7 +56,6 @@ export const EditableFilterDropdownButton = ({
|
||||
dropdownComponents={
|
||||
<ObjectFilterDropdownFilterInput filterDropdownId={recordFilter.id} />
|
||||
}
|
||||
dropdownHotkeyScope={hotkeyScope}
|
||||
dropdownOffset={{ y: 8, x: 0 }}
|
||||
dropdownPlacement="bottom-start"
|
||||
onClose={onFilterDropdownClose}
|
||||
|
||||
@ -34,9 +34,7 @@ export type UpdateViewButtonGroupProps = {
|
||||
hotkeyScope: HotkeyScope;
|
||||
};
|
||||
|
||||
export const UpdateViewButtonGroup = ({
|
||||
hotkeyScope,
|
||||
}: UpdateViewButtonGroupProps) => {
|
||||
export const UpdateViewButtonGroup = () => {
|
||||
const { saveCurrentViewFilterAndSorts } = useSaveCurrentViewFiltersAndSorts();
|
||||
|
||||
const { setViewPickerMode } = useViewPickerMode();
|
||||
@ -109,7 +107,6 @@ export const UpdateViewButtonGroup = ({
|
||||
<Button title="Update view" onClick={handleUpdateViewClick} />
|
||||
<Dropdown
|
||||
dropdownId={UPDATE_VIEW_BUTTON_DROPDOWN_ID}
|
||||
dropdownHotkeyScope={hotkeyScope}
|
||||
clickableComponent={
|
||||
<IconButton
|
||||
size="small"
|
||||
|
||||
@ -8,10 +8,8 @@ import { QueryParamsFiltersEffect } from '@/views/components/QueryParamsFiltersE
|
||||
import { ViewBarPageTitle } from '@/views/components/ViewBarPageTitle';
|
||||
import { ViewBarSkeletonLoader } from '@/views/components/ViewBarSkeletonLoader';
|
||||
import { ViewPickerDropdown } from '@/views/view-picker/components/ViewPickerDropdown';
|
||||
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
|
||||
|
||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||
import { VIEW_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ViewSortDropdownId';
|
||||
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
||||
import { ViewBarFilterDropdown } from '@/views/components/ViewBarFilterDropdown';
|
||||
@ -59,17 +57,9 @@ export const ViewBar = ({
|
||||
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||
value={{ instanceId: VIEW_BAR_FILTER_DROPDOWN_ID }}
|
||||
>
|
||||
<ViewBarFilterDropdown
|
||||
hotkeyScope={{
|
||||
scope: FiltersHotkeyScope.ObjectFilterDropdownButton,
|
||||
}}
|
||||
/>
|
||||
<ViewBarFilterDropdown />
|
||||
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
||||
<ObjectSortDropdownButton
|
||||
hotkeyScope={{
|
||||
scope: FiltersHotkeyScope.ObjectSortDropdownButton,
|
||||
}}
|
||||
/>
|
||||
<ObjectSortDropdownButton />
|
||||
{optionsDropdownButton}
|
||||
</>
|
||||
}
|
||||
@ -78,13 +68,7 @@ export const ViewBar = ({
|
||||
hasFilterButton
|
||||
viewBarId={viewBarId}
|
||||
objectNamePlural={objectNamePlural}
|
||||
rightComponent={
|
||||
<UpdateViewButtonGroup
|
||||
hotkeyScope={{
|
||||
scope: ViewsHotkeyScope.UpdateViewButtonDropdown,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
rightComponent={<UpdateViewButtonGroup />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@ -229,12 +229,7 @@ export const ViewBarDetails = ({
|
||||
value={{ instanceId: recordFilter.id }}
|
||||
>
|
||||
<DropdownScope dropdownScopeId={recordFilter.id}>
|
||||
<EditableFilterDropdownButton
|
||||
recordFilter={recordFilter}
|
||||
hotkeyScope={{
|
||||
scope: recordFilter.id,
|
||||
}}
|
||||
/>
|
||||
<EditableFilterDropdownButton recordFilter={recordFilter} />
|
||||
</DropdownScope>
|
||||
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
||||
))}
|
||||
|
||||
@ -1,26 +1,13 @@
|
||||
import { useResetFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useResetFilterDropdown';
|
||||
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
|
||||
export const ViewBarFilterButton = () => {
|
||||
const { resetFilterDropdown } = useResetFilterDropdown();
|
||||
|
||||
const { toggleDropdown, isDropdownOpen } = useDropdown(
|
||||
VIEW_BAR_FILTER_DROPDOWN_ID,
|
||||
);
|
||||
|
||||
const handleClick = () => {
|
||||
toggleDropdown();
|
||||
resetFilterDropdown();
|
||||
};
|
||||
const { isDropdownOpen } = useDropdown(VIEW_BAR_FILTER_DROPDOWN_ID);
|
||||
|
||||
return (
|
||||
<StyledHeaderDropdownButton
|
||||
onClick={handleClick}
|
||||
isUnfolded={isDropdownOpen}
|
||||
>
|
||||
<StyledHeaderDropdownButton isUnfolded={isDropdownOpen}>
|
||||
<Trans>Filter</Trans>
|
||||
</StyledHeaderDropdownButton>
|
||||
);
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { useResetFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useResetFilterDropdown';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { useVectorSearchFilterActions } from '@/views/hooks/useVectorSearchFilterActions';
|
||||
|
||||
@ -13,13 +12,7 @@ import { ViewBarFilterDropdownContent } from '@/views/components/ViewBarFilterDr
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { ViewBarFilterButton } from './ViewBarFilterButton';
|
||||
|
||||
type ViewBarFilterDropdownProps = {
|
||||
hotkeyScope: HotkeyScope;
|
||||
};
|
||||
|
||||
export const ViewBarFilterDropdown = ({
|
||||
hotkeyScope,
|
||||
}: ViewBarFilterDropdownProps) => {
|
||||
export const ViewBarFilterDropdown = () => {
|
||||
const { resetFilterDropdown } = useResetFilterDropdown();
|
||||
const { removeEmptyVectorSearchFilter } = useVectorSearchFilterActions();
|
||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||
@ -47,13 +40,17 @@ export const ViewBarFilterDropdown = ({
|
||||
removeEmptyVectorSearchFilter();
|
||||
};
|
||||
|
||||
const handleDropdownOpen = () => {
|
||||
resetFilterDropdown();
|
||||
};
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={VIEW_BAR_FILTER_DROPDOWN_ID}
|
||||
onClose={handleDropdownClose}
|
||||
onOpen={handleDropdownOpen}
|
||||
clickableComponent={<ViewBarFilterButton />}
|
||||
dropdownComponents={<ViewBarFilterDropdownContent />}
|
||||
dropdownHotkeyScope={hotkeyScope}
|
||||
dropdownOffset={{ y: 8 }}
|
||||
onClickOutside={handleDropdownClickOutside}
|
||||
excludedClickOutsideIds={[OPERAND_DROPDOWN_CLICK_OUTSIDE_ID]}
|
||||
|
||||
@ -119,9 +119,7 @@ export const ViewBarFilterDropdownAdvancedFilterButton = () => {
|
||||
}
|
||||
|
||||
closeObjectFilterDropdown();
|
||||
openAdvancedFilterDropdown({
|
||||
scope: ADVANCED_FILTER_DROPDOWN_ID,
|
||||
});
|
||||
openAdvancedFilterDropdown();
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -10,15 +10,16 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl
|
||||
|
||||
import { FILTER_FIELD_LIST_ID } from '@/object-record/object-filter-dropdown/constants/FilterFieldListId';
|
||||
import { useFilterDropdownSelectableFieldMetadataItems } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdownSelectableFieldMetadataItems';
|
||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { ViewBarFilterDropdownBottomMenu } from '@/views/components/ViewBarFilterDropdownBottomMenu';
|
||||
import { ViewBarFilterDropdownFieldSelectMenuItem } from '@/views/components/ViewBarFilterDropdownFieldSelectMenuItem';
|
||||
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { VIEW_BAR_FILTER_BOTTOM_MENU_ITEM_IDS } from '@/views/constants/ViewBarFilterBottomMenuItemIds';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
|
||||
export const StyledInput = styled.input`
|
||||
@ -92,9 +93,10 @@ export const ViewBarFilterDropdownFieldSelectMenu = () => {
|
||||
}
|
||||
/>
|
||||
<SelectableList
|
||||
hotkeyScope={FiltersHotkeyScope.ObjectFilterDropdownButton}
|
||||
selectableItemIdArray={selectableFieldMetadataItemIds}
|
||||
selectableListInstanceId={FILTER_FIELD_LIST_ID}
|
||||
focusId={VIEW_BAR_FILTER_DROPDOWN_ID}
|
||||
hotkeyScope={DropdownHotkeyScope.Dropdown}
|
||||
>
|
||||
{shouldShowVisibleFields && (
|
||||
<>
|
||||
|
||||
@ -15,16 +15,20 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-fi
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
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 { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||
import { getMockPersonObjectMetadataItem } from '~/testing/mock-data/people';
|
||||
|
||||
const mockSetHotkeyScope = jest.fn();
|
||||
const mockPushFocusItemToFocusStack = jest.fn();
|
||||
|
||||
jest.mock('@/ui/utilities/hotkey/hooks/useSetHotkeyScope', () => ({
|
||||
useSetHotkeyScope: () => mockSetHotkeyScope,
|
||||
jest.mock('@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack', () => ({
|
||||
usePushFocusItemToFocusStack: () => ({
|
||||
pushFocusItemToFocusStack: mockPushFocusItemToFocusStack,
|
||||
}),
|
||||
}));
|
||||
|
||||
const peopleObjectMetadataItemMock = getMockPersonObjectMetadataItem();
|
||||
@ -109,7 +113,7 @@ describe('useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown', () =
|
||||
);
|
||||
expect(result.current.objectFilterDropdownFilterIsSelected).toBe(true);
|
||||
expect(result.current.selectedOperandInDropdown).toBe(defaultOperand);
|
||||
expect(mockSetHotkeyScope).not.toHaveBeenCalled();
|
||||
expect(mockPushFocusItemToFocusStack).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should initialize filter with a relation field', () => {
|
||||
@ -161,9 +165,17 @@ describe('useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown', () =
|
||||
);
|
||||
expect(result.current.objectFilterDropdownFilterIsSelected).toBe(true);
|
||||
expect(result.current.selectedOperandInDropdown).toBe(defaultOperand);
|
||||
expect(mockSetHotkeyScope).toHaveBeenCalledWith(
|
||||
SingleRecordPickerHotkeyScope.SingleRecordPicker,
|
||||
);
|
||||
expect(mockPushFocusItemToFocusStack).toHaveBeenCalledWith({
|
||||
focusId: VIEW_BAR_FILTER_DROPDOWN_ID,
|
||||
component: {
|
||||
type: FocusComponentType.DROPDOWN,
|
||||
instanceId: personCompanyFieldMetadataItemMock.id,
|
||||
},
|
||||
hotkeyScope: {
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
},
|
||||
memoizeKey: personCompanyFieldMetadataItemMock.id,
|
||||
});
|
||||
});
|
||||
|
||||
it('should initialize filter with a duplicate field on city', () => {
|
||||
|
||||
@ -10,9 +10,11 @@ import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-record/record-filter/utils/findDuplicateRecordFilterInNonAdvancedRecordFilters';
|
||||
import { getDateFilterDisplayValue } from '@/object-record/record-filter/utils/getDateFilterDisplayValue';
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
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 { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
@ -24,8 +26,6 @@ export const useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown =
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
const currentRecordFiltersCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
@ -48,6 +48,8 @@ export const useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown =
|
||||
const { upsertObjectFilterDropdownCurrentFilter } =
|
||||
useUpsertObjectFilterDropdownCurrentFilter();
|
||||
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
|
||||
const initializeFilterOnFieldMetataItemFromViewBarFilterDropdown =
|
||||
useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
@ -66,7 +68,17 @@ export const useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown =
|
||||
);
|
||||
|
||||
if (filterType === 'RELATION' || filterType === 'SELECT') {
|
||||
setHotkeyScope(SingleRecordPickerHotkeyScope.SingleRecordPicker);
|
||||
pushFocusItemToFocusStack({
|
||||
focusId: VIEW_BAR_FILTER_DROPDOWN_ID,
|
||||
component: {
|
||||
type: FocusComponentType.DROPDOWN,
|
||||
instanceId: fieldMetadataItem.id,
|
||||
},
|
||||
hotkeyScope: {
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
},
|
||||
memoizeKey: fieldMetadataItem.id,
|
||||
});
|
||||
}
|
||||
|
||||
set(objectFilterDropdownFilterIsSelectedCallbackState, true);
|
||||
@ -130,11 +142,11 @@ export const useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown =
|
||||
},
|
||||
[
|
||||
fieldMetadataItemUsedInDropdownCallbackState,
|
||||
currentRecordFiltersCallbackState,
|
||||
objectFilterDropdownFilterIsSelectedCallbackState,
|
||||
pushFocusItemToFocusStack,
|
||||
objectFilterDropdownCurrentRecordFilterCallbackState,
|
||||
selectedOperandInDropdownCallbackState,
|
||||
setHotkeyScope,
|
||||
objectFilterDropdownFilterIsSelectedCallbackState,
|
||||
currentRecordFiltersCallbackState,
|
||||
upsertObjectFilterDropdownCurrentFilter,
|
||||
],
|
||||
);
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
export enum ViewsHotkeyScope {
|
||||
ListDropdown = 'views-list-dropdown',
|
||||
UpdateViewButtonDropdown = 'update-view-button-dropdown',
|
||||
}
|
||||
@ -10,18 +10,18 @@ import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenu
|
||||
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 { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
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 { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState';
|
||||
import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType';
|
||||
import { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
||||
import { ViewPickerCreateButton } from '@/views/view-picker/components/ViewPickerCreateButton';
|
||||
import { ViewPickerIconAndNameContainer } from '@/views/view-picker/components/ViewPickerIconAndNameContainer';
|
||||
import { ViewPickerSaveButtonContainer } from '@/views/view-picker/components/ViewPickerSaveButtonContainer';
|
||||
import { ViewPickerSelectContainer } from '@/views/view-picker/components/ViewPickerSelectContainer';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { VIEW_PICKER_KANBAN_FIELD_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerKanbanFieldDropdownId';
|
||||
import { VIEW_PICKER_TYPE_SELECT_OPTIONS } from '@/views/view-picker/constants/ViewPickerTypeSelectOptions';
|
||||
import { VIEW_PICKER_VIEW_TYPE_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerViewTypeDropdownId';
|
||||
@ -78,15 +78,13 @@ export const ViewPickerContentCreateMode = () => {
|
||||
viewPickerTypeComponentState,
|
||||
);
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
const { createViewFromCurrentState } = useCreateViewFromCurrentState();
|
||||
|
||||
const { availableFieldsForKanban } = useGetAvailableFieldsForKanban();
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Enter,
|
||||
async () => {
|
||||
useHotkeysOnFocusedElement({
|
||||
keys: [Key.Enter],
|
||||
callback: async () => {
|
||||
if (viewPickerIsPersisting) {
|
||||
return;
|
||||
}
|
||||
@ -100,8 +98,15 @@ export const ViewPickerContentCreateMode = () => {
|
||||
|
||||
await createViewFromCurrentState();
|
||||
},
|
||||
ViewsHotkeyScope.ListDropdown,
|
||||
);
|
||||
focusId: VIEW_PICKER_DROPDOWN_ID,
|
||||
scope: DropdownHotkeyScope.Dropdown,
|
||||
dependencies: [
|
||||
viewPickerIsPersisting,
|
||||
createViewFromCurrentState,
|
||||
viewPickerType,
|
||||
availableFieldsForKanban,
|
||||
],
|
||||
});
|
||||
|
||||
const defaultIcon = viewTypeIconMapping(viewPickerType).displayName;
|
||||
|
||||
@ -141,11 +146,7 @@ export const ViewPickerContentCreateMode = () => {
|
||||
</DropdownMenuHeader>
|
||||
<DropdownMenuItemsContainer>
|
||||
<ViewPickerIconAndNameContainer>
|
||||
<IconPicker
|
||||
onChange={onIconChange}
|
||||
selectedIconKey={selectedIcon}
|
||||
onClose={() => setHotkeyScope(ViewsHotkeyScope.ListDropdown)}
|
||||
/>
|
||||
<IconPicker onChange={onIconChange} selectedIconKey={selectedIcon} />
|
||||
<TextInputV2
|
||||
value={viewPickerInputName}
|
||||
onChange={(value) => {
|
||||
|
||||
@ -7,15 +7,15 @@ import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenu
|
||||
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 { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
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 { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
||||
import { ViewPickerEditButton } from '@/views/view-picker/components/ViewPickerEditButton';
|
||||
import { ViewPickerIconAndNameContainer } from '@/views/view-picker/components/ViewPickerIconAndNameContainer';
|
||||
import { ViewPickerSaveButtonContainer } from '@/views/view-picker/components/ViewPickerSaveButtonContainer';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { useUpdateViewFromCurrentState } from '@/views/view-picker/hooks/useUpdateViewFromCurrentState';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
import { viewPickerInputNameComponentState } from '@/views/view-picker/states/viewPickerInputNameComponentState';
|
||||
@ -39,21 +39,21 @@ export const ViewPickerContentEditMode = () => {
|
||||
viewPickerIsDirtyComponentState,
|
||||
);
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
const { updateViewFromCurrentState } = useUpdateViewFromCurrentState();
|
||||
|
||||
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 onIconChange = ({ iconKey }: { iconKey: string }) => {
|
||||
setViewPickerIsDirty(true);
|
||||
@ -83,7 +83,6 @@ export const ViewPickerContentEditMode = () => {
|
||||
<IconPicker
|
||||
onChange={onIconChange}
|
||||
selectedIconKey={viewPickerSelectedIcon}
|
||||
onClose={() => setHotkeyScope(ViewsHotkeyScope.ListDropdown)}
|
||||
/>
|
||||
<TextInputV2
|
||||
value={viewPickerInputName}
|
||||
|
||||
@ -6,7 +6,6 @@ import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/S
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { useGetRecordIndexTotalCount } from '@/views/hooks/internal/useGetRecordIndexTotalCount';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
||||
import { ViewPickerContentCreateMode } from '@/views/view-picker/components/ViewPickerContentCreateMode';
|
||||
import { ViewPickerContentEditMode } from '@/views/view-picker/components/ViewPickerContentEditMode';
|
||||
import { ViewPickerContentEffect } from '@/views/view-picker/components/ViewPickerContentEffect';
|
||||
@ -71,7 +70,6 @@ export const ViewPickerDropdown = () => {
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={VIEW_PICKER_DROPDOWN_ID}
|
||||
dropdownHotkeyScope={{ scope: ViewsHotkeyScope.ListDropdown }}
|
||||
dropdownOffset={{ x: 0, y: 8 }}
|
||||
dropdownPlacement="bottom-start"
|
||||
onClickOutside={handleClickOutside}
|
||||
|
||||
Reference in New Issue
Block a user