first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,146 @@
# Sheet
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs --> - sheet.variants — `sheetOverlayVariants`, `sheetCont…
- [sheet.variants](./sheet.variants.md) — `sheetOverlayVariants`, `sheetContentVariants`, `sheetHeaderVariants`, `sheetFooterVariants`, `sheetTitleVariants`, `sh…
- sheet.variants — `sheetOverlayVariants`, `sheetCont…
- [sheet.variants](./sheet.variants.md) — `sheetOverlayVariants`, `sheetContentVariants`, `sheetHeaderVariants`, `sheetFooterVariants`, `sheetTitleVariants`, `sh…
- sheet.variants — `sheetOverlayVariants`, `sheetCont…
- [sheet.variants](./sheet.variants.md) — `sheetOverlayVariants`, `sheetContentVariants`, `sheetHeaderVariants`, `sheetFooterVariants`, `sheetTitleVariants`, `sh…
- sheet.variants — `sheetOverlayVariants`, `sheetCont…
- [sheet.variants](./sheet.variants.md) — `sheetOverlayVariants`, `sheetContentVariants`, `sheetHeaderVariants`, `sheetFooterVariants`, `sheetTitleVariants`, `sh…
- [sheet.variants](./sheet.variants.md) — `sheetOverlayVariants`, `sheetContentVariants`, `sheetHeaderVariants`, `sheetFooterVariants`, `sheetTitleVariants`, `sh…
## Purpose
`<Sheet>` and its sub-components (`<SheetTrigger>`, `<SheetPortal>`, `<SheetOverlay>`, `<SheetContent>`, `<SheetHeader>`, `<SheetFooter>`, `<SheetTitle>`, `<SheetDescription>`, `<SheetClose>`) are the chassis side-anchored panel primitives built on `@radix-ui/react-dialog`. Sheet is structurally a Dialog with side-anchored positioning, so Radix supplies the same WAI-ARIA dialog semantics (focus-trap, restore-focus, Escape closes, click-outside closes) and the chassis adds a `side` axis on `<SheetContent>` (`top` / `right` / `bottom` / `left`).
Per the WAI-ARIA dialog pattern, every sheet MUST contain a `<SheetTitle>` so the accessible name is announced. Use `className="sr-only"` if the visible UI does not need a heading. Logical-property edges (`start-0` / `end-0`) ensure `left` and `right` automatically swap under `dir="rtl"`.
## Features
- Four side anchors (`top`, `right`, `bottom`, `left`) with matching slide-in/slide-out animations.
- Focus-trap on open; restore-focus on close (Radix-managed).
- Escape closes; click on the overlay backdrop closes the sheet.
- Translated close-button `aria-label` via `react-ui.sheet.close` (Close / 关闭 / إغلاق / Cau / Закрыть).
- Theme-driven cva overrides for every slot via `useThemedVariants("Sheet<Slot>")`.
- All sub-components forward refs to their underlying Radix elements.
- `motion-reduce:animate-none` collapses the slide animation under `prefers-reduced-motion: reduce`.
- Logical-property anchoring (`start-0` / `end-0`) so `left` and `right` flip in RTL automatically.
## Usage: Basic Example
```tsx
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@suaveplan/react-ui";
export function FiltersSheet() {
return (
<Sheet>
<SheetTrigger>Filters</SheetTrigger>
<SheetContent side="right">
<SheetHeader>
<SheetTitle>Filters</SheetTitle>
<SheetDescription>Refine the results.</SheetDescription>
</SheetHeader>
<SheetFooter>
<SheetClose>Apply</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>
);
}
```
## Usage: Advanced Example
```tsx
import {
Button,
Sheet,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@suaveplan/react-ui";
import { useState } from "react";
interface NavItem {
readonly id: string;
readonly label: string;
}
export function MobileNavSheet({ items }: { items: readonly NavItem[] }) {
const [open, setOpen] = useState(false);
return (
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>
<Button variant="outline">Open menu</Button>
</SheetTrigger>
<SheetContent side="left">
<SheetHeader>
<SheetTitle>Navigation</SheetTitle>
<SheetDescription>Browse the app.</SheetDescription>
</SheetHeader>
<nav className="mt-4 flex flex-col gap-1">
{items.map((item) => (
<a
key={item.id}
href={`#${item.id}`}
className="rounded px-3 py-2 hover:bg-accent"
onClick={() => setOpen(false)}
>
{item.label}
</a>
))}
</nav>
</SheetContent>
</Sheet>
);
}
```
## API Reference
### `<Sheet>`
Renders the Radix Dialog Root. Same lifecycle props as `<Dialog>`.
### `<SheetContent>`
| Prop | Type | Default | Description |
|---|---|---|---|
| `side` | `"top" \| "right" \| "bottom" \| "left"` | `"right"` | Anchor edge (RTL flips left/right). |
| `closeAriaLabelKey` | `TranslationKey` | `react-ui.sheet.close` | Override the close-button accessible name. |
### `<SheetTitle>`
REQUIRED — Radix surfaces a dev warning when omitted. Render `className="sr-only"` if no visible heading is needed.
### `<SheetTrigger>`, `<SheetPortal>`, `<SheetOverlay>`, `<SheetHeader>`, `<SheetFooter>`, `<SheetDescription>`, `<SheetClose>`
Same as Dialog's analogous sub-components — direct re-exports of the Radix sub-components with the chassis cva applied.
## Implementation Notes
- The Radix Content props type is a discriminated union once cva-extra variant props (`side`) are layered on; TS cannot narrow the spread back through the chassis surface, so `<SheetContent>` casts the Radix Content to a relaxed shape via `unknown`. The runtime accepts both shapes equivalently. This mirrors the Wave 3b ToggleGroup reconciliation finding and is documented in the implementation comment.
- The chassis NEVER assigns a numeric `z-index` to the overlay or content — Radix portals handle stacking.
- `start-0` / `end-0` are logical properties — `left` / `right` automatically swap in RTL without a chevron-flip step.
- `motion-reduce:animate-none motion-reduce:transition-none` collapses both the slide and the duration transitions under `prefers-reduced-motion: reduce`.
- `<SheetContent>` self-portals via `<SheetPortal>` so consumers do not need to remember to portal manually — matches the shadcn upstream convention exactly.