@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.
Files changed (127) hide show
  1. package/dist/composed/inline-edit.d.ts.map +1 -1
  2. package/dist/composed/inline-edit.js +42 -40
  3. package/dist/composed/inline-edit.js.map +1 -1
  4. package/dist/test-utils/conformance.d.ts +37 -0
  5. package/dist/test-utils/conformance.d.ts.map +1 -0
  6. package/docs/components/composed/activity-feed.md +6 -0
  7. package/docs/components/composed/avatar-group.md +8 -0
  8. package/docs/components/composed/bulk-action-bar.md +6 -0
  9. package/docs/components/composed/command-palette.md +7 -0
  10. package/docs/components/composed/confirm-dialog.md +6 -0
  11. package/docs/components/composed/content-card.md +6 -0
  12. package/docs/components/composed/date-picker.md +10 -0
  13. package/docs/components/composed/deadline-indicator.md +7 -0
  14. package/docs/components/composed/emoji-picker.md +8 -0
  15. package/docs/components/composed/empty-state.md +8 -0
  16. package/docs/components/composed/error-boundary.md +7 -0
  17. package/docs/components/composed/file-preview.md +8 -0
  18. package/docs/components/composed/filter-bar.md +8 -0
  19. package/docs/components/composed/form-section.md +6 -0
  20. package/docs/components/composed/global-loading.md +6 -0
  21. package/docs/components/composed/inline-edit.md +8 -0
  22. package/docs/components/composed/loading-skeleton.md +7 -0
  23. package/docs/components/composed/markdown-viewer.md +9 -0
  24. package/docs/components/composed/master-detail.md +7 -0
  25. package/docs/components/composed/member-picker.md +7 -0
  26. package/docs/components/composed/multi-select-popover.md +11 -0
  27. package/docs/components/composed/page-header.md +7 -0
  28. package/docs/components/composed/page-skeletons.md +10 -0
  29. package/docs/components/composed/priority-indicator.md +7 -0
  30. package/docs/components/composed/responsive-overlay.md +7 -0
  31. package/docs/components/composed/rich-chat-input.md +12 -0
  32. package/docs/components/composed/rich-text-editor.md +9 -0
  33. package/docs/components/composed/schedule-view.md +8 -0
  34. package/docs/components/composed/simple-tooltip.md +7 -0
  35. package/docs/components/composed/status-badge.md +10 -0
  36. package/docs/components/shell/app-command-palette.md +8 -0
  37. package/docs/components/shell/bottom-navbar.md +12 -0
  38. package/docs/components/shell/command-registry.md +7 -0
  39. package/docs/components/shell/link-context.md +15 -0
  40. package/docs/components/shell/notification-center.md +10 -0
  41. package/docs/components/shell/notification-preferences.md +7 -0
  42. package/docs/components/shell/sidebar.md +11 -0
  43. package/docs/components/shell/top-bar.md +11 -0
  44. package/docs/components/ui/accordion.md +10 -0
  45. package/docs/components/ui/alert-dialog.md +10 -1
  46. package/docs/components/ui/alert.md +10 -2
  47. package/docs/components/ui/aspect-ratio.md +7 -0
  48. package/docs/components/ui/autocomplete.md +7 -0
  49. package/docs/components/ui/avatar.md +10 -0
  50. package/docs/components/ui/badge-group.md +7 -0
  51. package/docs/components/ui/badge-indicator.md +7 -0
  52. package/docs/components/ui/badge.md +12 -0
  53. package/docs/components/ui/banner.md +7 -0
  54. package/docs/components/ui/breadcrumb.md +8 -0
  55. package/docs/components/ui/button-group.md +24 -4
  56. package/docs/components/ui/button-processing.md +5 -0
  57. package/docs/components/ui/button.md +9 -0
  58. package/docs/components/ui/card.md +16 -4
  59. package/docs/components/ui/charts.md +9 -0
  60. package/docs/components/ui/chat.md +9 -0
  61. package/docs/components/ui/checkbox.md +15 -1
  62. package/docs/components/ui/chip.md +9 -0
  63. package/docs/components/ui/code.md +7 -0
  64. package/docs/components/ui/collapsible.md +9 -0
  65. package/docs/components/ui/color-input.md +8 -0
  66. package/docs/components/ui/color-swatch.md +7 -0
  67. package/docs/components/ui/combobox.md +16 -3
  68. package/docs/components/ui/container.md +11 -0
  69. package/docs/components/ui/context-menu.md +8 -0
  70. package/docs/components/ui/data-table-body.md +4 -0
  71. package/docs/components/ui/data-table-bulk-actions.md +4 -0
  72. package/docs/components/ui/data-table-card.md +4 -0
  73. package/docs/components/ui/data-table-context.md +4 -0
  74. package/docs/components/ui/data-table-header.md +4 -0
  75. package/docs/components/ui/data-table-pagination.md +4 -0
  76. package/docs/components/ui/data-table-toolbar.md +7 -0
  77. package/docs/components/ui/data-table.md +25 -0
  78. package/docs/components/ui/devalok-grain.md +8 -0
  79. package/docs/components/ui/dialog.md +10 -0
  80. package/docs/components/ui/dropdown-menu.md +10 -0
  81. package/docs/components/ui/file-upload.md +8 -0
  82. package/docs/components/ui/form.md +21 -0
  83. package/docs/components/ui/hover-card.md +9 -0
  84. package/docs/components/ui/icon-button.md +7 -0
  85. package/docs/components/ui/icon-context.md +7 -0
  86. package/docs/components/ui/icon-group.md +9 -0
  87. package/docs/components/ui/icon.md +7 -0
  88. package/docs/components/ui/input-otp.md +29 -7
  89. package/docs/components/ui/input.md +7 -0
  90. package/docs/components/ui/label.md +7 -1
  91. package/docs/components/ui/link.md +7 -0
  92. package/docs/components/ui/menubar.md +9 -0
  93. package/docs/components/ui/navigation-menu.md +9 -0
  94. package/docs/components/ui/number-input.md +10 -0
  95. package/docs/components/ui/pagination.md +10 -0
  96. package/docs/components/ui/popover.md +9 -0
  97. package/docs/components/ui/progress-ring.md +7 -0
  98. package/docs/components/ui/progress.md +7 -0
  99. package/docs/components/ui/radio.md +27 -2
  100. package/docs/components/ui/search-input.md +8 -0
  101. package/docs/components/ui/segmented-control.md +8 -0
  102. package/docs/components/ui/select.md +14 -3
  103. package/docs/components/ui/separator.md +7 -0
  104. package/docs/components/ui/sheet.md +10 -0
  105. package/docs/components/ui/sidebar.md +30 -0
  106. package/docs/components/ui/skeleton.md +7 -0
  107. package/docs/components/ui/slider.md +15 -1
  108. package/docs/components/ui/spinner.md +7 -0
  109. package/docs/components/ui/split-button.md +11 -0
  110. package/docs/components/ui/stack.md +8 -0
  111. package/docs/components/ui/stat-card.md +9 -0
  112. package/docs/components/ui/status-dot.md +9 -0
  113. package/docs/components/ui/stepper.md +8 -0
  114. package/docs/components/ui/switch.md +8 -0
  115. package/docs/components/ui/table.md +8 -0
  116. package/docs/components/ui/tabs.md +10 -2
  117. package/docs/components/ui/text.md +9 -4
  118. package/docs/components/ui/textarea.md +7 -1
  119. package/docs/components/ui/toast.md +9 -0
  120. package/docs/components/ui/toaster.md +8 -0
  121. package/docs/components/ui/toggle-group.md +13 -4
  122. package/docs/components/ui/toggle.md +10 -2
  123. package/docs/components/ui/tooltip.md +11 -1
  124. package/docs/components/ui/tree-view.md +12 -0
  125. package/docs/components/ui/visually-hidden.md +7 -0
  126. package/llms-full.txt +1116 -44
  127. package/package.json +1 -1
