fix: navigate with arrow keys in select/multi-select (#5983)

closes: #4977



https://github.com/twentyhq/twenty/assets/13139771/8121814c-9a8a-4a8d-9290-1aebe145220f

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
Aditya Pimpalkar
2024-08-02 19:12:46 +01:00
committed by GitHub
parent c5d95dc4c8
commit 1f5c25ac0a
17 changed files with 518 additions and 153 deletions

View File

@ -10,7 +10,9 @@ import { useRef } from 'react';
import { Keys } from 'react-hotkeys-hook';
import { Key } from 'ts-key-enum';
import { SINGLE_ENTITY_SELECT_BASE_LIST } from '@/object-record/relation-picker/constants/SingleEntitySelectBaseList';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { HotkeyEffect } from '@/ui/utilities/hotkey/components/HotkeyEffect';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
@ -66,6 +68,10 @@ export const Dropdown = ({
const { isDropdownOpen, toggleDropdown, closeDropdown, dropdownWidth } =
useDropdown(dropdownId);
const { handleResetSelectedPosition } = useSelectableList(
SINGLE_ENTITY_SELECT_BASE_LIST,
);
const offsetMiddlewares = [];
if (isDefined(dropdownOffset.x)) {
@ -94,6 +100,7 @@ export const Dropdown = ({
if (isDropdownOpen) {
closeDropdown();
handleResetSelectedPosition();
}
},
});
@ -107,9 +114,10 @@ export const Dropdown = ({
[Key.Escape],
() => {
closeDropdown();
handleResetSelectedPosition();
},
dropdownHotkeyScope.scope,
[closeDropdown],
[closeDropdown, handleResetSelectedPosition],
);
return (

View File

@ -1,6 +1,12 @@
import { useResetRecoilState, useSetRecoilState } from 'recoil';
import {
useRecoilCallback,
useResetRecoilState,
useSetRecoilState,
} from 'recoil';
import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListStates';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { isDefined } from '~/utils/isDefined';
export const useSelectableList = (selectableListId?: string) => {
const {
@ -24,6 +30,18 @@ export const useSelectableList = (selectableListId?: string) => {
resetSelectedItemIdState();
};
const handleResetSelectedPosition = useRecoilCallback(
({ snapshot, set }) =>
() => {
const selectedItemId = getSnapshotValue(snapshot, selectedItemIdState);
if (isDefined(selectedItemId)) {
set(selectedItemIdState, null);
set(isSelectedItemIdSelector(selectedItemId), false);
}
},
[selectedItemIdState, isSelectedItemIdSelector],
);
return {
selectableListId: scopeId,
@ -31,5 +49,6 @@ export const useSelectableList = (selectableListId?: string) => {
isSelectedItemIdSelector,
setSelectableListOnEnter,
resetSelectedItem,
handleResetSelectedPosition,
};
};

View File

@ -17,6 +17,7 @@ type MenuItemMultiSelectProps = {
color?: ThemeColor;
LeftIcon?: IconComponent;
selected: boolean;
isKeySelected?: boolean;
text: string;
className: string;
onSelectChange?: (selected: boolean) => void;
@ -27,6 +28,7 @@ export const MenuItemMultiSelect = ({
LeftIcon,
text,
selected,
isKeySelected,
className,
onSelectChange,
}: MenuItemMultiSelectProps) => {
@ -35,7 +37,11 @@ export const MenuItemMultiSelect = ({
};
return (
<StyledMenuItemBase className={className} onClick={handleOnClick}>
<StyledMenuItemBase
isKeySelected={isKeySelected}
className={className}
onClick={handleOnClick}
>
<StyledLeftContentWithCheckboxContainer>
<Checkbox checked={selected} />
{color ? (

View File

@ -14,6 +14,7 @@ import {
type MenuItemMultiSelectTagProps = {
selected: boolean;
className?: string;
isKeySelected?: boolean;
onClick?: () => void;
color: ThemeColor;
text: string;
@ -24,10 +25,15 @@ export const MenuItemMultiSelectTag = ({
selected,
className,
onClick,
isKeySelected,
text,
}: MenuItemMultiSelectTagProps) => {
return (
<StyledMenuItemBase onClick={onClick} className={className}>
<StyledMenuItemBase
isKeySelected={isKeySelected}
onClick={onClick}
className={className}
>
<Checkbox
size={CheckboxSize.Small}
shape={CheckboxShape.Squared}

View File

@ -7,6 +7,7 @@ import { StyledMenuItemSelect } from './MenuItemSelect';
type MenuItemSelectTagProps = {
selected: boolean;
isKeySelected?: boolean;
className?: string;
onClick?: () => void;
color: ThemeColor | 'transparent';
@ -17,6 +18,7 @@ type MenuItemSelectTagProps = {
export const MenuItemSelectTag = ({
color,
selected,
isKeySelected,
className,
onClick,
text,
@ -29,6 +31,7 @@ export const MenuItemSelectTag = ({
onClick={onClick}
className={className}
selected={selected}
isKeySelected={isKeySelected}
>
<StyledMenuItemLeftContent>
<Tag variant={variant} color={color} text={text} />

View File

@ -32,6 +32,9 @@ export const StyledMenuItemBase = styled.div<MenuItemBaseProps>`
padding: var(--vertical-padding) var(--horizontal-padding);
${({ theme, isKeySelected }) =>
isKeySelected ? `background: ${theme.background.transparent.light};` : ''}
${({ isHoverBackgroundDisabled }) =>
isHoverBackgroundDisabled ?? HOVER_BACKGROUND};