@devalok/shilp-sutra 0.37.0 → 0.37.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/composed/inline-edit.d.ts.map +1 -1
- package/dist/composed/inline-edit.js +42 -40
- package/dist/composed/inline-edit.js.map +1 -1
- package/dist/test-utils/conformance.d.ts +37 -0
- package/dist/test-utils/conformance.d.ts.map +1 -0
- package/docs/components/composed/activity-feed.md +6 -0
- package/docs/components/composed/avatar-group.md +8 -0
- package/docs/components/composed/bulk-action-bar.md +6 -0
- package/docs/components/composed/command-palette.md +7 -0
- package/docs/components/composed/confirm-dialog.md +6 -0
- package/docs/components/composed/content-card.md +6 -0
- package/docs/components/composed/date-picker.md +10 -0
- package/docs/components/composed/deadline-indicator.md +7 -0
- package/docs/components/composed/emoji-picker.md +8 -0
- package/docs/components/composed/empty-state.md +8 -0
- package/docs/components/composed/error-boundary.md +7 -0
- package/docs/components/composed/file-preview.md +8 -0
- package/docs/components/composed/filter-bar.md +8 -0
- package/docs/components/composed/form-section.md +6 -0
- package/docs/components/composed/global-loading.md +6 -0
- package/docs/components/composed/inline-edit.md +8 -0
- package/docs/components/composed/loading-skeleton.md +7 -0
- package/docs/components/composed/markdown-viewer.md +9 -0
- package/docs/components/composed/master-detail.md +7 -0
- package/docs/components/composed/member-picker.md +7 -0
- package/docs/components/composed/multi-select-popover.md +11 -0
- package/docs/components/composed/page-header.md +7 -0
- package/docs/components/composed/page-skeletons.md +10 -0
- package/docs/components/composed/priority-indicator.md +7 -0
- package/docs/components/composed/responsive-overlay.md +7 -0
- package/docs/components/composed/rich-chat-input.md +12 -0
- package/docs/components/composed/rich-text-editor.md +9 -0
- package/docs/components/composed/schedule-view.md +8 -0
- package/docs/components/composed/simple-tooltip.md +7 -0
- package/docs/components/composed/status-badge.md +10 -0
- package/docs/components/shell/app-command-palette.md +8 -0
- package/docs/components/shell/bottom-navbar.md +12 -0
- package/docs/components/shell/command-registry.md +7 -0
- package/docs/components/shell/link-context.md +15 -0
- package/docs/components/shell/notification-center.md +10 -0
- package/docs/components/shell/notification-preferences.md +7 -0
- package/docs/components/shell/sidebar.md +11 -0
- package/docs/components/shell/top-bar.md +11 -0
- package/docs/components/ui/accordion.md +10 -0
- package/docs/components/ui/alert-dialog.md +10 -1
- package/docs/components/ui/alert.md +10 -2
- package/docs/components/ui/aspect-ratio.md +7 -0
- package/docs/components/ui/autocomplete.md +7 -0
- package/docs/components/ui/avatar.md +10 -0
- package/docs/components/ui/badge-group.md +7 -0
- package/docs/components/ui/badge-indicator.md +7 -0
- package/docs/components/ui/badge.md +12 -0
- package/docs/components/ui/banner.md +7 -0
- package/docs/components/ui/breadcrumb.md +8 -0
- package/docs/components/ui/button-group.md +24 -4
- package/docs/components/ui/button-processing.md +5 -0
- package/docs/components/ui/button.md +9 -0
- package/docs/components/ui/card.md +16 -4
- package/docs/components/ui/charts.md +9 -0
- package/docs/components/ui/chat.md +9 -0
- package/docs/components/ui/checkbox.md +15 -1
- package/docs/components/ui/chip.md +9 -0
- package/docs/components/ui/code.md +7 -0
- package/docs/components/ui/collapsible.md +9 -0
- package/docs/components/ui/color-input.md +8 -0
- package/docs/components/ui/color-swatch.md +7 -0
- package/docs/components/ui/combobox.md +16 -3
- package/docs/components/ui/container.md +11 -0
- package/docs/components/ui/context-menu.md +8 -0
- package/docs/components/ui/data-table-body.md +4 -0
- package/docs/components/ui/data-table-bulk-actions.md +4 -0
- package/docs/components/ui/data-table-card.md +4 -0
- package/docs/components/ui/data-table-context.md +4 -0
- package/docs/components/ui/data-table-header.md +4 -0
- package/docs/components/ui/data-table-pagination.md +4 -0
- package/docs/components/ui/data-table-toolbar.md +7 -0
- package/docs/components/ui/data-table.md +25 -0
- package/docs/components/ui/devalok-grain.md +8 -0
- package/docs/components/ui/dialog.md +10 -0
- package/docs/components/ui/dropdown-menu.md +10 -0
- package/docs/components/ui/file-upload.md +8 -0
- package/docs/components/ui/form.md +21 -0
- package/docs/components/ui/hover-card.md +9 -0
- package/docs/components/ui/icon-button.md +7 -0
- package/docs/components/ui/icon-context.md +7 -0
- package/docs/components/ui/icon-group.md +9 -0
- package/docs/components/ui/icon.md +7 -0
- package/docs/components/ui/input-otp.md +29 -7
- package/docs/components/ui/input.md +7 -0
- package/docs/components/ui/label.md +7 -1
- package/docs/components/ui/link.md +7 -0
- package/docs/components/ui/menubar.md +9 -0
- package/docs/components/ui/navigation-menu.md +9 -0
- package/docs/components/ui/number-input.md +10 -0
- package/docs/components/ui/pagination.md +10 -0
- package/docs/components/ui/popover.md +9 -0
- package/docs/components/ui/progress-ring.md +7 -0
- package/docs/components/ui/progress.md +7 -0
- package/docs/components/ui/radio.md +27 -2
- package/docs/components/ui/search-input.md +8 -0
- package/docs/components/ui/segmented-control.md +8 -0
- package/docs/components/ui/select.md +14 -3
- package/docs/components/ui/separator.md +7 -0
- package/docs/components/ui/sheet.md +10 -0
- package/docs/components/ui/sidebar.md +30 -0
- package/docs/components/ui/skeleton.md +7 -0
- package/docs/components/ui/slider.md +15 -1
- package/docs/components/ui/spinner.md +7 -0
- package/docs/components/ui/split-button.md +11 -0
- package/docs/components/ui/stack.md +8 -0
- package/docs/components/ui/stat-card.md +9 -0
- package/docs/components/ui/status-dot.md +9 -0
- package/docs/components/ui/stepper.md +8 -0
- package/docs/components/ui/switch.md +8 -0
- package/docs/components/ui/table.md +8 -0
- package/docs/components/ui/tabs.md +10 -2
- package/docs/components/ui/text.md +9 -4
- package/docs/components/ui/textarea.md +7 -1
- package/docs/components/ui/toast.md +9 -0
- package/docs/components/ui/toaster.md +8 -0
- package/docs/components/ui/toggle-group.md +13 -4
- package/docs/components/ui/toggle.md +10 -2
- package/docs/components/ui/tooltip.md +11 -1
- package/docs/components/ui/tree-view.md +12 -0
- package/docs/components/ui/visually-hidden.md +7 -0
- package/llms-full.txt +1116 -44
- package/package.json +1 -1
|
@@ -14,8 +14,14 @@
|
|
|
14
14
|
<Label htmlFor="email" required>Email Address</Label>
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
## Composability
|
|
18
|
+
- **Label is NOT auto-wired by FormField** — you must explicitly pair `<Label htmlFor="x" />` with the matching `<Input id="x" />` (or Checkbox/Radio/Switch/Select). Screen-reader label association depends on this.
|
|
19
|
+
- Radix Label primitive underneath — clicking the Label focuses its associated control, which is why the `htmlFor`/`id` pairing matters.
|
|
20
|
+
- `required={true}` only renders the red asterisk; it does NOT set `aria-required` on the associated control (that comes from FormField context on the control itself).
|
|
21
|
+
- Works with any input-like component in the library — pair with Input, Textarea, NumberInput, Checkbox, Radio, Switch, Select, Combobox, Autocomplete.
|
|
22
|
+
|
|
17
23
|
## Gotchas
|
|
18
|
-
- Use with FormField for automatic aria wiring
|
|
24
|
+
- Use with FormField for automatic aria wiring on the control (but the Label-to-control association is always manual)
|
|
19
25
|
|
|
20
26
|
## Changes
|
|
21
27
|
### v0.2.0
|
|
@@ -18,8 +18,15 @@
|
|
|
18
18
|
<Link asChild><NextLink href="/about">About</NextLink></Link>
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
## Composability
|
|
22
|
+
- **Framework router integration via `asChild`:** `<Link asChild><NextLink href="/foo">...</NextLink></Link>` — Link's styling transfers to the child (NextLink/react-router Link/any `<a>`-like component) while preserving the child's navigation semantics. Don't use `asChild` for plain anchors — it's unnecessary and adds a layer.
|
|
23
|
+
- **inline vs block:** Default `inline` (display: inline) so Link composes naturally inside paragraphs and mixed text. Set `inline={false}` for full-width link regions (card wrappers, list items).
|
|
24
|
+
- No context, no cascade. Safe to use anywhere.
|
|
25
|
+
- For icon + text links, nest Icon inside — Link doesn't auto-size via IconProvider (unlike Button), so pass an explicit `size` to the Icon.
|
|
26
|
+
|
|
21
27
|
## Gotchas
|
|
22
28
|
- Use asChild with framework-specific Link components (e.g. Next.js Link)
|
|
29
|
+
- Don't nest interactive elements (buttons, form controls) inside a Link — that's invalid HTML and breaks screen-reader navigation
|
|
23
30
|
|
|
24
31
|
## Changes
|
|
25
32
|
### v0.18.0
|
|
@@ -30,8 +30,17 @@
|
|
|
30
30
|
</Menubar>
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
## Composability
|
|
34
|
+
- Radix Menubar — shares the item-variant vocabulary with DropdownMenu and ContextMenu (checkbox items, radio groups, sub-menus, labels, separators, shortcuts).
|
|
35
|
+
- **Key difference from DropdownMenu:** Menubar is the horizontal top-bar-menu pattern (File / Edit / View / Help). Multiple MenubarMenu children sit side-by-side at the root; opening one closes the others, and arrow keys move between them.
|
|
36
|
+
- **Typical use:** Desktop app-like UIs where the menu is always visible at the top (code editors, design tools). For a single collapsed trigger, use DropdownMenu instead.
|
|
37
|
+
- **Controlled open:** Pass `value` + `onValueChange` to Menubar root to control which MenubarMenu is open (value = menu's `value` prop or falsy for none).
|
|
38
|
+
- **Portal + z-index:** z-popover (1400).
|
|
39
|
+
|
|
33
40
|
## Gotchas
|
|
34
41
|
- Follows the standard Radix Menubar compound pattern
|
|
42
|
+
- Don't use Menubar for a single dropdown — use DropdownMenu instead
|
|
43
|
+
- MenubarShortcut is decorative (same as DropdownMenuShortcut) — bind shortcuts separately
|
|
35
44
|
|
|
36
45
|
## Changes
|
|
37
46
|
### v0.18.0
|
|
@@ -31,8 +31,17 @@
|
|
|
31
31
|
</NavigationMenu>
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
## Composability
|
|
35
|
+
- **Radix NavigationMenu** underneath — keyboard model (Tab between items, Arrow for panel navigation, Esc to close) is pre-wired.
|
|
36
|
+
- **NavigationMenuLink vs NavigationMenuTrigger:** Use Link for simple nav items (no dropdown); use Trigger + Content for items with a panel of sub-links.
|
|
37
|
+
- **NavigationMenuViewport** is the animated container that holds the active Content panel — it auto-positions below the triggers. NavigationMenuIndicator is the small arrow/caret pointing from trigger to viewport.
|
|
38
|
+
- **Purpose:** Top-level site navigation (Products, Solutions, Resources) with rich dropdowns containing links grouped by category. Don't use for context menus (use DropdownMenu) or action toolbars (use ButtonGroup).
|
|
39
|
+
- **Router integration:** Use `<NavigationMenuLink asChild><NextLink href="/...">...</NextLink></NavigationMenuLink>` for framework-specific Link components.
|
|
40
|
+
- **Portal + z-popover (1400)** — content panels portal to body and stack above Dialog/Sheet.
|
|
41
|
+
|
|
34
42
|
## Gotchas
|
|
35
43
|
- Uses Framer Motion for enter/exit animations (v0.18.0)
|
|
44
|
+
- NavigationMenu is NOT for sidebar nav — use Sidebar; NOT for mobile nav — use Sheet or BottomNavbar
|
|
36
45
|
|
|
37
46
|
## Changes
|
|
38
47
|
### v0.18.0
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
## Props
|
|
8
8
|
value: number (default: 0)
|
|
9
9
|
onValueChange: (value: number) => void
|
|
10
|
+
size: "xs" | "sm" | "md" | "lg"
|
|
11
|
+
state: "default" | "error" | "warning" | "success" (border color)
|
|
10
12
|
min: number
|
|
11
13
|
max: number
|
|
12
14
|
step: number (default: 1)
|
|
@@ -14,6 +16,8 @@
|
|
|
14
16
|
|
|
15
17
|
## Defaults
|
|
16
18
|
value: 0
|
|
19
|
+
size: "md"
|
|
20
|
+
state: "default"
|
|
17
21
|
step: 1
|
|
18
22
|
min: Number.MIN_SAFE_INTEGER
|
|
19
23
|
max: Number.MAX_SAFE_INTEGER
|
|
@@ -23,6 +27,12 @@
|
|
|
23
27
|
<NumberInput value={qty} onValueChange={setQty} min={1} max={99} />
|
|
24
28
|
```
|
|
25
29
|
|
|
30
|
+
## Composability
|
|
31
|
+
- **FormField auto-consumption:** Inside `<FormField>`, inherits `aria-describedby`, `aria-invalid`, `aria-required`. `state` from FormField context drives the border color unless overridden.
|
|
32
|
+
- **IconProvider cascade:** The `+` and `−` stepper icons auto-size via IconProvider per the input size (xs/sm/md/lg → xs/sm/sm/md icons).
|
|
33
|
+
- **Controlled only** (design choice): no `defaultValue` — pair `value` + `onValueChange` every time. The min/max bounds disable the stepper buttons automatically when reached.
|
|
34
|
+
- **Label pairing:** Manual via `<Label htmlFor="x" />` + `<NumberInput id="x" />`.
|
|
35
|
+
|
|
26
36
|
## Gotchas
|
|
27
37
|
- Controlled only — buttons won't work without onValueChange
|
|
28
38
|
|
|
@@ -36,8 +36,18 @@
|
|
|
36
36
|
</PaginationRoot>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
## Composability
|
|
40
|
+
- **Two APIs in one component:**
|
|
41
|
+
- Low-level compound (PaginationRoot + Content + Item + Link + Previous/Next/Ellipsis) — full control over rendering
|
|
42
|
+
- High-level `PaginationNav` — pass `totalPages` + `currentPage` + `onPageChange` and it renders the whole thing using `generatePagination`
|
|
43
|
+
- **Use PaginationNav for 95% of cases.** Reach for the compound API when you need custom page-button rendering (e.g. pagination with input "jump to page" or custom ellipsis handling).
|
|
44
|
+
- **generatePagination** utility — pass `current`, `total`, `siblingCount` to get the `[1, ..., 5, 6, 7, ..., 20]` structure. Use it standalone if rendering pagination elsewhere (e.g. in a DataTable's footer).
|
|
45
|
+
- **Router integration:** Each PaginationLink accepts `asChild` — wrap with NextLink/react-router Link for URL-based pagination.
|
|
46
|
+
- **DataTable already has built-in pagination** — don't add Pagination separately; use DataTable's `pagination` prop.
|
|
47
|
+
|
|
39
48
|
## Gotchas
|
|
40
49
|
- Root component is PaginationRoot (NOT Pagination)
|
|
50
|
+
- PaginationNav is the convenience wrapper — prefer it unless you need custom rendering
|
|
41
51
|
|
|
42
52
|
## Changes
|
|
43
53
|
### v0.1.1
|
|
@@ -18,8 +18,17 @@
|
|
|
18
18
|
</Popover>
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
## Composability
|
|
22
|
+
- Built on Radix Popover — accepts `open`, `onOpenChange`, `defaultOpen`, `modal`.
|
|
23
|
+
- **Trigger:** `<PopoverTrigger asChild>` wraps any focusable element.
|
|
24
|
+
- **PopoverAnchor:** Optional — decouples the visual anchor from the interactive trigger. Useful when the trigger is small (e.g. an icon button) but you want the popover to position relative to a larger surrounding element.
|
|
25
|
+
- **Positioning:** PopoverContent accepts `side` (top / right / bottom / left), `align` (start / center / end), `sideOffset`, and `collisionPadding` — all forwarded to Floating UI via Radix.
|
|
26
|
+
- **Portal rendering:** Content portals to body; z-index is `z-popover` (1400) — above Dialog (`z-dialog`) so nested popovers-in-dialogs work correctly.
|
|
27
|
+
- **Not for tooltips** — use Tooltip for transient hover-label content; Popover is for interactive content (forms, menus, pickers).
|
|
28
|
+
|
|
21
29
|
## Gotchas
|
|
22
30
|
- Uses Framer Motion for enter/exit animations (v0.18.0)
|
|
31
|
+
- If content needs to be modal (backdrop, focus trap), pass `modal={true}` to the root Popover
|
|
23
32
|
|
|
24
33
|
## Changes
|
|
25
34
|
### v0.18.0
|
|
@@ -35,6 +35,13 @@
|
|
|
35
35
|
/>
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
## Composability
|
|
39
|
+
- **SVG-based circular progress** — pure SVG, no chart library dependency.
|
|
40
|
+
- **MultiProgressRing** — concentric rings for multi-metric visualization (Apple Activity style: Move + Exercise + Stand). Don't stack more than 4-5 rings at a size; the innermost rings become too thin. Size auto-allocates ring stroke; pass `size="lg"` for more room.
|
|
41
|
+
- **ProgressRing vs Progress:** Use ProgressRing for dashboard tiles, at-a-glance status, multi-metric visualizations. Use Progress for linear "percentage filled" UIs.
|
|
42
|
+
- **`showValue={true}`** renders the percentage in the center (ProgressRing only). For MultiProgressRing, use external labels since center would conflict with multiple values.
|
|
43
|
+
- **Label for a11y:** `label` falls back to `"{n}% progress"` so screen readers always get meaningful context.
|
|
44
|
+
|
|
38
45
|
## Gotchas
|
|
39
46
|
- Uses Framer Motion for the animated fill — not server-safe
|
|
40
47
|
- Value is clamped to `[0, max]` internally
|
|
@@ -22,6 +22,13 @@
|
|
|
22
22
|
<Progress size="sm" /> {/* indeterminate */}
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Composability
|
|
26
|
+
- **Radix Progress** underneath — `value` (determinate) or absent (indeterminate). Standard ARIA: role=progressbar, aria-valuenow/min/max.
|
|
27
|
+
- **autoColor semantic signal:** Maps value thresholds to color so consumers don't have to manually compute: 0–59=default, 60–84=warning, 85–100=success, >100=error. Useful for storage meters, budget trackers, goal progress.
|
|
28
|
+
- **Indeterminate:** Omit `value` to get a continuous animated indeterminate bar. Use for unknown-duration loads.
|
|
29
|
+
- **Progress vs ProgressRing:** Progress is a linear bar (horizontal). ProgressRing is circular. ProgressRing offers multi-ring stacked variants; Progress doesn't.
|
|
30
|
+
- **Inside Card/StatCard:** StatCard has a `progress` prop that renders a thin inline version — use that inside StatCards instead of a separate Progress.
|
|
31
|
+
|
|
25
32
|
## Gotchas
|
|
26
33
|
- Omit value (or pass undefined) for indeterminate animation
|
|
27
34
|
- `autoColor` overrides `color` when `value` is set — do not pass both unless you want autoColor to win
|
|
@@ -4,9 +4,26 @@
|
|
|
4
4
|
- Server-safe: No
|
|
5
5
|
- Category: ui
|
|
6
6
|
|
|
7
|
+
## Props
|
|
8
|
+
### RadioGroup
|
|
9
|
+
value: string (controlled)
|
|
10
|
+
onValueChange: (value: string) => void
|
|
11
|
+
defaultValue: string
|
|
12
|
+
disabled: boolean (propagates to all items)
|
|
13
|
+
orientation: "horizontal" | "vertical"
|
|
14
|
+
name: string (form name for all items)
|
|
15
|
+
|
|
16
|
+
### RadioGroupItem
|
|
17
|
+
value: string (REQUIRED — what's selected when this item is checked)
|
|
18
|
+
size: "sm" | "md" | "lg"
|
|
19
|
+
disabled: boolean (item-level override)
|
|
20
|
+
|
|
7
21
|
## Compound Components
|
|
8
|
-
RadioGroup (root
|
|
9
|
-
RadioGroupItem (value
|
|
22
|
+
RadioGroup (root — value, onValueChange, defaultValue, disabled propagated)
|
|
23
|
+
RadioGroupItem (value REQUIRED, size/disabled individually overridable)
|
|
24
|
+
|
|
25
|
+
## Defaults
|
|
26
|
+
RadioGroupItem size="md"
|
|
10
27
|
|
|
11
28
|
## Example
|
|
12
29
|
```jsx
|
|
@@ -22,9 +39,17 @@
|
|
|
22
39
|
</RadioGroup>
|
|
23
40
|
```
|
|
24
41
|
|
|
42
|
+
## Composability
|
|
43
|
+
- Radix RadioGroup — keyboard navigation (arrow keys to move between items, space to select) is pre-wired.
|
|
44
|
+
- **RadioGroup propagates** `disabled` to every RadioGroupItem; items can opt back in with `disabled={false}` for granular control (rare).
|
|
45
|
+
- **Labels:** RadioGroupItem has no intrinsic label — pair each with `<Label htmlFor="x" />` + `<RadioGroupItem id="x" value="..." />`. Screen readers announce the group label (from FormField or aria-labelledby on RadioGroup) plus each item's label.
|
|
46
|
+
- **Form libraries:** RadioGroup works with react-hook-form via Controller (onValueChange maps to field.onChange). The `name` prop puts a hidden form input per item for native form serialization.
|
|
47
|
+
- **FormField integration:** RadioGroup does NOT auto-consume FormField error state. For error visuals, style the RadioGroup surround (e.g. via aria-invalid on a wrapping fieldset) — individual radios don't show red borders the way Inputs do.
|
|
48
|
+
|
|
25
49
|
## Gotchas
|
|
26
50
|
- Each RadioGroupItem needs a unique `value` prop
|
|
27
51
|
- Pair each item with a Label for accessibility
|
|
52
|
+
- RadioGroup does NOT auto-inherit FormField error state — handle error styling at the group level
|
|
28
53
|
|
|
29
54
|
## Changes
|
|
30
55
|
### v0.4.2
|
|
@@ -26,8 +26,16 @@
|
|
|
26
26
|
/>
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
## Composability
|
|
30
|
+
- Purpose-built variant of Input for search — renders the leading search icon and a contextual clear/loading trailing slot. For anything more custom, use Input with explicit `startSection` / `endSection`.
|
|
31
|
+
- **`onClear` makes the X button appear** only when `value` is non-empty. Pair them so users can reset.
|
|
32
|
+
- **`loading={true}` swaps the clear button for a spinner** with `aria-busy="true"` on the input — useful for debounced/async search.
|
|
33
|
+
- Doesn't auto-consume FormField (no `state` prop) — wrap a regular Input inside FormField for validated search fields.
|
|
34
|
+
- Keyboard: Escape auto-triggers `onClear` when wired (handled via `type="search"`'s native behavior on most browsers).
|
|
35
|
+
|
|
29
36
|
## Gotchas
|
|
30
37
|
- HTML native "size" attribute is excluded — use CSS width instead
|
|
38
|
+
- Clear button only appears when both `onClear` is provided AND `value` is non-empty
|
|
31
39
|
|
|
32
40
|
## Changes
|
|
33
41
|
### v0.15.0
|
|
@@ -31,9 +31,17 @@
|
|
|
31
31
|
/>
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
## Composability
|
|
35
|
+
- **Data-driven, not compound** — unlike Tabs/ToggleGroup, SegmentedControl takes an `options` array rather than children. This makes it easier to render from a list but harder to customize per-option styling; use Tabs if you need compound children.
|
|
36
|
+
- **When to use vs Tabs:** SegmentedControl is for mutually-exclusive VIEW-MODE toggles (List/Grid/Kanban) — short labels, no associated content panel. Tabs is for content switching where each tab has a corresponding TabsContent. Both render `role="tablist"`.
|
|
37
|
+
- **Option icons** auto-size based on the `size` prop — don't set explicit icon sizes.
|
|
38
|
+
- Fully controlled — there's no `defaultSelectedId`. Manage state in parent.
|
|
39
|
+
- Built from scratch (no Radix primitive) — standard HTML buttons with `aria-selected` and roving tabindex.
|
|
40
|
+
|
|
34
41
|
## Gotchas
|
|
35
42
|
- Controlled only — selectedId + onSelect are required
|
|
36
43
|
- Uses data-driven API (options prop), not compound children
|
|
44
|
+
- Use Tabs (not SegmentedControl) when you need associated content panels per option
|
|
37
45
|
|
|
38
46
|
## Changes
|
|
39
47
|
### v0.18.0
|
|
@@ -6,11 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
## Props
|
|
8
8
|
### SelectTrigger
|
|
9
|
-
|
|
9
|
+
variant: "default" | "outline" | "ghost"
|
|
10
|
+
color: "default" | "error" | "success" | "warning" (sets aria-invalid when error)
|
|
11
|
+
size: "xs" | "sm" | "md" | "lg"
|
|
10
12
|
|
|
11
13
|
## Compound Components
|
|
12
14
|
Select (root — value, onValueChange, defaultValue)
|
|
13
|
-
SelectTrigger (size
|
|
15
|
+
SelectTrigger (variant/color/size go HERE, not on Select root)
|
|
14
16
|
SelectValue (placeholder)
|
|
15
17
|
SelectContent
|
|
16
18
|
SelectGroup (optional grouping)
|
|
@@ -19,7 +21,7 @@
|
|
|
19
21
|
SelectSeparator
|
|
20
22
|
|
|
21
23
|
## Defaults
|
|
22
|
-
SelectTrigger
|
|
24
|
+
SelectTrigger variant="default", color="default", size="md"
|
|
23
25
|
|
|
24
26
|
## Example
|
|
25
27
|
```jsx
|
|
@@ -34,6 +36,15 @@
|
|
|
34
36
|
</Select>
|
|
35
37
|
```
|
|
36
38
|
|
|
39
|
+
## Composability
|
|
40
|
+
- **Radix Select** underneath — `value`/`onValueChange`/`defaultValue`/`open`/`onOpenChange` standard state.
|
|
41
|
+
- **Styling props live on SelectTrigger, not Select root.** The Select root owns value/state; the Trigger owns appearance (variant/color/size). Setting `<Select size="lg">` silently does nothing — TypeScript won't catch it.
|
|
42
|
+
- **SelectItem requires `value`** — unique within the Select. Labels are the children of SelectItem.
|
|
43
|
+
- **SelectGroup + SelectLabel:** Organize options into sections with a non-interactive section heading.
|
|
44
|
+
- **FormField integration:** Set `color="error"` on SelectTrigger for error visuals. Not auto-consumed from FormField (same as Checkbox/Radio — form-library convention for select controls).
|
|
45
|
+
- **Portal + z-popover (1400):** content portals to body, stacks above Dialog/Sheet/other overlays.
|
|
46
|
+
- **Select vs Combobox vs Autocomplete:** Select = short fixed list, click-to-open, no typeahead. Combobox = searchable, forced selection. Autocomplete = searchable, free text. Pick by list size and search need.
|
|
47
|
+
|
|
37
48
|
## Gotchas
|
|
38
49
|
- Size goes on SelectTrigger, NOT on Select root
|
|
39
50
|
- `<Select size="lg">` is silently ignored (no TypeScript error)
|
|
@@ -18,8 +18,15 @@
|
|
|
18
18
|
<Separator orientation="vertical" className="h-6" />
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
## Composability
|
|
22
|
+
- Radix Separator — no context, no cascade. Drop it anywhere; it inherits its stretch dimension from its parent container (full width for horizontal, full height for vertical — but vertical needs an explicit height from the parent flexbox).
|
|
23
|
+
- `decorative={true}` (default) sets `role="none"` — screen readers skip it. Set `decorative={false}` for semantic separators (e.g. between navigation sections) so screen readers announce the boundary.
|
|
24
|
+
- Gradient variants compose cleanly with any surface color — they use `bg-transparent` + inline linear-gradient, so the underlying `bg-*` of the parent shows through.
|
|
25
|
+
- Common inside Menu/DropdownMenu/Sheet components; their internal *Separator subcomponents already wrap this one.
|
|
26
|
+
|
|
21
27
|
## Gotchas
|
|
22
28
|
- When decorative is true, the separator is hidden from screen readers
|
|
29
|
+
- Vertical separator needs an explicit height from the parent flex container (`h-6`, `h-full`, etc.)
|
|
23
30
|
|
|
24
31
|
## Changes
|
|
25
32
|
### v0.22.0
|
|
@@ -32,8 +32,18 @@
|
|
|
32
32
|
</Sheet>
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
## Defaults
|
|
36
|
+
side="right"
|
|
37
|
+
|
|
38
|
+
## Composability
|
|
39
|
+
- Same primitives as Dialog — open/onOpenChange/defaultOpen, trigger asChild, portal rendering, focus trap.
|
|
40
|
+
- `side` controls both the enter-from edge and the layout: top/bottom sides full-width, left/right sides ~75% of viewport (capped at sm breakpoint).
|
|
41
|
+
- Use Sheet for side-anchored drawers (settings panels, mobile navigation); use Dialog for centered modals.
|
|
42
|
+
- On mobile (`isMobile` from use-mobile), consider Sheet as the mobile-friendly equivalent of a Dialog/Popover — more thumb-reachable on tall screens.
|
|
43
|
+
|
|
35
44
|
## Gotchas
|
|
36
45
|
- Uses Framer Motion for slide enter/exit animations (v0.18.0)
|
|
46
|
+
- SheetTitle is required for accessibility (same rule as Dialog)
|
|
37
47
|
|
|
38
48
|
## Changes
|
|
39
49
|
### v0.18.0
|
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
- Server-safe: No
|
|
5
5
|
- Category: ui
|
|
6
6
|
|
|
7
|
+
## Props
|
|
8
|
+
### SidebarMenuButton
|
|
9
|
+
variant: "default" | "outline"
|
|
10
|
+
size: "sm" | "md" | "lg"
|
|
11
|
+
isActive: boolean (highlights as current nav item)
|
|
12
|
+
tooltip: ReactNode | string (shown when sidebar is collapsed)
|
|
13
|
+
asChild: boolean (render as Slot — common with next/link)
|
|
14
|
+
|
|
7
15
|
## Compound Components
|
|
8
16
|
SidebarProvider (context provider — must wrap everything)
|
|
9
17
|
Sidebar (root panel)
|
|
@@ -32,6 +40,9 @@
|
|
|
32
40
|
## Hook
|
|
33
41
|
useSidebar() => { state, open, setOpen, openMobile, setOpenMobile, isMobile, toggleSidebar }
|
|
34
42
|
|
|
43
|
+
## Defaults
|
|
44
|
+
SidebarMenuButton variant="default", size="md"
|
|
45
|
+
|
|
35
46
|
## Example
|
|
36
47
|
```jsx
|
|
37
48
|
<SidebarProvider>
|
|
@@ -59,9 +70,28 @@
|
|
|
59
70
|
</SidebarProvider>
|
|
60
71
|
```
|
|
61
72
|
|
|
73
|
+
## Composability
|
|
74
|
+
The whole Sidebar ecosystem is driven by `SidebarContext` — the Provider owns the expand/collapse state and every descendant reads from it.
|
|
75
|
+
|
|
76
|
+
**Who reads the context:**
|
|
77
|
+
- `Sidebar` — applies collapsed / expanded / off-canvas styles based on `state`
|
|
78
|
+
- `SidebarTrigger` — calls `toggleSidebar()` on click; reflects aria-expanded
|
|
79
|
+
- `SidebarMenuButton` — uses `state === 'collapsed'` to show its `tooltip` (hidden label appears only when sidebar is icon-width)
|
|
80
|
+
- `SidebarInset` — main content area adjusts its left offset based on sidebar width + state
|
|
81
|
+
- `SidebarRail` — invisible hit target on the outer edge for click-to-toggle
|
|
82
|
+
- Any user component that calls `useSidebar()` — full access to open/isMobile/toggle
|
|
83
|
+
|
|
84
|
+
**Desktop vs mobile:** Context tracks `isMobile` via the `use-mobile` hook and branches behavior: on desktop the sidebar collapses to an icon rail; on mobile it becomes an off-canvas drawer controlled by `openMobile`.
|
|
85
|
+
|
|
86
|
+
**Controlled or uncontrolled:** `SidebarProvider` accepts `open` + `onOpenChange` (controlled) or `defaultOpen` (uncontrolled). State is synced to a cookie for cross-route persistence.
|
|
87
|
+
|
|
88
|
+
**Next.js / router integration:** `SidebarMenuButton` with `asChild` wraps any link element (`next/link`, `react-router Link`, plain `<a>`) — it transfers its styling + isActive state to the child while preserving the link's navigation semantics.
|
|
89
|
+
|
|
62
90
|
## Gotchas
|
|
63
91
|
- SidebarProvider MUST wrap both Sidebar and SidebarInset
|
|
64
92
|
- Use SidebarMenuButton for nav items (supports tooltip in collapsed state)
|
|
93
|
+
- `tooltip` is only visible when sidebar is collapsed — providing one doesn't duplicate the visible label
|
|
94
|
+
- Cookie-based state persistence means the sidebar defaults to its prior state on page reload — use `defaultOpen` to override if needed
|
|
65
95
|
|
|
66
96
|
## Changes
|
|
67
97
|
### v0.18.0
|
|
@@ -67,6 +67,13 @@
|
|
|
67
67
|
<SkeletonImage height="h-64" />
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
## Composability
|
|
71
|
+
- Server-safe — can render in RSC trees during server-side loading states.
|
|
72
|
+
- **Pattern:** One SkeletonGroup per load region (wraps with `role="status"` + `aria-busy="true"` + announces the `label`). Inside, compose the individual shape skeletons (Avatar, Text, Button, Chart, Image) to mirror the structure that will appear when loaded.
|
|
73
|
+
- Use LoadingSkeleton (composed) instead for pre-built layouts — CardSkeleton, TableSkeleton, ListSkeleton, BoardSkeleton — or PageSkeletons for full-page placeholders.
|
|
74
|
+
- `animation="none"` disables animation entirely — useful when placed inside components that already have their own load animation.
|
|
75
|
+
- No context cascade — each skeleton is independent. If you want to drive multiple skeletons from one "reduced motion" setting, either set `animation="none"` on each or rely on the `useReducedMotion` hook (shimmer already respects it automatically).
|
|
76
|
+
|
|
70
77
|
## Gotchas
|
|
71
78
|
- shimmer respects prefers-reduced-motion
|
|
72
79
|
- SkeletonGroup adds role="status" and aria-busy="true" — wrap multiple skeletons for a11y
|
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
- Category: ui
|
|
6
6
|
|
|
7
7
|
## Props
|
|
8
|
-
|
|
8
|
+
size: "sm" | "md" | "lg" (track height and thumb dimensions)
|
|
9
|
+
color: "accent" | "success" | "warning" | "error" (thumb border + focus ring color)
|
|
10
|
+
(plus standard Radix Slider props: value, onValueChange, defaultValue, min, max, step, aria-label)
|
|
11
|
+
|
|
12
|
+
## Defaults
|
|
13
|
+
size="md", color="accent"
|
|
9
14
|
|
|
10
15
|
## Example
|
|
11
16
|
```jsx
|
|
@@ -13,9 +18,18 @@
|
|
|
13
18
|
<Slider defaultValue={[25, 75]} max={100} step={1} /> {/* range slider */}
|
|
14
19
|
```
|
|
15
20
|
|
|
21
|
+
## Composability
|
|
22
|
+
- Radix Slider primitive — keyboard navigation (arrow keys, Home/End, PageUp/PageDown) pre-wired.
|
|
23
|
+
- **Value is always an array** — single-thumb: `[50]`; range: `[25, 75]`. Don't pass a plain number.
|
|
24
|
+
- **Multi-thumb range:** Pass `[start, end]` — renders two thumbs that can cross each other by default. Use `minStepsBetweenThumbs` to enforce a gap.
|
|
25
|
+
- **FormField:** Slider does NOT auto-consume FormField state. No validation UX — sliders usually don't need it (values are always valid by construction).
|
|
26
|
+
- **No label pairing via Label** — use `aria-label` or `aria-labelledby` directly on the Slider. The thumb is the focusable/labeled element.
|
|
27
|
+
- Not portal-rendered — inline; overflow rules of parents apply.
|
|
28
|
+
|
|
16
29
|
## Gotchas
|
|
17
30
|
- value is number[] (array), not a single number
|
|
18
31
|
- Multi-thumb: Pass array `defaultValue={[25, 75]}` for range sliders — renders one thumb per value
|
|
32
|
+
- Slider does NOT auto-consume FormField — sliders don't have validation state visuals by design
|
|
19
33
|
|
|
20
34
|
## Changes
|
|
21
35
|
### v0.18.0
|
|
@@ -24,6 +24,13 @@
|
|
|
24
24
|
<Spinner variant="bare" /> {/* uses currentColor, for embedding in buttons */}
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
## Composability
|
|
28
|
+
- **Prefer Button's `loading` prop** for inline button spinners — Button's integration is automatic (disables, sets aria-busy, positions the spinner). Manual Spinner inside Button is more work for no gain.
|
|
29
|
+
- **`variant="bare"`** uses `currentColor` — drop it into any surface (button, toolbar, badge, icon group) and it picks up the parent's text color automatically.
|
|
30
|
+
- **State transitions:** `spinning → success → idle` / `spinning → error → idle`. Use the state machine for async operation feedback (the success checkmark, error X animate in). Pair with `onComplete` to trigger next-step logic after the transition.
|
|
31
|
+
- **delay for flicker prevention:** Set `delay={150}` so very fast operations don't flash a spinner. The spinner mounts only after the delay elapses — if the operation completes first, the user never sees it.
|
|
32
|
+
- **Icon.state="loading" uses Spinner internally** — same underlying component. If you're inside an Icon context, prefer `<Icon state="loading" />` for consistent sizing.
|
|
33
|
+
|
|
27
34
|
## Gotchas
|
|
28
35
|
- Renders role="status" with sr-only "Loading..." text — no need for aria-label
|
|
29
36
|
- Button has built-in loading prop — prefer that over manual Spinner composition
|
|
@@ -35,6 +35,17 @@ import { SplitButton } from '@devalok/shilp-sutra'
|
|
|
35
35
|
| dropdownLabel | string | 'More options' | aria-label for trigger |
|
|
36
36
|
| dropdownIcon | ReactNode | chevron-down | Custom trigger icon |
|
|
37
37
|
|
|
38
|
+
## Composability
|
|
39
|
+
- **Two-in-one button:** visually unified `[Action | ▼]` with the left half being the primary click and the right half opening a dropdown. Use for actions that have a most-common choice plus alternatives (Save vs. Save-As-Draft, Send vs. Schedule).
|
|
40
|
+
- **Built on Button + Popover internally** — inherits Button's variant/color/size vocabulary and Popover's placement prop (`top-end` default works for most top-of-page toolbars).
|
|
41
|
+
- **Dropdown content is consumer-provided** — pass any JSX via `dropdownContent` (typically a DropdownMenu, list of actions, a custom panel, or a small form). Don't try to shove a full-featured menu into the chevron; keep it focused on 2–5 alternatives.
|
|
42
|
+
- **ButtonGroup compatibility:** Put SplitButton inside a `<ButtonGroup>` — it inherits variant/color/size from the group context just like Button does. Position-aware corners work too.
|
|
43
|
+
- **Controlled dropdown:** Pass `open` + `onOpenChange` for controlled state; omit for uncontrolled. Useful when the dropdown must close programmatically after a selection.
|
|
44
|
+
|
|
45
|
+
## Gotchas
|
|
46
|
+
- Always provide `dropdownLabel` (aria-label on the chevron trigger) — defaults to "More options" but context-specific labels are better
|
|
47
|
+
- `triggerSide="left"` flips the chevron to the left — rare, but useful for RTL layouts or when the primary action is the secondary emphasis
|
|
48
|
+
|
|
38
49
|
## Changes
|
|
39
50
|
|
|
40
51
|
### v0.33.0
|
|
@@ -23,6 +23,14 @@
|
|
|
23
23
|
</Stack>
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
## Composability
|
|
27
|
+
- **Server-safe layout primitive.** Nothing to hydrate — works anywhere.
|
|
28
|
+
- **Pattern:** Stack wraps child elements in a flex container. Swap between vertical/horizontal without rewriting the child layout.
|
|
29
|
+
- **Polymorphic via `as`:** Use `as="ul"` / `as="ol"` for list semantics with flex styling; `as="section"` for major page divisions; etc.
|
|
30
|
+
- **gap is design-system tokenized** — use token strings (`"ds-04"`) or numeric shortcuts (`4` → `"ds-04"`). Raw numbers map 1:1 to the `ds-0N` token set.
|
|
31
|
+
- **Responsive direction:** Not built in — for responsive direction changes use Tailwind's `flex-col md:flex-row` directly on a plain div, or wrap multiple Stacks with display-toggling.
|
|
32
|
+
- Container vs Stack: Container centers + caps width; Stack arranges children. Compose them: `<Container><Stack>...</Stack></Container>`.
|
|
33
|
+
|
|
26
34
|
## Gotchas
|
|
27
35
|
- "row" and "column" are aliases for "horizontal" and "vertical"
|
|
28
36
|
- gap accepts both token strings and numeric values
|
|
@@ -47,6 +47,15 @@
|
|
|
47
47
|
/>
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
## Composability
|
|
51
|
+
- **High-density metric card** — optimized for dashboards. Everything optional except `value`. Mix and match features (delta, sparkline, progress, secondary label, footer) per metric's needs.
|
|
52
|
+
- **Router integration via href:** Internally uses `LinkContext` to resolve framework-specific Link components (Next.js, react-router). Set `href` in a LinkProvider-wrapped tree to get seamless client-side navigation without custom asChild wiring.
|
|
53
|
+
- **Interactive modes:** `onClick` makes the entire card a button; `href` makes it a link. Mutually exclusive — href wins if both are set.
|
|
54
|
+
- **Accent bar semantic:** Use `accent` to signal metric health at a glance (success for positive, warning for at-risk, error for over-target). Combine with delta.direction for layered emphasis.
|
|
55
|
+
- **Sparkline:** Pure SVG, lightweight — no chart library. For rich charts use Chart components. Minimum 2 data points.
|
|
56
|
+
- **Icon auto-sizing:** Accepts `ComponentType<{ className }>` OR `ReactNode`. The component prop (e.g. `icon={IconBolt}`) is preferred — icon is rendered at a consistent size.
|
|
57
|
+
- **Loading state:** `loading={true}` renders the full card skeleton — use during initial data fetch.
|
|
58
|
+
|
|
50
59
|
## Gotchas
|
|
51
60
|
- delta.direction "up" = green, "down" = red, "neutral" = grey
|
|
52
61
|
- `label` and `title` are aliases — use either, not both
|
|
@@ -21,6 +21,15 @@
|
|
|
21
21
|
<StatusDot status="warning" size="lg" label="Elevated load" />
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
## Composability
|
|
25
|
+
- **Server-safe presentational dot** — simple status indicator, pairs with inline text.
|
|
26
|
+
- **Status semantics map to color:** healthy=success, warning=warning, critical=error, neutral=muted surface, inactive=dimmed. The pulse animation calls attention to "healthy" by default (active presence); you can flip it for other statuses by setting pulse explicitly.
|
|
27
|
+
- **StatusDot vs BadgeIndicator vs StatusBadge:**
|
|
28
|
+
- StatusDot = tiny presence/status indicator with optional inline label (e.g. "Service online")
|
|
29
|
+
- BadgeIndicator = overlay on another element (notification dot on a bell icon)
|
|
30
|
+
- StatusBadge (composed) = full pill-style badge with colored bg and label text (e.g. ticket status)
|
|
31
|
+
- **Label composability:** If you pass `label`, it renders inline after the dot. Use `labelClassName` for custom typography (e.g. font-mono for status codes).
|
|
32
|
+
|
|
24
33
|
## Gotchas
|
|
25
34
|
- The `pulse` prop auto-enables for "healthy" status — pass `pulse={false}` to suppress
|
|
26
35
|
- Status type is exported as `StatusDotStatus` if you need it in consumer code
|
|
@@ -37,8 +37,16 @@
|
|
|
37
37
|
</Stepper>
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
## Composability
|
|
41
|
+
- `Stepper` passes `activeStep` + `orientation` + each step's index down to every `Step` child via `StepperContext`. Each Step derives its own status (completed / active / pending) from its position vs `activeStep`.
|
|
42
|
+
- Step index is assigned by position in children — order matters. Don't conditionally render Steps via `&&` or `.filter()`; it shifts the indices and breaks the active highlight.
|
|
43
|
+
- `StepperContent` is separate from `Stepper` — it's the animated panel surface that shows one child per step index. Pass the same `activeStep` value to both.
|
|
44
|
+
- `orientation="vertical"` swaps the Step layout (stacked with connecting line on the left) AND changes how StepperContent animates (vertical crossfade instead of horizontal slide).
|
|
45
|
+
- Custom icons via `Step.icon` override the default number/checkmark — the icon slot still receives the status-based styling (muted for pending, accent for active/completed).
|
|
46
|
+
|
|
40
47
|
## Gotchas
|
|
41
48
|
- Steps before activeStep are "completed", at activeStep is "active", after is "pending"
|
|
49
|
+
- Don't conditionally render Step children — position is the index contract
|
|
42
50
|
|
|
43
51
|
## Changes
|
|
44
52
|
### v0.18.0
|
|
@@ -22,9 +22,17 @@
|
|
|
22
22
|
<Switch size="lg" color="success" thumbIcon={<IconCheck size={14} />} />
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Composability
|
|
26
|
+
- Radix Switch primitive — `checked` / `onCheckedChange` / `defaultChecked` standard control model.
|
|
27
|
+
- **FormField:** Switch does NOT auto-consume FormField state (same as Checkbox/Radio — form-library convention for toggles). Pass `error` explicitly when needed.
|
|
28
|
+
- **thumbIcon slot:** Any ReactNode renders inside the thumb circle — commonly used for check/X glyphs that animate with the thumb position.
|
|
29
|
+
- **Label pairing:** Manual — pair with `<Label htmlFor="x" />` + `<Switch id="x" />`, or wrap both in a `<label>` for click-to-toggle.
|
|
30
|
+
- Pair with FormHelperText (outside FormField wiring) for custom validation messages.
|
|
31
|
+
|
|
25
32
|
## Gotchas
|
|
26
33
|
- Use error prop for validation states (matches Checkbox API)
|
|
27
34
|
- `error` overrides `color` — when error is true, checked state always uses error-9
|
|
35
|
+
- Switch does NOT auto-consume FormField — pass `error` explicitly inside a FormField
|
|
28
36
|
|
|
29
37
|
## Changes
|
|
30
38
|
### v0.29.0
|
|
@@ -33,8 +33,16 @@
|
|
|
33
33
|
</Table>
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
## Composability
|
|
37
|
+
- **Server-safe pure HTML wrappers** — Table and sub-components are thin semantic wrappers around `<table>`, `<thead>`, `<tbody>`, etc. No state, no context. Safe in RSC trees.
|
|
38
|
+
- **Table vs DataTable:** Table is presentational — you control every row, cell, header. DataTable (from `ui/data-table`) is feature-rich — sorting, filtering, pagination, selection, virtualization built in. Pick by whether you need that machinery.
|
|
39
|
+
- **Use cases for bare Table:** Static data displays, marketing comparison tables, documentation tables, small lists where DataTable would be overkill.
|
|
40
|
+
- **Composes with UI primitives inside cells:** Badge for status pills, Avatar for user cells, IconButton for row actions, StatusDot for state indicators. All server-safe if the table is server-rendered.
|
|
41
|
+
- **TableCaption** renders as HTML `<caption>` — useful for a summary description that screen readers announce before the table content.
|
|
42
|
+
|
|
36
43
|
## Gotchas
|
|
37
44
|
- Table headers automatically have scope="col" for screen reader navigation
|
|
45
|
+
- For anything beyond trivial display, prefer DataTable — don't rebuild sorting/pagination/selection on top of bare Table
|
|
38
46
|
|
|
39
47
|
## Changes
|
|
40
48
|
### v0.18.0
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
### TabsList
|
|
14
14
|
variant: "line" | "contained"
|
|
15
|
+
size: "sm" | "md" | "lg"
|
|
16
|
+
orientation: "horizontal" | "vertical"
|
|
15
17
|
|
|
16
18
|
### TabsTrigger
|
|
17
19
|
value: string (REQUIRED)
|
|
@@ -27,7 +29,7 @@
|
|
|
27
29
|
TabsContent (value)
|
|
28
30
|
|
|
29
31
|
## Defaults
|
|
30
|
-
TabsList variant
|
|
32
|
+
TabsList variant="line", size="md", orientation="horizontal"
|
|
31
33
|
|
|
32
34
|
## Example
|
|
33
35
|
```jsx
|
|
@@ -41,8 +43,14 @@
|
|
|
41
43
|
</Tabs>
|
|
42
44
|
```
|
|
43
45
|
|
|
46
|
+
## Composability
|
|
47
|
+
- TabsList propagates `variant`, `size`, and `orientation` to every TabsTrigger child via `TabsListContext`. TabsTrigger reads all three from context; explicit props on a trigger override the inherited value.
|
|
48
|
+
- `orientation="vertical"` on TabsList changes the TabsList layout (flex-col + left border) AND the `roving-tabindex` keyboard behavior (ArrowUp/Down navigate, not ArrowLeft/Right).
|
|
49
|
+
- Tabs (root) is just the Radix Tabs.Root — state props (value, defaultValue, onValueChange) live there; styling props live on TabsList.
|
|
50
|
+
- Tabs content is rendered inline (not portalled) — container-scoped queries work fine in tests.
|
|
51
|
+
|
|
44
52
|
## Gotchas
|
|
45
|
-
- variant
|
|
53
|
+
- variant/size/orientation go on TabsList, NOT on Tabs root or individual TabsTrigger
|
|
46
54
|
- Normally omit `variant` on TabsTrigger — it inherits from TabsList via context. You CAN set it per-trigger to override.
|
|
47
55
|
|
|
48
56
|
## Changes
|