@@ -28,6 +28,13 @@
28
28
  </ResponsiveOverlay>
29
29
  ```
30
30
 
31
+ ## Composability
32
+ - **One component, two containers.** Above `breakpoint`: centered Dialog. Below: bottom-anchored Sheet. Same content slot, different surface treatment per viewport.
33
+ - **Standard controlled model** — `open` + `onOpenChange` (same shape as Dialog/Sheet).
34
+ - **title + description pattern** — matches Dialog/Sheet's requirement for an accessible heading. Omit both only when the surrounding context makes the purpose obvious (rare).
35
+ - **SSR caveat:** `window.matchMedia` reads on mount — initial SSR render defaults to desktop (Dialog). Hydration flips to Sheet on mobile. Acceptable for most flows; visible layout shift on low-spec devices.
36
+ - **When to use:** Any modal that needs to behave differently on mobile (edit dialogs, filter panels, quick-action menus). For always-the-same behavior, use Dialog or Sheet directly.
37
+
31
38
  ## Gotchas
32
39
  - Renders a centered Dialog on desktop and a bottom Sheet on mobile — same content, different container
33
40
  - Uses `window.matchMedia` internally — SSR defaults to desktop (Dialog) until hydration
@@ -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" | "filled" | "outline"
8
+ variant: "subtle" | "solid" | "outline" | "filled" (deprecated alias for "solid")
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"
@@ -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>`)
@@ -21,6 +21,13 @@
21
21
  </Banner>
