import { CommonProps } from "@trackunit/react-components"; import { ReactElement, ReactNode } from "react"; import type { DrawerPosition } from "../../types"; import type { DrawerFloatingUiProps, DrawerVariant } from "./useDrawer"; /** * Presentational props for `Drawer`. State (`isOpen`), resolved `variant`, * focus-trap opt-in (`trapFocus`), `position`, and Floating UI wiring * (`floatingUi`) all flow in from `useDrawer()`. * * Decoupled from the full `UseDrawerReturnValue` — `Drawer` only declares the * props it actually reads. Consumers spread the hook return * (``) and TypeScript allows extra properties on spread * expressions, so the imperative actions (`open` / `close` / `toggle` / * `requestClose`) travel through the JSX without being typed here. This keeps * the Storybook autodocs table (and the component's declared surface) focused * on what `Drawer` genuinely consumes. Mirrors `Sheet`'s pattern in * `@trackunit/react-components`. */ export interface DrawerProps extends CommonProps { /** * Current open state — spread from `useDrawer()`. Drives the enter / exit * animation and whether the overlay renders (when `variant="modal"`). */ readonly isOpen: boolean; /** * Semantic variant controlling backdrop, focus trap, and dismiss behavior. * Spread from `useDrawer()`. See {@link DrawerVariant}. */ readonly variant: DrawerVariant; /** * Whether to trap focus inside the panel when `variant="modal"`. Ignored for * `variant="default"` (which never traps focus). Spread from `useDrawer()`. */ readonly trapFocus: boolean; /** * Which edge of the viewport the panel is anchored to and slides in from. * Spread from `useDrawer()`. */ readonly position: DrawerPosition; /** * Floating UI wiring for the panel's focus manager and dismiss bindings. * `Drawer` merges `refs.setFloating` onto the panel and uses `context` for * its `FloatingFocusManager`. Spread from `useDrawer()`. */ readonly floatingUi: DrawerFloatingUiProps; /** * Content rendered inside the drawer panel. Compose layout parts explicitly — typically * `` (or a custom header such as `CardHeader`) followed by the body. */ children?: ReactNode; /** * Whether to render the drawer in a portal or not. * Default is false. * If true, the drawer will be rendered in a portal at the end of the document. * This is useful when the drawer needs to be rendered on top of other elements. * For example, when the drawer is used with a map component. */ renderInPortal?: boolean; /** * The class name for the drawer container. */ containerClassName?: string; /** * Accessible name for the drawer's panel, forwarded as `aria-label`. Strongly recommended: * without either this or `ariaLabelledBy`, assistive technology has no name for the panel and * will announce it as an unnamed dialog / region. Mutually exclusive in intent with * `ariaLabelledBy` — set one or the other, not both. */ ariaLabel?: string; /** * Id of an existing element (typically a heading rendered inside the drawer body) whose text * names the drawer's panel, forwarded as `aria-labelledby`. Prefer this over `ariaLabel` when * the drawer body renders a visible heading so the two stay in sync. */ ariaLabelledBy?: string; /** * Internal signal fired exactly once per genuine open→close→fully-exited cycle, * once the panel has actually finished animating (or would have, in headless / * test environments where CSS transitions are suppressed) off-screen. Spread from * `useDrawer()`, which uses it to flip its `isExiting` state back to `false`. * * Does not fire for the enter-settle transitionend, on initial mount, while * remaining closed, or more than once for the same close cycle even if both the * real `transitionend` and the headless RAF fallback resolve it. */ readonly onExitComplete?: () => void; } /** * Drawers slide in from the left or right edge of the viewport as either a modal * dialog or a docked inspector panel. * * ### When to use * - For secondary content that doesn't need to be always visible * - For inspector panels or item detail views that slide in from the side * - When you need to preserve context of the underlying page * * ### When not to use * - For critical actions requiring user confirmation (use Modal instead) * - For simple tooltips or small contextual information (use Popover) * - To show a table selection and bulk actions (use ActionSheet instead) * * ### API * `Drawer` is a presentation component. Call `useDrawer()` to own the drawer's * open state, dismiss handling, and (optional) `onBeforeClose` guard, then spread * its return value onto ``. * * @example Basic modal drawer with the standard toolbar * ```tsx * import { Drawer, DrawerHeader, useDrawer } from "@trackunit/react-drawer"; * import { Button } from "@trackunit/react-components"; * * const FilterDrawer = () => { * const drawer = useDrawer({ position: "right", variant: "modal" }); * * return ( * <> * * * *
Filter controls go here
*
* * ); * }; * ``` * @example Guard dismissal with `onBeforeClose` * ```tsx * const drawer = useDrawer({ * variant: "modal", * onBeforeClose: async () => (await confirmDiscard()) === "discard", * }); * ``` * @example Non-modal inspector — background stays interactive * ```tsx * const drawer = useDrawer({ * isOpen: Boolean(selectedAssetId), * onClose: () => setSelectedAssetId(null), * position: "right", * variant: "default", * }); * * *

{selectedAsset?.name}

*
* ``` * @param {DrawerProps} props - The props for the Drawer component */ export declare const Drawer: { ({ isOpen, variant, trapFocus, position, floatingUi, children, "data-testid": dataTestId, className, renderInPortal, containerClassName, ariaLabel, ariaLabelledBy, onExitComplete, }: DrawerProps): ReactElement | null; displayName: string; };