@devalok/shilp-sutra 0.37.0 → 0.38.0
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/MIGRATION.md +67 -0
- package/dist/_chunks/tiptap.js +977 -968
- package/dist/_chunks/tiptap.js.map +1 -1
- package/dist/composed/index.d.ts +0 -2
- package/dist/composed/index.d.ts.map +1 -1
- package/dist/composed/index.js +5 -6
- 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/hooks/index.d.ts +2 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +0 -1
- package/dist/test-utils/conformance.d.ts +37 -0
- package/dist/test-utils/conformance.d.ts.map +1 -0
- package/dist/ui/alert.d.ts +1 -2
- package/dist/ui/alert.d.ts.map +1 -1
- package/dist/ui/alert.js +1 -27
- package/dist/ui/alert.js.map +1 -1
- package/dist/ui/banner.d.ts +3 -5
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +13 -13
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +2 -2
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/input.d.ts +1 -9
- package/dist/ui/input.d.ts.map +1 -1
- package/dist/ui/input.js +26 -27
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/segmented-control.d.ts +1 -1
- package/dist/ui/segmented-control.d.ts.map +1 -1
- package/dist/ui/segmented-control.js +2 -4
- package/dist/ui/segmented-control.js.map +1 -1
- package/docs/components/_header.md +1 -1
- 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/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 +13 -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 +10 -1
- 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 +11 -2
- 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 +21 -6
- 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/docs/recipes/customize-brand.md +216 -0
- package/docs/recipes/index.md +51 -0
- package/docs/recipes/install-astro.md +178 -0
- package/docs/recipes/install-next-app-router.md +230 -0
- package/docs/recipes/install-next-pages.md +123 -0
- package/docs/recipes/install-remix.md +171 -0
- package/docs/recipes/install-tanstack-start.md +143 -0
- package/docs/recipes/install-vite.md +170 -0
- package/docs/recipes/server-components.md +209 -0
- package/docs/recipes/troubleshoot.md +217 -0
- package/llms-full.txt +1133 -88
- package/llms.txt +33 -16
- package/package.json +45 -35
- package/dist/composed/responsive-overlay.d.ts +0 -23
- package/dist/composed/responsive-overlay.d.ts.map +0 -1
- package/dist/composed/responsive-overlay.js +0 -40
- package/dist/composed/responsive-overlay.js.map +0 -1
- package/dist/hooks/use-toast.d.ts +0 -17
- package/dist/hooks/use-toast.d.ts.map +0 -1
- package/dist/hooks/use-toast.js +0 -3
- package/dist/tailwind/index.cjs +0 -41
- package/dist/tailwind/index.d.ts +0 -2
- package/dist/tailwind/index.d.ts.map +0 -1
- package/dist/tailwind/index.js +0 -2
- package/dist/tailwind/preset.d.ts +0 -25
- package/dist/tailwind/preset.d.ts.map +0 -1
- package/dist/tailwind/preset.js +0 -17
- package/dist/tailwind/preset.js.map +0 -1
- package/docs/components/composed/responsive-overlay.md +0 -34
|
@@ -26,6 +26,12 @@
|
|
|
26
26
|
</FormSection>
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
## Composability
|
|
30
|
+
- **Visual grouping of related FormFields.** Wraps its children with a title + description + horizontal rule separator. No state, no context.
|
|
31
|
+
- **collapsible mode** wraps content in a Collapsible — useful for "Advanced settings" or optional form sections. `defaultOpen={false}` for initially-closed.
|
|
32
|
+
- **Pairs with FormField:** Each form control inside should be a FormField for consistent label + helper text + validation. FormSection doesn't auto-wrap; you still structure each field yourself.
|
|
33
|
+
- **Not a page-level header** — for a full form's main heading use PageHeader. FormSection is mid-form, between field groups.
|
|
34
|
+
|
|
29
35
|
## Gotchas
|
|
30
36
|
- `defaultOpen` only applies when `collapsible={true}` — otherwise the section is always open
|
|
31
37
|
- Renders a horizontal rule between the header and content automatically
|
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
<GlobalLoading isLoading={isNavigating} />
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
## Composability
|
|
19
|
+
- **Thin top-of-viewport progress bar** — for route-level navigation indicators (NProgress-style). Fixed at the top; z-toast layer.
|
|
20
|
+
- **Wire to router events:** Pair with Next.js `useRouter` + navigation events, or react-router's `useNavigation`, or a custom global loading state in Redux/Zustand. Set `isLoading={true}` during transit, `false` when landed.
|
|
21
|
+
- **Not for in-page loading** — use Spinner, Skeleton, or LoadingSkeleton for component-level loading states. GlobalLoading is strictly for cross-route / full-page transitions.
|
|
22
|
+
- **Auto-unmounts when isLoading=false** — no need to manage visibility via classes or conditional rendering.
|
|
23
|
+
|
|
18
24
|
## Gotchas
|
|
19
25
|
- Fixed-position bar at top of viewport (z-toast layer)
|
|
20
26
|
- Renders nothing when `isLoading` is false
|
|
@@ -25,6 +25,14 @@
|
|
|
25
25
|
/>
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
## Composability
|
|
29
|
+
- **contentEditable-based** — the text IS the editor (Notion / Linear / Figma layer-name pattern). No separate input field appears.
|
|
30
|
+
- **Keyboard contract:** Click to focus (auto-selects text, like Finder rename). Type to edit. Enter saves, Escape reverts. Paste strips rich content.
|
|
31
|
+
- **Async save:** `onSave` can return a Promise — InlineEdit shows a spinner and disables editing while pending. On rejection, text reverts to the original value automatically.
|
|
32
|
+
- **Accessibility:** Accepts `aria-label` and `aria-labelledby` (forwarded to the role="textbox" span) — required when the text isn't self-descriptive. Falls back to `placeholder` as label when neither is provided.
|
|
33
|
+
- **Not inside FormField** — InlineEdit is for in-place editing of existing content (task title, project name); use regular FormField + Input for traditional forms.
|
|
34
|
+
- **textClassName for typography control:** Pass `"text-ds-lg font-semibold"` to make it look like a heading without changing the underlying element.
|
|
35
|
+
|
|
28
36
|
## Gotchas
|
|
29
37
|
- Uses contentEditable — the text IS the editor. No input field appears.
|
|
30
38
|
- Click to focus → cursor appears in text. Type to edit. Enter saves. Escape reverts.
|
|
@@ -39,6 +39,13 @@ Exports: CardSkeleton, TableSkeleton, BoardSkeleton, ListSkeleton
|
|
|
39
39
|
<ListSkeleton rows={10} showAvatar={false} />
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
## Composability
|
|
43
|
+
- **Pre-composed skeleton layouts** — CardSkeleton, TableSkeleton, BoardSkeleton, ListSkeleton. Each mimics the shape of a common DS layout so users see meaningful loading placeholders.
|
|
44
|
+
- **Built on ui/Skeleton** — for custom loading layouts, use Skeleton directly (rectangle/circle/text variants). These composed versions are just opinionated shape combinations.
|
|
45
|
+
- **Server-safe** — use during SSR for initial-paint skeletons in Next.js app router (while server data streams in).
|
|
46
|
+
- **Pairs with conditional rendering:** `{isLoading ? <TableSkeleton rows={8} /> : <DataTable data={rows} />}`.
|
|
47
|
+
- **PageSkeletons (separate file)** provides full-page placeholders (DashboardSkeleton, ProjectListSkeleton, TaskDetailSkeleton) — use those for route-level loading states.
|
|
48
|
+
|
|
42
49
|
## Gotchas
|
|
43
50
|
- Server-safe: can be imported directly in Next.js Server Components
|
|
44
51
|
- These are pre-composed skeleton layouts — for individual skeleton shapes, use the `Skeleton` UI component
|
|
@@ -20,6 +20,15 @@
|
|
|
20
20
|
<MarkdownViewer content={trustedHtml} allowHtml />
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
## Composability
|
|
24
|
+
- **Read-only markdown renderer.** For editing, use RichTextEditor (TipTap-based). MarkdownViewer is strictly for display.
|
|
25
|
+
- **Built on react-markdown + remark-gfm** — GFM tables, strikethrough, task lists supported out of the box.
|
|
26
|
+
- **Syntax highlighting is lazy:** Code blocks with a language fence (```ts, ```python) lazy-load react-syntax-highlighter. First render shows a plain `<pre>` fallback. Don't pre-import.
|
|
27
|
+
- **Security posture:** Raw HTML is stripped by default — `allowHtml={true}` must be explicit, and ONLY for trusted content (XSS vector otherwise).
|
|
28
|
+
- **Links open external by default** (`target="_blank"` + `rel="noopener noreferrer"`). Override via `linkTarget`.
|
|
29
|
+
- **compact mode** for inline use (comments, message bubbles). Default spacing is for article-body content.
|
|
30
|
+
- **Pairs with Chat's Message.Body** — render markdown from user messages safely. Always keep `allowHtml={false}` for user-generated content.
|
|
31
|
+
|
|
23
32
|
## Gotchas
|
|
24
33
|
- Code blocks with a language fence are syntax-highlighted via `react-syntax-highlighter` (lazy-loaded) — the first render shows a plain `<pre>` fallback
|
|
25
34
|
- GFM (tables, strikethrough, task lists) is supported via `remark-gfm`
|
|
@@ -42,6 +42,13 @@ MasterDetail (root), MasterDetail.List, MasterDetail.Detail, MasterDetail.ListIt
|
|
|
42
42
|
</MasterDetail>
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
## Composability
|
|
46
|
+
- **Responsive list+detail layout.** Desktop: side-by-side panels. Mobile (below `breakpoint`): stacked, mutually exclusive (list OR detail, controlled by `selected`).
|
|
47
|
+
- **Compound structure:** `MasterDetail.List` contains `MasterDetail.ListItem[]` (interactive). `MasterDetail.Detail` holds the currently-selected view.
|
|
48
|
+
- **onBack is required for mobile** — renders the back button in Detail pane. Omitting it leaves users stranded once they drill into an item on mobile.
|
|
49
|
+
- **SSR gotcha:** Uses `window.matchMedia` — initial SSR render picks desktop mode; hydrates to mobile mode if viewport is narrow. If that causes layout shift, consider rendering this only after mount (via `useState(false)` + `useEffect`).
|
|
50
|
+
- **Pairs with EmptyState** — render EmptyState inside Detail when `selected === null` on desktop ("Pick an item to get started").
|
|
51
|
+
|
|
45
52
|
## Gotchas
|
|
46
53
|
- On mobile (below breakpoint), List and Detail are mutually exclusive — selecting an item hides the list
|
|
47
54
|
- The `onBack` callback is required for the mobile back button to appear in the Detail pane
|
|
@@ -22,6 +22,13 @@
|
|
|
22
22
|
</MemberPicker>
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Composability
|
|
26
|
+
- **Trigger + Popover + search list.** Pass any button/element as `children` to act as the trigger. Typical pairing: outline Button that says "Assign" or an IconButton with avatar overflow.
|
|
27
|
+
- **Single vs multi:** `multiple={true}` allows multiple selections; `false` (default) replaces the previous selection. `selectedIds` is always an array in both modes — consumer controls semantics.
|
|
28
|
+
- **onSelect with a single ID:** Fires once per click with one memberId. Toggle logic in multi mode is consumer responsibility (derive the new array from the click).
|
|
29
|
+
- **Avatar display:** Uses ui/Avatar internally — supply `avatar` URL in the member object, fallback to initials from `name`.
|
|
30
|
+
- **For general-purpose multi-select** (non-members), use MultiSelectPopover which has the same popover+search pattern without member-specific avatar rendering.
|
|
31
|
+
|
|
25
32
|
## Gotchas
|
|
26
33
|
- `children` is used as the trigger element (e.g., a Button)
|
|
27
34
|
- `onSelect` is called with a single `memberId` — toggle logic is up to the consumer
|
|
@@ -47,6 +47,17 @@
|
|
|
47
47
|
</MultiSelectPopover>
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
## Composability
|
|
51
|
+
- **Generalized multi-select popover** — picks from a fixed list (items) or grouped list (groups), with search, async search, and custom rendering.
|
|
52
|
+
- **Items vs groups (mutually exclusive):** Pass `items` for flat lists, `groups` for sectioned lists. Don't pass both.
|
|
53
|
+
- **Async search via onSearch:** When provided, local filtering is disabled — the callback owns filtering and returns a new list. `searchDebounce` (default 300ms) throttles calls.
|
|
54
|
+
- **renderItem escape hatch:** Pass `(item, selected) => ReactNode` for custom item rendering (avatar + multi-line descriptions, etc.). Built-in default renders image + label + description.
|
|
55
|
+
- **maxSelections behavior:** At the limit, clicking a new item REPLACES the oldest selection (FIFO). `maxSelections={1}` effectively acts as single-select.
|
|
56
|
+
- **MultiSelectPopover vs Combobox vs MemberPicker:**
|
|
57
|
+
- Combobox = form-field multi-select (typeahead + selection in place)
|
|
58
|
+
- MultiSelectPopover = button-triggered popup for bulk selection (good for "Assign to" / "Add tags" scenarios)
|
|
59
|
+
- MemberPicker = MultiSelectPopover specialized for team-member UI
|
|
60
|
+
|
|
50
61
|
## Gotchas
|
|
51
62
|
- Supply either `items` (flat) or `groups` (sectioned), not both
|
|
52
63
|
- When `onSearch` is provided, local filtering is disabled — the callback must return results
|
|
@@ -28,6 +28,13 @@
|
|
|
28
28
|
/>
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
## Composability
|
|
32
|
+
- **Server-safe page-top header** with title + subtitle + breadcrumbs + actions slot. Renders Breadcrumb internally from the `breadcrumbs` array.
|
|
33
|
+
- **Auto-derived title:** If `title` is omitted, the last breadcrumb's `label` becomes the h1. Saves duplication when the page title matches the breadcrumb leaf.
|
|
34
|
+
- **Breadcrumb contract:** Last item should NOT have an `href` (it's the current page — renders as BreadcrumbPage, not a link). Items with `href` render as BreadcrumbLink.
|
|
35
|
+
- **actions slot:** Typically one to three buttons (Save, Cancel, More). For larger action groups, use ButtonGroup or a toolbar.
|
|
36
|
+
- **Not for tabs / sub-navigation** — pair with Tabs rendered below PageHeader for that.
|
|
37
|
+
|
|
31
38
|
## Gotchas
|
|
32
39
|
- Server-safe: can be imported directly in Next.js Server Components
|
|
33
40
|
- If `title` is omitted, the last breadcrumb's `label` is used as the page title
|
|
@@ -19,6 +19,16 @@ Exports: DashboardSkeleton, ProjectListSkeleton, TaskDetailSkeleton
|
|
|
19
19
|
<TaskDetailSkeleton />
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
## Composability
|
|
23
|
+
- **Full-page skeleton layouts** for route-level loading states. Each mimics a common page shape (dashboard tiles, project list with filters, task detail with sidebar).
|
|
24
|
+
- **Server-safe** — use in Next.js app router `loading.tsx` files for instant route-transition feedback while data streams.
|
|
25
|
+
- **Built on LoadingSkeleton + ui/Skeleton** — these just assemble the pre-built regional skeletons into page-shaped layouts.
|
|
26
|
+
- **When to use which skeleton tier:**
|
|
27
|
+
- `<Skeleton>` (ui) — single shape for a single element
|
|
28
|
+
- `<CardSkeleton>` / `<TableSkeleton>` (LoadingSkeleton) — individual region shape
|
|
29
|
+
- `<DashboardSkeleton>` / etc. (PageSkeletons) — full page placeholder
|
|
30
|
+
- **Fixed layout structure** — the className prop adjusts the outer container, but internal layout isn't customizable. For custom page skeletons, compose LoadingSkeleton pieces yourself.
|
|
31
|
+
|
|
22
32
|
## Gotchas
|
|
23
33
|
- Server-safe: can be imported directly in Next.js Server Components
|
|
24
34
|
- These are full-page skeleton layouts — for smaller skeleton sections, use LoadingSkeleton components
|
|
@@ -19,6 +19,13 @@ Priority = 'LOW' | 'MEDIUM' | 'HIGH' | 'URGENT' | 'low' | 'medium' | 'high' | 'u
|
|
|
19
19
|
<PriorityIndicator priority="low" display="compact" />
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
## Composability
|
|
23
|
+
- **Server-safe priority label** — icon + color + text for task / issue priority.
|
|
24
|
+
- **Composes inside list rows, DataTable cells, Card headers, task panels** — anywhere a priority flag fits.
|
|
25
|
+
- **display="compact"** shows only the icon (with priority text as title attribute for tooltip). Use in tight cells; use `display="full"` (default) in free space.
|
|
26
|
+
- **Case-insensitive priority** — accepts both UPPERCASE (LOW/MEDIUM/HIGH/URGENT) and lowercase. Designed to match both backend conventions without manual coercion.
|
|
27
|
+
- Color semantics: LOW=success, MEDIUM=warning, HIGH=error, URGENT=error with bolder icon.
|
|
28
|
+
|
|
22
29
|
## Gotchas
|
|
23
30
|
- Case-insensitive — "low" and "LOW" both work
|
|
24
31
|
- Server-safe: can be imported directly in Next.js Server Components
|
|
@@ -67,6 +67,18 @@ SlashCommandGroup: { label: string; commands: SlashCommand[] }
|
|
|
67
67
|
/>
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
## Composability
|
|
71
|
+
- **Chat-specific TipTap editor** — purpose-built for AI + human messaging. Built on RichTextEditor primitives but pre-configured for the chat UX (auto-resize, Enter-to-send, inline toolbar).
|
|
72
|
+
- **Variant drives the UX envelope:**
|
|
73
|
+
- `compact` — 2-3 line inline (chat bubble composer)
|
|
74
|
+
- `expanded` — 5+ lines with always-visible toolbar (AI prompt input)
|
|
75
|
+
- `minimal` — single line, toolbar on focus (reply composer, quick comment)
|
|
76
|
+
- **Toolbar is opt-in per feature:** Icons only appear when their corresponding handler/prop is set. `onFileUpload` → attach button appears. `slashCommands` → slash button appears. `mentions` or `onMentionSearch` → @ button appears.
|
|
77
|
+
- **Composes with Message from ui/chat:** RichChatInput is the composer; Message is the read-only render of the message after send. Use them together for a complete chat UX (RichChatInput at the bottom, MessageList above).
|
|
78
|
+
- **TipTap is bundled** — no need to install `@tiptap/*` directly.
|
|
79
|
+
- **For general rich text editing** (not chat — long-form docs, notes), use RichTextEditor instead.
|
|
80
|
+
- **isStreaming + onCancel** — when the receiving side is streaming a response, show a stop button in place of send. Standard AI chat pattern.
|
|
81
|
+
|
|
70
82
|
## Gotchas
|
|
71
83
|
- Tiptap is bundled — no need to install `@tiptap/*` packages separately
|
|
72
84
|
- Enter sends by default; use `enterBehavior="newline"` for long-form composition (Cmd/Ctrl+Enter always sends)
|
|
@@ -47,6 +47,15 @@ MentionItem: { id: string; label: string; avatar?: string }
|
|
|
47
47
|
<RichTextViewer content={savedHtml} />
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
## Composability
|
|
51
|
+
- **Two exports — editor + viewer.** RichTextEditor for composition; RichTextViewer for read-only rendering of saved HTML. Both share the same prose styling so round-trip display matches the editor.
|
|
52
|
+
- **TipTap v3 bundled** — no `@tiptap/*` install needed. Consumers can't mix in arbitrary TipTap extensions without forking.
|
|
53
|
+
- **Toolbar whitelist via `toolbar` prop:** Pass an array of ToolbarItem names to show only those buttons. Omit to show all. Dividers auto-collapse between empty groups.
|
|
54
|
+
- **Image upload:** Without `onImageUpload`, pasted/dropped images are inlined as base64 (HTML bloats fast). Provide the handler to upload and return a URL.
|
|
55
|
+
- **Mentions:** Static `mentions` array OR async `onMentionSearch` (which takes precedence). The viewer always renders mentions correctly from saved HTML — no mention props needed on the viewer side.
|
|
56
|
+
- **For chat composition specifically** (AI + team chat with streaming / slash commands), use RichChatInput — it's built on the same foundation but pre-configured for chat UX.
|
|
57
|
+
- **Pairs with MarkdownViewer** — many teams use RichTextEditor for compose (WYSIWYG), but render saved content as markdown for simpler serialization. Convert HTML ↔ markdown at the storage boundary.
|
|
58
|
+
|
|
50
59
|
## Gotchas
|
|
51
60
|
- Tiptap is bundled — no need to install `@tiptap/*` packages separately
|
|
52
61
|
- Emoji picker requires `@emoji-mart/react` + `@emoji-mart/data` peers
|
|
@@ -29,6 +29,14 @@ Event colors: "primary" | "success" | "warning" | "error" | "info" | "neutral"
|
|
|
29
29
|
/>
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
## Composability
|
|
33
|
+
- **Day / Week calendar view** for time-block display (meetings, shifts, availability). Not a full calendar app — no month view, no drag-to-create.
|
|
34
|
+
- **Event data is consumer-owned:** You pass `events` as an array; ScheduleView doesn't fetch, doesn't cache, doesn't expand recurring events. All scheduling logic lives in your app.
|
|
35
|
+
- **Event click + slot click** — `onEventClick` for existing events; `onSlotClick` for creating new events (fires with start/end of the empty slot).
|
|
36
|
+
- **Color vocabulary matches the DS** — `primary/success/warning/error/info/neutral`. Map your event types to these at the data layer.
|
|
37
|
+
- **endHour is exclusive:** `endHour=18` means the last visible slot starts at 17:30 (with 30min slots). Match your UX expectation: 9-5 typically means `startHour=9, endHour=18`.
|
|
38
|
+
- **Pairs with date-picker/composed** — use DatePicker or DateRangePicker to choose which date to show; pass that as ScheduleView's `date`.
|
|
39
|
+
|
|
32
40
|
## Gotchas
|
|
33
41
|
- `endHour` is exclusive — `endHour=18` means the last visible slot starts at 17:30 (with default 30min slots)
|
|
34
42
|
- `onSlotClick` fires when clicking an empty time slot — useful for creating new events
|
|
@@ -21,6 +21,13 @@
|
|
|
21
21
|
</SimpleTooltip>
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
## Composability
|
|
25
|
+
- **One-liner Tooltip** — wraps TooltipProvider + Tooltip + TooltipTrigger + TooltipContent so consumers don't have to manually compose them for a simple label.
|
|
26
|
+
- **When to use:** 90% of tooltip use cases (icon-only button labels, abbreviated text expansions, secondary info). Use the ui/Tooltip compound for advanced cases (controlled open, nested triggers, custom animations).
|
|
27
|
+
- **Auto-provides its own TooltipProvider** — safe to drop anywhere. You can still wrap a broader TooltipProvider at layout level for shared `delayDuration`; SimpleTooltip respects it if present.
|
|
28
|
+
- **Content must be inert** — same rule as ui/Tooltip. For interactive popped content, use Popover or HoverCard.
|
|
29
|
+
- **Pairs with IconButton** — the canonical pattern for labeled icon buttons.
|
|
30
|
+
|
|
24
31
|
## Gotchas
|
|
25
32
|
- Wraps the full Tooltip compound (Provider + Tooltip + Trigger + Content) into one component — no need for TooltipProvider
|
|
26
33
|
- Unlike the low-level Tooltip, SimpleTooltip does not require wrapping in a TooltipProvider
|
|
@@ -28,6 +28,16 @@ Note: StatusBadge was server-safe prior to v0.18.0 but is NO LONGER server-safe
|
|
|
28
28
|
<StatusBadge status="active" onClick={() => openStatusPicker()} />
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
## Composability
|
|
32
|
+
- **Semantic pill for workflow status.** Built on ui/Badge but with opinionated status → color mapping (active=success, pending=warning, rejected=error, etc.).
|
|
33
|
+
- **status vs color discriminated union:** Pass either `status` (auto-mapped color) or `color` (explicit). Don't pass both — `color` wins if you do.
|
|
34
|
+
- **Interactive mode:** Passing `onClick` renders as a `<button>` with a trailing chevron — common pattern for opening a status picker dropdown. Pair with a Popover or DropdownMenu for the status selector.
|
|
35
|
+
- **Pairs with DataTable, Card headers, activity feeds** — anywhere an inline status pill fits. Use `size="sm"` for dense rows.
|
|
36
|
+
- **StatusBadge vs ui/Badge vs StatusDot:**
|
|
37
|
+
- StatusBadge = workflow status pill with built-in status semantics
|
|
38
|
+
- ui/Badge = generic badge with full color/variant/shape control
|
|
39
|
+
- StatusDot = tiny presence indicator (no label pill)
|
|
40
|
+
|
|
31
41
|
## Gotchas
|
|
32
42
|
- When `color` is set, it takes priority over `status` for styling
|
|
33
43
|
- Props use a discriminated union — pass either `status` or `color`, not both
|
|
@@ -31,6 +31,14 @@ AppCommandPaletteUser: { name: string, role?: string }
|
|
|
31
31
|
/>
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
## Composability
|
|
35
|
+
- **Shell-level wrapper around composed/CommandPalette** — adds opinionated app conventions: user-aware admin command groups, search result integration, navigation dispatch.
|
|
36
|
+
- **Required setup:** Place inside `<CommandRegistryProvider>` (which owns the list of page items). Typically at app root next to TopBar.
|
|
37
|
+
- **Router integration via onNavigate:** Pass `(path) => router.push(path)` (Next.js) or equivalent for your framework. All page command clicks funnel through this callback.
|
|
38
|
+
- **Server-search integration:** Pass `onSearch` + `searchResults` + `onSearchResultSelect` for async search (API calls). `isSearching` drives a loading state. When these props are omitted, AppCommandPalette falls back to local filtering of registered pages.
|
|
39
|
+
- **Admin gating:** `isAdmin=true` surfaces `adminPages` from CommandRegistry. Takes precedence over `user.role`-based detection so you can force admin mode during testing / impersonation.
|
|
40
|
+
- **For scoped, non-app-wide palettes** (per-page command trees, custom popups), use composed/CommandPalette directly without the Registry layer.
|
|
41
|
+
|
|
34
42
|
## Gotchas
|
|
35
43
|
- Uses CommandRegistry context for page navigation items (see CommandRegistryProvider)
|
|
36
44
|
- `isAdmin` takes precedence over `user.role` for showing admin command groups
|
|
@@ -28,6 +28,18 @@ BottomNavbarUser: { name: string, role?: string }
|
|
|
28
28
|
/>
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
## Composability
|
|
32
|
+
- **Mobile-only bottom nav** — fixed to bottom of viewport. Desktop should use AppSidebar instead.
|
|
33
|
+
- **Responsive switch pattern:** Use `useIsMobile()` hook to conditionally render AppSidebar (desktop) or BottomNavbar (mobile). Example:
|
|
34
|
+
```jsx
|
|
35
|
+
const isMobile = useIsMobile()
|
|
36
|
+
return isMobile ? <BottomNavbar ... /> : <AppSidebar ... />
|
|
37
|
+
```
|
|
38
|
+
- **Primary vs overflow:** `primaryItems` (max 4) for the always-visible slots; `moreItems` go into a "More" sheet that opens on tap. Don't exceed 4 primary — the bar becomes cramped.
|
|
39
|
+
- **Router integration via LinkProvider:** Each nav item is rendered using the framework-specific Link component registered in LinkProvider. Without LinkProvider, you get full-page reloads on tap.
|
|
40
|
+
- **Badge numbers** cap at 99+ (same as BadgeIndicator pattern).
|
|
41
|
+
- **Not for desktop:** The viewport-fixed positioning + touch-optimized sizing don't translate well to desktop. Hide behind `md:hidden`.
|
|
42
|
+
|
|
31
43
|
## Gotchas
|
|
32
44
|
- Designed for mobile viewports — fixed to bottom of screen
|
|
33
45
|
- Max 4 `primaryItems` recommended; overflow goes in `moreItems` shown in a "More" sheet
|
|
@@ -38,6 +38,13 @@ CommandPageItem: { id: string, label: string, icon: ReactNode, path: string, key
|
|
|
38
38
|
</CommandRegistryProvider>
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
## Composability
|
|
42
|
+
- **Context provider for AppCommandPalette.** Registers page-level navigation items that the command palette surfaces as commands.
|
|
43
|
+
- **Place at app root** — wrap both AppCommandPalette and the rest of the app inside `<CommandRegistryProvider>`. Positioning matters: any AppCommandPalette outside the provider gets `useCommandRegistry() === null` and falls back to minimal functionality.
|
|
44
|
+
- **Separation of pages vs adminPages** — the palette filters based on user role / `isAdmin` flag. Keep admin-only routes in the adminPages array to avoid leaking them to regular users.
|
|
45
|
+
- **useCommandRegistry()** is the consumer hook — returns the full registry or null. Use in your own command-aware components (e.g. a Spotlight-style keyboard-search embed elsewhere in the app).
|
|
46
|
+
- **Works with LinkProvider** — CommandPaletteItems navigate via `onNavigate` prop on AppCommandPalette, which routes to your framework's Link component.
|
|
47
|
+
|
|
41
48
|
## Gotchas
|
|
42
49
|
- Provides the command registry context consumed by AppCommandPalette
|
|
43
50
|
- Place at app root, wrapping both AppCommandPalette and the rest of the app
|
|
@@ -28,6 +28,21 @@ import Link from 'next/link'
|
|
|
28
28
|
</LinkProvider>
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
## Composability
|
|
32
|
+
- **The framework router bridge for all shell components.** Without LinkProvider, AppSidebar / BottomNavbar / TopBar.UserMenu / AppCommandPalette render plain `<a>` tags — that means full page reloads instead of client-side navigation.
|
|
33
|
+
- **Required setup:**
|
|
34
|
+
```tsx
|
|
35
|
+
// Next.js
|
|
36
|
+
import Link from 'next/link'
|
|
37
|
+
<LinkProvider component={Link}>
|
|
38
|
+
<App />
|
|
39
|
+
</LinkProvider>
|
|
40
|
+
```
|
|
41
|
+
- **Place at app root** — above every shell component that renders nav links.
|
|
42
|
+
- **component must be forwardRef** (Next.js Link, Remix Link, react-router Link all qualify). Custom components need to forward ref + forward className + forward all anchor props.
|
|
43
|
+
- **Consumer components use `useLink()`** — returns the registered component or falls back to plain `<a>`. Your own components can consume this hook to integrate with the same router abstraction.
|
|
44
|
+
- **ui-category components don't consume LinkProvider** — they use `asChild` for router integration (e.g. `<Button asChild><NextLink ...>...</NextLink></Button>`). LinkProvider is shell-specific because shell components embed link arrays (can't use asChild per-item without breaking the data-driven API).
|
|
45
|
+
|
|
31
46
|
## Gotchas
|
|
32
47
|
- Without LinkProvider, shell components render plain `<a>` tags (full page reloads)
|
|
33
48
|
- Place at app root, wrapping all shell components that render navigation links
|
|
@@ -44,6 +44,16 @@ NotificationAction: { label: string, variant?: 'primary' | 'default' | 'danger',
|
|
|
44
44
|
/>
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
## Composability
|
|
48
|
+
- **Bell + Popover + notification list** — renders the bell button with unread count badge and a popover list on click.
|
|
49
|
+
- **Typical placement:** Inside `<TopBar.Right>` — common pattern is `<TopBar.IconButton>` for utility actions PLUS `<NotificationCenter>` for the bell.
|
|
50
|
+
- **No hardcoded routes** — `getNotificationRoute` is the consumer's routing decision. Return the correct path per notification type (task → `/tasks/:id`, comment → `/threads/:id`, etc.) or null for non-routable notifications.
|
|
51
|
+
- **onNavigate** fires when a notification with a route is clicked — wire to your router's push/navigate call.
|
|
52
|
+
- **Pagination:** Pass `hasMore` + `onFetchMore` for infinite-scroll of older notifications.
|
|
53
|
+
- **emptySlot + footerSlot + headerActions** are content slots for customization — keep the bell+popover shell, swap the inside.
|
|
54
|
+
- **Pairs with NotificationPreferences** (separate page component) for letting users configure which notification tiers/channels they want to receive.
|
|
55
|
+
- **onDismiss** is optional — when provided, per-notification X buttons appear. Otherwise mark-as-read is the only dismissal mechanism.
|
|
56
|
+
|
|
47
57
|
## Gotchas
|
|
48
58
|
- Typically rendered inside TopBar's `notificationSlot` prop
|
|
49
59
|
- `getNotificationRoute` must be provided for clickable notifications — no hardcoded routes
|
|
@@ -32,6 +32,13 @@ NotificationProject: { id: string, title: string }
|
|
|
32
32
|
/>
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
## Composability
|
|
36
|
+
- **Full-page preferences UI** — typically rendered on a settings page (`/settings/notifications`). Not an overlay; not a dropdown.
|
|
37
|
+
- **Per-project preferences** — each preference is tied to a project + channel + tier. Users can mute/unmute and adjust tier (INFO / IMPORTANT / CRITICAL threshold) per project-channel combo.
|
|
38
|
+
- **All callback props support Promise<void>** — integrate with server actions / fetch calls without manual loading state management.
|
|
39
|
+
- **Pairs with NotificationCenter** — NotificationCenter shows notifications in real time (driven by these preferences); NotificationPreferences lets users tune the rules.
|
|
40
|
+
- **Data ownership is consumer-side** — you pass `preferences` + `projects`; NotificationPreferences renders. No built-in persistence or sync.
|
|
41
|
+
|
|
35
42
|
## Gotchas
|
|
36
43
|
- Manages per-project notification preferences (channel, tier, mute)
|
|
37
44
|
- All callback props support async (Promise<void>) for server-side operations
|
|
@@ -48,6 +48,17 @@ SidebarPromo: { text: string, icon?: ReactNode, action?: { label: string, href?:
|
|
|
48
48
|
/>
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
## Composability
|
|
52
|
+
- **Opinionated app sidebar** — data-driven via `navGroups`, with user profile header, navigation groups (with optional labels + group actions), and a configurable footer (links + version + optional promo banner).
|
|
53
|
+
- **Required setup (three providers):**
|
|
54
|
+
- `SidebarProvider` (from ui/sidebar) — owns expanded/collapsed state + cookie persistence
|
|
55
|
+
- `LinkProvider` — framework router integration for nav item links
|
|
56
|
+
- `CommandRegistryProvider` (if pairing with AppCommandPalette) — registers the same navGroups so keyboard search finds them
|
|
57
|
+
- **renderItem escape hatch:** Custom per-item rendering (e.g. custom icons per item type, status decorations, hover previews). Return `null` to fall back to default.
|
|
58
|
+
- **Nested navigation:** NavItem's `children: NavSubItem[]` renders a collapsible subsection. Auto-opens if a child matches the current path.
|
|
59
|
+
- **Footer as slot:** `footer` can include links, version info, a ReactNode slot (e.g. theme toggle), and a dismissable promo banner — structure it once, compose.
|
|
60
|
+
- **Pairs with TopBar + BottomNavbar:** Desktop layout = AppSidebar + TopBar. Mobile layout = hide AppSidebar, show BottomNavbar.
|
|
61
|
+
|
|
51
62
|
## Gotchas
|
|
52
63
|
- Must be wrapped in SidebarProvider (from ui/sidebar)
|
|
53
64
|
- Requires LinkProvider for framework-specific link components
|
|
@@ -111,6 +111,17 @@ UserMenuItem fields:
|
|
|
111
111
|
</TopBar>
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
+
## Composability
|
|
115
|
+
- **Composition-based, NOT data-driven.** Use dot-notation subcomponents (`TopBar.Left`, `TopBar.Center`, `TopBar.Right`, `TopBar.Section`, `TopBar.IconButton`, `TopBar.Title`, `TopBar.UserMenu`) to assemble. No "props config" — explicit JSX.
|
|
116
|
+
- **Two-zone vs three-zone layout** — adding `TopBar.Center` flips the root from `flex` to CSS grid (`1fr auto 1fr`) for true centering. Standard apps are two-zone (Left + Right); dashboards with prominent search are three-zone.
|
|
117
|
+
- **Required providers:**
|
|
118
|
+
- `SidebarProvider` — for SidebarTrigger inside `TopBar.Left` to work
|
|
119
|
+
- `LinkProvider` — for TopBar.UserMenu's menu items that use `href`
|
|
120
|
+
- **NotificationCenter lives inside TopBar.Right** — it's a complete bell+popover component. Drop it in a TopBar.Section next to other icon buttons.
|
|
121
|
+
- **UserMenu is composable:** `userMenuItems` inserts custom items between the built-in Profile and the color-mode toggle. Each item can navigate (href), run an action (onClick), or show a separator/badge/color decoration.
|
|
122
|
+
- **Responsive hiding:** Actions that shouldn't appear on mobile use `className="hidden md:flex"` on the IconButton — the component doesn't enforce mobile hiding; that's layout responsibility.
|
|
123
|
+
- **Pairs with AppSidebar** — desktop app shell is typically `<TopBar>` + `<AppSidebar>` + main content region.
|
|
124
|
+
|
|
114
125
|
## Gotchas
|
|
115
126
|
- Without `TopBar.Center`, layout is flex (two-zone). With it, layout switches to CSS grid `1fr auto 1fr` for true centering.
|
|
116
127
|
- `TopBar.IconButton` renders any number of action buttons — no artificial limit. Use responsive hiding (`className="hidden md:flex"`) for mobile.
|
|
@@ -30,9 +30,19 @@
|
|
|
30
30
|
</Accordion>
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
## Composability
|
|
34
|
+
- Built on Radix Accordion — accepts `value`/`defaultValue`/`onValueChange` matching the `type` discriminated union.
|
|
35
|
+
- **`type="single"`** — value is a string (which item is open). Only one item open at a time. Pair with `collapsible` to allow closing the current item by re-clicking it.
|
|
36
|
+
- **`type="multiple"`** — value is a string[] (which items are open). Multiple can be open at once.
|
|
37
|
+
- **AccordionTrigger chevron:** Inline SVG that auto-rotates via the `data-state` attribute Radix sets (`open` / `closed`). The `chevronPosition` prop controls render order inside the trigger (left / right) — rotation still works from either position.
|
|
38
|
+
- **AccordionContent:** Uses Radix CSS custom properties (`--radix-accordion-content-height`) for open/close height animation. Framer Motion handles the fade. Don't wrap AccordionContent children in additional motion components — doubles the animation.
|
|
39
|
+
- **Inline, not portalled** — parent `overflow: hidden` WILL clip an open accordion. Keep accordions out of tight overflow contexts or use `overflow-visible` on the container.
|
|
40
|
+
|
|
33
41
|
## Gotchas
|
|
34
42
|
- type is REQUIRED — omitting it causes runtime error
|
|
35
43
|
- collapsible only works with type="single"
|
|
44
|
+
- Each AccordionItem needs a unique `value` — duplicates silently break toggling
|
|
45
|
+
- Don't put focusable elements inside AccordionTrigger — the trigger IS the focusable button, nested focusables break screen reader navigation
|
|
36
46
|
|
|
37
47
|
## Changes
|
|
38
48
|
### v0.29.0
|
|
@@ -42,8 +42,17 @@
|
|
|
42
42
|
</AlertDialog>
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
## Composability
|
|
46
|
+
- Built on Radix AlertDialog — like Dialog but **non-dismissible** by clicking outside or pressing Escape. The user must choose Cancel or Action.
|
|
47
|
+
- Same portal + trigger + asChild pattern as Dialog.
|
|
48
|
+
- `AlertDialogAction` and `AlertDialogCancel` are semantically distinct from generic buttons: they auto-close the dialog on click. Use them even if you wrap them around a styled Button via `asChild` so the close behavior stays wired.
|
|
49
|
+
- **Focus management:** Initial focus lands on `AlertDialogCancel` (the safe default) — destructive confirmation is always one tab away.
|
|
50
|
+
- Use AlertDialog for destructive / irreversible actions; use Dialog for everything else.
|
|
51
|
+
|
|
45
52
|
## Gotchas
|
|
46
|
-
- AlertDialogAction does NOT have color="error" styling — add it yourself via className or wrap a Button
|
|
53
|
+
- AlertDialogAction does NOT have color="error" styling — add it yourself via className or wrap a Button with `asChild`
|
|
54
|
+
- Do NOT add a close-on-outside-click handler — the non-dismissible behavior is the whole point
|
|
55
|
+
- AlertDialogCancel receives initial focus; don't flip the convention
|
|
47
56
|
|
|
48
57
|
## Changes
|
|
49
58
|
### v0.19.1
|
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
- Category: ui
|
|
6
6
|
|
|
7
7
|
## Props
|
|
8
|
-
variant: "subtle" | "
|
|
8
|
+
variant: "subtle" | "solid" | "outline"
|
|
9
9
|
color: "info" | "success" | "warning" | "error" | "neutral"
|
|
10
|
+
size: "sm" | "md" | "lg"
|
|
10
11
|
title: string (optional)
|
|
11
12
|
onDismiss: () => void (optional, shows X button when provided)
|
|
12
13
|
children: ReactNode (body text)
|
|
13
14
|
|
|
14
15
|
## Defaults
|
|
15
|
-
variant="subtle", color="info"
|
|
16
|
+
variant="subtle", color="info", size="md"
|
|
16
17
|
|
|
17
18
|
## Example
|
|
18
19
|
```jsx
|
|
@@ -21,6 +22,13 @@
|
|
|
21
22
|
</Alert>
|
|
22
23
|
```
|
|
23
24
|
|
|
25
|
+
## Composability
|
|
26
|
+
- **Flat, not compound** — unlike Dialog/Card, there's no `<AlertTitle>` / `<AlertDescription>`. Use the `title` prop for the heading and `children` for the body text. This simplifies the API and prevents composition traps (missing title, out-of-order header parts).
|
|
27
|
+
- **Auto-icon by color:** Icon is selected automatically from color (info→circle, success→check, warning→triangle, error→alert). Pass a custom `icon` prop to override.
|
|
28
|
+
- **Role=alert:** Announces assertively to screen readers. Don't stack multiple Alerts in a row — the last one wins.
|
|
29
|
+
- **Dismissal pattern:** Pass `onDismiss` for user-dismissable alerts; the library tracks the exit animation before calling back. For persistent alerts (system state), omit `onDismiss`.
|
|
30
|
+
- **Not for transient messages** — use Toast for transient/time-limited notifications and Banner for page-level announcements. Alert is inline, in-flow, block-level.
|
|
31
|
+
|
|
24
32
|
## Gotchas
|
|
25
33
|
- NOT a compound component — use title prop, NOT <AlertTitle>
|
|
26
34
|
- DO NOT use variant="destructive" — use color="error"
|
|
@@ -28,6 +36,9 @@
|
|
|
28
36
|
- Icon is auto-selected by color (info=circle, success=check, warning=triangle, error=alert)
|
|
29
37
|
|
|
30
38
|
## Changes
|
|
39
|
+
### v0.38.0
|
|
40
|
+
- **Removed** (BREAKING) `variant="filled"` deprecated alias. Use `variant="solid"`.
|
|
41
|
+
|
|
31
42
|
### v0.31.0
|
|
32
43
|
- **Added** `size` prop: `sm | md | lg`. Default `md` (non-breaking).
|
|
33
44
|
|
|
@@ -17,8 +17,15 @@
|
|
|
17
17
|
</AspectRatio>
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
## Composability
|
|
21
|
+
- Radix AspectRatio primitive — pure layout wrapper, no context, no cascade.
|
|
22
|
+
- **Child fill pattern:** Its child is absolutely positioned to fill. Pair with `object-cover` / `object-contain` on `<img>`/`<video>` and `w-full h-full` for anything else.
|
|
23
|
+
- Useful as a responsive-image container, a chart area (pair with Chart components), or a placeholder frame for media skeletons.
|
|
24
|
+
- Works inside Card, any layout component, or flex/grid containers — nothing to configure.
|
|
25
|
+
|
|
20
26
|
## Gotchas
|
|
21
27
|
- ratio is a number, not a string — use `16/9` not `"16/9"`
|
|
28
|
+
- The child must be size-fluid (`w-full h-full` or absolutely positioned) — elements with intrinsic size escape the aspect-ratio box
|
|
22
29
|
|
|
23
30
|
## Changes
|
|
24
31
|
### v0.1.0
|
|
@@ -27,6 +27,13 @@
|
|
|
27
27
|
/>
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
## Composability
|
|
31
|
+
- **Autocomplete vs Combobox:** Autocomplete allows free-text input (users can type anything); Combobox enforces selection from the list. Pick by whether "off-list" values are valid (e.g. city field that accepts typos → Autocomplete; tag picker from a fixed vocabulary → Combobox).
|
|
32
|
+
- **Value shape is an object** (`{ value, label }`), not a plain string — this preserves label/value decoupling for display-vs-storage.
|
|
33
|
+
- **FormField:** Does NOT auto-consume FormField state. Set explicit error styling via className if needed.
|
|
34
|
+
- **Portal rendering:** Dropdown portals to body with z-popover (1400) — stacks above Dialog/Sheet.
|
|
35
|
+
- **Keyboard:** ArrowDown/Up navigate suggestions, Enter selects, Esc closes. Typeahead is the input's native filtering.
|
|
36
|
+
|
|
30
37
|
## Gotchas
|
|
31
38
|
- Allows free-text input (no forced selection) — use Combobox for forced selection
|
|
32
39
|
- value is an object { value, label }, NOT just a string
|
|
@@ -31,10 +31,20 @@
|
|
|
31
31
|
</Avatar>
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
## Composability
|
|
35
|
+
- **Two internal contexts cascade to AvatarFallback:**
|
|
36
|
+
- `AvatarSizeContext` — carries the Avatar's `size` so AvatarFallback's font size scales without re-specifying (xs → `text-[9px]`, sm → `text-ds-xs`, md → `text-ds-sm`, lg → `text-ds-md`, xl → `text-ds-lg`)
|
|
37
|
+
- `AvatarShapeContext` — carries `shape` so AvatarFallback inherits the same border-radius (critical for `shape="square"` / `shape="rounded"` — without context the fallback would always be `rounded-ds-full` regardless of parent)
|
|
38
|
+
- **Status + Ring + Badge are independent** — you can stack all three on one Avatar. They render in separate layers so they don't conflict visually.
|
|
39
|
+
- **Use with AvatarGroup:** AvatarGroup applies its own `size` to children. If your Avatar has an explicit `size`, it overrides AvatarGroup's default — keep it consistent across the group.
|
|
40
|
+
- **AvatarFallback colorSeed:** Deterministic background color from the seed string — identical user IDs produce identical backgrounds across renders. Useful for user-identifying avatars without photos.
|
|
41
|
+
- **Ring offset color:** The ring renders with `ring-offset` matching the current surface — it assumes the Avatar sits on `bg-surface-raised`. On other backgrounds, add a ring-offset className to compensate.
|
|
42
|
+
|
|
34
43
|
## Gotchas
|
|
35
44
|
- Status dot renders with role="img" and aria-label (accessible, not decorative)
|
|
36
45
|
- Dot size scales automatically with avatar size
|
|
37
46
|
- AvatarFallback font size scales automatically with avatar size (via AvatarSizeContext)
|
|
47
|
+
- AvatarFallback shape inherits from Avatar (via AvatarShapeContext) — setting `rounded-*` on AvatarFallback directly conflicts with the context
|
|
38
48
|
- Ring offset color matches the surface context — ensure it sits on the expected background
|
|
39
49
|
- Badge is hidden when value is `0` (falsy); use `"dot"` for presence without a count
|
|
40
50
|
- Online status dot pulses with a CSS animation
|
|
@@ -27,6 +27,13 @@
|
|
|
27
27
|
{/* Renders: React, TypeScript, Tailwind, +2 */}
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
## Composability
|
|
31
|
+
- **Wrapper for Badge children** — doesn't style children, just lays them out and optionally collapses overflow into a "+N" indicator.
|
|
32
|
+
- **Server-safe** — can render in RSC trees (children still need to be server-safe themselves).
|
|
33
|
+
- **Overflow indicator is a Badge** — picks `variant="outline" color="neutral"` and the `size` prop on BadgeGroup. Child badges keep their own variant/color/size.
|
|
34
|
+
- **Click-to-reveal pattern:** Pair `onOverflowClick` with a Popover / Sheet / Dialog that shows the full list. Without the handler, the overflow badge is inert (decorative count).
|
|
35
|
+
- Doesn't accept arbitrary children — only Badges. Non-Badge children render but may look off (no gap rhythm matching).
|
|
36
|
+
|
|
30
37
|
## Gotchas
|
|
31
38
|
- Overflow badge is always `variant="outline" color="neutral"`
|
|
32
39
|
- `size` only applies to the overflow badge — child badges keep their own size
|
|
@@ -29,6 +29,13 @@
|
|
|
29
29
|
</Badge.Indicator>
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
## Composability
|
|
33
|
+
- **Overlay wrapper** — takes any child and overlays a positioned count/dot at the specified corner. The child must be inline-friendly (anything that renders in a span-wrapped position: relative context).
|
|
34
|
+
- **Common pairings:** IconButton (notification bell with count), Avatar (online presence dot), Button (cart with item count), tabs (unread indicator).
|
|
35
|
+
- **Invisible for layout stability:** Use `invisible={true}` to keep the child's position consistent when the badge should disappear — avoids layout shift as counts appear/disappear.
|
|
36
|
+
- **showZero vs hide-on-zero:** By default `count={0}` hides the indicator. Set `showZero={true}` for use cases where "zero" is meaningful (scores, pending items that should display 0 explicitly).
|
|
37
|
+
- **Dot vs count:** `dot={true}` is a presence-only pulse indicator (online, new activity); count is a numeric badge. They're mutually exclusive — setting both uses dot.
|
|
38
|
+
|
|
32
39
|
## Gotchas
|
|
33
40
|
- Wraps children in `position: relative` span — the indicator is absolutely positioned
|
|
34
41
|
- Animation uses spring physics, respects `prefers-reduced-motion`
|
|
@@ -36,6 +36,18 @@
|
|
|
36
36
|
<Badge color="custom" style={{ '--badge-color': '#8b5cf6' }}>Custom</Badge>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
## Composability
|
|
40
|
+
- **Badge.Group** (BadgeGroup) wraps a set of badges with overflow collapse (`max` + "+N" indicator) and gap control. Use it for filter chips, tag lists, user cluster avatars-equivalent.
|
|
41
|
+
- **Badge.Indicator** (BadgeIndicator) attaches a count / dot overlay to ANY child (icons, avatars, buttons). It's positioning-only — doesn't style the child.
|
|
42
|
+
- **Interactive modes:**
|
|
43
|
+
- `onClick` alone → renders as `<button>` (standard interactive badge)
|
|
44
|
+
- `onDismiss` alone → renders as `<span>` with an inner X button
|
|
45
|
+
- Both → renders as `<div role="button">` (avoids invalid nested buttons) — the X button inside handles its own click isolation
|
|
46
|
+
- **asChild:** Use with router Links for nav-style badges (`<Badge asChild><Link href="/tags/react">React</Link></Badge>`).
|
|
47
|
+
- **Custom colors via CSS variables:** Set `color="custom"` + inline style `style={{ '--badge-color': '#...' }}`. For solid variant, also set `--badge-fg-color` for the foreground.
|
|
48
|
+
- **Icon slots auto-size via IconProvider** — same cascade as Button. Don't set explicit size on nested `<Icon>`.
|
|
49
|
+
- **Chip (deprecated)** was merged into Badge — use Badge with `onClick` and `selected` for the old Chip use case.
|
|
50
|
+
|
|
39
51
|
## Gotchas
|
|
40
52
|
- DO NOT use variant="destructive" — use variant="solid" color="error"
|
|
41
53
|
- Badge is now interactive when `onClick` is provided (renders as `<button>`)
|