22
22
  ```
23
23
 
24
+ ## Composability
25
+ - **Banner vs Alert vs Toast:** Banner is full-width, top-of-page / top-of-region announcements (maintenance, quota, trial-expiring). Alert is inline in-flow. Toast is transient floating notifications. Pick by where the message lives in the visual hierarchy.
26
+ - **actions slot:** Pass one or more `<Button>` elements — the container flex-wraps on narrow viewports so actions drop below the message rather than squeezing horizontally.
27
+ - **Role=alert** announces assertively. Same constraint as Alert — don't stack multiple Banners.
28
+ - **Dismissal timing:** `onDismiss` fires AFTER the exit animation completes, not on click. Use it to remove the banner from state only after it's visually gone.
29
+ - Works inside Shell layouts (TopBar / Sidebar / main content) — usually sits above main content, below the TopBar.
30
+
24
31
  ## Gotchas
25
32
  - Banner is full-width (spans container). Alert is inline.
26
33
  - Renders role="alert" automatically
@@ -26,8 +26,16 @@
26
26
  </Breadcrumb>
27
27
  ```
28
28
 
29
+ ## Composability
30
+ - **Compound structure only** — no context cascade, each part is standalone. The semantic shape (`<nav>` → `<ol>` → `<li>`) is what matters for a11y, not any internal state.
31
+ - **BreadcrumbLink vs BreadcrumbPage:** Use BreadcrumbLink for everything except the current page; BreadcrumbPage for the current page (not clickable, renders without href, announced as "current page" via aria-current).
32
+ - **Router integration:** Use `<BreadcrumbLink asChild><NextLink href="/x">...</NextLink></BreadcrumbLink>` (Radix Slot pattern).
33
+ - **Truncation:** For long paths, use BreadcrumbEllipsis between the first and last items instead of showing all. Pair with a DropdownMenu (open the ellipsis to show hidden intermediate items) if you need to expose them.
34
+ - **PageHeader (composed) auto-builds Breadcrumb** from its `breadcrumbs` prop — use that higher-level component for page-top breadcrumbs and save this component for inline or custom positioning.
35
+
29
36
  ## Gotchas
30
37
  - Use BreadcrumbPage for the current (non-clickable) page, BreadcrumbLink for navigable items
38
+ - Don't wrap BreadcrumbPage in a link — it's the current location by definition
31
39
 
32
40
  ## Changes
33
41
  ### v0.18.0
@@ -5,24 +5,44 @@
5
5
  - Category: ui
6
6
 
7
7
  ## Props
8
- variant: ButtonProps['variant'] (propagated to children)
8
+ variant: ButtonProps['variant'] (propagated to children via context)
9
9
  color: ButtonProps['color'] (propagated to children)
10
10
  size: ButtonProps['size'] (propagated to children)
11
- orientation: "horizontal" | "vertical" (default: "horizontal")
11
+ weight: ButtonProps['weight'] (propagated to children)
12
+ shape: ButtonProps['shape'] (propagated to children)
13
+ disabled: boolean (propagates to all children)
14
+ orientation: "horizontal" | "vertical"
15
+ attached: boolean (true = buttons visually merge with shared borders; false = spaced apart via gap)
16
+ fullWidth: boolean (group stretches to parent width; children stretch equally)
12
17
 
13
18
  ## Defaults
14
- orientation="horizontal"
19
+ orientation="horizontal", attached=true
15
20
 
16
21
  ## Example
17
22
  ```jsx
18
23
  <ButtonGroup variant="outline" size="sm">
19
24
  <Button>Bold</Button>
20
25
  <Button>Italic</Button>
26
+ <Button>Underline</Button>
27
+ </ButtonGroup>
28
+
29
+ {/* Spaced, not attached */}
30
+ <ButtonGroup attached={false} variant="soft">
31
+ <Button>Save</Button>
32
+ <Button>Cancel</Button>
21
33
  </ButtonGroup>
22
34
  ```
