Files
twenty/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useDropdown.ts
T
Raphaël Bosi 1ab51d41aa Replace hotkey scopes by focus stack (Part 2 - Record Table, Rows and Cells) (#12798)
# Replace hotkey scopes by focus stack (Part 2 - Record Table, Rows and
Cells)

This PR is the second part of a refactoring aiming to deprecate the
hotkey scopes api in favor of the new focus stack api which is more
robust.
Part 1: https://github.com/twentyhq/twenty/pull/12673

The record table shortcuts are no longer centralized in the record
table, they now split and the focused element is in charge of applying
the desired shortcuts. (For instance: The rows are in charge of the row
navigation and the cells of the cells navigation).

## Video QA:


https://github.com/user-attachments/assets/f0bb9eed-8a2a-4b6d-a82f-1998e929f122


## Bugfixes:

### Fix record table click outside not working after opening and closing
a cell

Introduced by https://github.com/twentyhq/twenty/pull/11644

#### Before


https://github.com/user-attachments/assets/d28deda8-15e9-4ffe-b60a-e8b54625f8e5


#### After


https://github.com/user-attachments/assets/3f7e1ffc-15d9-4336-aeb0-bebd8ae0cbe0


### Fix ObjectFilterDropdownFilterInput hotkeys

Introduced by https://github.com/twentyhq/twenty/pull/12673

#### Before


https://github.com/user-attachments/assets/ab2039bd-ebe1-49ba-8377-a6b300664469


#### After


https://github.com/user-attachments/assets/90597453-dab2-426b-a134-0a24b0de0a6b
2025-06-25 13:18:51 +00:00

99 lines
3.2 KiB
TypeScript

import { useRecoilCallback, useRecoilState } from 'recoil';
import { useDropdownStates } from '@/ui/layout/dropdown/hooks/internal/useDropdownStates';
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
import { GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useCallback } from 'react';
export const useDropdown = (dropdownId?: string) => {
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
const { removeFocusItemFromFocusStackById } =
useRemoveFocusItemFromFocusStackById();
const { scopeId, isDropdownOpenState, dropdownPlacementState } =
useDropdownStates({ dropdownScopeId: dropdownId });
const { setActiveDropdownFocusIdAndMemorizePrevious } =
useSetActiveDropdownFocusIdAndMemorizePrevious();
const { goBackToPreviousDropdownFocusId } =
useGoBackToPreviousDropdownFocusId();
const [isDropdownOpen, setIsDropdownOpen] =
useRecoilState(isDropdownOpenState);
const [dropdownPlacement, setDropdownPlacement] = useRecoilState(
dropdownPlacementState,
);
const closeDropdown = useCallback(() => {
if (isDropdownOpen) {
setIsDropdownOpen(false);
goBackToPreviousDropdownFocusId();
removeFocusItemFromFocusStackById({
focusId: dropdownId ?? scopeId,
});
}
}, [
isDropdownOpen,
setIsDropdownOpen,
goBackToPreviousDropdownFocusId,
removeFocusItemFromFocusStackById,
dropdownId,
scopeId,
]);
const openDropdown = useRecoilCallback(
() => (globalHotkeysConfig?: Partial<GlobalHotkeysConfig>) => {
if (!isDropdownOpen) {
setIsDropdownOpen(true);
setActiveDropdownFocusIdAndMemorizePrevious(dropdownId ?? scopeId);
pushFocusItemToFocusStack({
focusId: dropdownId ?? scopeId,
component: {
type: FocusComponentType.DROPDOWN,
instanceId: dropdownId ?? scopeId,
},
globalHotkeysConfig,
// TODO: Remove this once we've fully migrated away from hotkey scopes
hotkeyScope: { scope: 'dropdown' } as HotkeyScope,
});
}
},
[
isDropdownOpen,
setIsDropdownOpen,
setActiveDropdownFocusIdAndMemorizePrevious,
pushFocusItemToFocusStack,
dropdownId,
scopeId,
],
);
const toggleDropdown = (
globalHotkeysConfig?: Partial<GlobalHotkeysConfig>,
) => {
if (isDropdownOpen) {
closeDropdown();
} else {
openDropdown(globalHotkeysConfig);
}
};
return {
scopeId,
isDropdownOpen,
closeDropdown,
toggleDropdown,
openDropdown,
dropdownPlacement,
setDropdownPlacement,
};
};