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:
@ -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 (
|
||||
|
||||
@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
@ -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 ? (
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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} />
|
||||
|
||||
@ -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};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user