23
35
 
36
+ ## Composability
37
+ - Every Button child reads variant/color/size/weight/shape/disabled from ButtonGroup context. Explicit props on individual children override context.
38
+ - **Position-aware border radius:** Child Buttons read their position in the group (first / middle / last) and apply appropriate corner radii inline. Works for both horizontal and vertical orientations.
39
+ - **Focus z-index isolation:** The focused button rises above its siblings so the focus ring isn't clipped by adjacent borders.
40
+ - **Tonal dividers:** For solid/soft/ghost variants without visible borders, ButtonGroup injects subtle divider elements between children.
41
+ - **Works with SplitButton:** `<SplitButton>` inside a `<ButtonGroup>` inherits the same context and position rules.
42
+
24
43
  ## Gotchas
25
- - Children can override variant/size individually
44
+ - Children can override variant/size individually — context is a default, not a lock
45
+ - `attached={false}` disables the position-aware border radius (children use their default corners)
26
46
 
27
47
  ## Changes
28
48
  ### v0.33.0
@@ -10,6 +10,11 @@ Internal component that renders the processing animation overlay for Button. Con
10
10
 
11
11
  See `Button` docs for the public API.
12
12
 
13
+ ## Composability
14
+ - **Internal only — do NOT import or use directly.** The Button component owns the lifecycle of this overlay.
15
+ - Drives Button's `processing` prop rendering. If you're building a custom button and want similar marching-ants feedback, copy the SVG/animation pattern — don't reach into this component.
16
+ - Listed here for reference so consumers grep'ing for "processing" find the behavior origin.
17
+
13
18
  ## Changes
14
19
  ### v0.29.0
15
20
  - **Added** Initial release — marching ants processing overlay (SVG dashed rect with animated stroke-dashoffset). Speed tiers: ambient (3s), working (2s), urgent (1s). Color maps to step-11 tokens for visibility on all variants.
@@ -34,6 +34,15 @@
34
34
  <Button variant="soft" color="warning" size="compact-sm" shape="pill">Overdue</Button>
35
35
  ```
36
36
 
37
+ ## Composability
38
+ - **ButtonGroup context consumption:** When nested inside `<ButtonGroup>`, Button auto-inherits variant/color/size/weight/shape/disabled. Explicit props on the individual Button override. The context also drives position-aware border-radius (first/middle/last within an attached group).
39
+ - **IconProvider cascade:** Icons in `startIcon`/`endIcon` auto-size via IconProvider per the button size (xs→sm, sm→sm, md→md, lg→md, icon-xs→xs, icon-lg→lg). Don't pass explicit `size` to `<Icon>` inside Button.
40
+ - **asChild for router links:** `<Button asChild><Link href="/foo">...</Link></Button>` transfers Button's styling to the Link while preserving navigation semantics. Required for Next.js `<Link>` / react-router `<Link>`.
41
+ - **onClickAsync state machine:** Overrides onClick. Auto-cycles `idle → loading (aria-busy, spinner) → success (checkmark) → idle` on resolve; `loading → error (X mark) → idle` on reject. Duration controlled by `asyncFeedbackDuration` (1500ms default). Auto-activates `processing='working'` during loading — marching-ants border keeps users visually aware.
42
+ - **Processing vs loading:** `loading` is a short async state (shows spinner, blocks clicks). `processing` is a longer-running state (marching ants border, may or may not block clicks based on `processingDisabled`). Use onClickAsync for simple request cases; use processing explicitly for long-running background operations.
43
+ - **DevalokGrain children:** Grain elements are auto-extracted and rendered as direct button children for absolute positioning — lets you layer grain texture on solid-variant buttons without breaking layout.
44
+ - **Prefer `variant="soft"` over `variant="outline"` for secondary actions** (see Gotchas for details). This is a design-system-wide convention.
45
+
37
46
  ## Gotchas
38
47
  - **Prefer `variant="soft"` over `variant="outline"` for secondary actions.** Soft (tinted step-3 bg, step-11 text) is the Devalok-recommended default — it feels warmer and brand-consistent. Use `outline` only when soft's tint would disappear (on colored/surface-raised bg), in toolbar/icon-dense contexts, or when you need outline's stronger hierarchy next to a primary action.
39
48
  - DO NOT use variant="destructive" — use variant="solid" color="error"
@@ -6,18 +6,22 @@
6
6
 
7
7
  ## Props
8
8
  variant: "default" | "elevated" | "outline" | "flat"
9
+ color: "default" | "accent" | "error" | "success" | "warning" | "info" | "neutral" (border accent color)
10
+ size: "sm" | "md" | "lg" (padding — propagated to CardHeader/CardContent/CardFooter via context)
9
11
  interactive: boolean (enables hover shadow lift + pointer cursor)
12
+ accent: "left" | "top" | "right" | "bottom" (render a colored accent bar on the specified edge)
13
+ accentColor: "default" | "accent" | "error" | "success" | "warning" | "info" (color of the accent bar; default maps to accent-9)
10
14
 
11
15
  ## Compound Components
12
16
  Card (root)
13
- CardHeader
17
+ CardHeader ← inherits size from Card context
14
18
  CardTitle
15
19
  CardDescription
16
- CardContent
17
- CardFooter
20
+ CardContent ← inherits size from Card context
21
+ CardFooter ← inherits size from Card context
18
22
 
19
23
  ## Defaults
20
- variant="default"
24
+ variant="default", color="default", size="md"
21
25
 
22
26
  ## Example
23
27
  ```jsx
