Skip to content

Commit

Permalink
Allow to use any HTML Element as menu item
Browse files Browse the repository at this point in the history
The code works with any HTML element, there's nothing that requires
specifically `HTMLAnchorElement` (`<a>`) except `e.currentTarget.href`
which is already conditional. Thus the current limitation is only a
typing issue introduced by unnecessarily specific `ref` type. We can
make it a generic parameter, but it wouldn't bring any real benefit,
just increase complexity and decrease flexibility.

Resolves #174
  • Loading branch information
jirutka committed Oct 17, 2024
1 parent 040caac commit 5eaf493
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 9 deletions.
13 changes: 7 additions & 6 deletions src/use-dropdown-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ export interface ButtonProps<ButtonElement extends HTMLElement>

// Create interface for item properties
export interface ItemProps {
onKeyDown: (e: React.KeyboardEvent<HTMLAnchorElement>) => void;
onKeyDown: (e: React.KeyboardEvent<HTMLElement>) => void;
tabIndex: number;
role: string;
ref: React.RefObject<HTMLAnchorElement>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ref: React.RefObject<any>;
}

// A custom Hook that abstracts away the listeners/controls for dropdown menus
Expand Down Expand Up @@ -43,8 +44,8 @@ export default function useDropdownMenu<ButtonElement extends HTMLElement = HTML

// Create refs
const buttonRef = useRef<ButtonElement>(null);
const itemRefs = useMemo<React.RefObject<HTMLAnchorElement>[]>(
() => Array.from({ length: itemCount }, () => createRef<HTMLAnchorElement>()),
const itemRefs = useMemo<React.RefObject<HTMLElement>[]>(
() => Array.from({ length: itemCount }, () => createRef<HTMLElement>()),
[itemCount]
);

Expand Down Expand Up @@ -171,7 +172,7 @@ export default function useDropdownMenu<ButtonElement extends HTMLElement = HTML
};

// Create a function that handles menu logic based on keyboard events that occur on menu items
const itemListener = (e: React.KeyboardEvent<HTMLAnchorElement>): void => {
const itemListener = (e: React.KeyboardEvent<HTMLElement | HTMLAnchorElement>): void => {
// Destructure the key property from the event object
const { key } = e;

Expand All @@ -189,7 +190,7 @@ export default function useDropdownMenu<ButtonElement extends HTMLElement = HTML
setIsOpen(false);
return;
} else if (key === 'Enter' || key === ' ') {
if (!e.currentTarget.href) {
if (!('href' in e.currentTarget && e.currentTarget.href)) {
e.currentTarget.click();
}

Expand Down
6 changes: 3 additions & 3 deletions website/docs/design/return-object.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ This Hook returns an object of the following shape:
};
itemProps: [
{
onKeyDown: (e: React.KeyboardEvent<HTMLAnchorElement>) => void;
onKeyDown: (e: React.KeyboardEvent<HTMLElement>) => void;
tabIndex: -1;
role: 'menuitem';
ref: React.RefObject<HTMLAnchorElement>;
ref: React.RefObject<any>;
};
...
];
Expand All @@ -45,4 +45,4 @@ This Hook returns an object of the following shape:
- **ref:** A React ref applied to each menu item, used to manage focus.
- **isOpen:** A boolean value indicating if the menu is open or closed. The developer should use this value to make the menu visible or not.
- **setIsOpen:** A function useful for allowing the developer to programmatically open/close the menu.
- **moveFocus:** A function that moves the browser’s focus to the specified item index.
- **moveFocus:** A function that moves the browser’s focus to the specified item index.

0 comments on commit 5eaf493

Please sign in to comment.