fix(ui): jumpto interactions

- Autofocus on popover open
- Autoselect number on popover open
- Enter works to change page when input is focused
- Esc works to close popover when input is focused
This commit is contained in:
psychedelicious 2024-07-25 11:42:52 +10:00
parent cf1af94f53
commit 524647b1f1

View File

@ -11,7 +11,7 @@ import {
useDisclosure, useDisclosure,
} from '@invoke-ai/ui-library'; } from '@invoke-ai/ui-library';
import { useGalleryPagination } from 'features/gallery/hooks/useGalleryPagination'; import { useGalleryPagination } from 'features/gallery/hooks/useGalleryPagination';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -20,6 +20,16 @@ export const JumpTo = () => {
const { goToPage, currentPage, pages } = useGalleryPagination(); const { goToPage, currentPage, pages } = useGalleryPagination();
const [newPage, setNewPage] = useState(currentPage); const [newPage, setNewPage] = useState(currentPage);
const { isOpen, onToggle, onClose } = useDisclosure(); const { isOpen, onToggle, onClose } = useDisclosure();
const ref = useRef<HTMLInputElement>(null);
const onOpen = useCallback(() => {
setNewPage(currentPage);
setTimeout(() => {
const input = ref.current?.querySelector('input');
input?.focus();
input?.select();
}, 0);
}, [currentPage]);
const onChangeJumpTo = useCallback((v: number) => { const onChangeJumpTo = useCallback((v: number) => {
setNewPage(v - 1); setNewPage(v - 1);
@ -33,30 +43,40 @@ export const JumpTo = () => {
useHotkeys( useHotkeys(
'enter', 'enter',
() => { () => {
if (isOpen) {
onClickGo(); onClickGo();
}
}, },
{ enabled: isOpen, enableOnFormTags: ['input'] },
[isOpen, onClickGo] [isOpen, onClickGo]
); );
useHotkeys(
'esc',
() => {
setNewPage(currentPage);
onClose();
},
{ enabled: isOpen, enableOnFormTags: ['input'] },
[isOpen, onClose]
);
useEffect(() => { useEffect(() => {
setNewPage(currentPage); setNewPage(currentPage);
}, [currentPage]); }, [currentPage]);
return ( return (
<Popover isOpen={isOpen} onClose={onClose}> <Popover isOpen={isOpen} onClose={onClose} onOpen={onOpen}>
<PopoverTrigger> <PopoverTrigger>
<Button aria-label={t('gallery.jump')} size="xs" onClick={onToggle}> <Button aria-label={t('gallery.jump')} size="sm" onClick={onToggle} variant="outline">
{t('gallery.jump')} {t('gallery.jump')}
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent> <PopoverContent>
<PopoverArrow /> <PopoverArrow />
<PopoverBody> <PopoverBody>
<Flex gap={2}> <Flex gap={2} alignItems="center">
<FormControl> <FormControl>
<CompositeNumberInput <CompositeNumberInput
ref={ref}
size="sm" size="sm"
maxW="60px" maxW="60px"
value={newPage + 1} value={newPage + 1}
@ -65,10 +85,10 @@ export const JumpTo = () => {
step={1} step={1}
onChange={onChangeJumpTo} onChange={onChangeJumpTo}
/> />
<Button size="sm" onClick={onClickGo}> </FormControl>
<Button h="full" size="sm" onClick={onClickGo}>
{t('gallery.go')} {t('gallery.go')}
</Button> </Button>
</FormControl>
</Flex> </Flex>
</PopoverBody> </PopoverBody>
</PopoverContent> </PopoverContent>