Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 4x 9x | import type { ButtonHTMLAttributes, HTMLAttributes, ReactNode } from 'react';
/**
* Dropdown menu primitives. Styling lives in globals.css (`.dropdown-menu*`);
* these only compose markup and class names, so open / close / positioning
* stays with the consumer.
*
* <DropdownMenu>
* <DropdownItem icon={<Sun />} role="menuitemradio" aria-checked>Light</DropdownItem>
* <DropdownItem icon={<Sun />} trailing={<ChevronRight />}>Appearance</DropdownItem>
* </DropdownMenu>
*/
export function DropdownMenu({
className,
role = 'menu',
children,
...rest
}: HTMLAttributes<HTMLDivElement>) {
return (
<div className={['dropdown-menu', className].filter(Boolean).join(' ')} role={role} {...rest}>
{children}
</div>
);
}
interface DropdownItemProps extends ButtonHTMLAttributes<HTMLButtonElement> {
/** Leading icon, before the label. */
icon?: ReactNode;
/** Trailing element, e.g. a caret for submenu items. */
trailing?: ReactNode;
}
export function DropdownItem({
icon,
trailing,
className,
type = 'button',
children,
...rest
}: DropdownItemProps) {
return (
<button type={type} className={['dropdown-menu__item', className].filter(Boolean).join(' ')} {...rest}>
{icon}
<span className="dropdown-menu__label">{children}</span>
{trailing}
</button>
);
}
|