@@ -30,8 +34,16 @@
30
34
  </Card>
31
35
  ```
32
36
 
37
+ ## Composability
38
+ - **Size cascades through context** — Card's `size` prop sets padding on CardHeader, CardContent, and CardFooter via `CardSizeContext`. Don't set padding classes on sub-components directly; override via `className` if needed.
39
+ - **Not a compound state machine** — Card, CardHeader, CardTitle, etc. are purely structural. No open/close state.
40
+ - **Accent bar is independent:** The `accent` / `accentColor` props render a decorative colored edge bar (absolutely positioned, `aria-hidden`). Works alongside `color` (which tints the border) — the two can stack for layered emphasis.
41
+ - **Interactive cards:** Set `interactive={true}` + `onClick` for clickable cards (entire surface becomes the button). Add `aria-label` on the Card root when there's no visible heading. For complex multi-action cards, prefer standard Card with explicit buttons inside.
42
+ - **ContentCard (composed)** is a higher-level wrapper with built-in header/footer slots and title/actions — use it for list-row-style cards; use Card directly for custom layouts.
43
+
33
44
  ## Gotchas
34
45
  - Use `interactive` prop for clickable cards — adds hover lift and pointer cursor
46
+ - Don't override CardHeader/CardContent/CardFooter padding via className if you want the size cascade to work — set size on Card instead
35
47
 
36
48
  ## Changes
37
49
  ### v0.31.0
@@ -28,9 +28,18 @@ import { BarChart } from '@devalok/shilp-sutra/ui/charts'
28
28
  <BarChart data={salesData} />
29
29
  ```
30
30
 
31
+ ## Composability
32
+ - **ChartContainer wraps all chart primitives** — provides responsive sizing (fills parent width, configurable aspect ratio) and a consistent background/padding. Always render charts inside a ChartContainer unless you're building a custom container.
33
+ - **Legend is a sibling, not a child** — render `<Legend items={...} />` next to your chart (above/below), not nested. Use `onHover` / `onClick` handlers in Legend + chart to sync hover highlights.
34
+ - **Data shape is chart-specific** — BarChart wants `[{ label, value }]`, LineChart wants `[{ x, y, series }]`, etc. Each chart's props doc spells out the shape; don't assume cross-chart compatibility.
35
+ - **Sparkline is the only chart safe to use inline** — it's a minimal 1-line SVG, no axes, no legend. Use it inside StatCard, tables, tight cells. For anything larger, reach for the full chart types.
36
+ - **Entrance animations** — all charts use Framer Motion spring-based entry. Animations respect `prefers-reduced-motion`.
37
+ - **Accessibility:** Charts render role="img" with aria-label from the chart title. For dense data, provide a hidden accessible table fallback manually (WCAG requirement for complex charts).
38
+
31
39
  ## Gotchas
32
40
  - Barrel-isolated since v0.5.0 — must use `@devalok/shilp-sutra/ui/charts`, NOT the `ui` barrel
33
41
  - Requires D3 as an optional peer dependency
42
+ - Chart components do NOT auto-generate accessible data tables — add one manually for WCAG compliance on complex charts
34
43
 
35
44
  ## Changes
36
45
  ### v0.18.0