Fix/scope hotkeys (#581)
* WIP * asd * Fix * Fix lint * Removed console log * asd * Removed isDefined * Fix/debounce company card onchange (#580) * Add internal state and debounce for editable text card * Use debounce for date fields too * Update refetch * Nit * Removed comments * Ménage --------- Co-authored-by: Emilien Chauvet <emilien.chauvet.enpc@gmail.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { useRef } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { IconPlus } from '@tabler/icons-react';
|
||||
|
||||
@@ -7,6 +8,7 @@ import { DropdownMenuButton } from '@/ui/components/menu/DropdownMenuButton';
|
||||
import { DropdownMenuItemContainer } from '@/ui/components/menu/DropdownMenuItemContainer';
|
||||
import { DropdownMenuSearch } from '@/ui/components/menu/DropdownMenuSearch';
|
||||
import { DropdownMenuSeparator } from '@/ui/components/menu/DropdownMenuSeparator';
|
||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { isDefined } from '@/utils/type-guards/isDefined';
|
||||
|
||||
import { useEntitySelectSearch } from '../hooks/useEntitySelectSearch';
|
||||
@@ -27,19 +29,27 @@ export function SingleEntitySelect<
|
||||
entities,
|
||||
onEntitySelected,
|
||||
onCreate,
|
||||
onCancel,
|
||||
}: {
|
||||
onCancel?: () => void;
|
||||
onCreate?: () => void;
|
||||
entities: EntitiesForSingleEntitySelect<CustomEntityForSelect>;
|
||||
onEntitySelected: (entity: CustomEntityForSelect) => void;
|
||||
}) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const { searchFilter, handleSearchFilterChange } = useEntitySelectSearch();
|
||||
|
||||
const showCreateButton = isDefined(onCreate) && searchFilter !== '';
|
||||
|
||||
useListenClickOutsideArrayOfRef([containerRef], () => {
|
||||
onCancel?.();
|
||||
});
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenu ref={containerRef}>
|
||||
<DropdownMenuSearch
|
||||
value={searchFilter}
|
||||
onChange={handleSearchFilterChange}
|
||||
@@ -60,6 +70,7 @@ export function SingleEntitySelect<
|
||||
<SingleEntitySelectBase
|
||||
entities={entities}
|
||||
onEntitySelected={onEntitySelected}
|
||||
onCancel={onCancel}
|
||||
/>
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useRef } from 'react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
@@ -27,30 +28,41 @@ export function SingleEntitySelectBase<
|
||||
>({
|
||||
entities,
|
||||
onEntitySelected,
|
||||
onCancel,
|
||||
}: {
|
||||
entities: EntitiesForSingleEntitySelect<CustomEntityForSelect>;
|
||||
onEntitySelected: (entity: CustomEntityForSelect) => void;
|
||||
onCancel?: () => void;
|
||||
}) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const entitiesInDropdown = isDefined(entities.selectedEntity)
|
||||
? [entities.selectedEntity, ...(entities.entitiesToSelect ?? [])]
|
||||
: entities.entitiesToSelect ?? [];
|
||||
|
||||
const { hoveredIndex } = useEntitySelectScroll({
|
||||
const { hoveredIndex, resetScroll } = useEntitySelectScroll({
|
||||
entities: entitiesInDropdown,
|
||||
containerRef,
|
||||
});
|
||||
|
||||
// TODO: move to better place for scopping
|
||||
useScopedHotkeys(
|
||||
'enter',
|
||||
Key.Enter,
|
||||
() => {
|
||||
onEntitySelected(entitiesInDropdown[hoveredIndex]);
|
||||
resetScroll();
|
||||
},
|
||||
InternalHotkeysScope.RelationPicker,
|
||||
[entitiesInDropdown, hoveredIndex, onEntitySelected],
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
() => {
|
||||
onCancel?.();
|
||||
},
|
||||
InternalHotkeysScope.RelationPicker,
|
||||
[onCancel],
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownMenuItemContainer ref={containerRef}>
|
||||
{entities.loading ? (
|
||||
|
||||
@@ -21,6 +21,22 @@ export function useEntitySelectScroll<
|
||||
relationPickerHoverIndexScopedState,
|
||||
);
|
||||
|
||||
function resetScroll() {
|
||||
setHoveredIndex(0);
|
||||
|
||||
const currentHoveredRef = containerRef.current?.children[0] as HTMLElement;
|
||||
|
||||
scrollIntoView(currentHoveredRef, {
|
||||
align: {
|
||||
top: 0,
|
||||
},
|
||||
isScrollable: (target) => {
|
||||
return target === containerRef.current;
|
||||
},
|
||||
time: 0,
|
||||
});
|
||||
}
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.ArrowUp,
|
||||
() => {
|
||||
@@ -60,7 +76,6 @@ export function useEntitySelectScroll<
|
||||
] as HTMLElement;
|
||||
|
||||
if (currentHoveredRef) {
|
||||
console.log({ currentHoveredRef, containerRef });
|
||||
scrollIntoView(currentHoveredRef, {
|
||||
align: {
|
||||
top: 0.15,
|
||||
@@ -78,5 +93,6 @@ export function useEntitySelectScroll<
|
||||
|
||||
return {
|
||||
hoveredIndex,
|
||||
resetScroll,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user