@devalok/shilp-sutra 0.56.0 → 0.59.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.
Files changed (374) hide show
  1. package/MIGRATION.md +198 -0
  2. package/dist/_chunks/badge-group.js +75 -174
  3. package/dist/_chunks/badge-group.js.map +1 -1
  4. package/dist/_chunks/chat.js +270 -253
  5. package/dist/_chunks/chat.js.map +1 -1
  6. package/dist/_chunks/document-preview.js +1 -1
  7. package/dist/_chunks/document-preview.js.map +1 -1
  8. package/dist/_chunks/emoji-suggestion.js +1 -1
  9. package/dist/_chunks/emoji-suggestion.js.map +1 -1
  10. package/dist/_chunks/image-preview.js +71 -70
  11. package/dist/_chunks/image-preview.js.map +1 -1
  12. package/dist/_chunks/mention-suggestion.js +2 -2
  13. package/dist/_chunks/mention-suggestion.js.map +1 -1
  14. package/dist/_chunks/motion-preference.js +15 -0
  15. package/dist/_chunks/motion-preference.js.map +1 -0
  16. package/dist/_chunks/motion-provider.js +1 -1
  17. package/dist/_chunks/motion-provider.js.map +1 -1
  18. package/dist/_chunks/oauth-button.js +1 -1
  19. package/dist/_chunks/oauth-button.js.map +1 -1
  20. package/dist/_chunks/popover.js +50 -49
  21. package/dist/_chunks/popover.js.map +1 -1
  22. package/dist/_chunks/primitives-internal.js +29 -29
  23. package/dist/_chunks/primitives-internal.js.map +1 -1
  24. package/dist/_chunks/shared.js +48 -47
  25. package/dist/_chunks/shared.js.map +1 -1
  26. package/dist/_chunks/success.js +36 -36
  27. package/dist/_chunks/success.js.map +1 -1
  28. package/dist/_chunks/tree-view.js +1 -1
  29. package/dist/_chunks/tree-view.js.map +1 -1
  30. package/dist/_chunks/use-calendar.js +4 -4
  31. package/dist/_chunks/use-calendar.js.map +1 -1
  32. package/dist/ai/block-renderer.js +8 -8
  33. package/dist/ai/blocks/text.js +1 -1
  34. package/dist/ai/blocks/text.js.map +1 -1
  35. package/dist/ai/command-bar.js +67 -67
  36. package/dist/ai/command-bar.js.map +1 -1
  37. package/dist/ai/conversation.js +35 -35
  38. package/dist/ai/conversation.js.map +1 -1
  39. package/dist/ai/index.js +4 -4
  40. package/dist/composed/activity-feed.d.ts.map +1 -1
  41. package/dist/composed/activity-feed.js +109 -108
  42. package/dist/composed/activity-feed.js.map +1 -1
  43. package/dist/composed/avatar-group.d.ts +7 -2
  44. package/dist/composed/avatar-group.d.ts.map +1 -1
  45. package/dist/composed/avatar-group.js +3 -3
  46. package/dist/composed/avatar-group.js.map +1 -1
  47. package/dist/composed/command-palette.js +137 -137
  48. package/dist/composed/command-palette.js.map +1 -1
  49. package/dist/composed/content-card.js +2 -2
  50. package/dist/composed/content-card.js.map +1 -1
  51. package/dist/composed/date-picker/index.js +9 -9
  52. package/dist/composed/date-picker/index.js.map +1 -1
  53. package/dist/composed/diff.d.ts +23 -2
  54. package/dist/composed/diff.d.ts.map +1 -1
  55. package/dist/composed/diff.js +341 -260
  56. package/dist/composed/diff.js.map +1 -1
  57. package/dist/composed/emoji-picker.js +3 -3
  58. package/dist/composed/emoji-picker.js.map +1 -1
  59. package/dist/composed/empty-state.js +4 -4
  60. package/dist/composed/error-boundary.js +2 -2
  61. package/dist/composed/error-boundary.js.map +1 -1
  62. package/dist/composed/file-preview/image-preview.d.ts.map +1 -1
  63. package/dist/composed/file-preview/shared.d.ts.map +1 -1
  64. package/dist/composed/file-preview/video-preview.d.ts.map +1 -1
  65. package/dist/composed/file-preview.js +152 -151
  66. package/dist/composed/file-preview.js.map +1 -1
  67. package/dist/composed/filter-bar.d.ts.map +1 -1
  68. package/dist/composed/filter-bar.js +53 -52
  69. package/dist/composed/filter-bar.js.map +1 -1
  70. package/dist/composed/form-section.d.ts.map +1 -1
  71. package/dist/composed/form-section.js +38 -37
  72. package/dist/composed/form-section.js.map +1 -1
  73. package/dist/composed/inline-edit.js +1 -1
  74. package/dist/composed/inline-edit.js.map +1 -1
  75. package/dist/composed/loading-skeleton.js +3 -3
  76. package/dist/composed/loading-skeleton.js.map +1 -1
  77. package/dist/composed/master-detail.d.ts.map +1 -1
  78. package/dist/composed/master-detail.js +1 -1
  79. package/dist/composed/master-detail.js.map +1 -1
  80. package/dist/composed/member-picker.js +1 -1
  81. package/dist/composed/member-picker.js.map +1 -1
  82. package/dist/composed/multi-select-popover.d.ts.map +1 -1
  83. package/dist/composed/multi-select-popover.js +109 -108
  84. package/dist/composed/multi-select-popover.js.map +1 -1
  85. package/dist/composed/page-skeletons.js +4 -4
  86. package/dist/composed/page-skeletons.js.map +1 -1
  87. package/dist/composed/responsive-modal.js +1 -1
  88. package/dist/composed/responsive-modal.js.map +1 -1
  89. package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
  90. package/dist/composed/rich-chat-input/reply-banner.d.ts.map +1 -1
  91. package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
  92. package/dist/composed/rich-chat-input.d.ts.map +1 -1
  93. package/dist/composed/rich-chat-input.js +473 -472
  94. package/dist/composed/rich-chat-input.js.map +1 -1
  95. package/dist/composed/rich-text-editor.js +6 -6
  96. package/dist/composed/rich-text-editor.js.map +1 -1
  97. package/dist/composed/schedule-view.js +5 -5
  98. package/dist/composed/schedule-view.js.map +1 -1
  99. package/dist/composed/status-badge.d.ts.map +1 -1
  100. package/dist/composed/status-badge.js +29 -28
  101. package/dist/composed/status-badge.js.map +1 -1
  102. package/dist/hooks/index.d.ts +1 -0
  103. package/dist/hooks/index.d.ts.map +1 -1
  104. package/dist/hooks/index.js +4 -3
  105. package/dist/hooks/use-container-size.d.ts +18 -0
  106. package/dist/hooks/use-container-size.d.ts.map +1 -0
  107. package/dist/hooks/use-container-size.js +28 -0
  108. package/dist/hooks/use-container-size.js.map +1 -0
  109. package/dist/motion/index.d.ts +1 -0
  110. package/dist/motion/index.d.ts.map +1 -1
  111. package/dist/motion/index.js +2 -15
  112. package/dist/motion/motion-preference.d.ts +36 -0
  113. package/dist/motion/motion-preference.d.ts.map +1 -0
  114. package/dist/motion/motion-provider.d.ts +2 -1
  115. package/dist/motion/motion-provider.d.ts.map +1 -1
  116. package/dist/motion/primitives-index.js +103 -102
  117. package/dist/motion/primitives-index.js.map +1 -1
  118. package/dist/motion/primitives.d.ts.map +1 -1
  119. package/dist/shell/app-shell.d.ts +101 -0
  120. package/dist/shell/app-shell.d.ts.map +1 -0
  121. package/dist/shell/app-shell.js +76 -0
  122. package/dist/shell/app-shell.js.map +1 -0
  123. package/dist/shell/bottom-navbar.js +21 -21
  124. package/dist/shell/bottom-navbar.js.map +1 -1
  125. package/dist/shell/index.d.ts +2 -1
  126. package/dist/shell/index.d.ts.map +1 -1
  127. package/dist/shell/index.js +6 -5
  128. package/dist/shell/notification-center.d.ts +17 -0
  129. package/dist/shell/notification-center.d.ts.map +1 -1
  130. package/dist/shell/notification-center.js +110 -105
  131. package/dist/shell/notification-center.js.map +1 -1
  132. package/dist/shell/notification-preferences.js +1 -1
  133. package/dist/shell/notification-preferences.js.map +1 -1
  134. package/dist/shell/top-bar.js +7 -7
  135. package/dist/shell/top-bar.js.map +1 -1
  136. package/dist/tokens/generate-scale.d.ts +49 -0
  137. package/dist/tokens/generate-scale.d.ts.map +1 -1
  138. package/dist/tokens/index.css +1 -0
  139. package/dist/tokens/palettes.css +292 -0
  140. package/dist/tokens/primitives.css +29 -26
  141. package/dist/tokens/semantic.css +170 -47
  142. package/dist/tokens/shilp-sutra.css +1 -0
  143. package/dist/tokens/utilities.css +10 -7
  144. package/dist/tokens/variants.css +1 -1
  145. package/dist/ui/accordion.d.ts.map +1 -1
  146. package/dist/ui/accordion.js +27 -26
  147. package/dist/ui/accordion.js.map +1 -1
  148. package/dist/ui/alert-dialog.d.ts.map +1 -1
  149. package/dist/ui/alert-dialog.js +60 -59
  150. package/dist/ui/alert-dialog.js.map +1 -1
  151. package/dist/ui/alert.d.ts.map +1 -1
  152. package/dist/ui/alert.js +55 -113
  153. package/dist/ui/alert.js.map +1 -1
  154. package/dist/ui/autocomplete.js +80 -80
  155. package/dist/ui/autocomplete.js.map +1 -1
  156. package/dist/ui/avatar.d.ts.map +1 -1
  157. package/dist/ui/avatar.js +71 -70
  158. package/dist/ui/avatar.js.map +1 -1
  159. package/dist/ui/badge-indicator.d.ts +4 -8
  160. package/dist/ui/badge-indicator.d.ts.map +1 -1
  161. package/dist/ui/badge-indicator.js +3 -8
  162. package/dist/ui/badge-indicator.js.map +1 -1
  163. package/dist/ui/badge.d.ts +55 -34
  164. package/dist/ui/badge.d.ts.map +1 -1
  165. package/dist/ui/banner.d.ts.map +1 -1
  166. package/dist/ui/banner.js +43 -41
  167. package/dist/ui/banner.js.map +1 -1
  168. package/dist/ui/button-group.d.ts.map +1 -1
  169. package/dist/ui/button-group.js +3 -23
  170. package/dist/ui/button-group.js.map +1 -1
  171. package/dist/ui/button.d.ts +10 -1
  172. package/dist/ui/button.d.ts.map +1 -1
  173. package/dist/ui/button.js +79 -212
  174. package/dist/ui/button.js.map +1 -1
  175. package/dist/ui/card.d.ts.map +1 -1
  176. package/dist/ui/card.js +78 -75
  177. package/dist/ui/card.js.map +1 -1
  178. package/dist/ui/charts/radar-chart.d.ts.map +1 -1
  179. package/dist/ui/charts/radar-chart.js +1 -1
  180. package/dist/ui/charts/radar-chart.js.map +1 -1
  181. package/dist/ui/chat/date-separator.d.ts +8 -1
  182. package/dist/ui/chat/date-separator.d.ts.map +1 -1
  183. package/dist/ui/chat/message-list.d.ts.map +1 -1
  184. package/dist/ui/chat/message.d.ts.map +1 -1
  185. package/dist/ui/chat/typing-indicator.d.ts.map +1 -1
  186. package/dist/ui/checkbox.js +1 -1
  187. package/dist/ui/checkbox.js.map +1 -1
  188. package/dist/ui/code.js +2 -2
  189. package/dist/ui/code.js.map +1 -1
  190. package/dist/ui/color-input.d.ts.map +1 -1
  191. package/dist/ui/color-input.js +151 -150
  192. package/dist/ui/color-input.js.map +1 -1
  193. package/dist/ui/combobox.d.ts +14 -0
  194. package/dist/ui/combobox.d.ts.map +1 -1
  195. package/dist/ui/combobox.js +156 -152
  196. package/dist/ui/combobox.js.map +1 -1
  197. package/dist/ui/context-menu.d.ts.map +1 -1
  198. package/dist/ui/context-menu.js +70 -69
  199. package/dist/ui/context-menu.js.map +1 -1
  200. package/dist/ui/data-table-body.d.ts +3 -1
  201. package/dist/ui/data-table-body.d.ts.map +1 -1
  202. package/dist/ui/data-table-body.js +93 -92
  203. package/dist/ui/data-table-body.js.map +1 -1
  204. package/dist/ui/data-table-bulk-actions.d.ts +7 -1
  205. package/dist/ui/data-table-bulk-actions.d.ts.map +1 -1
  206. package/dist/ui/data-table-bulk-actions.js +14 -8
  207. package/dist/ui/data-table-bulk-actions.js.map +1 -1
  208. package/dist/ui/data-table-card.d.ts.map +1 -1
  209. package/dist/ui/data-table-card.js +66 -47
  210. package/dist/ui/data-table-card.js.map +1 -1
  211. package/dist/ui/data-table-context.d.ts +4 -0
  212. package/dist/ui/data-table-context.d.ts.map +1 -1
  213. package/dist/ui/data-table-context.js +2 -2
  214. package/dist/ui/data-table-context.js.map +1 -1
  215. package/dist/ui/data-table-header.d.ts.map +1 -1
  216. package/dist/ui/data-table-header.js +50 -46
  217. package/dist/ui/data-table-header.js.map +1 -1
  218. package/dist/ui/data-table-pagination.js +3 -3
  219. package/dist/ui/data-table-pagination.js.map +1 -1
  220. package/dist/ui/data-table-toolbar.d.ts +11 -1
  221. package/dist/ui/data-table-toolbar.d.ts.map +1 -1
  222. package/dist/ui/data-table-toolbar.js +7 -7
  223. package/dist/ui/data-table-toolbar.js.map +1 -1
  224. package/dist/ui/data-table.d.ts +52 -5
  225. package/dist/ui/data-table.d.ts.map +1 -1
  226. package/dist/ui/data-table.js +181 -169
  227. package/dist/ui/data-table.js.map +1 -1
  228. package/dist/ui/dialog.d.ts.map +1 -1
  229. package/dist/ui/dialog.js +62 -61
  230. package/dist/ui/dialog.js.map +1 -1
  231. package/dist/ui/dot.d.ts.map +1 -1
  232. package/dist/ui/dot.js +10 -41
  233. package/dist/ui/dot.js.map +1 -1
  234. package/dist/ui/dropdown-menu.d.ts.map +1 -1
  235. package/dist/ui/dropdown-menu.js +79 -78
  236. package/dist/ui/dropdown-menu.js.map +1 -1
  237. package/dist/ui/file-upload.d.ts.map +1 -1
  238. package/dist/ui/file-upload.js +117 -116
  239. package/dist/ui/file-upload.js.map +1 -1
  240. package/dist/ui/form.d.ts.map +1 -1
  241. package/dist/ui/form.js +27 -26
  242. package/dist/ui/form.js.map +1 -1
  243. package/dist/ui/hover-card.d.ts.map +1 -1
  244. package/dist/ui/hover-card.js +26 -25
  245. package/dist/ui/hover-card.js.map +1 -1
  246. package/dist/ui/icon.js +7 -7
  247. package/dist/ui/index.d.ts +2 -2
  248. package/dist/ui/index.d.ts.map +1 -1
  249. package/dist/ui/index.js +3 -3
  250. package/dist/ui/index.js.map +1 -1
  251. package/dist/ui/input-otp.js +1 -1
  252. package/dist/ui/input-otp.js.map +1 -1
  253. package/dist/ui/input.js +8 -8
  254. package/dist/ui/input.js.map +1 -1
  255. package/dist/ui/menubar.d.ts.map +1 -1
  256. package/dist/ui/menubar.js +73 -72
  257. package/dist/ui/menubar.js.map +1 -1
  258. package/dist/ui/navigation-menu.d.ts.map +1 -1
  259. package/dist/ui/navigation-menu.js +80 -79
  260. package/dist/ui/navigation-menu.js.map +1 -1
  261. package/dist/ui/number-input.js +3 -3
  262. package/dist/ui/number-input.js.map +1 -1
  263. package/dist/ui/pagination.js +1 -1
  264. package/dist/ui/pagination.js.map +1 -1
  265. package/dist/ui/popover.d.ts.map +1 -1
  266. package/dist/ui/progress-ring.js +2 -2
  267. package/dist/ui/progress-ring.js.map +1 -1
  268. package/dist/ui/progress.d.ts.map +1 -1
  269. package/dist/ui/progress.js +82 -74
  270. package/dist/ui/progress.js.map +1 -1
  271. package/dist/ui/radio.d.ts.map +1 -1
  272. package/dist/ui/radio.js +32 -31
  273. package/dist/ui/radio.js.map +1 -1
  274. package/dist/ui/search-input.d.ts.map +1 -1
  275. package/dist/ui/search-input.js +28 -27
  276. package/dist/ui/search-input.js.map +1 -1
  277. package/dist/ui/select.d.ts.map +1 -1
  278. package/dist/ui/select.js +67 -66
  279. package/dist/ui/select.js.map +1 -1
  280. package/dist/ui/sheet.js +1 -1
  281. package/dist/ui/sheet.js.map +1 -1
  282. package/dist/ui/sidebar.d.ts.map +1 -1
  283. package/dist/ui/sidebar.js +14 -14
  284. package/dist/ui/sidebar.js.map +1 -1
  285. package/dist/ui/slider.d.ts +63 -9
  286. package/dist/ui/slider.d.ts.map +1 -1
  287. package/dist/ui/slider.js +75 -33
  288. package/dist/ui/slider.js.map +1 -1
  289. package/dist/ui/split-button.d.ts +8 -2
  290. package/dist/ui/split-button.d.ts.map +1 -1
  291. package/dist/ui/split-button.js +49 -95
  292. package/dist/ui/split-button.js.map +1 -1
  293. package/dist/ui/stat-card.d.ts.map +1 -1
  294. package/dist/ui/stat-card.js +89 -88
  295. package/dist/ui/stat-card.js.map +1 -1
  296. package/dist/ui/stat-flash.js +16 -16
  297. package/dist/ui/stepper.d.ts.map +1 -1
  298. package/dist/ui/stepper.js +63 -62
  299. package/dist/ui/stepper.js.map +1 -1
  300. package/dist/ui/surface.d.ts.map +1 -1
  301. package/dist/ui/surface.js +2 -2
  302. package/dist/ui/surface.js.map +1 -1
  303. package/dist/ui/switch.js +1 -1
  304. package/dist/ui/switch.js.map +1 -1
  305. package/dist/ui/table.js +3 -3
  306. package/dist/ui/table.js.map +1 -1
  307. package/dist/ui/tabs.d.ts.map +1 -1
  308. package/dist/ui/tabs.js +68 -67
  309. package/dist/ui/tabs.js.map +1 -1
  310. package/dist/ui/textarea.js +5 -5
  311. package/dist/ui/textarea.js.map +1 -1
  312. package/dist/ui/toast.d.ts.map +1 -1
  313. package/dist/ui/toast.js +196 -195
  314. package/dist/ui/toast.js.map +1 -1
  315. package/dist/ui/toggle.d.ts.map +1 -1
  316. package/dist/ui/toggle.js +26 -24
  317. package/dist/ui/toggle.js.map +1 -1
  318. package/dist/ui/tooltip.d.ts.map +1 -1
  319. package/dist/ui/tooltip.js +37 -36
  320. package/dist/ui/tooltip.js.map +1 -1
  321. package/dist/ui/tree-view/tree-item.d.ts.map +1 -1
  322. package/docs/components/composed/avatar-group.md +4 -4
  323. package/docs/components/composed/diff.md +10 -2
  324. package/docs/components/composed/schedule-view.md +1 -1
  325. package/docs/components/shell/app-shell.md +132 -0
  326. package/docs/components/ui/avatar.md +1 -1
  327. package/docs/components/ui/button.md +1 -1
  328. package/docs/components/ui/chat.md +7 -1
  329. package/docs/components/ui/color-swatch.md +1 -1
  330. package/docs/components/ui/data-table-toolbar.md +6 -2
  331. package/docs/components/ui/data-table.md +41 -7
  332. package/docs/components/ui/dot.md +1 -1
  333. package/docs/components/ui/progress.md +1 -0
  334. package/docs/components/ui/surface.md +3 -3
  335. package/docs/components/ui/table.md +2 -2
  336. package/docs/recipes/customize-brand.md +58 -0
  337. package/docs/recipes/install-astro.md +1 -0
  338. package/docs/recipes/install-next-app-router.md +1 -0
  339. package/docs/recipes/install-next-pages.md +22 -1
  340. package/docs/recipes/install-remix.md +1 -0
  341. package/docs/recipes/install-tanstack-start.md +1 -0
  342. package/docs/recipes/install-vite.md +2 -0
  343. package/docs/recipes/server-components.md +7 -4
  344. package/docs/recipes/troubleshoot.md +1 -0
  345. package/llms.txt +2 -1
  346. package/make-kit/Guidelines.md +2 -2
  347. package/make-kit/components/button.md +1 -1
  348. package/make-kit/components/card.md +6 -6
  349. package/make-kit/components/surface.md +4 -4
  350. package/make-kit/foundations/color.md +4 -4
  351. package/make-kit/foundations/dark-mode.md +1 -1
  352. package/make-kit/foundations/radius.md +1 -1
  353. package/make-kit/foundations/surfaces.md +9 -9
  354. package/mcp-manifest.json +358 -35
  355. package/package.json +8 -4
  356. package/skill/SKILL.md +12 -6
  357. package/skill/references/components.md +2 -1
  358. package/skill/references/customize-brand.md +58 -0
  359. package/skill/references/server-components.md +7 -4
  360. package/skill/references/setup-astro.md +1 -0
  361. package/skill/references/setup-next-app-router.md +1 -0
  362. package/skill/references/setup-next-pages.md +22 -1
  363. package/skill/references/setup-remix.md +1 -0
  364. package/skill/references/setup-tanstack-start.md +1 -0
  365. package/skill/references/setup-vite.md +2 -0
  366. package/skill/references/troubleshoot.md +1 -0
  367. package/dist/motion/check-motion-provider.d.ts +0 -2
  368. package/dist/motion/check-motion-provider.d.ts.map +0 -1
  369. package/dist/motion/index.js.map +0 -1
  370. package/dist/primitives/react-toast.d.ts +0 -120
  371. package/dist/ui/charts/_internal/scales.d.ts +0 -5
  372. package/dist/ui/charts/_internal/scales.d.ts.map +0 -1
  373. package/dist/ui/lib/slot.d.ts +0 -8
  374. package/dist/ui/lib/slot.d.ts.map +0 -1
