Fix dropdown open index

This commit is contained in:
Gregory Schier
2024-02-11 14:16:11 -08:00
parent 5892774082
commit a208b934e4

View File

@@ -20,7 +20,7 @@ import React, {
useRef, useRef,
useState, useState,
} from 'react'; } from 'react';
import { useKey, useKeyPressEvent, useWindowSize } from 'react-use'; import { useKey, useWindowSize } from 'react-use';
import type { HotkeyAction } from '../../hooks/useHotKey'; import type { HotkeyAction } from '../../hooks/useHotKey';
import { useHotKey } from '../../hooks/useHotKey'; import { useHotKey } from '../../hooks/useHotKey';
import { Overlay } from '../Overlay'; import { Overlay } from '../Overlay';
@@ -60,8 +60,8 @@ export interface DropdownProps {
export interface DropdownRef { export interface DropdownRef {
isOpen: boolean; isOpen: boolean;
open: (activeIndex?: number) => void; open: () => void;
toggle: (activeIndex?: number) => void; toggle: () => void;
close?: () => void; close?: () => void;
next?: () => void; next?: () => void;
prev?: () => void; prev?: () => void;
@@ -88,21 +88,17 @@ export const Dropdown = forwardRef<DropdownRef, DropdownProps>(function Dropdown
useHotKey(openOnHotKeyAction ?? null, () => { useHotKey(openOnHotKeyAction ?? null, () => {
setIsOpen(true); setIsOpen(true);
menuRef.current?.next?.();
}); });
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
...menuRef.current, ...menuRef.current,
isOpen: isOpen, isOpen: isOpen,
toggle(activeIndex?: number) { toggle() {
if (!isOpen) this.open(activeIndex); if (!isOpen) this.open();
else setIsOpen(false); else setIsOpen(false);
}, },
open(activeIndex?: number) { open() {
if (activeIndex === undefined) {
setDefaultSelectedIndex(undefined);
} else {
setDefaultSelectedIndex(activeIndex >= 0 ? activeIndex : items.length + activeIndex);
}
setIsOpen(true); setIsOpen(true);
}, },
})); }));
@@ -225,21 +221,23 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
setMenuStyles({ maxHeight: windowBox.height - menuBox.top - 5 }); setMenuStyles({ maxHeight: windowBox.height - menuBox.top - 5 });
}, []); }, []);
const handleClose = useCallback(() => {
onClose();
setSelectedIndex(null);
}, [onClose]);
// Close menu on space bar // Close menu on space bar
const handleMenuKeyDown = useCallback( const handleMenuKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLDivElement>) => { (e: React.KeyboardEvent<HTMLDivElement>) => {
if (e.key === ' ') { if (e.key === ' ') {
e.preventDefault(); e.preventDefault();
onClose(); handleClose();
} }
}, },
[onClose], [handleClose],
); );
useKeyPressEvent('Escape', (e) => { useHotKey('dropdown.close', handleClose);
e.preventDefault();
onClose();
});
const handlePrev = useCallback(() => { const handlePrev = useCallback(() => {
setSelectedIndex((currIndex) => { setSelectedIndex((currIndex) => {
@@ -287,19 +285,19 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
const handleSelect = useCallback( const handleSelect = useCallback(
(i: DropdownItem) => { (i: DropdownItem) => {
onClose(); handleClose();
setSelectedIndex(null); setSelectedIndex(null);
if (i.type !== 'separator') { if (i.type !== 'separator') {
i.onSelect?.(); i.onSelect?.();
} }
}, },
[onClose], [handleClose],
); );
useImperativeHandle( useImperativeHandle(
ref, ref,
() => ({ () => ({
close: onClose, close: handleClose,
prev: handlePrev, prev: handlePrev,
next: handleNext, next: handleNext,
select: () => { select: () => {
@@ -308,7 +306,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
handleSelect(item); handleSelect(item);
}, },
}), }),
[handleNext, handlePrev, handleSelect, items, onClose, selectedIndex], [handleClose, handleNext, handlePrev, handleSelect, items, selectedIndex],
); );
const { containerStyles, triangleStyles } = useMemo<{ const { containerStyles, triangleStyles } = useMemo<{
@@ -365,7 +363,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
{isOpen && ( {isOpen && (
<Overlay open variant="transparent" portalName="dropdown" zIndex={50}> <Overlay open variant="transparent" portalName="dropdown" zIndex={50}>
<div> <div>
<div tabIndex={-1} aria-hidden className="fixed inset-0 z-30" onClick={onClose} /> <div tabIndex={-1} aria-hidden className="fixed inset-0 z-30" onClick={handleClose} />
<motion.div <motion.div
tabIndex={0} tabIndex={0}
onKeyDown={handleMenuKeyDown} onKeyDown={handleMenuKeyDown}