first commit
This commit is contained in:
149
docs/ui/react/react-ui/src/components/drawer/drawer.md
Normal file
149
docs/ui/react/react-ui/src/components/drawer/drawer.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Drawer
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs --> - drawer.variants — `drawerOverlayVariants`, `drawerC…
|
||||
- [drawer.variants](./drawer.variants.md) — `drawerOverlayVariants`, `drawerContentVariants`, `drawerHandleVariants`, `drawerHeaderVariants`, `drawerFooterVariants…
|
||||
- drawer.variants — `drawerOverlayVariants`, `drawerC…
|
||||
|
||||
- [drawer.variants](./drawer.variants.md) — `drawerOverlayVariants`, `drawerContentVariants`, `drawerHandleVariants`, `drawerHeaderVariants`, `drawerFooterVariants…
|
||||
|
||||
- drawer.variants — `drawerOverlayVariants`, `drawerC…
|
||||
|
||||
- [drawer.variants](./drawer.variants.md) — `drawerOverlayVariants`, `drawerContentVariants`, `drawerHandleVariants`, `drawerHeaderVariants`, `drawerFooterVariants…
|
||||
|
||||
- drawer.variants — `drawerOverlayVariants`, `drawerC…
|
||||
|
||||
- [drawer.variants](./drawer.variants.md) — `drawerOverlayVariants`, `drawerContentVariants`, `drawerHandleVariants`, `drawerHeaderVariants`, `drawerFooterVariants…
|
||||
- [drawer.variants](./drawer.variants.md) — `drawerOverlayVariants`, `drawerContentVariants`, `drawerHandleVariants`, `drawerHeaderVariants`, `drawerFooterVariants…
|
||||
|
||||
## Purpose
|
||||
|
||||
`<Drawer>` and its sub-components (`<DrawerTrigger>`, `<DrawerPortal>`, `<DrawerOverlay>`, `<DrawerContent>`, `<DrawerHandle>`, `<DrawerHeader>`, `<DrawerFooter>`, `<DrawerTitle>`, `<DrawerDescription>`, `<DrawerClose>`) are the chassis bottom-anchored modal panel primitives built on `vaul`. Vaul wraps `@radix-ui/react-dialog` internally so the WAI-ARIA dialog semantics (focus-trap, restore-focus, Escape closes, click-outside closes) are inherited; vaul layers on the swipe-down dismiss gesture, snap-points, and background-scale animation that distinguish a Drawer from a Sheet.
|
||||
|
||||
Per the WAI-ARIA dialog pattern, every drawer MUST contain a `<DrawerTitle>` so the accessible name is announced. Use `className="sr-only"` if the visible UI does not need a heading. Drawer is mobile-first — the panel slides up from the bottom and is grabbable by the small handle at the top.
|
||||
|
||||
## Features
|
||||
|
||||
- Bottom-anchored slide-up panel with swipe-down dismiss gesture (vaul-native).
|
||||
- Snap-points support via vaul (`snapPoints={[0.4, 0.8]}`).
|
||||
- Background-scale animation while the drawer is open (`shouldScaleBackground`, default `true`).
|
||||
- Drag handle at the top of the panel (rendered automatically inside `<DrawerContent>`).
|
||||
- Focus-trap on open; restore-focus on close (vaul → Radix-managed).
|
||||
- Escape closes the drawer; click on the overlay backdrop closes the drawer.
|
||||
- All sub-components forward refs.
|
||||
- Theme-driven cva overrides for every slot via `useThemedVariants("Drawer<Slot>")`.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```tsx
|
||||
import {
|
||||
Drawer,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerDescription,
|
||||
DrawerFooter,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
DrawerTrigger,
|
||||
} from "@suaveplan/react-ui";
|
||||
|
||||
export function AccountDrawer() {
|
||||
return (
|
||||
<Drawer>
|
||||
<DrawerTrigger>Open settings</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Account settings</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Manage your account preferences.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<DrawerFooter>
|
||||
<DrawerClose>Close</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```tsx
|
||||
import {
|
||||
Button,
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
DrawerDescription,
|
||||
DrawerFooter,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
} from "@suaveplan/react-ui";
|
||||
import { useState } from "react";
|
||||
|
||||
export function SnappingFiltersDrawer() {
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<Drawer
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
snapPoints={[0.4, 0.7, 1.0]}
|
||||
shouldScaleBackground
|
||||
>
|
||||
<Button onClick={() => setOpen(true)}>Open filters</Button>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Filters</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Drag the handle to expand.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="p-4">…filter controls…</div>
|
||||
<DrawerFooter>
|
||||
<Button variant="outline" onClick={() => setOpen(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={() => setOpen(false)}>Apply</Button>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `<Drawer>`
|
||||
|
||||
Wraps vaul's `Drawer.Root`. Inherits every prop from vaul including:
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `open` | `boolean` | _uncontrolled_ | Controlled open state. |
|
||||
| `defaultOpen` | `boolean` | `false` | Initial open state. |
|
||||
| `onOpenChange` | `(open: boolean) => void` | _none_ | Fires on open/close transitions. |
|
||||
| `snapPoints` | `(number \| string)[]` | _none_ | Optional snap-point heights. |
|
||||
| `shouldScaleBackground` | `boolean` | `true` | Scale the page behind the drawer while open. |
|
||||
| `dismissible` | `boolean` | `true` | Allow Escape / click-outside / drag-down dismissal. |
|
||||
| `modal` | `boolean` | `true` | Keep focus trapped inside the drawer. |
|
||||
|
||||
### `<DrawerContent>`
|
||||
|
||||
Renders the bottom-anchored panel. Self-portals via `<DrawerPortal>` and renders a drag handle at the top.
|
||||
|
||||
### `<DrawerTitle>`
|
||||
|
||||
REQUIRED — vaul/Radix surfaces a dev warning when omitted. Render `className="sr-only"` if no visible heading is needed.
|
||||
|
||||
### `<DrawerTrigger>`, `<DrawerPortal>`, `<DrawerOverlay>`, `<DrawerHandle>`, `<DrawerHeader>`, `<DrawerFooter>`, `<DrawerDescription>`, `<DrawerClose>`
|
||||
|
||||
Direct re-exports of the vaul sub-components with the chassis cva applied.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The chassis NEVER assigns a numeric `z-index` to the overlay or content panels — vaul/Radix portals handle stacking.
|
||||
- `<DrawerContent>` self-portals via `<DrawerPortal>` and renders a `<DrawerHandle>` at the top automatically — consumers do not need to compose them manually. This matches the shadcn `drawer` upstream recipe.
|
||||
- Drag-down dismissal is a vaul-native gesture that requires real pointer events; happy-dom-based unit tests cover the open/close lifecycle via Escape and `onOpenChange` rather than the drag gesture itself. End-to-end coverage of the swipe gesture lives in the consumer's Playwright suite.
|
||||
- `shouldScaleBackground` defaults to `true` (chassis-overrides vaul's `false`) because the scale-down effect is the primary visual cue distinguishing a Drawer from a Sheet.
|
||||
- Vaul's `DrawerClose` button forwards to `onOpenChange(false)` rather than mutating internal state directly — controlled consumers should listen on `onOpenChange` and update their local `open` state to honour the close request.
|
||||
Reference in New Issue
Block a user