@@ -0,0 +1,132 @@
1
+ # AppShell
2
+
3
+ - Import: @devalok/shilp-sutra/shell/app-shell
4
+ - Server-safe: No
5
+ - Category: shell
6
+
7
+ ## Overview
8
+
9
+ The frame that lets a bar span above **both** the sidebar and the content.
10
+
11
+ `SidebarProvider` renders a single flex row, so a bar can only live *inside* the
12
+ content pane — which is why every shadcn example puts its `<header>` inside
13
+ `SidebarInset`. AppShell is the other arrangement: the bar is a sibling above the
14
+ row, the way Carbon's `Header` sits above its `SideNav`.
15
+
16
+ It provides layout and surfaces only. Put `TopBar` in the bar slot and compose
17
+ the `Sidebar` primitives in the sidebar slot — AppShell does not replace either.
18
+
19
+ ## Subcomponents
20
+
21
+ | Component | Purpose |
22
+ |-----------|---------|
23
+ | `AppShell` | Root — owns the chrome surface and the arrangement |
24
+ | `AppShellBar` | Full-width bar above everything. Minimum height, never fixed. |
25
+ | `AppShellBody` | The row beneath the bar: sidebar alongside canvas |
26
+ | `AppShellSidebar` | Fixed-width slot, 16rem or 3rem collapsed |
27
+ | `AppShellCanvas` | The content pane; becomes an inset panel when `variant="inset"` |
28
+
29
+ ## Props
30
+
31
+ ### AppShell
32
+ variant?: 'flat' | 'inset'
33
+ chrome?: 'dim' | 'bright'
34
+ className?: string
35
+
36
+ Defaults: `variant` is `flat`, `chrome` is `dim`. `chrome` only applies when
37
+ `variant="inset"`.
38
+
39
+ ### AppShellBar
40
+ bordered?: boolean
41
+ className?: string
42
+
43
+ Defaults: `bordered` is `true` when the shell is flat and `false` when inset.
44
+
45
+ ### AppShellSidebar
46
+ collapsed?: boolean
47
+ className?: string
48
+
49
+ Defaults: `collapsed` is `false` — 16rem expanded, 3rem collapsed.
50
+
51
+ ### AppShellBody / AppShellCanvas
52
+ className?: string
53
+
54
+ ## Example
55
+
56
+ ```tsx
57
+ import {
58
+ AppShell, AppShellBar, AppShellBody, AppShellCanvas, AppShellSidebar,
59
+ } from '@devalok/shilp-sutra/shell/app-shell'
60
+ import { TopBar } from '@devalok/shilp-sutra/shell/top-bar'
61
+
62
+ export function Layout({ children }) {
63
+ return (
64
+ <AppShell variant="inset" chrome="dim">
65
+ <AppShellBar>
66
+ <TopBar>
67
+ <TopBar.Left><TopBar.Title>Projects</TopBar.Title></TopBar.Left>
68
+ <TopBar.Right><TopBar.UserMenu user={user} /></TopBar.Right>
69
+ </TopBar>
70
+ </AppShellBar>
71
+
72
+ <AppShellBody>
73
+ <AppShellSidebar>
74
+ <Nav />
75
+ </AppShellSidebar>
76
+ <AppShellCanvas className="overflow-auto">
77
+ {children}
78
+ </AppShellCanvas>
79
+ </AppShellBody>
80
+ </AppShell>
81
+ )
82
+ }
83
+ ```
84
+
85
+ ## The three arrangements
86
+
87
+ **`variant="flat"`** — chrome and content share one surface; a hairline on the
88
+ sidebar and under the bar does the separating. Widest content area.
89
+
90
+ **`variant="inset"`** — the content sits in a rounded panel inside the chrome.
91
+ `chrome` then decides which plane the frame takes and which the work takes:
92
+
93
+ | | light chrome | light canvas | dark chrome | dark canvas |
94
+ |---|---|---|---|---|
95
+ | `chrome="dim"` | `#eeeeee` | `#ffffff` | `#0a0a0a` | `#171717` |
96
+ | `chrome="bright"` | `#ffffff` | `#eeeeee` | `#171717` | `#0a0a0a` |
97
+
98
+ Both come from the same two tokens — `surface-sunken` and `surface-panel` —
99
+ swapped. There is no third tier and no per-theme special case.
100
+
101
+ The choice is not really about lightness. With `dim` a brand tint lands on the
102
+ frame and the work area stays neutral; with `bright` it is the reverse. That
103
+ decides whether your brand colour surrounds the work or sits underneath it.
104
+
105
+ ## Composability
106
+
107
+ Layout only. It sets surfaces, widths and the inset geometry; everything inside
108
+ each slot is yours. Any component can go in any slot.
109
+
110
+ `AppShellSidebar` uses the same widths as `Sidebar` (16rem, 3rem collapsed), so
111
+ the two agree whether or not you nest one inside the other.
112
+
113
+ ## Gotchas
114
+
115
+ **The bar height is a minimum, not a fixed value.** `TopBar` sizes to its
116
+ content, and a two-line workspace switcher legitimately needs more room than a
117
+ one-line one. Setting a fixed height clips it.
118
+
119
+ **The inset canvas is flush to the bar and the sidebar** and floats only off the
120
+ bottom-right. That is deliberate: it reads as the frame opening up rather than a
121
+ card dropped into the middle. A symmetric gap fights that.
122
+
123
+ **No shadow on the inset canvas.** It is a frame, not a floating thing — shadows
124
+ are reserved for what genuinely floats (menus, dialogs, popovers).
125
+
126
+ **A bar is optional, and dropping it is a product decision.** Without one, the
127
+ account and workspace switcher move into the sidebar footer. That changes what
128
+ the shell is for, not just how it looks.
129
+
130
+ ## Changes
131
+
132
+ - 0.57.0 — added
@@ -38,7 +38,7 @@
38
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
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
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.
41
+ - **Ring offset color:** The ring renders with `ring-offset` matching the current surface — it assumes the Avatar sits on `bg-surface-panel`. On other backgrounds, add a ring-offset className to compensate.
42
42
 
