@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
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-body.js","names":[],"sources":["../../src/ui/data-table-body.tsx"],"sourcesContent":["'use client'\n\nimport { flexRender,type Row } from '@tanstack/react-table'\nimport { type VirtualItem } from '@tanstack/react-virtual'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport {\n getColumnMetaClasses,\n getPinnedCellStyle,\n INTERACTIVE_SELECTOR,\n isColumnEditable,\n useDataTableContext,\n} from './data-table-context'\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\nimport { Skeleton } from './skeleton'\nimport { TableBody, TableCell, TableRow } from './table'\n\n// ── CellEditInput ───────────────────────────────────────────────\n\n/**\n * Inline edit input rendered inside a table cell.\n * Auto-focuses, saves on Enter/blur, cancels on Escape.\n */\nfunction CellEditInput({\n initialValue,\n onSave,\n onCancel,\n}: {\n initialValue: string\n onSave: (value: string) => void\n onCancel: () => void\n}) {\n const [value, setValue] = useState(initialValue)\n const inputRef = useRef<HTMLInputElement>(null)\n\n useEffect(() => {\n inputRef.current?.focus()\n inputRef.current?.select()\n }, [])\n\n const handleSave = useCallback(() => {\n onSave(value)\n }, [onSave, value])\n\n return (\n <input\n ref={inputRef}\n type=\"text\"\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onBlur={handleSave}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault()\n handleSave()\n } else if (e.key === 'Escape') {\n e.preventDefault()\n onCancel()\n }\n }}\n className={cn(\n 'h-ds-xs-plus w-full rounded-control',\n 'border border-accent-7 bg-surface-raised-hover',\n 'px-ds-02 text-body-sm',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden focus:border-accent-7',\n )}\n aria-label=\"Edit cell value\"\n />\n )\n}\n\n// ── DataRow ─────────────────────────────────────────────────────\n\n/** Render a single data row (shared between virtual and non-virtual paths) */\nfunction DataTableRow<TData>({\n row,\n style,\n}: {\n row: Row<TData>\n style?: React.CSSProperties\n}) {\n const {\n table,\n columnPinningState,\n editable,\n editingCell,\n setEditingCell,\n onCellEdit,\n virtualRows,\n onRowClick,\n } = useDataTableContext<TData>()\n\n const handleRowClick = useCallback(\n (e: React.MouseEvent<HTMLTableRowElement>) => {\n if (!onRowClick) return\n const target = e.target as HTMLElement\n if (target.closest(INTERACTIVE_SELECTOR)) return\n onRowClick(row.original)\n },\n [onRowClick, row.original],\n )\n\n const visibleCells = row.getVisibleCells()\n\n return (\n <TableRow\n data-state={row.getIsSelected() && 'selected'}\n style={style}\n className={cn(\n virtualRows ? 'absolute w-full flex' : undefined,\n onRowClick && 'cursor-pointer',\n )}\n onClick={onRowClick ? handleRowClick : undefined}\n >\n {visibleCells.map((cell) => {\n const pinned = getPinnedCellStyle(cell.column.id, columnPinningState)\n const isEditing =\n editingCell?.rowIndex === row.index &&\n editingCell?.columnId === cell.column.id\n\n return (\n <TableCell\n key={cell.id}\n className={cn(\n pinned.className,\n virtualRows && 'flex-1',\n getColumnMetaClasses(\n cell.column.columnDef.meta as Record<string, unknown>,\n ),\n )}\n style={pinned.style}\n onDoubleClick={() => {\n if (isColumnEditable(cell.column.id, editable, table)) {\n setEditingCell({\n rowIndex: row.index,\n columnId: cell.column.id,\n })\n }\n }}\n >\n {isEditing ? (\n <CellEditInput\n initialValue={String(cell.getValue() ?? '')}\n onSave={(value) => {\n onCellEdit?.(row.index, cell.column.id, value)\n setEditingCell(null)\n }}\n onCancel={() => setEditingCell(null)}\n />\n ) : (\n flexRender(cell.column.columnDef.cell, cell.getContext())\n )}\n </TableCell>\n )\n })}\n </TableRow>\n )\n}\n\n// ── ExpandedRow ─────────────────────────────────────────────────\n\n/** Render expanded content row below the data row */\nfunction DataTableExpandedRow<TData>({\n row,\n style,\n}: {\n row: Row<TData>\n style?: React.CSSProperties\n}) {\n const { allColumns, expandable, renderExpanded, virtualRows } =\n useDataTableContext<TData>()\n // Self-guarded (StatFlash pattern) — reveal collapses to an instant swap\n // without relying on a consumer MotionProvider.\n const prefersReduced = useReducedMotion()\n\n if (!expandable || !renderExpanded) return null\n\n const expanded = row.getIsExpanded()\n\n // Virtual rows are absolutely positioned with measured heights — a height\n // animation would fight the virtualizer, so the reveal is instant there.\n if (virtualRows) {\n if (!expanded) return null\n return (\n <TableRow style={style} className=\"absolute w-full flex\">\n <TableCell\n colSpan={allColumns.length}\n className=\"bg-surface-base p-ds-05 flex-1\"\n >\n {renderExpanded(row.original)}\n </TableCell>\n </TableRow>\n )\n }\n\n return (\n <AnimatePresence initial={false}>\n {expanded && (\n <TableRow style={style}>\n <TableCell\n colSpan={allColumns.length}\n // A recess, not a raised layer — surface-raised would vanish on a\n // card. Padding moves to the inner div so the collapsed state has\n // zero height.\n className=\"bg-surface-base p-0\"\n >\n <motion.div\n className=\"overflow-hidden\"\n initial={prefersReduced ? false : { height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={prefersReduced ? undefined : { height: 0, opacity: 0 }}\n transition={\n prefersReduced ? { duration: 0 } : { ...springs.smooth }\n }\n >\n <div className=\"p-ds-05\">{renderExpanded(row.original)}</div>\n </motion.div>\n </TableCell>\n </TableRow>\n )}\n </AnimatePresence>\n )\n}\n\n// ── SkeletonRows ────────────────────────────────────────────────\n\nfunction DataTableSkeletonRows({\n rowCount,\n}: {\n rowCount: number\n}) {\n const { allColumns } = useDataTableContext()\n const visibleColumnCount = allColumns.length\n const skeletonWidths = ['w-3/4', 'w-1/2', 'w-2/3', 'w-full']\n\n return (\n <TableBody>\n {Array.from({ length: rowCount }, (_, rowIdx) => (\n <TableRow key={`skeleton-${rowIdx}`}>\n {Array.from({ length: visibleColumnCount }, (_, colIdx) => {\n const colId = allColumns[colIdx]?.id ?? allColumns[colIdx]?.header\n const isSelect = colId === '_select'\n return (\n <TableCell key={`skeleton-${rowIdx}-${colIdx}`}>\n {isSelect ? (\n <Skeleton\n variant=\"text\"\n className=\"h-4 w-4\"\n animation=\"pulse\"\n />\n ) : (\n <Skeleton\n variant=\"text\"\n className={cn(\n 'h-4',\n skeletonWidths[colIdx % skeletonWidths.length],\n )}\n animation=\"pulse\"\n />\n )}\n </TableCell>\n )\n })}\n </TableRow>\n ))}\n </TableBody>\n )\n}\n\n// ── DataTableBody (orchestrates all body rendering) ─────────────\n\nexport function DataTableBody<TData>({\n loading,\n skeletonRowCount,\n noResultsText,\n emptyState,\n virtualItems,\n totalVirtualSize,\n}: {\n loading?: boolean\n skeletonRowCount: number\n noResultsText?: string\n emptyState?: React.ReactNode\n virtualItems?: VirtualItem[]\n totalVirtualSize?: number\n}) {\n const { table, allColumns, virtualRows } = useDataTableContext<TData>()\n const rows = table.getRowModel().rows\n\n // Loading state: show skeleton rows\n if (loading) {\n return <DataTableSkeletonRows rowCount={skeletonRowCount} />\n }\n\n if (!rows.length) {\n return (\n <TableBody>\n <TableRow>\n <TableCell\n colSpan={allColumns.length}\n className={cn(\n 'py-ds-07 text-center',\n !emptyState && 'text-surface-fg-subtle',\n )}\n >\n {emptyState || noResultsText || 'No results.'}\n </TableCell>\n </TableRow>\n </TableBody>\n )\n }\n\n if (virtualRows && virtualItems) {\n return (\n <TableBody\n style={{\n height: `${totalVirtualSize}px`,\n position: 'relative',\n }}\n >\n {virtualItems.map((virtualRow) => {\n const row = rows[virtualRow.index]\n return (\n <DataTableRow\n key={row.id}\n row={row}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: `${virtualRow.size}px`,\n transform: `translateY(${virtualRow.start}px)`,\n }}\n />\n )\n })}\n </TableBody>\n )\n }\n\n // Standard (non-virtual) rendering\n return (\n <TableBody>\n {rows.map((row) => (\n <React.Fragment key={row.id}>\n <DataTableRow row={row} />\n <DataTableExpandedRow row={row} />\n </React.Fragment>\n ))}\n </TableBody>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"data-table-body.js","names":[],"sources":["../../src/ui/data-table-body.tsx"],"sourcesContent":["'use client'\n\nimport { flexRender,type Row } from '@tanstack/react-table'\nimport { type VirtualItem } from '@tanstack/react-virtual'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport {\n getColumnMetaClasses,\n getPinnedCellStyle,\n INTERACTIVE_SELECTOR,\n isColumnEditable,\n useDataTableContext,\n} from './data-table-context'\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\nimport { Skeleton } from './skeleton'\nimport { TableBody, TableCell, TableRow } from './table'\n\n// ── CellEditInput ───────────────────────────────────────────────\n\n/**\n * Inline edit input rendered inside a table cell.\n * Auto-focuses, saves on Enter/blur, cancels on Escape.\n */\nfunction CellEditInput({\n initialValue,\n onSave,\n onCancel,\n}: {\n initialValue: string\n onSave: (value: string) => void\n onCancel: () => void\n}) {\n const [value, setValue] = useState(initialValue)\n const inputRef = useRef<HTMLInputElement>(null)\n\n useEffect(() => {\n inputRef.current?.focus()\n inputRef.current?.select()\n }, [])\n\n const handleSave = useCallback(() => {\n onSave(value)\n }, [onSave, value])\n\n return (\n <input\n ref={inputRef}\n type=\"text\"\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onBlur={handleSave}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault()\n handleSave()\n } else if (e.key === 'Escape') {\n e.preventDefault()\n onCancel()\n }\n }}\n className={cn(\n 'h-ds-xs-plus w-full rounded-control',\n 'border border-accent-7 bg-surface-panel-hover',\n 'px-ds-02 text-body-sm',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden focus:border-accent-7',\n )}\n aria-label=\"Edit cell value\"\n />\n )\n}\n\n// ── DataRow ─────────────────────────────────────────────────────\n\n/** Render a single data row (shared between virtual and non-virtual paths) */\nfunction DataTableRow<TData>({ row }: { row: Row<TData> }) {\n const {\n table,\n columnPinningState,\n editable,\n editingCell,\n setEditingCell,\n onCellEdit,\n onRowClick,\n rowClassName,\n } = useDataTableContext<TData>()\n\n const handleRowClick = useCallback(\n (e: React.MouseEvent<HTMLTableRowElement>) => {\n if (!onRowClick) return\n const target = e.target as HTMLElement\n if (target.closest(INTERACTIVE_SELECTOR)) return\n onRowClick(row.original)\n },\n [onRowClick, row.original],\n )\n\n const visibleCells = row.getVisibleCells()\n\n return (\n <TableRow\n data-state={row.getIsSelected() && 'selected'}\n className={cn(\n onRowClick && 'cursor-pointer',\n rowClassName?.(row.original),\n )}\n onClick={onRowClick ? handleRowClick : undefined}\n >\n {visibleCells.map((cell) => {\n const pinned = getPinnedCellStyle(cell.column.id, columnPinningState)\n const isEditing =\n editingCell?.rowIndex === row.index &&\n editingCell?.columnId === cell.column.id\n\n return (\n <TableCell\n key={cell.id}\n className={cn(\n pinned.className,\n getColumnMetaClasses(\n cell.column.columnDef.meta as Record<string, unknown>,\n ),\n )}\n style={pinned.style}\n onDoubleClick={() => {\n if (isColumnEditable(cell.column.id, editable, table)) {\n setEditingCell({\n rowIndex: row.index,\n columnId: cell.column.id,\n })\n }\n }}\n >\n {isEditing ? (\n <CellEditInput\n initialValue={String(cell.getValue() ?? '')}\n onSave={(value) => {\n onCellEdit?.(row.index, cell.column.id, value)\n setEditingCell(null)\n }}\n onCancel={() => setEditingCell(null)}\n />\n ) : (\n flexRender(cell.column.columnDef.cell, cell.getContext())\n )}\n </TableCell>\n )\n })}\n </TableRow>\n )\n}\n\n// ── ExpandedRow ─────────────────────────────────────────────────\n\n/** Render expanded content row below the data row */\nfunction DataTableExpandedRow<TData>({ row }: { row: Row<TData> }) {\n const { allColumns, expandable, renderExpanded, virtualRows } =\n useDataTableContext<TData>()\n // Self-guarded (StatFlash pattern) — reveal collapses to an instant swap\n // without relying on a consumer MotionProvider.\n const prefersReduced = useReducedMotion()\n\n if (!expandable || !renderExpanded) return null\n\n const expanded = row.getIsExpanded()\n\n // In virtual mode the reveal is instant: the row group's height is watched by\n // the virtualizer's ResizeObserver, and an animating height would fire a\n // resize on every frame of the spring.\n if (virtualRows) {\n if (!expanded) return null\n return (\n <TableRow>\n <TableCell colSpan={allColumns.length} className=\"bg-surface-sunken p-ds-05\">\n {renderExpanded(row.original)}\n </TableCell>\n </TableRow>\n )\n }\n\n return (\n <AnimatePresence initial={false}>\n {expanded && (\n <TableRow>\n <TableCell\n colSpan={allColumns.length}\n // A recess, not a raised layer — surface-panel would vanish on a\n // card. Padding moves to the inner div so the collapsed state has\n // zero height.\n className=\"bg-surface-sunken p-0\"\n >\n <motion.div\n className=\"overflow-hidden\"\n initial={prefersReduced ? false : { height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={prefersReduced ? undefined : { height: 0, opacity: 0 }}\n transition={\n prefersReduced ? { duration: 0 } : { ...springs.smooth }\n }\n >\n <div className=\"p-ds-05\">{renderExpanded(row.original)}</div>\n </motion.div>\n </TableCell>\n </TableRow>\n )}\n </AnimatePresence>\n )\n}\n\n// ── SkeletonRows ────────────────────────────────────────────────\n\nfunction DataTableSkeletonRows({\n rowCount,\n}: {\n rowCount: number\n}) {\n const { allColumns } = useDataTableContext()\n const visibleColumnCount = allColumns.length\n const skeletonWidths = ['w-3/4', 'w-1/2', 'w-2/3', 'w-full']\n\n return (\n <TableBody>\n {Array.from({ length: rowCount }, (_, rowIdx) => (\n <TableRow key={`skeleton-${rowIdx}`}>\n {Array.from({ length: visibleColumnCount }, (_, colIdx) => {\n const colId = allColumns[colIdx]?.id ?? allColumns[colIdx]?.header\n const isSelect = colId === '_select'\n return (\n <TableCell key={`skeleton-${rowIdx}-${colIdx}`}>\n {isSelect ? (\n <Skeleton\n variant=\"text\"\n className=\"h-4 w-4\"\n animation=\"pulse\"\n />\n ) : (\n <Skeleton\n variant=\"text\"\n className={cn(\n 'h-4',\n skeletonWidths[colIdx % skeletonWidths.length],\n )}\n animation=\"pulse\"\n />\n )}\n </TableCell>\n )\n })}\n </TableRow>\n ))}\n </TableBody>\n )\n}\n\n// ── DataTableBody (orchestrates all body rendering) ─────────────\n\nexport function DataTableBody<TData>({\n loading,\n skeletonRowCount,\n noResultsText,\n emptyState,\n virtualItems,\n totalVirtualSize,\n measureRow,\n}: {\n loading?: boolean\n skeletonRowCount: number\n noResultsText?: string\n emptyState?: React.ReactNode\n virtualItems?: VirtualItem[]\n totalVirtualSize?: number\n /** `virtualizer.measureElement` — attached to each virtual row group */\n measureRow?: (node: HTMLTableSectionElement | null) => void\n}) {\n const { table, allColumns, virtualRows } = useDataTableContext<TData>()\n const rows = table.getRowModel().rows\n\n // Loading state: show skeleton rows\n if (loading) {\n return <DataTableSkeletonRows rowCount={skeletonRowCount} />\n }\n\n if (!rows.length) {\n return (\n <TableBody>\n <TableRow>\n <TableCell\n colSpan={allColumns.length}\n className={cn(\n 'py-ds-07 text-center',\n !emptyState && 'text-surface-fg-subtle',\n )}\n >\n {emptyState || noResultsText || 'No results.'}\n </TableCell>\n </TableRow>\n </TableBody>\n )\n }\n\n if (virtualRows && virtualItems) {\n // Each windowed row gets its OWN <tbody> (valid HTML — a table may hold any\n // number of row groups) carrying `data-index` + the virtualizer's\n // `measureElement` ref. That group is what gets measured, so a row's height\n // INCLUDES its expanded detail row and `getTotalSize()` stays truthful.\n //\n // Rows stay in normal table flow; the window is positioned by spacer row\n // groups above and below instead of absolute offsets. Two consequences worth\n // knowing: an expanded panel can never paint on top of the next row (flow\n // layout forbids it), and column widths keep tracking <thead> because the\n // cells are still real table cells.\n const firstItem = virtualItems[0]\n const lastItem = virtualItems[virtualItems.length - 1]\n const padTop = firstItem ? firstItem.start : 0\n const padBottom = lastItem ? Math.max(0, (totalVirtualSize ?? 0) - lastItem.end) : 0\n const spacerCell = (height: number) => (\n <tbody aria-hidden=\"true\">\n <tr>\n <td colSpan={allColumns.length} style={{ height, padding: 0, border: 0 }} />\n </tr>\n </tbody>\n )\n\n return (\n <>\n {padTop > 0 && spacerCell(padTop)}\n {virtualItems.map((virtualRow) => {\n const row = rows[virtualRow.index]\n const isLastRow = virtualRow.index === rows.length - 1\n return (\n <tbody\n key={row.id}\n ref={measureRow}\n data-index={virtualRow.index}\n className={cn(isLastRow && '[&_tr:last-child]:border-0')}\n >\n <DataTableRow row={row} />\n <DataTableExpandedRow row={row} />\n </tbody>\n )\n })}\n {padBottom > 0 && spacerCell(padBottom)}\n </>\n )\n }\n\n // Standard (non-virtual) rendering\n return (\n <TableBody>\n {rows.map((row) => (\n <React.Fragment key={row.id}>\n <DataTableRow row={row} />\n <DataTableExpandedRow row={row} />\n </React.Fragment>\n ))}\n </TableBody>\n )\n}\n"],"mappings":";;;;;;;;;;;AAyBA,SAAS,EAAc,EACrB,iBACA,WACA,eAKC;CACD,IAAM,CAAC,GAAO,KAAY,EAAS,CAAY,GACzC,IAAW,EAAyB,IAAI;CAE9C,QAAgB;EAEd,AADA,EAAS,SAAS,MAAM,GACxB,EAAS,SAAS,OAAO;CAC3B,GAAG,CAAC,CAAC;CAEL,IAAM,IAAa,QAAkB;EACnC,EAAO,CAAK;CACd,GAAG,CAAC,GAAQ,CAAK,CAAC;CAElB,OACE,kBAAC,SAAD;EACE,KAAK;EACL,MAAK;EACE;EACP,WAAW,MAAM,EAAS,EAAE,OAAO,KAAK;EACxC,QAAQ;EACR,YAAY,MAAM;GAChB,AAAI,EAAE,QAAQ,WACZ,EAAE,eAAe,GACjB,EAAW,KACF,EAAE,QAAQ,aACnB,EAAE,eAAe,GACjB,EAAS;EAEb;EACA,WAAW,EACT,uCACA,iDACA,yBACA,sDACA,sCACF;EACA,cAAW;CACZ,CAAA;AAEL;AAKA,SAAS,EAAoB,EAAE,UAA4B;CACzD,IAAM,EACJ,UACA,uBACA,aACA,gBACA,mBACA,eACA,eACA,oBACE,EAA2B,GAEzB,IAAiB,GACpB,MAA6C;EACvC,MACU,EAAE,OACN,QAAA,yDAA4B,KACvC,EAAW,EAAI,QAAQ;CACzB,GACA,CAAC,GAAY,EAAI,QAAQ,CAC3B,GAEM,IAAe,EAAI,gBAAgB;CAEzC,OACE,kBAAC,GAAD;EACE,cAAY,EAAI,cAAc,KAAK;EACnC,WAAW,EACT,KAAc,kBACd,IAAe,EAAI,QAAQ,CAC7B;EACA,SAAS,IAAa,IAAiB,KAAA;YAEtC,EAAa,KAAK,MAAS;GAC1B,IAAM,IAAS,EAAmB,EAAK,OAAO,IAAI,CAAkB,GAC9D,IACJ,GAAa,aAAa,EAAI,SAC9B,GAAa,aAAa,EAAK,OAAO;GAExC,OACE,kBAAC,GAAD;IAEE,WAAW,EACT,EAAO,WACP,EACE,EAAK,OAAO,UAAU,IACxB,CACF;IACA,OAAO,EAAO;IACd,qBAAqB;KACnB,AAAI,EAAiB,EAAK,OAAO,IAAI,GAAU,CAAK,KAClD,EAAe;MACb,UAAU,EAAI;MACd,UAAU,EAAK,OAAO;KACxB,CAAC;IAEL;cAEC,IACC,kBAAC,GAAD;KACE,cAAc,OAAO,EAAK,SAAS,KAAK,EAAE;KAC1C,SAAS,MAAU;MAEjB,AADA,IAAa,EAAI,OAAO,EAAK,OAAO,IAAI,CAAK,GAC7C,EAAe,IAAI;KACrB;KACA,gBAAgB,EAAe,IAAI;IACpC,CAAA,IAED,EAAW,EAAK,OAAO,UAAU,MAAM,EAAK,WAAW,CAAC;GAEjD,GA7BJ,EAAK,EA6BD;EAEf,CAAC;CACO,CAAA;AAEd;AAKA,SAAS,EAA4B,EAAE,UAA4B;CACjE,IAAM,EAAE,eAAY,eAAY,mBAAgB,mBAC9C,EAA2B,GAGvB,IAAiB,EAAiB;CAExC,IAAI,CAAC,KAAc,CAAC,GAAgB,OAAO;CAE3C,IAAM,IAAW,EAAI,cAAc;CAgBnC,OAXI,IACG,IAEH,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EAAW,SAAS,EAAW;EAAQ,WAAU;YAC9C,EAAe,EAAI,QAAQ;CACnB,CAAA,EACH,CAAA,IANU,OAWtB,kBAAC,GAAD;EAAiB,SAAS;YACvB,KACC,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;GACE,SAAS,EAAW;GAIpB,WAAU;aAEV,kBAAC,EAAO,KAAR;IACE,WAAU;IACV,SAAS,MAAyB;KAAE,QAAQ;KAAG,SAAS;IAAE;IAC1D,SAAS;KAAE,QAAQ;KAAQ,SAAS;IAAE;IACtC,MAAM,IAAiB,KAAA,IAAY;KAAE,QAAQ;KAAG,SAAS;IAAE;IAC3D,YACE,IAAiB,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAQ,OAAO;cAGzD,kBAAC,OAAD;KAAK,WAAU;eAAW,EAAe,EAAI,QAAQ;IAAO,CAAA;GAClD,CAAA;EACH,CAAA,EACH,CAAA;CAEG,CAAA;AAErB;AAIA,SAAS,EAAsB,EAC7B,eAGC;CACD,IAAM,EAAE,kBAAe,EAAoB,GACrC,IAAqB,EAAW,QAChC,IAAiB;EAAC;EAAS;EAAS;EAAS;CAAQ;CAE3D,OACE,kBAAC,GAAD,EAAA,UACG,MAAM,KAAK,EAAE,QAAQ,EAAS,IAAI,GAAG,MACpC,kBAAC,GAAD,EAAA,UACG,MAAM,KAAK,EAAE,QAAQ,EAAmB,IAAI,GAAG,MAI5C,kBAAC,GAAD,EAAA,WAHY,EAAW,EAAO,EAAE,MAAM,EAAW,EAAO,EAAE,YACjC,YAIrB,kBAAC,GAAD;EACE,SAAQ;EACR,WAAU;EACV,WAAU;CACX,CAAA,IAED,kBAAC,GAAD;EACE,SAAQ;EACR,WAAW,EACT,OACA,EAAe,IAAS,EAAe,OACzC;EACA,WAAU;CACX,CAAA,EAEM,GAjBK,YAAY,EAAO,GAAG,GAiB3B,CAEd,EACO,GAzBK,YAAY,GAyBjB,CACX,EACQ,CAAA;AAEf;AAIA,SAAgB,EAAqB,EACnC,YACA,qBACA,kBACA,eACA,iBACA,qBACA,iBAUC;CACD,IAAM,EAAE,UAAO,eAAY,mBAAgB,EAA2B,GAChE,IAAO,EAAM,YAAY,CAAC,CAAC;CAGjC,IAAI,GACF,OAAO,kBAAC,GAAD,EAAuB,UAAU,EAAmB,CAAA;CAG7D,IAAI,CAAC,EAAK,QACR,OACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EACE,SAAS,EAAW;EACpB,WAAW,EACT,wBACA,CAAC,KAAc,wBACjB;YAEC,KAAc,KAAiB;CACvB,CAAA,EACH,CAAA,EACD,CAAA;CAIf,IAAI,KAAe,GAAc;EAW/B,IAAM,IAAY,EAAa,IACzB,IAAW,EAAa,EAAa,SAAS,IAC9C,IAAS,IAAY,EAAU,QAAQ,GACvC,IAAY,IAAW,KAAK,IAAI,IAAI,KAAoB,KAAK,EAAS,GAAG,IAAI,GAC7E,KAAc,MAClB,kBAAC,SAAD;GAAO,eAAY;aACjB,kBAAC,MAAD,EAAA,UACE,kBAAC,MAAD;IAAI,SAAS,EAAW;IAAQ,OAAO;KAAE;KAAQ,SAAS;KAAG,QAAQ;IAAE;GAAI,CAAA,EACzE,CAAA;EACC,CAAA;EAGT,OACE,kBAAA,GAAA,EAAA,UAAA;GACG,IAAS,KAAK,EAAW,CAAM;GAC/B,EAAa,KAAK,MAAe;IAChC,IAAM,IAAM,EAAK,EAAW,QACtB,IAAY,EAAW,UAAU,EAAK,SAAS;IACrD,OACE,kBAAC,SAAD;KAEE,KAAK;KACL,cAAY,EAAW;KACvB,WAAW,EAAG,KAAa,4BAA4B;eAJzD,CAME,kBAAC,GAAD,EAAmB,OAAM,CAAA,GACzB,kBAAC,GAAD,EAA2B,OAAM,CAAA,CAC5B;OAPA,EAAI,EAOJ;GAEX,CAAC;GACA,IAAY,KAAK,EAAW,CAAS;EACtC,EAAA,CAAA;CAEN;CAGA,OACE,kBAAC,GAAD,EAAA,UACG,EAAK,KAAK,MACT,kBAAC,EAAM,UAAP,EAAA,UAAA,CACE,kBAAC,GAAD,EAAmB,OAAM,CAAA,GACzB,kBAAC,GAAD,EAA2B,OAAM,CAAA,CACnB,EAAA,GAHK,EAAI,EAGT,CACjB,EACQ,CAAA;AAEf"}
@@ -1,9 +1,14 @@
1
1
  import { Table } from '@tanstack/react-table';
