61 lines
1.3 KiB
TypeScript
61 lines
1.3 KiB
TypeScript
import type { ReactNode, RefObject } from 'react';
|
||
|
||
interface DrawerBaseProps {
|
||
panelRef: RefObject<HTMLElement | null>;
|
||
closeRef: RefObject<HTMLButtonElement | null>;
|
||
sheetRef?: RefObject<HTMLDivElement | null>;
|
||
id: string;
|
||
open: boolean;
|
||
className?: string;
|
||
sheetClassName?: string;
|
||
closeLabel: string;
|
||
closeText?: string;
|
||
onClose: () => unknown;
|
||
leading?: ReactNode;
|
||
children: ReactNode;
|
||
}
|
||
|
||
type DrawerProps = DrawerBaseProps & (
|
||
| { labelledBy: string; label?: never }
|
||
| { label: string; labelledBy?: never }
|
||
);
|
||
|
||
export function Drawer({
|
||
panelRef,
|
||
closeRef,
|
||
sheetRef,
|
||
id,
|
||
open,
|
||
className = '',
|
||
sheetClassName = '',
|
||
labelledBy,
|
||
label,
|
||
closeLabel,
|
||
closeText = '×',
|
||
onClose,
|
||
leading,
|
||
children,
|
||
}: DrawerProps) {
|
||
return <aside
|
||
ref={panelRef}
|
||
id={id}
|
||
className={`client-drawer${className ? ` ${className}` : ''}${open ? ' is-open' : ''}`}
|
||
aria-labelledby={labelledBy}
|
||
aria-label={label}
|
||
aria-hidden={!open}
|
||
inert={!open ? true : undefined}
|
||
>
|
||
<div ref={sheetRef} className={`client-drawer-sheet${sheetClassName ? ` ${sheetClassName}` : ''}`}>
|
||
{leading}
|
||
<button
|
||
ref={closeRef}
|
||
className="client-drawer-close"
|
||
type="button"
|
||
aria-label={closeLabel}
|
||
onClick={onClose}
|
||
>{closeText}</button>
|
||
{children}
|
||
</div>
|
||
</aside>;
|
||
}
|