43
43
  ## Gotchas
44
44
  - Status dot renders with role="img" and aria-label (accessible, not decorative)
@@ -44,7 +44,7 @@
44
44
  - **Prefer `variant="soft"` over `variant="outline"` for secondary actions** (see Gotchas for details). This is a design-system-wide convention.
45
45
 
46
46
  ## Gotchas
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.
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-panel bg), in toolbar/icon-dense contexts, or when you need outline's stronger hierarchy next to a primary action.
48
48
  - DO NOT use variant="destructive" — use variant="solid" color="error"
49
49
  - DO NOT use variant="secondary" — use variant="soft" (preferred) or variant="ghost"
50
50
  - DO NOT use size="default" — use size="md"
@@ -155,13 +155,16 @@ Horizontal rule with a formatted date label.
155
155
 
156
156
  ### Props
157
157
  date: Date | string (REQUIRED)
158
- format: (date: Date) => string — custom date formatter
158
+ format: (date: Date) => string — custom date formatter (overrides locale/timeZone)
159
+ locale: string — BCP 47 locale for the default label's month name (default 'en-US')
160
+ timeZone: string — IANA time zone for the "Today"/"Yesterday" day-boundary comparison and formatting (default: browser's local time zone)
159
161
  className: string
160
162
 
161
163
  ### Example
162
164
  ```jsx
163
165
  <DateSeparator date={new Date()} />
164
166
  <DateSeparator date="2026-03-25" format={(d) => d.toLocaleDateString()} />
167
+ <DateSeparator date={new Date()} locale="fr-FR" timeZone="Europe/Paris" />
165
168
  ```
166
169
 
167
170
  ---
@@ -219,5 +222,8 @@ Animated bouncing dots with a text description of who is typing.
219
222
  - DateSeparator's default formatter shows "Today", "Yesterday", or "Mon DD" / "Mon DD, YYYY"
220
223
 
221
224
  ## Changes
225
+ ### Unreleased
226
+ - **Added** `DateSeparator` gained `locale?: string` and `timeZone?: string` props — the default label previously always used `en-US` month names and the browser's local time zone.
227
+
222
228
  ### v0.29.0
223
229
  - **Added** Initial release — 7 chat primitives (MessageList, Message, SystemMessage, MessageInput, DateSeparator, UnreadSeparator, TypingIndicator)
@@ -23,7 +23,7 @@
23
23
  ## Composability
24
24
  - **Server-safe, decorative-only primitive.** Accepts any valid CSS color string — hex, rgb, oklch, hsl, named. Pure presentation, no context.
25
25
  - **Usage patterns:** Inline color marker next to a label, preview dot in lists, color-indicator in a category chip, legend swatch for charts.
26
- - **`ring={true}`** adds a subtle outline — essential for white/very-light colors that would otherwise disappear on surface-raised backgrounds.
26
+ - **`ring={true}`** adds a subtle outline — essential for white/very-light colors that would otherwise disappear on surface-panel backgrounds.
27
27
  - **Interactive color picking:** Use ColorInput (which opens a full picker). ColorSwatch is display-only.
28
28
  - No IconProvider cascade, no FormField consumption — composes freely with anything.
29
29
 
@@ -11,10 +11,11 @@
11
11
  onGlobalFilterChange: (value: string) => void
12
12
  density: 'compact' | 'standard' | 'comfortable'
13
13
  onDensityChange: (density: Density) => void
14
- enableExport: boolean
14
+ enableExport: boolean — show the Export CSV button (default true)
15
+ onExport: (visibleRows: TData[]) => void — replaces the built-in CSV logic; receives the currently visible filtered rows
15
16
 
16
17
  ## Defaults
17
- none
18
+ enableExport=true, globalFilter=false
18
19
 
19
20
  ## Example
20
21
  ```jsx
@@ -44,6 +45,9 @@ import { DataTableToolbar } from '@devalok/shilp-sutra/ui/data-table-toolbar'
44
45
  - Prefer DataTable's `toolbar={true}` prop over rendering this directly
45
46
 
46
47
  ## Changes
48
+ ### v0.57.0
49
+ - **Added** `onExport?: (visibleRows: TData[]) => void` — when provided, replaces the built-in CSV logic. Same signature as `DataTable`'s `onExport`, so the prop forwards straight through.
50
+
47
51
  ### v0.5.0
48
52
  - **Changed** (BREAKING) Removed from `@devalok/shilp-sutra/ui` barrel export — must use `@devalok/shilp-sutra/ui/data-table-toolbar`
49
53
 
@@ -5,20 +5,23 @@
5
5
  - Category: ui
6
6
 
7
7
  ## Props
8
- columns: ColumnDef<TData>[] (TanStack column definitions)
8
+ columns: ColumnDef<TData, TValue>[] (TanStack column definitions)
9
9
  data: TData[]
10
+ className: string — class name for the wrapper div
10
11
  sortable: boolean — enable column sorting
11
- onSort: (key: string, dir: 'asc' | 'desc' | false) => void — server-side sort callback (enables manualSorting)
12
+ onSort: (key: string, direction: 'asc' | 'desc' | false) => void — server-side sort callback (enables manualSorting)
12
13
  filterable: boolean — enable per-column filters
14
+ filterableColumns: string[] — restrict filter inputs to these column IDs (only with filterable; omit for all filterable columns)
13
15
  globalFilter: boolean — enable global search
14
16
  paginated: boolean — enable client-side pagination
15
17
  pagination: { page: number, pageSize: number, total: number, onPageChange: (page: number) => void } — server-side pagination (1-based page)
16
18
  pageSize: number (default 10)
19
+ pageSizeOptions: number[] — page-size selector options (default [10, 20, 50, 100])
17
20
  selectable: boolean — enable row selection with checkboxes
18
21
  selectedIds: Set<string> — controlled selection state
19
22
  selectableFilter: (row: TData) => boolean — disable selection on certain rows
20
23
  getRowId: (row: TData) => string — custom row ID accessor
21
- onSelectionChange: (selectedRows: TData[]) => void
24
+ onSelectionChange: (selectedRows: TData[], selectedIds: Set<string>) => void — does NOT fire on mount
22
25
  expandable: boolean — enable row expansion
23
26
  renderExpanded: (row: TData) => ReactNode — expanded row content
24
27
  singleExpand: boolean — only one row expanded at a time
@@ -27,15 +30,23 @@
27
30
  noResultsText: string (default "No results.")
28
31
  stickyHeader: boolean — sticky table header
29
32
  onRowClick: (row: TData) => void — row click handler (excludes interactive element clicks)
30
- bulkActions: BulkAction<TData>[]floating action bar on selection { label, onClick, color?: 'default'|'error', disabled? }
33
+ rowClassName: (row: TData) => string | undefined conditional per-row class (the <tr> in table mode, the Card in card mode)
34
+ bulkActions: BulkAction<TData>[] — floating action bar on selection — { label, onClick, icon?: IconInput, color?: 'accent'|'error', disabled? }
35
+ bulkActionsPosition: 'bottom' | 'top' | 'inline' — where the bulk-actions bar renders (default 'bottom')
31
36
  toolbar: boolean — show DataTableToolbar (column visibility, density, CSV export)
37
+ enableExport: boolean — show the toolbar's Export CSV button (default true)
38
+ onExport: (visibleRows: TData[]) => void — replace the built-in CSV export
32
39
  editable: boolean — enable double-click cell editing
40
+ onCellEdit: (rowIndex: number, columnId: string, value: unknown) => void — fired on cell edit commit
33
41
  virtualRows: boolean — virtualize rows for large datasets
42
+ virtualRowHeight: number — ESTIMATED row height in px (default 48); real heights are measured after mount
43
+ maxHeight: number — max height of the virtual scroll container in px (default 600)
44
+ mobileView: 'card' | 'table' — stacked cards below the sm breakpoint (default 'table')
34
45
  columnPinning: { left?: string[], right?: string[] }
35
46
  density: 'compact' | 'standard' | 'comfortable'
36
47
 
37
48
  ## Defaults
38
- pageSize=10, noResultsText="No results."
49
+ pageSize=10, noResultsText="No results.", enableExport=true, mobileView='table', virtualRowHeight=48, maxHeight=600, density='standard'
39
50
 
40
51
  ## Example
41
52
  ```jsx
@@ -75,7 +86,11 @@ import { DataTable } from '@devalok/shilp-sutra/ui/data-table'
75
86
  **Row click model:**
76
87
  - `onRowClick` fires on row-level click BUT excludes clicks on checkboxes, buttons, links, and inputs automatically. No manual `stopPropagation` needed for standard interactive elements.
77
88
 
78
- **Virtualization:** `virtualRows={true}` enables row virtualization via `@tanstack/react-virtual`. Turn it on for 1000+ row datasets; the scroll container must have a bounded height.
89
+ **Virtualization:** `virtualRows={true}` enables row virtualization via `@tanstack/react-virtual`. Turn it on for 1000+ row datasets; the scroll container must have a bounded height. Rows stay in normal table flow (each windowed row is its own `<tbody>` measured by the virtualizer, with spacer row groups reserving the un-rendered remainder), so column widths keep tracking `<thead>` and `virtualRowHeight` is only the pre-measurement estimate.
90
+
91
+ **Virtualization + expansion:** `virtualRows` and `expandable` compose. Because each row group is measured, an expanded detail panel of any height contributes to the total scroll size and pushes the rows below it down. The reveal is instant in virtual mode (no height animation) — an animating height would fire a resize on every frame.
92
+
93
+ **Toolbar export:** the Export button renders whenever `toolbar` is on. The built-in CSV export walks `getFilteredRowModel()`, which under server-side `pagination` is only the current page — pass `onExport` to fetch the full set yourself, or `enableExport={false}` to drop the button.
79
94
 
80
95
  **Density integration:** density is forwarded to `Table`'s `density` prop, which sets `--table-py` (compact 4 / standard 8 / comfortable 12px → rows ≈ 29 / 37 / 45px; header tracks it). DataTableToolbar's density switcher updates this at runtime; the prop sets the initial state only.
81
96
 
@@ -88,13 +103,32 @@ import { DataTable } from '@devalok/shilp-sutra/ui/data-table'
88
103
  - onRowClick does NOT fire when clicking checkboxes, buttons, links, or inputs
89
104
  - Use density="compact" for Karm-style h-9 rows
90
105
  - `virtualRows={true}` requires a bounded scroll container — unbounded height silently disables virtualization
106
+ - `onSelectionChange` does NOT fire on mount, and does NOT fire when selection is synced from the `selectedIds` prop — only on genuine selection changes
107
+ - `filterableColumns` is ignored unless `filterable` is also set
108
+ - `rowClassName` returns are passed through `cn()` verbatim — a class that does not exist in the token set silently does nothing (use the real scale steps, e.g. `bg-error-3`, not invented names like `bg-error-subtle`)
91
109
 
92
110
  ## Changes
111
+ ### Unreleased
112
+ - **Added** `bulkActions[].icon?: IconInput` — icon rendered before the label in a bulk-action button.
113
+ - **Added** `bulkActionsPosition?: 'bottom' | 'top' | 'inline'` — where the bulk-actions bar renders (default `'bottom'`, matching prior behavior).
114
+
115
+ ### v0.57.0
116
+ - **Fixed** `onSelectionChange` no longer fires on mount with `[]` — first-render guard added. Root cause of the cascade reported in #213.
117
+ - **Fixed** `virtualRows + expandable` was a silent no-op — the expanded row was only rendered on the non-virtual path. Virtual rows now render one measured `<tbody>` per windowed row (with spacer row groups for the remainder) so the expanded panel renders, contributes its real height to `getTotalSize()`, and cannot overlap the row below.
118
+ - **Changed** Virtual rows are no longer absolutely positioned with a forced `virtualRowHeight`; they sit in normal table flow at their measured height, so column widths track `<thead>`. `virtualRowHeight` is now the pre-measurement ESTIMATE.
119
+ - **Fixed** `enableExport` was stranded on `DataTableToolbar` and never wired through `DataTableProps`. Now exposed with an `onExport` override. Default is unchanged (`true`) — the Export button still renders whenever `toolbar` is on.
120
+ - **Fixed** `filterable + mobileView="card"` rendered no filter inputs — they now render above the card list in `DataTableCards` (card mode renders no `<thead>` for them to live in).
121
+ - **Added** `onSelectionChange` receives `selectedIds: Set<string>` as second argument — complement of the `selectedIds` prop.
122
+ - **Added** `filterableColumns?: string[]` — restrict filter inputs to specific column IDs.
123
+ - **Added** `rowClassName?: (row: TData) => string | undefined` — conditional row classes in table and card layouts.
124
+ - **Added** `enableExport?: boolean` — hide the toolbar's Export CSV button from `DataTableProps`.
125
+ - **Added** `onExport?: (visibleRows: TData[]) => void` — override built-in CSV with a custom export handler.
126
+
93
127
  ### v0.45.0
94
128
  - **Fixed** Expander a11y per the expando-row spec: `aria-expanded` on the toggle button, visually-hidden "Expand rows" column header; chevron rotation uses `duration-fast-02 ease-productive-standard`.
95
129
  - **Added** Expanded-row content animates open/closed (height + opacity via framer, `springs.smooth`), self-guarded with `useReducedMotion` — instant swap for reduced-motion users. Virtualized tables keep the instant reveal (a height animation would fight the virtualizer's measurements).
96
130
  - **Changed** Density now drives Table's `--table-py` variable (rows ≈ 29 / 37 / 45px; was 29 / 53 / 85). Per-cell `cellPadding` threading removed from context.
97
- - **Fixed** Hover/selected states visible on cards: row/sort-button/expander hover use `surface-raised-hover` (was the invisible `surface-raised`); expanded row is a `surface-base` recess; sticky header bg is `surface-raised`; empty state uses `py-ds-07` (was raw `h-24`).
131
+ - **Fixed** Hover/selected states visible on cards: row/sort-button/expander hover use `surface-panel-hover` (was the invisible `surface-panel`); expanded row is a `surface-base` recess; sticky header bg is `surface-panel`; empty state uses `py-ds-07` (was raw `h-24`).
98
132
  - **Changed** Mobile card view composes `<Card size="sm" variant="outline">` (was a hand-rolled 12px bordered box).
99
133
 
100
134
  ### v0.29.0
@@ -49,7 +49,7 @@ sized, optionally pulsing, filled or ring.
49
49
  - **`pulse` = "live".** Off by default (static status). Turn it on for active/attention states (recording, live, connecting) — a pulsing dot reads as "happening now", so leave it off for settled statuses.
50
50
  - **Powers the higher-level pieces.** `StatusBadge` composes `<Badge>` + `<Dot>`; use `Dot` directly anywhere you need a coloured indicator without a pill.
51
51
  - **Three treatments:** `filled` (active), `ring` (hollow outline), `off` (faint same-tone fill + light border — present but inactive/disabled).
52
- - **`withBorder`** adds a contrast ring (`ring-2 ring-surface-raised`) so the dot reads on avatars, images, or coloured fills — the pattern Avatar's status dot uses.
52
+ - **`withBorder`** adds a contrast ring (`ring-2 ring-surface-panel`) so the dot reads on avatars, images, or coloured fills — the pattern Avatar's status dot uses.
53
53
  - **`pulseSpeed`** (slow/normal/fast) tunes the pulse tempo — fast for urgent (recording), slow for ambient (syncing).
54
54
 
55
55
  ## Gotchas
@@ -66,6 +66,7 @@ common cases, or the compound parts (`Progress.Root` / `Track` / `Indicator` /
66
66
  - Omit `value` (or pass `null`) for indeterminate.
67
67
  - Pass an explicit `color` to override `autoColor`.
68
68
  - Compound `Progress.Track` needs a name — an `aria-label`, or a `Progress.Label` whose `id` the Track's `aria-labelledby` points to. A Track with neither is an unnamed progressbar (axe will flag it).
69
+ - **`<Progress value={72} />` with no name warns in DEV.** `aria-valuenow` already carries the number, so an unnamed bar announces as "progressbar, 72%" — the reader learns the value but not *what* is progressing. Pass `label` (renders visible text and wires `aria-labelledby`) or `aria-label` when the bar must stay visually unlabelled. The component deliberately does **not** invent a default like "Progress: 72%": that would silence the audit while leaving the announcement equally uninformative, and only you know what the bar measures. Warns once per session, not per render.
69
70
  - `Progress.Indicator` / `Segment` / `Value` throw if rendered outside `Progress.Root`.
70
71
 
71
72
  ## Changes
@@ -18,8 +18,8 @@ The low-level elevated container primitive. Owns background + shadow + radius +
18
18
  Surface: elevation="raised", padding="none", radius="surface", bordered=false
19
19
 
20
20
  ## Elevation
21
- flat — bg-surface-raised, no shadow (pair with `bordered` for an on-page tile)
22
- raised — bg-surface-raised + shadow-raised (card level)
21
+ flat — bg-surface-panel, no shadow (pair with `bordered` for an on-page tile)
22
+ raised — bg-surface-panel + shadow-raised (card level)
23
23
  floating — bg-surface-overlay + shadow-floating (toasts, floating toolbars)
24
24
  overlay — bg-surface-overlay + shadow-overlay (popovers, menus, dialogs)
25
25
 
@@ -48,7 +48,7 @@ The low-level elevated container primitive. Owns background + shadow + radius +
48
48
 
49
49
  ## Gotchas
50
50
  - **Edge OR elevation, never both.** Combining `bordered` with a shadowed elevation (raised/floating/overlay) is the double-edge anti-pattern and dev-warns. Use `elevation="flat"` with `bordered`, or drop `bordered` and let the shadow be the edge.
51
- - `flat` still uses `bg-surface-raised` (a card without a shadow), not the page background — it is a surface, not a hole.
51
+ - `flat` still uses `bg-surface-panel` (a card without a shadow), not the page background — it is a surface, not a hole.
52
52
 
53
53
  ## Changes
54
54
  ### Unreleased
@@ -106,12 +106,12 @@ See the `RichCells` story for all of these live.
106
106
  - **Added** `TableRowLink` (ui/table-row-link) — real-anchor whole-row navigation with pseudo-element stretch (Safari-safe: anchored to the cell, clipped by the table's `overflow-x-clip`), row-level focus ring, `stretch={false}` title-only mode.
107
107
  - **Added** `TableRowActions` — hover/focus-revealed action cluster (opacity reveal, permanently tabbable, `:focus-within` + touch fallbacks, `persist` mode).
108
108
  - **Added** `numeric` prop on TableCell/TableHead — right-align + tabular figures.
109
- - **Fixed** TableFooter background was `color-mix(surface-raised 50%)` — invisible on cards (same mis-mapped shadcn `muted/50` family as the row hover). Now a `surface-base` band with a top hairline.
109
+ - **Fixed** TableFooter background was `color-mix(surface-panel 50%)` — invisible on cards (same mis-mapped shadcn `muted/50` family as the row hover). Now a `surface-base` band with a top hairline.
110
110
  - **Fixed** Selected+hover tie: selected rows get an explicit `hover:bg-accent-4` step (hover and selected previously tied on specificity).
111
111
  - **Added** Cell recipes section (user cell, tag overflow, money, empty-dash) + density→avatar mapping; `RichCells` / `SelectedRows` stories.
112
112
  - **Added** `density` prop (`compact | standard | comfortable`) via `--table-py`; header height tracks density instead of a fixed 40px
113
113
  - **Added** `striped` prop — opt-in zebra
114
- - **Changed** Rows regain their hairline separator (`border-b border-surface-border-subtle` — lost in the original port) and hover becomes visible on cards (`hover:bg-surface-raised-hover`, was the invisible `surface-raised`)
114
+ - **Changed** Rows regain their hairline separator (`border-b border-surface-border-subtle` — lost in the original port) and hover becomes visible on cards (`hover:bg-surface-panel-hover`, was the invisible `surface-panel`)
115
115
  - **Changed** Cells: `px-ds-04` interior, first/last cells read `--table-edge` (= `--card-spacing` inside a Card); header drops to `text-ds-sm` muted
116
116
  - **Changed** Default vertical rhythm tightens: standard rows ~53px → ~37px
117
117
 
@@ -256,6 +256,64 @@ Every override should consider both modes. Pattern:
256
256
 
257
257
  `.dark` is a regular class selector — its specificity is higher than `:root`/`@theme` body, so dark-mode overrides win when the class is active.
258
258
 
259
+ ## High contrast (`[data-contrast]`)
260
+
261
+ WCAG 2.2 SC 1.4.11 asks for **3:1** between a control's edge and its background.
262
+ The default control edge here is **2.00:1** in light and **2.08:1** in dark — a
263
+ deliberately softer look, and deliberately under that bar. It is recorded as
264
+ `CONTROL-EDGE-BELOW-AA` in the deviations register.
265
+
266
+ Set `data-contrast="high"` to opt into edges that clear the threshold:
267
+
268
+ ```html
269
+ <!-- whole app -->
270
+ <html data-contrast="high">
271
+ ```
272
+
273
+ ```tsx
274
+ {/* or one region — a data-entry screen inside an otherwise soft product */}
275
+ <div data-contrast="high">
276
+ <InvoiceForm />
277
+ </div>
278
+ ```
279
+
280
+ | | control edge, light | control edge, dark |
281
+ |---|---|---|
282
+ | default | `#b7b7b7` — 2.00:1 | `#4c4c4c` — 2.08:1 |
283
+ | `data-contrast="high"` | `#868686` — **3.64:1** | `#767676` — **3.93:1** |
284
+
285
+ It affects Input, Textarea, Select, Combobox, Checkbox, Radio, Switch,
286
+ NumberInput and outlined Button — anything using the control-edge tier. It does
287
+ **not** touch decorative borders (card and panel hairlines stay soft), and it
288
+ does not touch the chromatic ramps, so an outlined Button on a colour is
289
+ unchanged.
290
+
291
+ Composes with everything else — it is a plain attribute, like `.dark` and
292
+ `data-shape`:
293
+
294
+ ```html
295
+ <html class="dark" data-shape="sharp" data-contrast="high">
296
+ ```
297
+
298
+ **Two things worth knowing.**
299
+
300
+ If you override the neutral ramp, high contrast follows automatically — the
301
+ block resolves `--neutral-8` / `--neutral-9` by name rather than hard-coding
302
+ hexes, so a rebrand gets a correctly-scaled high-contrast mode for free.
303
+
304
+ If you want the *opposite* — compliant edges everywhere, with no attribute to
305
+ remember — set the tokens directly and skip the attribute entirely:
306
+
307
+ ```css
308
+ :root {
309
+ --color-surface-border-interactive: var(--neutral-8);
310
+ --color-surface-border-interactive-strong: var(--neutral-9);
311
+ }
312
+ ```
313
+
314
+ That is worth considering. A default is what most products ship, so leaving the
315
+ attribute unset means shipping the edge that misses 1.4.11.
316
+
259
317
  ## Forced colors (Windows high-contrast)
260
318
 
261
319
  If you override semantic colors, the `@media (forced-colors: active)` block in `semantic.css` continues to remap to system keywords. Your override is ignored when the user is in high-contrast mode — this is the correct behavior.
@@ -36,6 +36,7 @@ Some components ship hard peers as optional. **Install BEFORE first import.**
36
36
  | When you import… | Install |
37
37
  |---|---|
38
38
  | `@devalok/shilp-sutra/composed/date-picker` | `pnpm add date-fns` |
39
+ | `@devalok/shilp-sutra/composed/diff` | `pnpm add react-syntax-highlighter` |
39
40
  | `@devalok/shilp-sutra/composed/file-preview` | `pnpm add react-pdf react-zoom-pan-pinch` |
40
41
  | `@devalok/shilp-sutra/composed/markdown-viewer` | `pnpm add react-markdown react-syntax-highlighter remark-gfm` |
41
42
  | `@devalok/shilp-sutra/composed/rich-chat-input` | `pnpm add @tiptap/core @tiptap/extension-highlight @tiptap/extension-image @tiptap/extension-list @tiptap/extension-mention @tiptap/extension-text-align @tiptap/extensions @tiptap/markdown @tiptap/pm @tiptap/react @tiptap/starter-kit @tiptap/suggestion date-fns` |
@@ -49,6 +49,7 @@ Some components depend on third-party libraries that ship as optional peers. **I
49
49
  | When you import… | Install |
50
50
  |---|---|
51
51
  | `@devalok/shilp-sutra/composed/date-picker` | `pnpm add date-fns` |
52
+ | `@devalok/shilp-sutra/composed/diff` | `pnpm add react-syntax-highlighter` |
52
53
  | `@devalok/shilp-sutra/composed/file-preview` | `pnpm add react-pdf react-zoom-pan-pinch` |
53
54
  | `@devalok/shilp-sutra/composed/markdown-viewer` | `pnpm add react-markdown react-syntax-highlighter remark-gfm` |
54
55
  | `@devalok/shilp-sutra/composed/rich-chat-input` | `pnpm add @tiptap/core @tiptap/extension-highlight @tiptap/extension-image @tiptap/extension-list @tiptap/extension-mention @tiptap/extension-text-align @tiptap/extensions @tiptap/markdown @tiptap/pm @tiptap/react @tiptap/starter-kit @tiptap/suggestion date-fns` |
@@ -16,7 +16,28 @@ If both `app/` and `pages/` exist, prefer [install-next-app-router.md](./install
16
16
 
17
17
  Same dependencies as the App Router recipe — see [install-next-app-router.md § 2](./install-next-app-router.md#2-install-dependencies). Replace `next-themes`'s `attribute="class"` setup with the same on Pages Router (it works identically).
18
18
 
19
- **Optional peer dependencies** if you'll render `<DataTable>`, any chart, `<DatePicker>`, `<ScheduleView>`, `<InputOTP>`, `<FilePreview>`, `<MarkdownViewer>`, or `<Toaster>`, install the matching peers BEFORE first import. (The emoji picker and rich-text editors bundle their deps — no install needed; `@tabler/icons-react` auto-installs as a required peer.) Full table at [install-next-app-router.md § 2a](./install-next-app-router.md#2a-optional-peer-dependencies-install-only-when-importing-the-matching-subpath) — identical for Pages Router.
19
+ ### 2a. Optional peer dependencies (install only when importing the matching subpath)
20
+
21
+ Some components depend on third-party libraries that ship as optional peers. **Install BEFORE first import** of the matching component, or `next build` will exit with `Module not found`. Skip entirely if you only use core components (`Button`, `Text`, `Stack`, `Dialog`, `Toast`, `Form*`, `Input`, `Card`, etc.).
22
+
23
+ | When you import… | Install |
24
+ |---|---|
25
+ | `@devalok/shilp-sutra/composed/date-picker` | `pnpm add date-fns` |
26
+ | `@devalok/shilp-sutra/composed/diff` | `pnpm add react-syntax-highlighter` |
27
+ | `@devalok/shilp-sutra/composed/file-preview` | `pnpm add react-pdf react-zoom-pan-pinch` |
28
+ | `@devalok/shilp-sutra/composed/markdown-viewer` | `pnpm add react-markdown react-syntax-highlighter remark-gfm` |
29
+ | `@devalok/shilp-sutra/composed/rich-chat-input` | `pnpm add @tiptap/core @tiptap/extension-highlight @tiptap/extension-image @tiptap/extension-list @tiptap/extension-mention @tiptap/extension-text-align @tiptap/extensions @tiptap/markdown @tiptap/pm @tiptap/react @tiptap/starter-kit @tiptap/suggestion date-fns` |
30
+ | `@devalok/shilp-sutra/composed/rich-text-editor` | `pnpm add @tiptap/core @tiptap/extension-highlight @tiptap/extension-image @tiptap/extension-list @tiptap/extension-mention @tiptap/extension-text-align @tiptap/extensions @tiptap/markdown @tiptap/pm @tiptap/react @tiptap/starter-kit @tiptap/suggestion` |
31
+ | `@devalok/shilp-sutra/composed/schedule-view` | `pnpm add date-fns` |
32
+ | `@devalok/shilp-sutra/ui/charts` | `pnpm add d3-axis d3-scale d3-selection d3-shape` |
33
+ | `@devalok/shilp-sutra/ui/data-table` | `pnpm add @tanstack/react-table @tanstack/react-virtual` |
34
+ | `@devalok/shilp-sutra/ui/data-table-toolbar` | `pnpm add @tanstack/react-table` |
35
+ | `@devalok/shilp-sutra/ui/input-otp` | `pnpm add input-otp` |
36
+ | `@devalok/shilp-sutra/ui/toast` | `pnpm add sonner` |
37
+ | `@devalok/shilp-sutra/ui/toaster` | `pnpm add sonner` |
38
+ | Any `Icon` / `IconButton` with Tabler icons (near-universal — most components use icons internally, so it is a base-install peer) | `pnpm add @tabler/icons-react` |
39
+
40
+ > These aren't in core deps so consumers who never render a chart, OTP input, or rich-text editor don't pay the install / bundle cost. One-time decision at install.
20
41
 
21
42
  ## 3. PostCSS
22
43
 
@@ -32,6 +32,7 @@ Some components ship hard peers as optional. **Install BEFORE first import.**
32
32
  | When you import… | Install |
33
33
  |---|---|
34
34
  | `@devalok/shilp-sutra/composed/date-picker` | `pnpm add date-fns` |
35
+ | `@devalok/shilp-sutra/composed/diff` | `pnpm add react-syntax-highlighter` |
35
36
  | `@devalok/shilp-sutra/composed/file-preview` | `pnpm add react-pdf react-zoom-pan-pinch` |
36
37
  | `@devalok/shilp-sutra/composed/markdown-viewer` | `pnpm add react-markdown react-syntax-highlighter remark-gfm` |
37
38
  | `@devalok/shilp-sutra/composed/rich-chat-input` | `pnpm add @tiptap/core @tiptap/extension-highlight @tiptap/extension-image @tiptap/extension-list @tiptap/extension-mention @tiptap/extension-text-align @tiptap/extensions @tiptap/markdown @tiptap/pm @tiptap/react @tiptap/starter-kit @tiptap/suggestion date-fns` |
@@ -41,6 +41,7 @@ Some components ship hard peers as optional. **Install BEFORE first import.**
41
41
  | When you import… | Install |
42
42
  |---|---|
43
43
  | `@devalok/shilp-sutra/composed/date-picker` | `pnpm add date-fns` |
44
+ | `@devalok/shilp-sutra/composed/diff` | `pnpm add react-syntax-highlighter` |
44
45
  | `@devalok/shilp-sutra/composed/file-preview` | `pnpm add react-pdf react-zoom-pan-pinch` |
45
46
  | `@devalok/shilp-sutra/composed/markdown-viewer` | `pnpm add react-markdown react-syntax-highlighter remark-gfm` |
46
47
  | `@devalok/shilp-sutra/composed/rich-chat-input` | `pnpm add @tiptap/core @tiptap/extension-highlight @tiptap/extension-image @tiptap/extension-list @tiptap/extension-mention @tiptap/extension-text-align @tiptap/extensions @tiptap/markdown @tiptap/pm @tiptap/react @tiptap/starter-kit @tiptap/suggestion date-fns` |
@@ -47,6 +47,7 @@ Some components ship hard peers as optional. **Install BEFORE first import.**
47
47
  | When you import… | Install |
48
48
  |---|---|
49
49
  | `@devalok/shilp-sutra/composed/date-picker` | `pnpm add date-fns` |
50
+ | `@devalok/shilp-sutra/composed/diff` | `pnpm add react-syntax-highlighter` |
50
51
  | `@devalok/shilp-sutra/composed/file-preview` | `pnpm add react-pdf react-zoom-pan-pinch` |
51
52
  | `@devalok/shilp-sutra/composed/markdown-viewer` | `pnpm add react-markdown react-syntax-highlighter remark-gfm` |
52
53
  | `@devalok/shilp-sutra/composed/rich-chat-input` | `pnpm add @tiptap/core @tiptap/extension-highlight @tiptap/extension-image @tiptap/extension-list @tiptap/extension-mention @tiptap/extension-text-align @tiptap/extensions @tiptap/markdown @tiptap/pm @tiptap/react @tiptap/starter-kit @tiptap/suggestion date-fns` |
@@ -136,6 +137,7 @@ export function ThemeToggle() {
136
137
 
137
138
  If you installed `sonner`, mount the Toaster once near the app root:
138
139
 
140
+ <!-- typecheck-skip: imports the reader's own App entry -->
139
141
  ```tsx
140
142
  // src/main.tsx
141
143
  import { StrictMode } from "react";
@@ -78,7 +78,7 @@ export function MyButton() {
78
78
  |---|---|
79
79
  | `ContentCard` | All other composed components become client islands when rendered |
80
80
  | `PageHeader` | |
81
- | `LoadingSkeleton` | |
81
+ | `CardSkeleton` / `TableSkeleton` / `BoardSkeleton` / `ListSkeleton` | |
82
82
  | `PageSkeletons` | |
83
83
 
84
84
  ### `@devalok/shilp-sutra/shell`
@@ -127,20 +127,23 @@ All shilp-sutra components SSR cleanly. They have no client-only side effects at
127
127
 
128
128
  Use `<Suspense>` boundaries normally:
129
129
 
130
+ <!-- typecheck-skip: ClientHeavyComponent is the reader's own component -->
130
131
  ```tsx
131
132
  import { Suspense } from "react";
132
- import { LoadingSkeleton } from "@devalok/shilp-sutra/composed/loading-skeleton";
133
+ import { CardSkeleton } from "@devalok/shilp-sutra/composed/loading-skeleton";
133
134
 
134
135
  export default function Page() {
135
136
  return (
136
- <Suspense fallback={<LoadingSkeleton variant="page" />}>
137
+ <Suspense fallback={<CardSkeleton />}>
137
138
  <ClientHeavyComponent />
138
139
  </Suspense>
139
140
  );
140
141
  }
141
142
  ```
142
143
 
143
- Both `<Suspense>` and `<LoadingSkeleton>` are server-safe.
144
+ Both `<Suspense>` and the skeletons are server-safe. The module exports
145
+ `CardSkeleton`, `TableSkeleton`, `BoardSkeleton` and `ListSkeleton` — pick the
146
+ one whose shape matches what is loading.
144
147
 
145
148
  ## Common RSC mistakes
146
149
 
@@ -91,6 +91,7 @@ After editing, delete the lockfile + `node_modules` and reinstall.
91
91
 
92
92
  Add:
93
93
 
94
+ <!-- typecheck-skip: a fragment of next.config, not a standalone module -->
94
95
  ```ts
95
96
  transpilePackages: ["@devalok/shilp-sutra"],
96
97
  ```
package/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # @devalok/shilp-sutra
2
2
 
3
- > Radix UI + Tailwind 4 (CSS-first) + CVA design system for Devalok apps, v0.56.0.
3
+ > Radix UI + Tailwind 4 (CSS-first) + CVA design system for Devalok apps, v0.59.0.
4
4
  > Built on the same primitives as shadcn/ui but with DIFFERENT prop APIs — never guess from shadcn knowledge; verify every prop.
5
5
  > This file is a ROUTER: it tells you what exists and where to get details. Do not look for prop tables here — fetch them per component (MCP tool or per-component doc file below).
6
6
 
@@ -152,6 +152,7 @@ Format: `[name](doc path): summary`. Import paths follow `@devalok/shilp-sutra/<
152
152
 
153
153
  ### shell
154
154
  - [app-command-palette](docs/components/shell/app-command-palette.md)
155
+ - [app-shell](docs/components/shell/app-shell.md)
155
156
  - [bottom-navbar](docs/components/shell/bottom-navbar.md)
156
157
  - [command-registry](docs/components/shell/command-registry.md): Exports: CommandRegistryProvider, useCommandRegistry
157
158
  - [link-context](docs/components/shell/link-context.md): Exports: LinkProvider, useLink
@@ -22,10 +22,10 @@
22
22
  These are not preferences. Generated code that violates them is wrong.
23
23
 
24
24
  1. **Use design system components, not raw HTML.** `<Button>` not `<button>`. `<Input>` not `<input>`. `<Text>` not `<span>`/`<p>` (when typographic semantics matter). `<Stack>` not bare flex divs.
25
- 2. **Use semantic tokens, never hex / rgb / hsl.** `bg-surface-raised` not `bg-white`. `text-fg` not `text-zinc-900`. `bg-accent-9` not `bg-pink-500`.
25
+ 2. **Use semantic tokens, never hex / rgb / hsl.** `bg-surface-panel` not `bg-white`. `text-fg` not `text-zinc-900`. `bg-accent-9` not `bg-pink-500`.
26
26
  3. **Spacing uses `ds-*` cadence.** `p-ds-05`, `gap-ds-03`. Never `p-4` / `p-6`. Default cadence is `ds-03 / ds-05 / ds-07` (related items / grouped sections / page sections). Do not reach for every adjacent token (`ds-04`, `ds-06`) — three tiers, not five.
27
27
  4. **Prefer `variant="soft"` over `variant="outline"` for non-primary actions.** Soft (tinted bg, no visible border) reads better in data-dense UIs. Outline only when on a colored bg or paired with a primary for explicit hierarchy.
28
- 5. **Surface layering is strict.** Page = `surface-base`. Cards/panels/widgets = `surface-raised`. Dialogs/popovers/dropdowns/inputs = `surface-overlay`. Shell chrome (sidebar, topbar) = `surface-sunken`. Tooltips = `surface-inverted`. If you're unsure, read `foundations/surfaces.md`.
28
+ 5. **Surface layering is strict.** Page = `surface-base`. Cards/panels/widgets = `surface-panel`. Dialogs/popovers/dropdowns/inputs = `surface-overlay`. Shell chrome (sidebar, topbar) = `surface-sunken`. Tooltips = `surface-inverted`. If you're unsure, read `foundations/surfaces.md`.
29
29
  6. **Never combine `border-*` + `shadow-*` tokens.** Shadow tokens already include a 1px ring layer. Adding an explicit border creates a 2-px edge.
30
30
  7. **Icons use `<Icon icon={...} />` from `@tabler/icons-react`.** Do not import lucide, heroicons, mui-icons. The icon system auto-sizes via `IconProvider` context.
31
31
  8. **Toasts mount once at app root.** `<Toaster />` (singleton). All triggering is imperative: `toast.success("...")`, `toast.error("...")`.
@@ -19,7 +19,7 @@ import { Button } from '@devalok/shilp-sutra/ui/button'
19
19
  |---|---|
20
20
  | `solid` (default) | Primary CTA. One per region. Heavy visual weight. |
21
21
  | `soft` | Secondary action. **Preferred default for any non-primary action.** Tinted bg, colored text, no visible border — warmer than outline, brand-consistent. |
22
- | `outline` | Secondary action on a colored / `surface-raised` bg where soft's tint disappears. In toolbars / icon-dense rows. Paired adjacent to a primary that needs explicit hierarchy. |
22
+ | `outline` | Secondary action on a colored / `surface-panel` bg where soft's tint disappears. In toolbars / icon-dense rows. Paired adjacent to a primary that needs explicit hierarchy. |
23
23
  | `ghost` | Tertiary / dismissive — close, cancel, skip. Minimal weight. |
24
24
  | `link` | Inline action that should read as a link but behave as a button. Use sparingly. |
25
25