2
2
  import { default as React } from 'react';
3
+ import { IconInput } from './lib/icon-input.js';
4
+ /** Where the floating bulk-action bar renders. @default 'bottom' */
5
+ export type BulkActionsPosition = 'bottom' | 'top' | 'inline';
3
6
  /** Bulk action definition for the floating action bar */
4
7
  export interface BulkAction<TData> {
5
8
  label: string;
6
9
  onClick: (selectedRows: TData[]) => void;
10
+ /** Icon rendered before the label — useful for compact/mobile bars. */
11
+ icon?: IconInput;
7
12
  color?: 'accent' | 'error';
8
13
  disabled?: boolean;
9
14
  }
@@ -11,9 +16,10 @@ export interface BulkAction<TData> {
11
16
  * Floating action bar shown when rows are selected.
12
17
  * Internal — not exported to consumers.
13
18
  */
14
- export declare function DataTableBulkActions<TData>({ table, selectedRows, bulkActions, }: {
19
+ export declare function DataTableBulkActions<TData>({ table, selectedRows, bulkActions, position, }: {
15
20
  table: Table<TData>;
16
21
  selectedRows: TData[];
17
22
  bulkActions: BulkAction<TData>[];
23
+ position?: BulkActionsPosition;
18
24
  }): React.JSX.Element;
19
25
  //# sourceMappingURL=data-table-bulk-actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-bulk-actions.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-bulk-actions.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,yDAAyD;AACzD,MAAM,WAAW,UAAU,CAAC,KAAK;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,IAAI,CAAA;IACxC,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,EAC1C,KAAK,EACL,YAAY,EACZ,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IACnB,YAAY,EAAE,KAAK,EAAE,CAAA;IACrB,WAAW,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAA;CACjC,qBA0CA"}
1
+ {"version":3,"file":"data-table-bulk-actions.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-bulk-actions.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAGjD,oEAAoE;AACpE,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,CAAA;AAE7D,yDAAyD;AACzD,MAAM,WAAW,UAAU,CAAC,KAAK;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,IAAI,CAAA;IACxC,uEAAuE;IACvE,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAQD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,EAC1C,KAAK,EACL,YAAY,EACZ,WAAW,EACX,QAAmB,GACpB,EAAE;IACD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IACnB,YAAY,EAAE,KAAK,EAAE,CAAA;IACrB,WAAW,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAA;IAChC,QAAQ,CAAC,EAAE,mBAAmB,CAAA;CAC/B,qBA0CA"}
@@ -6,33 +6,39 @@ import "react";
6
6
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
7
7
  import { IconX as a } from "@tabler/icons-react";
8
8
  //#region src/ui/data-table-bulk-actions.tsx
9
- function o({ table: o, selectedRows: s, bulkActions: c }) {
9
+ var o = {
10
+ bottom: "fixed bottom-6 left-1/2 -translate-x-1/2 z-sticky animate-in slide-in-from-bottom-2",
11
+ top: "fixed top-6 left-1/2 -translate-x-1/2 z-sticky animate-in slide-in-from-top-2",
12
+ inline: "relative animate-in fade-in"
13
+ };
14
+ function s({ table: s, selectedRows: c, bulkActions: l, position: u = "bottom" }) {
10
15
  return /* @__PURE__ */ i("div", {
11
- className: e("fixed bottom-6 left-1/2 -translate-x-1/2 z-sticky", "flex items-center gap-ds-04 px-ds-05 py-ds-03", "rounded-overlay bg-surface-overlay shadow-floating", "animate-in slide-in-from-bottom-2"),
16
+ className: e(o[u], "flex items-center gap-ds-04 px-ds-05 py-ds-03", "rounded-overlay bg-surface-overlay shadow-floating"),
12
17
  role: "toolbar",
13
18
  "aria-label": "Bulk actions",
14
19
  children: [
15
20
  /* @__PURE__ */ i("span", {
16
21
  className: "text-body-sm font-medium text-surface-fg whitespace-nowrap",
17
- children: [s.length, " selected"]
22
+ children: [c.length, " selected"]
18
23
  }),
19
24
  /* @__PURE__ */ r("div", {
20
25
  className: "h-5 w-px bg-surface-border",
21
26
  "aria-hidden": "true"
22
27
  }),
23
- c.map((e) => /* @__PURE__ */ r(n, {
28
+ l.map((e) => /* @__PURE__ */ r(n, {
24
29
  size: "sm",
25
30
  variant: e.color === "error" ? "solid" : "outline",
26
31
  color: e.color === "error" ? "error" : void 0,
27
32
  disabled: e.disabled,
28
- onClick: () => e.onClick(s),
33
+ startIcon: e.icon,
34
+ onClick: () => e.onClick(c),
29
35
  children: e.label
30
36
  }, e.label)),
31
37
  /* @__PURE__ */ r("button", {
32
38
  type: "button",
33
- onClick: () => o.resetRowSelection(),
39
+ onClick: () => s.resetRowSelection(),
34
40
  "aria-label": "Clear selection",
35
- className: e("flex items-center justify-center p-ds-01", "rounded-control-inner hover:bg-surface-raised transition-colors", "text-surface-fg-muted hover:text-surface-fg"),
41
+ className: e("flex items-center justify-center p-ds-01", "rounded-control-inner hover:bg-surface-panel-hover transition-colors", "text-surface-fg-muted hover:text-surface-fg"),
36
42
  children: /* @__PURE__ */ r(t, {
37
43
  icon: a,
38
44
  size: "sm"
@@ -42,4 +48,4 @@ function o({ table: o, selectedRows: s, bulkActions: c }) {
42
48
  });
43
49
  }
44
50
  //#endregion
45
- export { o as DataTableBulkActions };
51
+ export { s as DataTableBulkActions };
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-bulk-actions.js","names":[],"sources":["../../src/ui/data-table-bulk-actions.tsx"],"sourcesContent":["'use client'\n\nimport { IconX } from '@tabler/icons-react'\nimport { type Table } from '@tanstack/react-table'\nimport React from 'react'\n\nimport { Button } from './button'\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\n/** Bulk action definition for the floating action bar */\nexport interface BulkAction<TData> {\n label: string\n onClick: (selectedRows: TData[]) => void\n color?: 'accent' | 'error'\n disabled?: boolean\n}\n\n/**\n * Floating action bar shown when rows are selected.\n * Internal — not exported to consumers.\n */\nexport function DataTableBulkActions<TData>({\n table,\n selectedRows,\n bulkActions,\n}: {\n table: Table<TData>\n selectedRows: TData[]\n bulkActions: BulkAction<TData>[]\n}) {\n return (\n <div\n className={cn(\n 'fixed bottom-6 left-1/2 -translate-x-1/2 z-sticky',\n 'flex items-center gap-ds-04 px-ds-05 py-ds-03',\n 'rounded-overlay bg-surface-overlay shadow-floating',\n 'animate-in slide-in-from-bottom-2',\n )}\n role=\"toolbar\"\n aria-label=\"Bulk actions\"\n >\n <span className=\"text-body-sm font-medium text-surface-fg whitespace-nowrap\">\n {selectedRows.length} selected\n </span>\n <div className=\"h-5 w-px bg-surface-border\" aria-hidden=\"true\" />\n {bulkActions.map((action) => (\n <Button\n key={action.label}\n size=\"sm\"\n variant={action.color === 'error' ? 'solid' : 'outline'}\n color={action.color === 'error' ? 'error' : undefined}\n disabled={action.disabled}\n onClick={() => action.onClick(selectedRows)}\n >\n {action.label}\n </Button>\n ))}\n <button\n type=\"button\"\n onClick={() => table.resetRowSelection()}\n aria-label=\"Clear selection\"\n className={cn(\n 'flex items-center justify-center p-ds-01',\n 'rounded-control-inner hover:bg-surface-raised transition-colors',\n 'text-surface-fg-muted hover:text-surface-fg',\n )}\n >\n <Icon icon={IconX} size=\"sm\" />\n </button>\n </div>\n )\n}\n"],"mappings":";;;;;;;;AAsBA,SAAgB,EAA4B,EAC1C,UACA,iBACA,kBAKC;CACD,OACE,kBAAC,OAAD;EACE,WAAW,EACT,qDACA,iDACA,sDACA,mCACF;EACA,MAAK;EACL,cAAW;YARb;GAUE,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACG,EAAa,QAAO,WACjB;;GACN,kBAAC,OAAD;IAAK,WAAU;IAA6B,eAAY;GAAQ,CAAA;GAC/D,EAAY,KAAK,MAChB,kBAAC,GAAD;IAEE,MAAK;IACL,SAAS,EAAO,UAAU,UAAU,UAAU;IAC9C,OAAO,EAAO,UAAU,UAAU,UAAU,KAAA;IAC5C,UAAU,EAAO;IACjB,eAAe,EAAO,QAAQ,CAAY;cAEzC,EAAO;GACF,GARD,EAAO,KAQN,CACT;GACD,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAM,kBAAkB;IACvC,cAAW;IACX,WAAW,EACT,4CACA,mEACA,6CACF;cAEA,kBAAC,GAAD;KAAM,MAAM;KAAO,MAAK;IAAM,CAAA;GACxB,CAAA;EACL;;AAET"}
1
+ {"version":3,"file":"data-table-bulk-actions.js","names":[],"sources":["../../src/ui/data-table-bulk-actions.tsx"],"sourcesContent":["'use client'\n\nimport { IconX } from '@tabler/icons-react'\nimport { type Table } from '@tanstack/react-table'\nimport React from 'react'\n\nimport { Button } from './button'\nimport { Icon } from './icon'\nimport type { IconInput } from './lib/icon-input'\nimport { cn } from './lib/utils'\n\n/** Where the floating bulk-action bar renders. @default 'bottom' */\nexport type BulkActionsPosition = 'bottom' | 'top' | 'inline'\n\n/** Bulk action definition for the floating action bar */\nexport interface BulkAction<TData> {\n label: string\n onClick: (selectedRows: TData[]) => void\n /** Icon rendered before the label — useful for compact/mobile bars. */\n icon?: IconInput\n color?: 'accent' | 'error'\n disabled?: boolean\n}\n\nconst POSITION_CLASSES: Record<BulkActionsPosition, string> = {\n bottom: 'fixed bottom-6 left-1/2 -translate-x-1/2 z-sticky animate-in slide-in-from-bottom-2',\n top: 'fixed top-6 left-1/2 -translate-x-1/2 z-sticky animate-in slide-in-from-top-2',\n inline: 'relative animate-in fade-in',\n}\n\n/**\n * Floating action bar shown when rows are selected.\n * Internal — not exported to consumers.\n */\nexport function DataTableBulkActions<TData>({\n table,\n selectedRows,\n bulkActions,\n position = 'bottom',\n}: {\n table: Table<TData>\n selectedRows: TData[]\n bulkActions: BulkAction<TData>[]\n position?: BulkActionsPosition\n}) {\n return (\n <div\n className={cn(\n POSITION_CLASSES[position],\n 'flex items-center gap-ds-04 px-ds-05 py-ds-03',\n 'rounded-overlay bg-surface-overlay shadow-floating',\n )}\n role=\"toolbar\"\n aria-label=\"Bulk actions\"\n >\n <span className=\"text-body-sm font-medium text-surface-fg whitespace-nowrap\">\n {selectedRows.length} selected\n </span>\n <div className=\"h-5 w-px bg-surface-border\" aria-hidden=\"true\" />\n {bulkActions.map((action) => (\n <Button\n key={action.label}\n size=\"sm\"\n variant={action.color === 'error' ? 'solid' : 'outline'}\n color={action.color === 'error' ? 'error' : undefined}\n disabled={action.disabled}\n startIcon={action.icon}\n onClick={() => action.onClick(selectedRows)}\n >\n {action.label}\n </Button>\n ))}\n <button\n type=\"button\"\n onClick={() => table.resetRowSelection()}\n aria-label=\"Clear selection\"\n className={cn(\n 'flex items-center justify-center p-ds-01',\n 'rounded-control-inner hover:bg-surface-panel-hover transition-colors',\n 'text-surface-fg-muted hover:text-surface-fg',\n )}\n >\n <Icon icon={IconX} size=\"sm\" />\n </button>\n </div>\n )\n}\n"],"mappings":";;;;;;;;AAwBA,IAAM,IAAwD;CAC5D,QAAQ;CACR,KAAK;CACL,QAAQ;AACV;AAMA,SAAgB,EAA4B,EAC1C,UACA,iBACA,gBACA,cAAW,YAMV;CACD,OACE,kBAAC,OAAD;EACE,WAAW,EACT,EAAiB,IACjB,iDACA,oDACF;EACA,MAAK;EACL,cAAW;YAPb;GASE,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACG,EAAa,QAAO,WACjB;;GACN,kBAAC,OAAD;IAAK,WAAU;IAA6B,eAAY;GAAQ,CAAA;GAC/D,EAAY,KAAK,MAChB,kBAAC,GAAD;IAEE,MAAK;IACL,SAAS,EAAO,UAAU,UAAU,UAAU;IAC9C,OAAO,EAAO,UAAU,UAAU,UAAU,KAAA;IAC5C,UAAU,EAAO;IACjB,WAAW,EAAO;IAClB,eAAe,EAAO,QAAQ,CAAY;cAEzC,EAAO;GACF,GATD,EAAO,KASN,CACT;GACD,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAM,kBAAkB;IACvC,cAAW;IACX,WAAW,EACT,4CACA,wEACA,6CACF;cAEA,kBAAC,GAAD;KAAM,MAAM;KAAO,MAAK;IAAM,CAAA;GACxB,CAAA;EACL;;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-card.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-card.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAA;AAazB,wBAAgB,cAAc,CAAC,KAAK,EAAE,EACpC,OAAO,EACP,gBAAgB,EAChB,aAAa,EACb,UAAU,GACX,EAAE;IACD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gBAAgB,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC7B,qBAkHA"}
1
+ {"version":3,"file":"data-table-card.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-card.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAA;AAazB,wBAAgB,cAAc,CAAC,KAAK,EAAE,EACpC,OAAO,EACP,gBAAgB,EAChB,aAAa,EACb,UAAU,GACX,EAAE;IACD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gBAAgB,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC7B,qBAyJA"}
@@ -9,8 +9,8 @@ import { Fragment as o, jsx as s, jsxs as c } from "react/jsx-runtime";
9
9
  import { flexRender as l } from "@tanstack/react-table";
10
10
  //#region src/ui/data-table-card.tsx
11
11
  function u({ loading: u, skeletonRowCount: d, noResultsText: f, emptyState: p }) {
12
- let { table: m, selectable: h } = a(), g = m.getRowModel().rows;
13
- return u ? /* @__PURE__ */ s("div", {
12
+ let { table: m, selectable: h, filterable: g, filterableColumns: _, rowClassName: v } = a(), y = m.getRowModel().rows;
13
+ if (u) return /* @__PURE__ */ s("div", {
14
14
  className: "flex flex-col gap-ds-03",
15
15
  children: Array.from({ length: d }, (e, i) => /* @__PURE__ */ s(n, {
16
16
  size: "sm",
@@ -40,54 +40,73 @@ function u({ loading: u, skeletonRowCount: d, noResultsText: f, emptyState: p })
40
40
  ]
41
41
  })] })
42
42
  }, `card-skeleton-${i}`))
43
- }) : g.length ? /* @__PURE__ */ s("div", {
44
- className: "flex flex-col gap-ds-03",
45
- role: "list",
46
- children: g.map((t) => {
47
- let a = t.getVisibleCells().filter((e) => e.column.id !== "_select" && e.column.id !== "_expand"), u = a[0], d = a.slice(1), f = t.getIsSelected();
48
- return /* @__PURE__ */ c(n, {
49
- role: "listitem",
50
- size: "sm",
51
- variant: "outline",
52
- className: e(f && "ring-2 ring-accent-9"),
53
- children: [/* @__PURE__ */ c(r, {
54
- className: "flex items-start justify-between gap-ds-03",
55
- children: [/* @__PURE__ */ s("div", {
56
- className: "min-w-0 flex-1 font-medium text-surface-fg",
57
- children: u && l(u.column.columnDef.cell, u.getContext())
58
- }), h && /* @__PURE__ */ s(i, {
59
- size: "sm",
60
- checked: f,
61
- disabled: !t.getCanSelect(),
62
- onCheckedChange: (e) => t.toggleSelected(!!e),
63
- "aria-label": "Select row",
64
- className: "shrink-0"
65
- })]
66
- }), d.length > 0 && /* @__PURE__ */ c(o, { children: [/* @__PURE__ */ s("div", {
67
- "aria-hidden": "true",
68
- className: "h-px w-full bg-surface-border-subtle"
69
- }), /* @__PURE__ */ s(r, {
70
- className: "flex flex-col gap-ds-01",
71
- children: d.map((e) => {
72
- let t = e.column.columnDef.meta;
73
- return t?.hideBelow === "md" || t?.hideBelow, /* @__PURE__ */ c("div", {
74
- className: "flex justify-between gap-ds-03 text-body-sm",
75
- children: [/* @__PURE__ */ s("span", {
76
- className: "shrink-0 text-surface-fg-muted",
77
- children: typeof e.column.columnDef.header == "string" ? e.column.columnDef.header : e.column.id
78
- }), /* @__PURE__ */ s("span", {
79
- className: "min-w-0 text-right text-surface-fg",
80
- children: l(e.column.columnDef.cell, e.getContext())
81
- })]
82
- }, e.id);
83
- })
84
- })] })]
85
- }, t.id);
86
- })
87
- }) : /* @__PURE__ */ s("div", {
43
+ });
44
+ if (!y.length) return /* @__PURE__ */ s("div", {
88
45
  className: e("py-ds-07 text-center", !p && "text-surface-fg-subtle"),
89
46
  children: p || f || "No results."
90
47
  });
48
+ let b = g ? m.getAllLeafColumns().filter((e) => e.id === "_select" || e.id === "_expand" ? !1 : _ ? _.includes(e.id) : e.columnDef.enableColumnFilter !== !1) : [];
49
+ return /* @__PURE__ */ c("div", {
50
+ className: "flex flex-col gap-ds-03",
51
+ children: [b.length > 0 && /* @__PURE__ */ s("div", {
52
+ className: "flex flex-col gap-ds-02",
53
+ children: b.map((t) => {
54
+ let n = typeof t.columnDef.header == "string" ? t.columnDef.header : t.id;
55
+ return /* @__PURE__ */ s("input", {
56
+ type: "text",
57
+ value: t.getFilterValue() ?? "",
58
+ onChange: (e) => t.setFilterValue(e.target.value),
59
+ placeholder: `Filter ${n}...`,
60
+ "aria-label": `Filter ${n}`,
61
+ className: e("h-ds-xs-plus w-full rounded-control", "border border-card-strong bg-surface-panel-hover", "px-ds-02 text-body-sm", "text-surface-fg placeholder:text-surface-fg-subtle", "outline-hidden focus:border-accent-7")
62
+ }, t.id);
63
+ })
64
+ }), /* @__PURE__ */ s("div", {
65
+ className: "flex flex-col gap-ds-03",
66
+ role: "list",
67
+ children: y.map((t) => {
68
+ let a = t.getVisibleCells().filter((e) => e.column.id !== "_select" && e.column.id !== "_expand"), u = a[0], d = a.slice(1), f = t.getIsSelected();
69
+ return /* @__PURE__ */ c(n, {
70
+ role: "listitem",
71
+ size: "sm",
72
+ variant: "outline",
73
+ className: e(f && "ring-2 ring-accent-9", v?.(t.original)),
74
+ children: [/* @__PURE__ */ c(r, {
75
+ className: "flex items-start justify-between gap-ds-03",
76
+ children: [/* @__PURE__ */ s("div", {
77
+ className: "min-w-0 flex-1 font-medium text-surface-fg",
78
+ children: u && l(u.column.columnDef.cell, u.getContext())
79
+ }), h && /* @__PURE__ */ s(i, {
80
+ size: "sm",
81
+ checked: f,
82
+ disabled: !t.getCanSelect(),
83
+ onCheckedChange: (e) => t.toggleSelected(!!e),
84
+ "aria-label": "Select row",
85
+ className: "shrink-0"
86
+ })]
87
+ }), d.length > 0 && /* @__PURE__ */ c(o, { children: [/* @__PURE__ */ s("div", {
88
+ "aria-hidden": "true",
89
+ className: "h-px w-full bg-surface-border-subtle"
90
+ }), /* @__PURE__ */ s(r, {
91
+ className: "flex flex-col gap-ds-01",
92
+ children: d.map((e) => {
93
+ let t = e.column.columnDef.meta;
94
+ return t?.hideBelow === "md" || t?.hideBelow, /* @__PURE__ */ c("div", {
95
+ className: "flex justify-between gap-ds-03 text-body-sm",
96
+ children: [/* @__PURE__ */ s("span", {
97
+ className: "shrink-0 text-surface-fg-muted",
98
+ children: typeof e.column.columnDef.header == "string" ? e.column.columnDef.header : e.column.id
99
+ }), /* @__PURE__ */ s("span", {
100
+ className: "min-w-0 text-right text-surface-fg",
101
+ children: l(e.column.columnDef.cell, e.getContext())
102
+ })]
103
+ }, e.id);
104
+ })
105
+ })] })]
106
+ }, t.id);
107
+ })
108
+ })]
109
+ });
91
110
  }
92
111
  //#endregion
93
112
  export { u as DataTableCards };
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-card.js","names":[],"sources":["../../src/ui/data-table-card.tsx"],"sourcesContent":["'use client'\n\nimport { flexRender } from '@tanstack/react-table'\nimport React from 'react'\n\nimport { Card, CardContent } from './card'\nimport { Checkbox } from './checkbox'\nimport { useDataTableContext } from './data-table-context'\nimport { cn } from './lib/utils'\nimport { Skeleton } from './skeleton'\n\n// ── DataTableCards ─────────────────────────────────────────────\n// Renders rows as vertically stacked cards for small (< sm) viewports.\n// Consumes the same TanStack Table instance from context — sorting,\n// filtering, pagination, and selection all work identically.\n\nexport function DataTableCards<TData>({\n loading,\n skeletonRowCount,\n noResultsText,\n emptyState,\n}: {\n loading?: boolean\n skeletonRowCount: number\n noResultsText?: string\n emptyState?: React.ReactNode\n}) {\n const { table, selectable } = useDataTableContext<TData>()\n const rows = table.getRowModel().rows\n\n // Loading skeleton\n if (loading) {\n return (\n <div className=\"flex flex-col gap-ds-03\">\n {Array.from({ length: skeletonRowCount }, (_, i) => (\n <Card key={`card-skeleton-${i}`} size=\"sm\" variant=\"outline\">\n <CardContent>\n <Skeleton variant=\"text\" className=\"mb-ds-03 h-5 w-2/3\" animation=\"pulse\" />\n <div className=\"flex flex-col gap-ds-02\">\n <Skeleton variant=\"text\" className=\"h-4 w-full\" animation=\"pulse\" />\n <Skeleton variant=\"text\" className=\"h-4 w-3/4\" animation=\"pulse\" />\n <Skeleton variant=\"text\" className=\"h-4 w-1/2\" animation=\"pulse\" />\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )\n }\n\n // Empty state\n if (!rows.length) {\n return (\n <div className={cn('py-ds-07 text-center', !emptyState && 'text-surface-fg-subtle')}>\n {emptyState || noResultsText || 'No results.'}\n </div>\n )\n }\n\n return (\n <div className=\"flex flex-col gap-ds-03\" role=\"list\">\n {rows.map((row) => {\n const cells = row.getVisibleCells()\n // Skip internal columns (_select, _expand) for card content\n const contentCells = cells.filter(\n (cell) => cell.column.id !== '_select' && cell.column.id !== '_expand',\n )\n const primaryCell = contentCells[0]\n const restCells = contentCells.slice(1)\n const isSelected = row.getIsSelected()\n\n return (\n <Card\n key={row.id}\n role=\"listitem\"\n size=\"sm\"\n // outline, not default — a phone screen of stacked shadow cards\n // accumulates lift (make-kit dense-list rule).\n variant=\"outline\"\n className={cn(isSelected && 'ring-2 ring-accent-9')}\n >\n {/* Header row: primary field + optional selection checkbox */}\n <CardContent className=\"flex items-start justify-between gap-ds-03\">\n <div className=\"min-w-0 flex-1 font-medium text-surface-fg\">\n {primaryCell &&\n flexRender(primaryCell.column.columnDef.cell, primaryCell.getContext())}\n </div>\n {selectable && (\n <Checkbox\n size=\"sm\"\n checked={isSelected}\n disabled={!row.getCanSelect()}\n onCheckedChange={(v) => row.toggleSelected(!!v)}\n aria-label=\"Select row\"\n className=\"shrink-0\"\n />\n )}\n </CardContent>\n\n {/* Label-value pairs for remaining columns, behind a full-width rule */}\n {restCells.length > 0 && (\n <>\n <div aria-hidden=\"true\" className=\"h-px w-full bg-surface-border-subtle\" />\n <CardContent className=\"flex flex-col gap-ds-01\">\n {restCells.map((cell) => {\n // Respect hideBelow column meta — skip hidden columns\n const meta = cell.column.columnDef.meta as\n | { hideBelow?: string }\n | undefined\n // In card mode on mobile, hideBelow='sm' columns are still useful\n // since we're showing all data in a card layout. Only skip if\n // the column is explicitly hidden via visibility toggle.\n if (meta?.hideBelow === 'md' || meta?.hideBelow === 'lg') {\n // These would normally be hidden at this breakpoint in table\n // mode too, so skip them in cards for consistency\n }\n\n // Derive header label text\n const header =\n typeof cell.column.columnDef.header === 'string'\n ? cell.column.columnDef.header\n : cell.column.id\n\n return (\n <div key={cell.id} className=\"flex justify-between gap-ds-03 text-body-sm\">\n <span className=\"shrink-0 text-surface-fg-muted\">{header}</span>\n <span className=\"min-w-0 text-right text-surface-fg\">\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </span>\n </div>\n )\n })}\n </CardContent>\n </>\n )}\n </Card>\n )\n })}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;AAgBA,SAAgB,EAAsB,EACpC,YACA,qBACA,kBACA,iBAMC;CACD,IAAM,EAAE,UAAO,kBAAe,EAA2B,GACnD,IAAO,EAAM,YAAY,CAAC,CAAC;CA+BjC,OA5BI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,EAAE,QAAQ,EAAiB,IAAI,GAAG,MAC5C,kBAAC,GAAD;GAAiC,MAAK;GAAK,SAAQ;aACjD,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;IAAU,SAAQ;IAAO,WAAU;IAAqB,WAAU;GAAS,CAAA,GAC3E,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAa,WAAU;KAAS,CAAA;KACnE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAY,WAAU;KAAS,CAAA;KAClE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAY,WAAU;KAAS,CAAA;IAC/D;KACM,EAAA,CAAA;EACT,GATK,iBAAiB,GAStB,CACP;CACE,CAAA,IAKJ,EAAK,SASR,kBAAC,OAAD;EAAK,WAAU;EAA0B,MAAK;YAC3C,EAAK,KAAK,MAAQ;GAGjB,IAAM,IAFQ,EAAI,gBAEG,CAAA,CAAM,QACxB,MAAS,EAAK,OAAO,OAAO,aAAa,EAAK,OAAO,OAAO,SAC/D,GACM,IAAc,EAAa,IAC3B,IAAY,EAAa,MAAM,CAAC,GAChC,IAAa,EAAI,cAAc;GAErC,OACE,kBAAC,GAAD;IAEE,MAAK;IACL,MAAK;IAGL,SAAQ;IACR,WAAW,EAAG,KAAc,sBAAsB;cAPpD,CAUE,kBAAC,GAAD;KAAa,WAAU;eAAvB,CACE,kBAAC,OAAD;MAAK,WAAU;gBACZ,KACC,EAAW,EAAY,OAAO,UAAU,MAAM,EAAY,WAAW,CAAC;KACrE,CAAA,GACJ,KACC,kBAAC,GAAD;MACE,MAAK;MACL,SAAS;MACT,UAAU,CAAC,EAAI,aAAa;MAC5B,kBAAkB,MAAM,EAAI,eAAe,CAAC,CAAC,CAAC;MAC9C,cAAW;MACX,WAAU;KACX,CAAA,CAEQ;QAGZ,EAAU,SAAS,KAClB,kBAAA,GAAA,EAAA,UAAA,CACA,kBAAC,OAAD;KAAK,eAAY;KAAO,WAAU;IAAwC,CAAA,GAC1E,kBAAC,GAAD;KAAa,WAAU;eACpB,EAAU,KAAK,MAAS;MAEvB,IAAM,IAAO,EAAK,OAAO,UAAU;MAiBnC,OAXI,GAAM,cAAc,QAAQ,GAAM,WAYpC,kBAAC,OAAD;OAAmB,WAAU;iBAA7B,CACE,kBAAC,QAAD;QAAM,WAAU;kBANlB,OAAO,EAAK,OAAO,UAAU,UAAW,WACpC,EAAK,OAAO,UAAU,SACtB,EAAK,OAAO;OAIiD,CAAA,GAC/D,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAW,EAAK,OAAO,UAAU,MAAM,EAAK,WAAW,CAAC;OACrD,CAAA,CACH;SALK,EAAK,EAKV;KAET,CAAC;IACU,CAAA,CACX,EAAA,CAAA,CAEA;MA9DC,EAAI,EA8DL;EAEV,CAAC;CACE,CAAA,IArFH,kBAAC,OAAD;EAAK,WAAW,EAAG,wBAAwB,CAAC,KAAc,wBAAwB;YAC/E,KAAc,KAAiB;CAC7B,CAAA;AAqFX"}
1
+ {"version":3,"file":"data-table-card.js","names":[],"sources":["../../src/ui/data-table-card.tsx"],"sourcesContent":["'use client'\n\nimport { flexRender } from '@tanstack/react-table'\nimport React from 'react'\n\nimport { Card, CardContent } from './card'\nimport { Checkbox } from './checkbox'\nimport { useDataTableContext } from './data-table-context'\nimport { cn } from './lib/utils'\nimport { Skeleton } from './skeleton'\n\n// ── DataTableCards ─────────────────────────────────────────────\n// Renders rows as vertically stacked cards for small (< sm) viewports.\n// Consumes the same TanStack Table instance from context — sorting,\n// filtering, pagination, and selection all work identically.\n\nexport function DataTableCards<TData>({\n loading,\n skeletonRowCount,\n noResultsText,\n emptyState,\n}: {\n loading?: boolean\n skeletonRowCount: number\n noResultsText?: string\n emptyState?: React.ReactNode\n}) {\n const { table, selectable, filterable, filterableColumns, rowClassName } = useDataTableContext<TData>()\n const rows = table.getRowModel().rows\n\n // Loading skeleton\n if (loading) {\n return (\n <div className=\"flex flex-col gap-ds-03\">\n {Array.from({ length: skeletonRowCount }, (_, i) => (\n <Card key={`card-skeleton-${i}`} size=\"sm\" variant=\"outline\">\n <CardContent>\n <Skeleton variant=\"text\" className=\"mb-ds-03 h-5 w-2/3\" animation=\"pulse\" />\n <div className=\"flex flex-col gap-ds-02\">\n <Skeleton variant=\"text\" className=\"h-4 w-full\" animation=\"pulse\" />\n <Skeleton variant=\"text\" className=\"h-4 w-3/4\" animation=\"pulse\" />\n <Skeleton variant=\"text\" className=\"h-4 w-1/2\" animation=\"pulse\" />\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )\n }\n\n // Empty state\n if (!rows.length) {\n return (\n <div className={cn('py-ds-07 text-center', !emptyState && 'text-surface-fg-subtle')}>\n {emptyState || noResultsText || 'No results.'}\n </div>\n )\n }\n\n // Filterable columns that should show an input in card mode.\n // Lives above the card list since there's no <thead> in card layout.\n const filterableCols = filterable\n ? table.getAllLeafColumns().filter((col) => {\n if (col.id === '_select' || col.id === '_expand') return false\n if (filterableColumns) return filterableColumns.includes(col.id)\n return col.columnDef.enableColumnFilter !== false\n })\n : []\n\n return (\n <div className=\"flex flex-col gap-ds-03\">\n {/* Filter inputs — rendered above the card list, one per filterable column */}\n {filterableCols.length > 0 && (\n <div className=\"flex flex-col gap-ds-02\">\n {filterableCols.map((col) => {\n const headerLabel =\n typeof col.columnDef.header === 'string' ? col.columnDef.header : col.id\n return (\n <input\n key={col.id}\n type=\"text\"\n value={(col.getFilterValue() as string) ?? ''}\n onChange={(e) => col.setFilterValue(e.target.value)}\n placeholder={`Filter ${headerLabel}...`}\n aria-label={`Filter ${headerLabel}`}\n className={cn(\n 'h-ds-xs-plus w-full rounded-control',\n 'border border-card-strong bg-surface-panel-hover',\n 'px-ds-02 text-body-sm',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden focus:border-accent-7',\n )}\n />\n )\n })}\n </div>\n )}\n\n <div className=\"flex flex-col gap-ds-03\" role=\"list\">\n {rows.map((row) => {\n const cells = row.getVisibleCells()\n // Skip internal columns (_select, _expand) for card content\n const contentCells = cells.filter(\n (cell) => cell.column.id !== '_select' && cell.column.id !== '_expand',\n )\n const primaryCell = contentCells[0]\n const restCells = contentCells.slice(1)\n const isSelected = row.getIsSelected()\n\n return (\n <Card\n key={row.id}\n role=\"listitem\"\n size=\"sm\"\n // outline, not default — a phone screen of stacked shadow cards\n // accumulates lift (make-kit dense-list rule).\n variant=\"outline\"\n className={cn(isSelected && 'ring-2 ring-accent-9', rowClassName?.(row.original))}\n >\n {/* Header row: primary field + optional selection checkbox */}\n <CardContent className=\"flex items-start justify-between gap-ds-03\">\n <div className=\"min-w-0 flex-1 font-medium text-surface-fg\">\n {primaryCell &&\n flexRender(primaryCell.column.columnDef.cell, primaryCell.getContext())}\n </div>\n {selectable && (\n <Checkbox\n size=\"sm\"\n checked={isSelected}\n disabled={!row.getCanSelect()}\n onCheckedChange={(v) => row.toggleSelected(!!v)}\n aria-label=\"Select row\"\n className=\"shrink-0\"\n />\n )}\n </CardContent>\n\n {/* Label-value pairs for remaining columns, behind a full-width rule */}\n {restCells.length > 0 && (\n <>\n <div aria-hidden=\"true\" className=\"h-px w-full bg-surface-border-subtle\" />\n <CardContent className=\"flex flex-col gap-ds-01\">\n {restCells.map((cell) => {\n // Respect hideBelow column meta — skip hidden columns\n const meta = cell.column.columnDef.meta as\n | { hideBelow?: string }\n | undefined\n // In card mode on mobile, hideBelow='sm' columns are still useful\n // since we're showing all data in a card layout. Only skip if\n // the column is explicitly hidden via visibility toggle.\n if (meta?.hideBelow === 'md' || meta?.hideBelow === 'lg') {\n // These would normally be hidden at this breakpoint in table\n // mode too, so skip them in cards for consistency\n }\n\n // Derive header label text\n const header =\n typeof cell.column.columnDef.header === 'string'\n ? cell.column.columnDef.header\n : cell.column.id\n\n return (\n <div key={cell.id} className=\"flex justify-between gap-ds-03 text-body-sm\">\n <span className=\"shrink-0 text-surface-fg-muted\">{header}</span>\n <span className=\"min-w-0 text-right text-surface-fg\">\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </span>\n </div>\n )\n })}\n </CardContent>\n </>\n )}\n </Card>\n )\n })}\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
@@ -21,6 +21,8 @@ export interface DataTableContextValue<TData = unknown> {
21
21
  sortable: boolean;
22
22
  /** Whether per-column filters are enabled */
23
23
  filterable: boolean;
24
+ /** When set, only these column IDs get filter inputs (subset of filterable columns) */
25
+ filterableColumns?: string[];
24
26
  /** Whether inline editing is enabled */
25
27
  editable: boolean;
26
28
  /** Whether row expansion is enabled */
@@ -41,6 +43,8 @@ export interface DataTableContextValue<TData = unknown> {
41
43
  renderExpanded?: (row: TData) => React.ReactNode;
42
44
  /** Row click handler */
43
45
  onRowClick?: (row: TData) => void;
46
+ /** Return a className for a given row — applied to the tr in table and card layouts */
47
+ rowClassName?: (row: TData) => string | undefined;
44
48
  }
45
49
  export declare function DataTableProvider<TData>({ children, value, }: {
46
50
  children: React.ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-context.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC3E,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,0DAA0D;AAC1D,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAA;AAIvE,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAS3E;AAED,4DAA4D;AAC5D,eAAO,MAAM,oBAAoB,4DACwB,CAAA;AAIzD,MAAM,WAAW,qBAAqB,CAAC,KAAK,GAAG,OAAO;IACpD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IACnB,yDAAyD;IACzD,UAAU,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;IAC/C,kDAAkD;IAClD,kBAAkB,EAAE,kBAAkB,CAAA;IACtC,iCAAiC;IACjC,QAAQ,EAAE,OAAO,CAAA;IACjB,6CAA6C;IAC7C,UAAU,EAAE,OAAO,CAAA;IACnB,wCAAwC;IACxC,QAAQ,EAAE,OAAO,CAAA;IACjB,uCAAuC;IACvC,UAAU,EAAE,OAAO,CAAA;IACnB,uCAAuC;IACvC,WAAW,EAAE,OAAO,CAAA;IACpB,uCAAuC;IACvC,UAAU,EAAE,OAAO,CAAA;IACnB,uBAAuB;IACvB,UAAU,EAAE,MAAM,GAAG,OAAO,CAAA;IAC5B,2BAA2B;IAC3B,WAAW,EAAE,WAAW,CAAA;IACxB,uBAAuB;IACvB,cAAc,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAA;IAC3C,2CAA2C;IAC3C,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACzE,+CAA+C;IAC/C,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,KAAK,CAAC,SAAS,CAAA;IAChD,wBAAwB;IACxB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAA;CAClC;AAID,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,EACvC,QAAQ,EACR,KAAK,GACN,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,KAAK,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAA;CACpC,qBAMA;AAED,wBAAgB,mBAAmB,CAAC,KAAK,GAAG,OAAO,KAGnC,qBAAqB,CAAC,KAAK,CAAC,CAC3C;AAID,2DAA2D;AAC3D,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,kBAAkB;;WASZ,KAAK,CAAC,aAAa;EAU9C;AAED,uCAAuC;AACvC,wBAAgB,gBAAgB,CAAC,KAAK,EACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAClB,OAAO,CAYT"}
1
+ {"version":3,"file":"data-table-context.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC3E,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,0DAA0D;AAC1D,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAA;AAIvE,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAS3E;AAED,4DAA4D;AAC5D,eAAO,MAAM,oBAAoB,4DACwB,CAAA;AAIzD,MAAM,WAAW,qBAAqB,CAAC,KAAK,GAAG,OAAO;IACpD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IACnB,yDAAyD;IACzD,UAAU,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;IAC/C,kDAAkD;IAClD,kBAAkB,EAAE,kBAAkB,CAAA;IACtC,iCAAiC;IACjC,QAAQ,EAAE,OAAO,CAAA;IACjB,6CAA6C;IAC7C,UAAU,EAAE,OAAO,CAAA;IACnB,uFAAuF;IACvF,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,wCAAwC;IACxC,QAAQ,EAAE,OAAO,CAAA;IACjB,uCAAuC;IACvC,UAAU,EAAE,OAAO,CAAA;IACnB,uCAAuC;IACvC,WAAW,EAAE,OAAO,CAAA;IACpB,uCAAuC;IACvC,UAAU,EAAE,OAAO,CAAA;IACnB,uBAAuB;IACvB,UAAU,EAAE,MAAM,GAAG,OAAO,CAAA;IAC5B,2BAA2B;IAC3B,WAAW,EAAE,WAAW,CAAA;IACxB,uBAAuB;IACvB,cAAc,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAA;IAC3C,2CAA2C;IAC3C,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACzE,+CAA+C;IAC/C,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,KAAK,CAAC,SAAS,CAAA;IAChD,wBAAwB;IACxB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAA;IACjC,uFAAuF;IACvF,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,MAAM,GAAG,SAAS,CAAA;CAClD;AAID,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,EACvC,QAAQ,EACR,KAAK,GACN,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,KAAK,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAA;CACpC,qBAMA;AAED,wBAAgB,mBAAmB,CAAC,KAAK,GAAG,OAAO,KAGnC,qBAAqB,CAAC,KAAK,CAAC,CAC3C;AAID,2DAA2D;AAC3D,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,kBAAkB;;WASZ,KAAK,CAAC,aAAa;EAU9C;AAED,uCAAuC;AACvC,wBAAgB,gBAAgB,CAAC,KAAK,EACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAClB,OAAO,CAYT"}
@@ -25,10 +25,10 @@ function s(e, t) {
25
25
  className: "",
26
26
  style: {}
27
27
  } : {
28
- className: "sticky bg-surface-base z-raised",
28
+ className: "sticky bg-surface-panel z-raised",
29
29
  style: { right: 0 }
30
30
  } : {
31
- className: "sticky bg-surface-base z-raised",
31
+ className: "sticky bg-surface-panel z-raised",
32
32
  style: { left: 0 }
33
33
  };
34
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-context.js","names":[],"sources":["../../src/ui/data-table-context.tsx"],"sourcesContent":["'use client'\n\nimport { type ColumnPinningState, type Table } from '@tanstack/react-table'\nimport React from 'react'\n\n// ── Shared types ────────────────────────────────────────────────\n\n/** Editing state: which cell is currently in edit mode */\nexport type EditingCell = { rowIndex: number; columnId: string } | null\n\n// ── Utility functions ───────────────────────────────────────────\n\nexport function getColumnMetaClasses(meta?: Record<string, unknown>): string {\n if (!meta) return ''\n const classes: string[] = []\n if (meta.align === 'right') classes.push('text-right tabular-nums')\n if (meta.align === 'center') classes.push('text-center')\n if (meta.hideBelow === 'sm') classes.push('hidden sm:table-cell')\n if (meta.hideBelow === 'md') classes.push('hidden md:table-cell')\n if (meta.hideBelow === 'lg') classes.push('hidden lg:table-cell')\n return classes.join(' ')\n}\n\n/** Interactive element selectors for row click filtering */\nexport const INTERACTIVE_SELECTOR =\n 'button, a, input, select, textarea, [role=\"checkbox\"]'\n\n// ── Context ─────────────────────────────────────────────────────\n\nexport interface DataTableContextValue<TData = unknown> {\n table: Table<TData>\n /** All assembled columns (including _select, _expand) */\n allColumns: { id?: string; header?: unknown }[]\n /** Column pinning state for sticky positioning */\n columnPinningState: ColumnPinningState\n /** Whether sorting is enabled */\n sortable: boolean\n /** Whether per-column filters are enabled */\n filterable: boolean\n /** Whether inline editing is enabled */\n editable: boolean\n /** Whether row expansion is enabled */\n expandable: boolean\n /** Whether virtual rows are enabled */\n virtualRows: boolean\n /** Whether row selection is enabled */\n selectable: boolean\n /** Mobile view mode */\n mobileView: 'card' | 'table'\n /** Current editing cell */\n editingCell: EditingCell\n /** Set editing cell */\n setEditingCell: (cell: EditingCell) => void\n /** Callback when a cell value is edited */\n onCellEdit?: (rowIndex: number, columnId: string, value: unknown) => void\n /** Render function for expanded row content */\n renderExpanded?: (row: TData) => React.ReactNode\n /** Row click handler */\n onRowClick?: (row: TData) => void\n}\n\nconst DataTableContext = React.createContext<DataTableContextValue | null>(null)\n\nexport function DataTableProvider<TData>({\n children,\n value,\n}: {\n children: React.ReactNode\n value: DataTableContextValue<TData>\n}) {\n return (\n <DataTableContext.Provider value={value as DataTableContextValue}>\n {children}\n </DataTableContext.Provider>\n )\n}\n\nexport function useDataTableContext<TData = unknown>() {\n const ctx = React.useContext(DataTableContext)\n if (!ctx) throw new Error('useDataTableContext must be used within DataTableProvider')\n return ctx as DataTableContextValue<TData>\n}\n\n// ── Shared helpers ──────────────────────────────────────────────\n\n/** Compute sticky positioning styles for pinned columns */\nexport function getPinnedCellStyle(\n columnId: string,\n columnPinningState: ColumnPinningState,\n) {\n const { left = [], right = [] } = columnPinningState\n const leftIndex = left.indexOf(columnId)\n const rightIndex = right.indexOf(columnId)\n\n if (leftIndex !== -1) {\n return {\n className: 'sticky bg-surface-base z-raised',\n style: { left: 0 } as React.CSSProperties,\n }\n }\n if (rightIndex !== -1) {\n return {\n className: 'sticky bg-surface-base z-raised',\n style: { right: 0 } as React.CSSProperties,\n }\n }\n return { className: '', style: {} as React.CSSProperties }\n}\n\n/** Check if a column allows editing */\nexport function isColumnEditable<TData>(\n columnId: string,\n editable: boolean,\n table: Table<TData>,\n): boolean {\n if (!editable) return false\n // Internal columns are never editable\n if (columnId === '_select' || columnId === '_expand') return false\n const col = table.getColumn(columnId)\n if (!col) return false\n const meta = col.columnDef.meta as\n | { enableEditing?: boolean }\n | undefined\n // Editable by default unless explicitly disabled\n if (meta?.enableEditing === false) return false\n return true\n}\n"],"mappings":";;;;AAYA,SAAgB,EAAqB,GAAwC;CAC3E,IAAI,CAAC,GAAM,OAAO;CAClB,IAAM,IAAoB,CAAC;CAM3B,OALI,EAAK,UAAU,WAAS,EAAQ,KAAK,yBAAyB,GAC9D,EAAK,UAAU,YAAU,EAAQ,KAAK,aAAa,GACnD,EAAK,cAAc,QAAM,EAAQ,KAAK,sBAAsB,GAC5D,EAAK,cAAc,QAAM,EAAQ,KAAK,sBAAsB,GAC5D,EAAK,cAAc,QAAM,EAAQ,KAAK,sBAAsB,GACzD,EAAQ,KAAK,GAAG;AACzB;AAGA,IAAa,IACX,2DAoCI,IAAmB,EAAM,cAA4C,IAAI;AAE/E,SAAgB,EAAyB,EACvC,aACA,YAIC;CACD,OACE,kBAAC,EAAiB,UAAlB;EAAkC;EAC/B;CACwB,CAAA;AAE/B;AAEA,SAAgB,IAAuC;CACrD,IAAM,IAAM,EAAM,WAAW,CAAgB;CAC7C,IAAI,CAAC,GAAK,MAAU,MAAM,2DAA2D;CACrF,OAAO;AACT;AAKA,SAAgB,EACd,GACA,GACA;CACA,IAAM,EAAE,UAAO,CAAC,GAAG,WAAQ,CAAC,MAAM,GAC5B,IAAY,EAAK,QAAQ,CAAQ,GACjC,IAAa,EAAM,QAAQ,CAAQ;CAczC,OAZI,MAAc,KAMd,MAAe,KAMZ;EAAE,WAAW;EAAI,OAAO,CAAC;CAAyB,IALhD;EACL,WAAW;EACX,OAAO,EAAE,OAAO,EAAE;CACpB,IATO;EACL,WAAW;EACX,OAAO,EAAE,MAAM,EAAE;CACnB;AASJ;AAGA,SAAgB,EACd,GACA,GACA,GACS;CAGT,IAFI,CAAC,KAED,MAAa,aAAa,MAAa,WAAW,OAAO;CAC7D,IAAM,IAAM,EAAM,UAAU,CAAQ;CAOpC,OADA,EALI,CAAC,KACQ,EAAI,UAAU,MAIjB,kBAAkB;AAE9B"}
1
+ {"version":3,"file":"data-table-context.js","names":[],"sources":["../../src/ui/data-table-context.tsx"],"sourcesContent":["'use client'\n\nimport { type ColumnPinningState, type Table } from '@tanstack/react-table'\nimport React from 'react'\n\n// ── Shared types ────────────────────────────────────────────────\n\n/** Editing state: which cell is currently in edit mode */\nexport type EditingCell = { rowIndex: number; columnId: string } | null\n\n// ── Utility functions ───────────────────────────────────────────\n\nexport function getColumnMetaClasses(meta?: Record<string, unknown>): string {\n if (!meta) return ''\n const classes: string[] = []\n if (meta.align === 'right') classes.push('text-right tabular-nums')\n if (meta.align === 'center') classes.push('text-center')\n if (meta.hideBelow === 'sm') classes.push('hidden sm:table-cell')\n if (meta.hideBelow === 'md') classes.push('hidden md:table-cell')\n if (meta.hideBelow === 'lg') classes.push('hidden lg:table-cell')\n return classes.join(' ')\n}\n\n/** Interactive element selectors for row click filtering */\nexport const INTERACTIVE_SELECTOR =\n 'button, a, input, select, textarea, [role=\"checkbox\"]'\n\n// ── Context ─────────────────────────────────────────────────────\n\nexport interface DataTableContextValue<TData = unknown> {\n table: Table<TData>\n /** All assembled columns (including _select, _expand) */\n allColumns: { id?: string; header?: unknown }[]\n /** Column pinning state for sticky positioning */\n columnPinningState: ColumnPinningState\n /** Whether sorting is enabled */\n sortable: boolean\n /** Whether per-column filters are enabled */\n filterable: boolean\n /** When set, only these column IDs get filter inputs (subset of filterable columns) */\n filterableColumns?: string[]\n /** Whether inline editing is enabled */\n editable: boolean\n /** Whether row expansion is enabled */\n expandable: boolean\n /** Whether virtual rows are enabled */\n virtualRows: boolean\n /** Whether row selection is enabled */\n selectable: boolean\n /** Mobile view mode */\n mobileView: 'card' | 'table'\n /** Current editing cell */\n editingCell: EditingCell\n /** Set editing cell */\n setEditingCell: (cell: EditingCell) => void\n /** Callback when a cell value is edited */\n onCellEdit?: (rowIndex: number, columnId: string, value: unknown) => void\n /** Render function for expanded row content */\n renderExpanded?: (row: TData) => React.ReactNode\n /** Row click handler */\n onRowClick?: (row: TData) => void\n /** Return a className for a given row — applied to the tr in table and card layouts */\n rowClassName?: (row: TData) => string | undefined\n}\n\nconst DataTableContext = React.createContext<DataTableContextValue | null>(null)\n\nexport function DataTableProvider<TData>({\n children,\n value,\n}: {\n children: React.ReactNode\n value: DataTableContextValue<TData>\n}) {\n return (\n <DataTableContext.Provider value={value as DataTableContextValue}>\n {children}\n </DataTableContext.Provider>\n )\n}\n\nexport function useDataTableContext<TData = unknown>() {\n const ctx = React.useContext(DataTableContext)\n if (!ctx) throw new Error('useDataTableContext must be used within DataTableProvider')\n return ctx as DataTableContextValue<TData>\n}\n\n// ── Shared helpers ──────────────────────────────────────────────\n\n/** Compute sticky positioning styles for pinned columns */\nexport function getPinnedCellStyle(\n columnId: string,\n columnPinningState: ColumnPinningState,\n) {\n const { left = [], right = [] } = columnPinningState\n const leftIndex = left.indexOf(columnId)\n const rightIndex = right.indexOf(columnId)\n\n if (leftIndex !== -1) {\n return {\n className: 'sticky bg-surface-panel z-raised',\n style: { left: 0 } as React.CSSProperties,\n }\n }\n if (rightIndex !== -1) {\n return {\n className: 'sticky bg-surface-panel z-raised',\n style: { right: 0 } as React.CSSProperties,\n }\n }\n return { className: '', style: {} as React.CSSProperties }\n}\n\n/** Check if a column allows editing */\nexport function isColumnEditable<TData>(\n columnId: string,\n editable: boolean,\n table: Table<TData>,\n): boolean {\n if (!editable) return false\n // Internal columns are never editable\n if (columnId === '_select' || columnId === '_expand') return false\n const col = table.getColumn(columnId)\n if (!col) return false\n const meta = col.columnDef.meta as\n | { enableEditing?: boolean }\n | undefined\n // Editable by default unless explicitly disabled\n if (meta?.enableEditing === false) return false\n return true\n}\n"],"mappings":";;;;AAYA,SAAgB,EAAqB,GAAwC;CAC3E,IAAI,CAAC,GAAM,OAAO;CAClB,IAAM,IAAoB,CAAC;CAM3B,OALI,EAAK,UAAU,WAAS,EAAQ,KAAK,yBAAyB,GAC9D,EAAK,UAAU,YAAU,EAAQ,KAAK,aAAa,GACnD,EAAK,cAAc,QAAM,EAAQ,KAAK,sBAAsB,GAC5D,EAAK,cAAc,QAAM,EAAQ,KAAK,sBAAsB,GAC5D,EAAK,cAAc,QAAM,EAAQ,KAAK,sBAAsB,GACzD,EAAQ,KAAK,GAAG;AACzB;AAGA,IAAa,IACX,2DAwCI,IAAmB,EAAM,cAA4C,IAAI;AAE/E,SAAgB,EAAyB,EACvC,aACA,YAIC;CACD,OACE,kBAAC,EAAiB,UAAlB;EAAkC;EAC/B;CACwB,CAAA;AAE/B;AAEA,SAAgB,IAAuC;CACrD,IAAM,IAAM,EAAM,WAAW,CAAgB;CAC7C,IAAI,CAAC,GAAK,MAAU,MAAM,2DAA2D;CACrF,OAAO;AACT;AAKA,SAAgB,EACd,GACA,GACA;CACA,IAAM,EAAE,UAAO,CAAC,GAAG,WAAQ,CAAC,MAAM,GAC5B,IAAY,EAAK,QAAQ,CAAQ,GACjC,IAAa,EAAM,QAAQ,CAAQ;CAczC,OAZI,MAAc,KAMd,MAAe,KAMZ;EAAE,WAAW;EAAI,OAAO,CAAC;CAAyB,IALhD;EACL,WAAW;EACX,OAAO,EAAE,OAAO,EAAE;CACpB,IATO;EACL,WAAW;EACX,OAAO,EAAE,MAAM,EAAE;CACnB;AASJ;AAGA,SAAgB,EACd,GACA,GACA,GACS;CAGT,IAFI,CAAC,KAED,MAAa,aAAa,MAAa,WAAW,OAAO;CAC7D,IAAM,IAAM,EAAM,UAAU,CAAQ;CAOpC,OADA,EALI,CAAC,KACQ,EAAI,UAAU,MAIjB,kBAAkB;AAE9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-header.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-header.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,MAAM,OAAO,CAAA;AAYzB;;;GAGG;AACH,iBAAS,mBAAmB,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,qBAwJxE;AAED,OAAO,EAAE,mBAAmB,IAAI,eAAe,EAAE,CAAA"}
1
+ {"version":3,"file":"data-table-header.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-header.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,MAAM,OAAO,CAAA;AAazB;;;GAGG;AACH,iBAAS,mBAAmB,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,qBAgKxE;AAED,OAAO,EAAE,mBAAmB,IAAI,eAAe,EAAE,CAAA"}
@@ -1,34 +1,35 @@
1
1
  "use client";
2
2
  import { springs as e } from "./lib/motion.js";
3
- import { cn as t } from "./lib/utils.js";
4
- import { Icon as n } from "./icon.js";
5
- import { getColumnMetaClasses as r, getPinnedCellStyle as i, useDataTableContext as a } from "./data-table-context.js";
6
- import { TableHead as o, TableHeader as s, TableRow as c } from "./table.js";
3
+ import { MotionPreference as t } from "../_chunks/motion-preference.js";
4
+ import { cn as n } from "./lib/utils.js";
5
+ import { Icon as r } from "./icon.js";
6
+ import { getColumnMetaClasses as i, getPinnedCellStyle as a, useDataTableContext as o } from "./data-table-context.js";
7
+ import { TableHead as s, TableHeader as c, TableRow as l } from "./table.js";
7
8
  import "react";
8
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
9
- import { IconArrowDown as d, IconArrowUp as f, IconArrowsSort as p } from "@tabler/icons-react";
10
- import { AnimatePresence as m, motion as h } from "framer-motion";
11
- import { flexRender as g } from "@tanstack/react-table";
9
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
10
+ import { IconArrowDown as f, IconArrowUp as p, IconArrowsSort as m } from "@tabler/icons-react";
11
+ import { AnimatePresence as h, motion as g } from "framer-motion";
12
+ import { flexRender as _ } from "@tanstack/react-table";
12
13
  //#region src/ui/data-table-header.tsx
13
- function _({ stickyHeader: _ }) {
14
- let { table: v, sortable: y, filterable: b, columnPinningState: x } = a();
15
- return /* @__PURE__ */ u(s, {
16
- className: t(_ && "sticky top-0 z-10 bg-surface-raised"),
17
- children: [v.getHeaderGroups().map((a) => /* @__PURE__ */ l(c, { children: a.headers.map((a) => {
18
- let s = y && a.column.getCanSort(), c = a.column.getIsSorted(), _ = i(a.column.id, x);
19
- return /* @__PURE__ */ l(o, {
20
- className: t(_.className, r(a.column.columnDef.meta)),
21
- style: _.style,
22
- "aria-sort": s ? c === "asc" ? "ascending" : c === "desc" ? "descending" : "none" : void 0,
23
- children: a.isPlaceholder ? null : s ? /* @__PURE__ */ u("button", {
14
+ function v({ stickyHeader: v }) {
15
+ let { table: y, sortable: b, filterable: x, filterableColumns: S, columnPinningState: C } = o();
16
+ return /* @__PURE__ */ d(c, {
17
+ className: n(v && "sticky top-0 z-10 bg-surface-panel"),
18
+ children: [y.getHeaderGroups().map((o) => /* @__PURE__ */ u(l, { children: o.headers.map((o) => {
19
+ let c = b && o.column.getCanSort(), l = o.column.getIsSorted(), v = a(o.column.id, C);
20
+ return /* @__PURE__ */ u(t, { children: /* @__PURE__ */ u(s, {
21
+ className: n(v.className, i(o.column.columnDef.meta)),
22
+ style: v.style,
23
+ "aria-sort": c ? l === "asc" ? "ascending" : l === "desc" ? "descending" : "none" : void 0,
24
+ children: o.isPlaceholder ? null : c ? /* @__PURE__ */ d("button", {
24
25
  type: "button",
25
- className: t("flex items-center gap-ds-01 font-medium", "cursor-pointer select-none", "-ml-ds-01 rounded-control-inner px-ds-01 py-ds-01", "hover:bg-surface-raised-hover transition-colors"),
26
- onClick: a.column.getToggleSortingHandler(),
27
- "aria-label": `Sort by ${typeof a.column.columnDef.header == "string" ? a.column.columnDef.header : a.column.id}`,
28
- children: [g(a.column.columnDef.header, a.getContext()), /* @__PURE__ */ l(m, {
26
+ className: n("flex items-center gap-ds-01 font-medium", "cursor-pointer select-none", "-ml-ds-01 rounded-control-inner px-ds-01 py-ds-01", "hover:bg-surface-panel-hover transition-colors"),
27
+ onClick: o.column.getToggleSortingHandler(),
28
+ "aria-label": `Sort by ${typeof o.column.columnDef.header == "string" ? o.column.columnDef.header : o.column.id}`,
29
+ children: [_(o.column.columnDef.header, o.getContext()), /* @__PURE__ */ u(h, {
29
30
  mode: "wait",
30
31
  initial: !1,
31
- children: c === "asc" ? /* @__PURE__ */ l(h.span, {
32
+ children: l === "asc" ? /* @__PURE__ */ u(g.span, {
32
33
  initial: {
33
34
  opacity: 0,
34
35
  rotate: 90
@@ -43,12 +44,12 @@ function _({ stickyHeader: _ }) {
43
44
  },
44
45
  transition: e.snappy,
45
46
  className: "inline-flex",
46
- children: /* @__PURE__ */ l(n, {
47
- icon: f,
47
+ children: /* @__PURE__ */ u(r, {
48
+ icon: p,
48
49
  size: "sm",
49
50
  className: "text-surface-fg-muted"
50
51
  })
51
- }, "asc") : c === "desc" ? /* @__PURE__ */ l(h.span, {
52
+ }, "asc") : l === "desc" ? /* @__PURE__ */ u(g.span, {
52
53
  initial: {
53
54
  opacity: 0,
54
55
  rotate: -90
@@ -63,38 +64,41 @@ function _({ stickyHeader: _ }) {
63
64
  },
64
65
  transition: e.snappy,
65
66
  className: "inline-flex",
66
- children: /* @__PURE__ */ l(n, {
67
- icon: d,
67
+ children: /* @__PURE__ */ u(r, {
68
+ icon: f,
68
69
  size: "sm",
69
70
  className: "text-surface-fg-muted"
70
71
  })
71
- }, "desc") : /* @__PURE__ */ l(h.span, {
72
+ }, "desc") : /* @__PURE__ */ u(g.span, {
72
73
  initial: { opacity: 0 },
73
74
  animate: { opacity: 1 },
74
75
  exit: { opacity: 0 },
75
76
  transition: e.snappy,
76
77
  className: "inline-flex",
77
- children: /* @__PURE__ */ l(n, {
78
- icon: p,
78
+ children: /* @__PURE__ */ u(r, {
79
+ icon: m,
79
80
  size: "sm",
80
81
  className: "text-surface-fg-subtle"
81
82
  })
82
83
  }, "unsorted")
83
84
  })]
84
- }) : g(a.column.columnDef.header, a.getContext())
85
- }, a.id);
86
- }) }, a.id)), b && v.getHeaderGroups().map((e) => /* @__PURE__ */ l(c, { children: e.headers.map((e) => /* @__PURE__ */ l(o, {
87
- className: "py-ds-01",
88
- children: e.isPlaceholder || e.column.columnDef.enableColumnFilter === !1 ? null : /* @__PURE__ */ l("input", {
89
- type: "text",
90
- value: e.column.getFilterValue() ?? "",
91
- onChange: (t) => e.column.setFilterValue(t.target.value),
92
- placeholder: `Filter ${typeof e.column.columnDef.header == "string" ? e.column.columnDef.header : ""}...`,
93
- "aria-label": `Filter ${typeof e.column.columnDef.header == "string" ? e.column.columnDef.header : e.column.id}`,
94
- className: t("h-ds-xs-plus w-full rounded-control", "border border-card-strong bg-surface-raised-hover", "px-ds-02 text-body-sm", "text-surface-fg placeholder:text-surface-fg-subtle", "outline-hidden focus:border-accent-7")
95
- })
96
- }, `${e.id}-filter`)) }, `${e.id}-filters`))]
85
+ }) : _(o.column.columnDef.header, o.getContext())
86
+ }, o.id) });
87
+ }) }, o.id)), x && y.getHeaderGroups().map((e) => /* @__PURE__ */ u(l, { children: e.headers.map((e) => {
88
+ let t = S ? S.includes(e.column.id) : e.column.columnDef.enableColumnFilter !== !1;
89
+ return /* @__PURE__ */ u(s, {
90
+ className: "py-ds-01",
91
+ children: e.isPlaceholder || !t ? null : /* @__PURE__ */ u("input", {
92
+ type: "text",
93
+ value: e.column.getFilterValue() ?? "",
94
+ onChange: (t) => e.column.setFilterValue(t.target.value),
95
+ placeholder: `Filter ${typeof e.column.columnDef.header == "string" ? e.column.columnDef.header : ""}...`,
96
+ "aria-label": `Filter ${typeof e.column.columnDef.header == "string" ? e.column.columnDef.header : e.column.id}`,
97
+ className: n("h-ds-xs-plus w-full rounded-control", "border border-card-strong bg-surface-panel-hover", "px-ds-02 text-body-sm", "text-surface-fg placeholder:text-surface-fg-subtle", "outline-hidden focus:border-accent-7")
98
+ })
99
+ }, `${e.id}-filter`);
100
+ }) }, `${e.id}-filters`))]
97
101
  });
98
102
  }
99
103
  //#endregion
100
- export { _ as DataTableHeader };
104
+ export { v as DataTableHeader };