Skip to content

Commit 5eaf493

Browse files
committed
Allow to use any HTML Element as menu item
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 sparksuite#174
1 parent 040caac commit 5eaf493

File tree

2 files changed

+10
-9
lines changed

2 files changed

+10
-9
lines changed

src/use-dropdown-menu.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ export interface ButtonProps<ButtonElement extends HTMLElement>
1212

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

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

4445
// Create refs
4546
const buttonRef = useRef<ButtonElement>(null);
46-
const itemRefs = useMemo<React.RefObject<HTMLAnchorElement>[]>(
47-
() => Array.from({ length: itemCount }, () => createRef<HTMLAnchorElement>()),
47+
const itemRefs = useMemo<React.RefObject<HTMLElement>[]>(
48+
() => Array.from({ length: itemCount }, () => createRef<HTMLElement>()),
4849
[itemCount]
4950
);
5051

@@ -171,7 +172,7 @@ export default function useDropdownMenu<ButtonElement extends HTMLElement = HTML
171172
};
172173

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

@@ -189,7 +190,7 @@ export default function useDropdownMenu<ButtonElement extends HTMLElement = HTML
189190
setIsOpen(false);
190191
return;
191192
} else if (key === 'Enter' || key === ' ') {
192-
if (!e.currentTarget.href) {
193+
if (!('href' in e.currentTarget && e.currentTarget.href)) {
193194
e.currentTarget.click();
194195
}
195196

website/docs/design/return-object.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ This Hook returns an object of the following shape:
1717
};
1818
itemProps: [
1919
{
20-
onKeyDown: (e: React.KeyboardEvent<HTMLAnchorElement>) => void;
20+
onKeyDown: (e: React.KeyboardEvent<HTMLElement>) => void;
2121
tabIndex: -1;
2222
role: 'menuitem';
23-
ref: React.RefObject<HTMLAnchorElement>;
23+
ref: React.RefObject<any>;
2424
};
2525
...
2626
];
@@ -45,4 +45,4 @@ This Hook returns an object of the following shape:
4545
- **ref:** A React ref applied to each menu item, used to manage focus.
4646
- **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.
4747
- **setIsOpen:** A function useful for allowing the developer to programmatically open/close the menu.
48-
- **moveFocus:** A function that moves the browser’s focus to the specified item index.
48+
- **moveFocus:** A function that moves the browser’s focus to the specified item index.

0 commit comments

Comments
 (0)