@devalok/shilp-sutra 0.38.0 → 0.40.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 (361) hide show
  1. package/AGENTS.md +151 -0
  2. package/MIGRATION.md +255 -0
  3. package/README.md +3 -0
  4. package/dist/_chunks/badge-group.js +76 -75
  5. package/dist/_chunks/badge-group.js.map +1 -1
  6. package/dist/_chunks/chart-container.js +50 -0
  7. package/dist/_chunks/chart-container.js.map +1 -0
  8. package/dist/_chunks/chat.js +236 -228
  9. package/dist/_chunks/chat.js.map +1 -1
  10. package/dist/_chunks/colors.js +30 -0
  11. package/dist/_chunks/colors.js.map +1 -0
  12. package/dist/_chunks/document-preview.js +2 -2
  13. package/dist/_chunks/document-preview.js.map +1 -1
  14. package/dist/_chunks/emoji-data.js +45 -0
  15. package/dist/_chunks/emoji-data.js.map +1 -0
  16. package/dist/_chunks/grid-lines.js +72 -0
  17. package/dist/_chunks/grid-lines.js.map +1 -0
  18. package/dist/_chunks/image-preview.js +2 -2
  19. package/dist/_chunks/image-preview.js.map +1 -1
  20. package/dist/_chunks/mention-suggestion.js +35 -263
  21. package/dist/_chunks/mention-suggestion.js.map +1 -1
  22. package/dist/_chunks/normalize-icon.js +18 -0
  23. package/dist/_chunks/normalize-icon.js.map +1 -0
  24. package/dist/_chunks/oauth-button.js +227 -0
  25. package/dist/_chunks/oauth-button.js.map +1 -0
  26. package/dist/_chunks/popover.js +3 -3
  27. package/dist/_chunks/popover.js.map +1 -1
  28. package/dist/_chunks/primitives.js +107 -107
  29. package/dist/_chunks/primitives.js.map +1 -1
  30. package/dist/_chunks/shared.js +5 -5
  31. package/dist/_chunks/shared.js.map +1 -1
  32. package/dist/_chunks/{text.js → success.js} +26 -63
  33. package/dist/_chunks/success.js.map +1 -0
  34. package/dist/_chunks/tiptap.js +1952 -1949
  35. package/dist/_chunks/tiptap.js.map +1 -1
  36. package/dist/_chunks/tooltip.js +58 -0
  37. package/dist/_chunks/tooltip.js.map +1 -0
  38. package/dist/_chunks/tree-view.js +101 -96
  39. package/dist/_chunks/tree-view.js.map +1 -1
  40. package/dist/_chunks/use-calendar.js +5 -5
  41. package/dist/_chunks/use-calendar.js.map +1 -1
  42. package/dist/ai/ai-command-provider.d.ts +3 -2
  43. package/dist/ai/ai-command-provider.d.ts.map +1 -1
  44. package/dist/ai/ai-command-provider.js.map +1 -1
  45. package/dist/ai/block-renderer.js +11 -9
  46. package/dist/ai/block-renderer.js.map +1 -1
  47. package/dist/ai/blocks/error.js +31 -0
  48. package/dist/ai/blocks/error.js.map +1 -0
  49. package/dist/ai/blocks/index.d.ts +0 -2
  50. package/dist/ai/blocks/index.d.ts.map +1 -1
  51. package/dist/ai/blocks/index.js +2 -2
  52. package/dist/ai/blocks/text.js +19 -0
  53. package/dist/ai/blocks/text.js.map +1 -0
  54. package/dist/ai/command-bar.d.ts.map +1 -1
  55. package/dist/ai/command-bar.js +198 -193
  56. package/dist/ai/command-bar.js.map +1 -1
  57. package/dist/ai/conversation.d.ts +2 -1
  58. package/dist/ai/conversation.d.ts.map +1 -1
  59. package/dist/ai/conversation.js +92 -87
  60. package/dist/ai/conversation.js.map +1 -1
  61. package/dist/ai/index.d.ts +0 -4
  62. package/dist/ai/index.d.ts.map +1 -1
  63. package/dist/ai/index.js +45 -46
  64. package/dist/ai/index.js.map +1 -1
  65. package/dist/composed/activity-feed.d.ts +2 -1
  66. package/dist/composed/activity-feed.d.ts.map +1 -1
  67. package/dist/composed/activity-feed.js +5 -5
  68. package/dist/composed/activity-feed.js.map +1 -1
  69. package/dist/composed/avatar-group.js +4 -4
  70. package/dist/composed/avatar-group.js.map +1 -1
  71. package/dist/composed/bulk-action-bar.d.ts +2 -2
  72. package/dist/composed/bulk-action-bar.d.ts.map +1 -1
  73. package/dist/composed/bulk-action-bar.js +12 -12
  74. package/dist/composed/bulk-action-bar.js.map +1 -1
  75. package/dist/composed/command-palette.d.ts +2 -1
  76. package/dist/composed/command-palette.d.ts.map +1 -1
  77. package/dist/composed/command-palette.js +106 -101
  78. package/dist/composed/command-palette.js.map +1 -1
  79. package/dist/composed/content-card.js +1 -1
  80. package/dist/composed/content-card.js.map +1 -1
  81. package/dist/composed/date-picker/index.js +747 -3
  82. package/dist/composed/date-picker/index.js.map +1 -0
  83. package/dist/composed/emoji-picker.js +4 -4
  84. package/dist/composed/emoji-picker.js.map +1 -1
  85. package/dist/composed/empty-state.d.ts +3 -3
  86. package/dist/composed/empty-state.d.ts.map +1 -1
  87. package/dist/composed/empty-state.js +40 -31
  88. package/dist/composed/empty-state.js.map +1 -1
  89. package/dist/composed/error-boundary.js +3 -3
  90. package/dist/composed/error-boundary.js.map +1 -1
  91. package/dist/composed/extensions/emoji-node.js +81 -0
  92. package/dist/composed/extensions/emoji-node.js.map +1 -0
  93. package/dist/composed/extensions/emoji-suggestion.js +117 -0
  94. package/dist/composed/extensions/emoji-suggestion.js.map +1 -0
  95. package/dist/composed/file-preview.js +498 -2
  96. package/dist/composed/file-preview.js.map +1 -0
  97. package/dist/composed/filter-bar.js +1 -1
  98. package/dist/composed/filter-bar.js.map +1 -1
  99. package/dist/composed/index.d.ts +0 -15
  100. package/dist/composed/index.d.ts.map +1 -1
  101. package/dist/composed/index.js +16 -24
  102. package/dist/composed/inline-edit.js +1 -1
  103. package/dist/composed/inline-edit.js.map +1 -1
  104. package/dist/composed/loading-skeleton.js +9 -9
  105. package/dist/composed/loading-skeleton.js.map +1 -1
  106. package/dist/composed/markdown-viewer.js +3 -3
  107. package/dist/composed/markdown-viewer.js.map +1 -1
  108. package/dist/composed/multi-select-popover.js +1 -1
  109. package/dist/composed/multi-select-popover.js.map +1 -1
  110. package/dist/composed/page-header.js +1 -1
  111. package/dist/composed/page-header.js.map +1 -1
  112. package/dist/composed/page-skeletons.js +15 -15
  113. package/dist/composed/page-skeletons.js.map +1 -1
  114. package/dist/composed/priority-indicator.js +3 -3
  115. package/dist/composed/priority-indicator.js.map +1 -1
  116. package/dist/composed/rich-chat-input.js +2073 -2
  117. package/dist/composed/rich-chat-input.js.map +1 -0
  118. package/dist/composed/rich-text-editor.js +75 -72
  119. package/dist/composed/rich-text-editor.js.map +1 -1
  120. package/dist/composed/schedule-view.js +3 -3
  121. package/dist/composed/schedule-view.js.map +1 -1
  122. package/dist/composed/status-badge.d.ts +3 -2
  123. package/dist/composed/status-badge.d.ts.map +1 -1
  124. package/dist/composed/status-badge.js +58 -53
  125. package/dist/composed/status-badge.js.map +1 -1
  126. package/dist/shell/app-command-palette.d.ts +2 -1
  127. package/dist/shell/app-command-palette.d.ts.map +1 -1
  128. package/dist/shell/app-command-palette.js.map +1 -1
  129. package/dist/shell/bottom-navbar.d.ts +3 -1
  130. package/dist/shell/bottom-navbar.d.ts.map +1 -1
  131. package/dist/shell/bottom-navbar.js +94 -86
  132. package/dist/shell/bottom-navbar.js.map +1 -1
  133. package/dist/shell/command-registry.d.ts +2 -1
  134. package/dist/shell/command-registry.d.ts.map +1 -1
  135. package/dist/shell/command-registry.js.map +1 -1
  136. package/dist/shell/notification-center.js +8 -8
  137. package/dist/shell/notification-center.js.map +1 -1
  138. package/dist/shell/notification-preferences.js +1 -1
  139. package/dist/shell/notification-preferences.js.map +1 -1
  140. package/dist/shell/sidebar.d.ts +7 -4
  141. package/dist/shell/sidebar.d.ts.map +1 -1
  142. package/dist/shell/sidebar.js +148 -134
  143. package/dist/shell/sidebar.js.map +1 -1
  144. package/dist/shell/top-bar.d.ts +4 -3
  145. package/dist/shell/top-bar.d.ts.map +1 -1
  146. package/dist/shell/top-bar.js +116 -108
  147. package/dist/shell/top-bar.js.map +1 -1
  148. package/dist/tokens/semantic.css +82 -9
  149. package/dist/ui/accordion.js +1 -1
  150. package/dist/ui/accordion.js.map +1 -1
  151. package/dist/ui/alert-dialog.js +3 -3
  152. package/dist/ui/alert-dialog.js.map +1 -1
  153. package/dist/ui/alert.js +2 -2
  154. package/dist/ui/alert.js.map +1 -1
  155. package/dist/ui/autocomplete.js +2 -2
  156. package/dist/ui/autocomplete.js.map +1 -1
  157. package/dist/ui/avatar.js +11 -11
  158. package/dist/ui/avatar.js.map +1 -1
  159. package/dist/ui/badge-indicator.js +1 -1
  160. package/dist/ui/badge-indicator.js.map +1 -1
  161. package/dist/ui/badge.d.ts +3 -2
  162. package/dist/ui/badge.d.ts.map +1 -1
  163. package/dist/ui/banner.js +1 -1
  164. package/dist/ui/banner.js.map +1 -1
  165. package/dist/ui/breadcrumb.js +1 -1
  166. package/dist/ui/breadcrumb.js.map +1 -1
  167. package/dist/ui/button.d.ts +5 -4
  168. package/dist/ui/button.d.ts.map +1 -1
  169. package/dist/ui/button.js +66 -65
  170. package/dist/ui/button.js.map +1 -1
  171. package/dist/ui/card.js +5 -5
  172. package/dist/ui/card.js.map +1 -1
  173. package/dist/ui/charts/area-chart.js +177 -0
  174. package/dist/ui/charts/area-chart.js.map +1 -0
  175. package/dist/ui/charts/bar-chart.js +127 -0
  176. package/dist/ui/charts/bar-chart.js.map +1 -0
  177. package/dist/ui/charts/chart-container.js +3 -0
  178. package/dist/ui/charts/gauge-chart.js +72 -0
  179. package/dist/ui/charts/gauge-chart.js.map +1 -0
  180. package/dist/ui/charts/index.js +10 -1035
  181. package/dist/ui/charts/line-chart.js +135 -0
  182. package/dist/ui/charts/line-chart.js.map +1 -0
  183. package/dist/ui/charts/pie-chart.js +111 -0
  184. package/dist/ui/charts/pie-chart.js.map +1 -0
  185. package/dist/ui/charts/radar-chart.js +170 -0
  186. package/dist/ui/charts/radar-chart.js.map +1 -0
  187. package/dist/ui/charts/sparkline.js +119 -0
  188. package/dist/ui/charts/sparkline.js.map +1 -0
  189. package/dist/ui/chat/message.d.ts +3 -3
  190. package/dist/ui/chat/message.d.ts.map +1 -1
  191. package/dist/ui/chat/system-message.d.ts +2 -1
  192. package/dist/ui/chat/system-message.d.ts.map +1 -1
  193. package/dist/ui/checkbox.js +1 -1
  194. package/dist/ui/checkbox.js.map +1 -1
  195. package/dist/ui/code.js +2 -2
  196. package/dist/ui/code.js.map +1 -1
  197. package/dist/ui/color-input.js +10 -10
  198. package/dist/ui/color-input.js.map +1 -1
  199. package/dist/ui/color-swatch.js +3 -3
  200. package/dist/ui/color-swatch.js.map +1 -1
  201. package/dist/ui/combobox.d.ts +2 -1
  202. package/dist/ui/combobox.d.ts.map +1 -1
  203. package/dist/ui/combobox.js +100 -95
  204. package/dist/ui/combobox.js.map +1 -1
  205. package/dist/ui/container.d.ts +6 -1
  206. package/dist/ui/container.d.ts.map +1 -1
  207. package/dist/ui/container.js +2 -1
  208. package/dist/ui/container.js.map +1 -1
  209. package/dist/ui/context-menu.js +6 -6
  210. package/dist/ui/context-menu.js.map +1 -1
  211. package/dist/ui/data-table-body.js +1 -1
  212. package/dist/ui/data-table-body.js.map +1 -1
  213. package/dist/ui/data-table-bulk-actions.js +2 -2
  214. package/dist/ui/data-table-bulk-actions.js.map +1 -1
  215. package/dist/ui/data-table-card.js +2 -2
  216. package/dist/ui/data-table-card.js.map +1 -1
  217. package/dist/ui/data-table-header.js +2 -2
  218. package/dist/ui/data-table-header.js.map +1 -1
  219. package/dist/ui/data-table-pagination.js +3 -3
  220. package/dist/ui/data-table-pagination.js.map +1 -1
  221. package/dist/ui/data-table-toolbar.js +1 -1
  222. package/dist/ui/data-table-toolbar.js.map +1 -1
  223. package/dist/ui/data-table.js +1 -1
  224. package/dist/ui/data-table.js.map +1 -1
  225. package/dist/ui/devalok-grain.d.ts +1 -1
  226. package/dist/ui/devalok-grain.js.map +1 -1
  227. package/dist/ui/dialog.js +2 -2
  228. package/dist/ui/dialog.js.map +1 -1
  229. package/dist/ui/dropdown-menu.js +6 -6
  230. package/dist/ui/dropdown-menu.js.map +1 -1
  231. package/dist/ui/file-upload.js +4 -4
  232. package/dist/ui/file-upload.js.map +1 -1
  233. package/dist/ui/hover-card.js +1 -1
  234. package/dist/ui/hover-card.js.map +1 -1
  235. package/dist/ui/icon-button.d.ts +9 -2
  236. package/dist/ui/icon-button.d.ts.map +1 -1
  237. package/dist/ui/icon-button.js +14 -13
  238. package/dist/ui/icon-button.js.map +1 -1
  239. package/dist/ui/index.d.ts +1 -3
  240. package/dist/ui/index.d.ts.map +1 -1
  241. package/dist/ui/index.js +31 -33
  242. package/dist/ui/index.js.map +1 -1
  243. package/dist/ui/input-otp.js +1 -1
  244. package/dist/ui/input-otp.js.map +1 -1
  245. package/dist/ui/input.js +2 -2
  246. package/dist/ui/input.js.map +1 -1
  247. package/dist/ui/lib/icon-input.d.ts +42 -0
  248. package/dist/ui/lib/icon-input.d.ts.map +1 -0
  249. package/dist/ui/lib/normalize-icon.d.ts +39 -0
  250. package/dist/ui/lib/normalize-icon.d.ts.map +1 -0
  251. package/dist/ui/link.js +1 -1
  252. package/dist/ui/link.js.map +1 -1
  253. package/dist/ui/menubar.js +8 -8
  254. package/dist/ui/menubar.js.map +1 -1
  255. package/dist/ui/navigation-menu.js +3 -3
  256. package/dist/ui/navigation-menu.js.map +1 -1
  257. package/dist/ui/number-input.js +3 -3
  258. package/dist/ui/number-input.js.map +1 -1
  259. package/dist/ui/oauth-button/index.d.ts +3 -0
  260. package/dist/ui/oauth-button/index.d.ts.map +1 -0
  261. package/dist/ui/oauth-button/index.js +3 -0
  262. package/dist/ui/oauth-button/oauth-button.d.ts +208 -0
  263. package/dist/ui/oauth-button/oauth-button.d.ts.map +1 -0
  264. package/dist/ui/pagination.js +1 -1
  265. package/dist/ui/pagination.js.map +1 -1
  266. package/dist/ui/progress.js +2 -2
  267. package/dist/ui/progress.js.map +1 -1
  268. package/dist/ui/radio.js +1 -1
  269. package/dist/ui/radio.js.map +1 -1
  270. package/dist/ui/segmented-control.d.ts +3 -4
  271. package/dist/ui/segmented-control.d.ts.map +1 -1
  272. package/dist/ui/segmented-control.js +53 -45
  273. package/dist/ui/segmented-control.js.map +1 -1
  274. package/dist/ui/select.js +3 -3
  275. package/dist/ui/select.js.map +1 -1
  276. package/dist/ui/sheet.js +2 -2
  277. package/dist/ui/sheet.js.map +1 -1
  278. package/dist/ui/sidebar.js +11 -11
  279. package/dist/ui/sidebar.js.map +1 -1
  280. package/dist/ui/skeleton.js +9 -9
  281. package/dist/ui/skeleton.js.map +1 -1
  282. package/dist/ui/slider.js +2 -2
  283. package/dist/ui/slider.js.map +1 -1
  284. package/dist/ui/split-button.js +7 -7
  285. package/dist/ui/split-button.js.map +1 -1
  286. package/dist/ui/stack.d.ts +6 -1
  287. package/dist/ui/stack.d.ts.map +1 -1
  288. package/dist/ui/stack.js +2 -1
  289. package/dist/ui/stack.js.map +1 -1
  290. package/dist/ui/stat-card.d.ts +2 -3
  291. package/dist/ui/stat-card.d.ts.map +1 -1
  292. package/dist/ui/stat-card.js +118 -116
  293. package/dist/ui/stat-card.js.map +1 -1
  294. package/dist/ui/status-dot.js +2 -2
  295. package/dist/ui/status-dot.js.map +1 -1
  296. package/dist/ui/stepper.d.ts +2 -1
  297. package/dist/ui/stepper.d.ts.map +1 -1
  298. package/dist/ui/stepper.js +74 -69
  299. package/dist/ui/stepper.js.map +1 -1
  300. package/dist/ui/switch.js +2 -2
  301. package/dist/ui/switch.js.map +1 -1
  302. package/dist/ui/tabs.js +3 -3
  303. package/dist/ui/tabs.js.map +1 -1
  304. package/dist/ui/text.d.ts +7 -2
  305. package/dist/ui/text.d.ts.map +1 -1
  306. package/dist/ui/text.js +2 -1
  307. package/dist/ui/text.js.map +1 -1
  308. package/dist/ui/textarea.js +1 -1
  309. package/dist/ui/textarea.js.map +1 -1
  310. package/dist/ui/toast.js +8 -8
  311. package/dist/ui/toast.js.map +1 -1
  312. package/dist/ui/toaster.d.ts +11 -2
  313. package/dist/ui/toaster.d.ts.map +1 -1
  314. package/dist/ui/toaster.js.map +1 -1
  315. package/dist/ui/toggle.js +1 -1
  316. package/dist/ui/toggle.js.map +1 -1
  317. package/dist/ui/tooltip.js +12 -12
  318. package/dist/ui/tooltip.js.map +1 -1
  319. package/dist/ui/tree-view/tree-item.d.ts +3 -2
  320. package/dist/ui/tree-view/tree-item.d.ts.map +1 -1
  321. package/dist/ui/tree-view/use-tree.d.ts +2 -1
  322. package/dist/ui/tree-view/use-tree.d.ts.map +1 -1
  323. package/docs/components/_header.md +90 -1
  324. package/docs/components/ui/oauth-button.md +86 -0
  325. package/docs/recipes/customize-brand.md +100 -4
  326. package/docs/recipes/index.md +5 -1
  327. package/docs/recipes/install-astro.md +15 -0
  328. package/docs/recipes/install-next-app-router.md +21 -5
  329. package/docs/recipes/install-next-pages.md +2 -0
  330. package/docs/recipes/install-remix.md +15 -0
  331. package/docs/recipes/install-tanstack-start.md +15 -0
  332. package/docs/recipes/install-vite.md +15 -0
  333. package/docs/recipes/troubleshoot.md +22 -0
  334. package/llms-full.txt +177 -2
  335. package/llms-quick.txt +247 -0
  336. package/llms.txt +116 -3
  337. package/package.json +80 -2
  338. package/scripts/welcome.mjs +219 -0
  339. package/skill/README.md +99 -0
  340. package/skill/SKILL.md +163 -0
  341. package/skill/install.sh +59 -0
  342. package/skill/references/components-full.md +7083 -0
  343. package/skill/references/components.md +778 -0
  344. package/skill/references/customize-brand.md +314 -0
  345. package/skill/references/server-components.md +211 -0
  346. package/skill/references/setup-astro.md +195 -0
  347. package/skill/references/setup-next-app-router.md +248 -0
  348. package/skill/references/setup-next-pages.md +127 -0
  349. package/skill/references/setup-remix.md +188 -0
  350. package/skill/references/setup-tanstack-start.md +160 -0
  351. package/skill/references/setup-vite.md +187 -0
  352. package/skill/references/troubleshoot.md +241 -0
  353. package/dist/_chunks/date-picker.js +0 -748
  354. package/dist/_chunks/date-picker.js.map +0 -1
  355. package/dist/_chunks/file-preview.js +0 -499
  356. package/dist/_chunks/file-preview.js.map +0 -1
  357. package/dist/_chunks/rich-chat-input.js +0 -2071
  358. package/dist/_chunks/rich-chat-input.js.map +0 -1
  359. package/dist/_chunks/text.js.map +0 -1
  360. package/dist/ui/charts/index.js.map +0 -1
  361. /package/{LICENSE → skill/LICENSE} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"context-menu.js","names":[],"sources":["../../src/ui/context-menu.tsx"],"sourcesContent":["'use client'\n\nimport * as ContextMenuPrimitive from \"@primitives/react-context-menu\"\nimport { IconCheck, IconChevronRight, IconCircle } from '@tabler/icons-react'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from \"react\"\n\nimport { Icon } from './icon'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from \"./lib/utils\"\n\n// ── Internal contexts to thread open state ──\n\nconst ContextMenuOpenContext = React.createContext(false)\nconst ContextMenuSubOpenContext = React.createContext(false)\n\nconst ContextMenu: React.FC<React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Root>> = ({\n onOpenChange,\n ...props\n}) => {\n const [open, setOpen] = React.useState(false)\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n setOpen(value)\n onOpenChange?.(value)\n },\n [onOpenChange],\n )\n\n return (\n <ContextMenuOpenContext.Provider value={open}>\n <ContextMenuPrimitive.Root onOpenChange={handleOpenChange} {...props} />\n </ContextMenuOpenContext.Provider>\n )\n}\nContextMenu.displayName = 'ContextMenu'\n\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger\n\nconst ContextMenuGroup = ContextMenuPrimitive.Group\n\nconst ContextMenuPortal = ContextMenuPrimitive.Portal\n\nconst ContextMenuSub: React.FC<React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Sub>> = ({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n ...props\n}) => {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? controlledOpen : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n if (!isControlled) setUncontrolledOpen(value)\n onOpenChange?.(value)\n },\n [isControlled, onOpenChange],\n )\n\n return (\n <ContextMenuSubOpenContext.Provider value={open}>\n <ContextMenuPrimitive.Sub open={open} onOpenChange={handleOpenChange} {...props} />\n </ContextMenuSubOpenContext.Provider>\n )\n}\nContextMenuSub.displayName = 'ContextMenuSub'\n\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup\n\nconst ContextMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {\n inset?: boolean\n }\n>(({ className, inset, children, ...props }, ref) => (\n <ContextMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center rounded-ds-md px-ds-03 py-ds-02b text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[state=open]:bg-surface-raised data-[state=open]:text-surface-fg\",\n inset && \"pl-ds-07\",\n className\n )}\n {...props}\n >\n {children}\n <Icon icon={IconChevronRight} size=\"sm\" className=\"ml-auto\" />\n </ContextMenuPrimitive.SubTrigger>\n))\nContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName\n\nconst ContextMenuSubContent = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>\n>(({ className, children, ...props }, ref) => {\n const open = React.useContext(ContextMenuSubOpenContext)\n\n return (\n <AnimatePresence>\n {open && (\n <ContextMenuPrimitive.SubContent\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n \"z-popover min-w-[8rem] overflow-hidden rounded-ds-lg border border-surface-border-strong bg-surface-overlay p-ds-02 text-surface-fg shadow-floating\",\n className\n )}\n >\n {children}\n </motion.div>\n </ContextMenuPrimitive.SubContent>\n )}\n </AnimatePresence>\n )\n})\nContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName\n\nconst ContextMenuContent = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\n>(({ className, children, ...props }, ref) => {\n const open = React.useContext(ContextMenuOpenContext)\n\n return (\n <AnimatePresence>\n {open && (\n <ContextMenuPrimitive.Portal forceMount>\n <ContextMenuPrimitive.Content\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n \"z-popover rounded-ds-lg border border-surface-border-strong bg-surface-overlay p-ds-02 text-surface-fg shadow-floating\",\n className\n )}\n >\n {children}\n </motion.div>\n </ContextMenuPrimitive.Content>\n </ContextMenuPrimitive.Portal>\n )}\n </AnimatePresence>\n )\n})\nContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName\n\nconst ContextMenuItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-ds-md px-ds-03 py-ds-02b text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled\",\n inset && \"pl-ds-07\",\n className\n )}\n {...props}\n />\n))\nContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName\n\nconst ContextMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <ContextMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-ds-md py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Icon icon={IconCheck} size=\"sm\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.CheckboxItem>\n))\nContextMenuCheckboxItem.displayName =\n ContextMenuPrimitive.CheckboxItem.displayName\n\nconst ContextMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <ContextMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-ds-md py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled\",\n className\n )}\n {...props}\n >\n <span className=\"absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Icon icon={IconCircle} size=\"sm\" className=\"fill-current\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.RadioItem>\n))\nContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName\n\nconst ContextMenuLabel = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"px-ds-03 py-ds-02b text-ds-md font-semibold text-surface-fg\",\n inset && \"pl-ds-07\",\n className\n )}\n {...props}\n />\n))\nContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName\n\nconst ContextMenuSeparator = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <ContextMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-ds-01 my-ds-02 h-px bg-surface-border\", className)}\n {...props}\n />\n))\nContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName\n\nconst ContextMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn(\n \"ml-auto text-ds-sm text-surface-fg-subtle\",\n className\n )}\n {...props}\n />\n )\n}\nContextMenuShortcut.displayName = \"ContextMenuShortcut\"\n\nexport type ContextMenuContentProps = React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\nexport type ContextMenuItemProps = React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item>\n\nexport {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n ContextMenuGroup,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuPortal,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"context-menu.js","names":[],"sources":["../../src/ui/context-menu.tsx"],"sourcesContent":["'use client'\n\nimport * as ContextMenuPrimitive from \"@primitives/react-context-menu\"\nimport { IconCheck, IconChevronRight, IconCircle } from '@tabler/icons-react'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from \"react\"\n\nimport { Icon } from './icon'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from \"./lib/utils\"\n\n// ── Internal contexts to thread open state ──\n\nconst ContextMenuOpenContext = React.createContext(false)\nconst ContextMenuSubOpenContext = React.createContext(false)\n\nconst ContextMenu: React.FC<React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Root>> = ({\n onOpenChange,\n ...props\n}) => {\n const [open, setOpen] = React.useState(false)\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n setOpen(value)\n onOpenChange?.(value)\n },\n [onOpenChange],\n )\n\n return (\n <ContextMenuOpenContext.Provider value={open}>\n <ContextMenuPrimitive.Root onOpenChange={handleOpenChange} {...props} />\n </ContextMenuOpenContext.Provider>\n )\n}\nContextMenu.displayName = 'ContextMenu'\n\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger\n\nconst ContextMenuGroup = ContextMenuPrimitive.Group\n\nconst ContextMenuPortal = ContextMenuPrimitive.Portal\n\nconst ContextMenuSub: React.FC<React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Sub>> = ({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n ...props\n}) => {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? controlledOpen : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n if (!isControlled) setUncontrolledOpen(value)\n onOpenChange?.(value)\n },\n [isControlled, onOpenChange],\n )\n\n return (\n <ContextMenuSubOpenContext.Provider value={open}>\n <ContextMenuPrimitive.Sub open={open} onOpenChange={handleOpenChange} {...props} />\n </ContextMenuSubOpenContext.Provider>\n )\n}\nContextMenuSub.displayName = 'ContextMenuSub'\n\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup\n\nconst ContextMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {\n inset?: boolean\n }\n>(({ className, inset, children, ...props }, ref) => (\n <ContextMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center rounded-control px-ds-03 py-ds-02b text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[state=open]:bg-surface-raised data-[state=open]:text-surface-fg\",\n inset && \"pl-ds-07\",\n className\n )}\n {...props}\n >\n {children}\n <Icon icon={IconChevronRight} size=\"sm\" className=\"ml-auto\" />\n </ContextMenuPrimitive.SubTrigger>\n))\nContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName\n\nconst ContextMenuSubContent = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>\n>(({ className, children, ...props }, ref) => {\n const open = React.useContext(ContextMenuSubOpenContext)\n\n return (\n <AnimatePresence>\n {open && (\n <ContextMenuPrimitive.SubContent\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n \"z-popover min-w-[8rem] overflow-hidden rounded-overlay border border-surface-border-strong bg-surface-overlay p-ds-02 text-surface-fg shadow-floating\",\n className\n )}\n >\n {children}\n </motion.div>\n </ContextMenuPrimitive.SubContent>\n )}\n </AnimatePresence>\n )\n})\nContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName\n\nconst ContextMenuContent = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\n>(({ className, children, ...props }, ref) => {\n const open = React.useContext(ContextMenuOpenContext)\n\n return (\n <AnimatePresence>\n {open && (\n <ContextMenuPrimitive.Portal forceMount>\n <ContextMenuPrimitive.Content\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n \"z-popover rounded-overlay border border-surface-border-strong bg-surface-overlay p-ds-02 text-surface-fg shadow-floating\",\n className\n )}\n >\n {children}\n </motion.div>\n </ContextMenuPrimitive.Content>\n </ContextMenuPrimitive.Portal>\n )}\n </AnimatePresence>\n )\n})\nContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName\n\nconst ContextMenuItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-control px-ds-03 py-ds-02b text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled\",\n inset && \"pl-ds-07\",\n className\n )}\n {...props}\n />\n))\nContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName\n\nconst ContextMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <ContextMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-control py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Icon icon={IconCheck} size=\"sm\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.CheckboxItem>\n))\nContextMenuCheckboxItem.displayName =\n ContextMenuPrimitive.CheckboxItem.displayName\n\nconst ContextMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <ContextMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-control py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled\",\n className\n )}\n {...props}\n >\n <span className=\"absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Icon icon={IconCircle} size=\"sm\" className=\"fill-current\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.RadioItem>\n))\nContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName\n\nconst ContextMenuLabel = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"px-ds-03 py-ds-02b text-ds-md font-semibold text-surface-fg\",\n inset && \"pl-ds-07\",\n className\n )}\n {...props}\n />\n))\nContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName\n\nconst ContextMenuSeparator = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <ContextMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-ds-01 my-ds-02 h-px bg-surface-border\", className)}\n {...props}\n />\n))\nContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName\n\nconst ContextMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn(\n \"ml-auto text-ds-sm text-surface-fg-subtle\",\n className\n )}\n {...props}\n />\n )\n}\nContextMenuShortcut.displayName = \"ContextMenuShortcut\"\n\nexport type ContextMenuContentProps = React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\nexport type ContextMenuItemProps = React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item>\n\nexport {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n ContextMenuGroup,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuPortal,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n}\n"],"mappings":"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"}
@@ -24,7 +24,7 @@ function _({ initialValue: t, onSave: n, onCancel: r }) {
24
24
  onKeyDown: (e) => {
25
25
  e.key === "Enter" ? (e.preventDefault(), s()) : e.key === "Escape" && (e.preventDefault(), r());
26
26
  },
27
- className: e("h-ds-xs-plus w-full rounded-ds-md", "border border-accent-7 bg-surface-raised-hover", "px-ds-02 text-ds-sm", "text-surface-fg placeholder:text-surface-fg-subtle", "outline-hidden focus:border-accent-7"),
27
+ className: e("h-ds-xs-plus w-full rounded-control", "border border-accent-7 bg-surface-raised-hover", "px-ds-02 text-ds-sm", "text-surface-fg placeholder:text-surface-fg-subtle", "outline-hidden focus:border-accent-7"),
28
28
  "aria-label": "Edit cell value"
29
29
  });
30
30
  }
@@ -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 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 { 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-ds-md',\n 'border border-accent-7 bg-surface-raised-hover',\n 'px-ds-02 text-ds-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 cellPadding,\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 cellPadding,\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\n if (!expandable || !row.getIsExpanded() || !renderExpanded) return null\n\n return (\n <TableRow\n style={style}\n className={virtualRows ? 'absolute w-full flex' : undefined}\n >\n <TableCell\n colSpan={allColumns.length}\n className={cn(\n 'bg-surface-raised p-ds-05',\n virtualRows && 'flex-1',\n )}\n >\n {renderExpanded(row.original)}\n </TableCell>\n </TableRow>\n )\n}\n\n// ── SkeletonRows ────────────────────────────────────────────────\n\nfunction DataTableSkeletonRows({\n rowCount,\n}: {\n rowCount: number\n}) {\n const { allColumns, cellPadding } = 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\n key={`skeleton-${rowIdx}-${colIdx}`}\n className={cellPadding}\n >\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 'h-24 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 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 { 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-ds-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 cellPadding,\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 cellPadding,\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\n if (!expandable || !row.getIsExpanded() || !renderExpanded) return null\n\n return (\n <TableRow\n style={style}\n className={virtualRows ? 'absolute w-full flex' : undefined}\n >\n <TableCell\n colSpan={allColumns.length}\n className={cn(\n 'bg-surface-raised p-ds-05',\n virtualRows && 'flex-1',\n )}\n >\n {renderExpanded(row.original)}\n </TableCell>\n </TableRow>\n )\n}\n\n// ── SkeletonRows ────────────────────────────────────────────────\n\nfunction DataTableSkeletonRows({\n rowCount,\n}: {\n rowCount: number\n}) {\n const { allColumns, cellPadding } = 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\n key={`skeleton-${rowIdx}-${colIdx}`}\n className={cellPadding}\n >\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 'h-24 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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"}
@@ -8,7 +8,7 @@ import { IconX as a } from "@tabler/icons-react";
8
8
  //#region src/ui/data-table-bulk-actions.tsx
9
9
  function o({ table: o, selectedRows: s, bulkActions: c }) {
10
10
  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-ds-lg border border-surface-border-strong bg-surface-overlay shadow-floating", "animate-in slide-in-from-bottom-2"),
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 border border-surface-border-strong bg-surface-overlay shadow-floating", "animate-in slide-in-from-bottom-2"),
12
12
  role: "toolbar",
13
13
  "aria-label": "Bulk actions",
14
14
  children: [
@@ -32,7 +32,7 @@ function o({ table: o, selectedRows: s, bulkActions: c }) {
32
32
  type: "button",
33
33
  onClick: () => o.resetRowSelection(),
34
34
  "aria-label": "Clear selection",
35
- className: e("flex items-center justify-center p-ds-01", "rounded-ds-sm hover:bg-surface-raised transition-colors", "text-surface-fg-muted hover:text-surface-fg"),
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"),
36
36
  children: /* @__PURE__ */ r(t, {
37
37
  icon: a,
38
38
  size: "sm"
@@ -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-ds-lg border border-surface-border-strong 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-ds-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-ds-sm 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;AACD,QACE,kBAAC,OAAD;EACE,WAAW,EACT,qDACA,iDACA,wFACA,oCACD;EACD,MAAK;EACL,cAAW;YARb;GAUE,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACG,EAAa,QAAO,YAChB;;GACP,kBAAC,OAAD;IAAK,WAAU;IAA6B,eAAY;IAAS,CAAA;GAChE,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,EAAa;cAE1C,EAAO;IACD,EARF,EAAO,MAQL,CACT;GACF,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAM,mBAAmB;IACxC,cAAW;IACX,WAAW,EACT,4CACA,2DACA,8CACD;cAED,kBAAC,GAAD;KAAM,MAAM;KAAO,MAAK;KAAO,CAAA;IACxB,CAAA;GACL"}
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 border border-surface-border-strong 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-ds-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;AACD,QACE,kBAAC,OAAD;EACE,WAAW,EACT,qDACA,iDACA,0FACA,oCACD;EACD,MAAK;EACL,cAAW;YARb;GAUE,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACG,EAAa,QAAO,YAChB;;GACP,kBAAC,OAAD;IAAK,WAAU;IAA6B,eAAY;IAAS,CAAA;GAChE,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,EAAa;cAE1C,EAAO;IACD,EARF,EAAO,MAQL,CACT;GACF,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAM,mBAAmB;IACxC,cAAW;IACX,WAAW,EACT,4CACA,mEACA,8CACD;cAED,kBAAC,GAAD;KAAM,MAAM;KAAO,MAAK;KAAO,CAAA;IACxB,CAAA;GACL"}
@@ -12,7 +12,7 @@ function s({ loading: s, skeletonRowCount: c, noResultsText: l, emptyState: u })
12
12
  return s ? /* @__PURE__ */ i("div", {
13
13
  className: "flex flex-col gap-ds-03",
14
14
  children: Array.from({ length: c }, (e, t) => /* @__PURE__ */ a("div", {
15
- className: "rounded-ds-lg border border-surface-border bg-surface-raised p-ds-04",
15
+ className: "rounded-surface border border-surface-border bg-surface-raised p-ds-04",
16
16
  children: [/* @__PURE__ */ i(r, {
17
17
  variant: "text",
18
18
  className: "mb-ds-03 h-5 w-2/3",
@@ -45,7 +45,7 @@ function s({ loading: s, skeletonRowCount: c, noResultsText: l, emptyState: u })
45
45
  let r = n.getVisibleCells().filter((e) => e.column.id !== "_select" && e.column.id !== "_expand"), s = r[0], c = r.slice(1), l = n.getIsSelected();
46
46
  return /* @__PURE__ */ a("div", {
47
47
  role: "listitem",
48
- className: e("rounded-ds-lg border border-surface-border bg-surface-raised p-ds-04", l && "ring-2 ring-accent-9"),
48
+ className: e("rounded-surface border border-surface-border bg-surface-raised p-ds-04", l && "ring-2 ring-accent-9"),
49
49
  children: [/* @__PURE__ */ a("div", {
50
50
  className: "flex items-start justify-between gap-ds-03 mb-ds-02",
51
51
  children: [/* @__PURE__ */ i("div", {
@@ -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 { 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 <div\n key={`card-skeleton-${i}`}\n className=\"rounded-ds-lg border border-surface-border bg-surface-raised p-ds-04\"\n >\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 </div>\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 <div\n key={row.id}\n role=\"listitem\"\n className={cn(\n 'rounded-ds-lg border border-surface-border bg-surface-raised p-ds-04',\n isSelected && 'ring-2 ring-accent-9',\n )}\n >\n {/* Header row: primary field + optional selection checkbox */}\n <div className=\"flex items-start justify-between gap-ds-03 mb-ds-02\">\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 </div>\n\n {/* Label-value pairs for remaining columns */}\n {restCells.length > 0 && (\n <div className=\"flex flex-col gap-ds-01 border-t border-surface-border pt-ds-02\">\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-ds-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 </div>\n )}\n </div>\n )\n })}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,EAAsB,EACpC,YACA,qBACA,kBACA,iBAMC;CACD,IAAM,EAAE,UAAO,kBAAe,GAA4B,EACpD,IAAO,EAAM,aAAa,CAAC;AAgCjC,QA7BI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,EAAE,QAAQ,GAAkB,GAAG,GAAG,MAC5C,kBAAC,OAAD;GAEE,WAAU;aAFZ,CAIE,kBAAC,GAAD;IAAU,SAAQ;IAAO,WAAU;IAAqB,WAAU;IAAU,CAAA,EAC5E,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAa,WAAU;MAAU,CAAA;KACpE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAY,WAAU;MAAU,CAAA;KACnE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAY,WAAU;MAAU,CAAA;KAC/D;MACF;KATC,iBAAiB,IASlB,CACN;EACE,CAAA,GAKL,EAAK,SASR,kBAAC,OAAD;EAAK,WAAU;EAA0B,MAAK;YAC3C,EAAK,KAAK,MAAQ;GAGjB,IAAM,IAFQ,EAAI,iBAAiB,CAER,QACxB,MAAS,EAAK,OAAO,OAAO,aAAa,EAAK,OAAO,OAAO,UAC9D,EACK,IAAc,EAAa,IAC3B,IAAY,EAAa,MAAM,EAAE,EACjC,IAAa,EAAI,eAAe;AAEtC,UACE,kBAAC,OAAD;IAEE,MAAK;IACL,WAAW,EACT,wEACA,KAAc,uBACf;cANH,CASE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACZ,KACC,EAAW,EAAY,OAAO,UAAU,MAAM,EAAY,YAAY,CAAC;MACrE,CAAA,EACL,KACC,kBAAC,GAAD;MACE,MAAK;MACL,SAAS;MACT,UAAU,CAAC,EAAI,cAAc;MAC7B,kBAAkB,MAAM,EAAI,eAAe,CAAC,CAAC,EAAE;MAC/C,cAAW;MACX,WAAU;MACV,CAAA,CAEA;QAGL,EAAU,SAAS,KAClB,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAU,KAAK,MAAS;MAEvB,IAAM,IAAO,EAAK,OAAO,UAAU;AAiBnC,aAXI,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;QAIkD,CAAA,EAChE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAW,EAAK,OAAO,UAAU,MAAM,EAAK,YAAY,CAAC;QACrD,CAAA,CACH;SALI,EAAK,GAKT;OAER;KACE,CAAA,CAEJ;MA1DC,EAAI,GA0DL;IAER;EACE,CAAA,GAjFJ,kBAAC,OAAD;EAAK,WAAW,EAAG,wBAAwB,CAAC,KAAc,yBAAyB;YAChF,KAAc,KAAiB;EAC5B,CAAA"}
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 { 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 <div\n key={`card-skeleton-${i}`}\n className=\"rounded-surface border border-surface-border bg-surface-raised p-ds-04\"\n >\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 </div>\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 <div\n key={row.id}\n role=\"listitem\"\n className={cn(\n 'rounded-surface border border-surface-border bg-surface-raised p-ds-04',\n isSelected && 'ring-2 ring-accent-9',\n )}\n >\n {/* Header row: primary field + optional selection checkbox */}\n <div className=\"flex items-start justify-between gap-ds-03 mb-ds-02\">\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 </div>\n\n {/* Label-value pairs for remaining columns */}\n {restCells.length > 0 && (\n <div className=\"flex flex-col gap-ds-01 border-t border-surface-border pt-ds-02\">\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-ds-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 </div>\n )}\n </div>\n )\n })}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,EAAsB,EACpC,YACA,qBACA,kBACA,iBAMC;CACD,IAAM,EAAE,UAAO,kBAAe,GAA4B,EACpD,IAAO,EAAM,aAAa,CAAC;AAgCjC,QA7BI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,EAAE,QAAQ,GAAkB,GAAG,GAAG,MAC5C,kBAAC,OAAD;GAEE,WAAU;aAFZ,CAIE,kBAAC,GAAD;IAAU,SAAQ;IAAO,WAAU;IAAqB,WAAU;IAAU,CAAA,EAC5E,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAa,WAAU;MAAU,CAAA;KACpE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAY,WAAU;MAAU,CAAA;KACnE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAY,WAAU;MAAU,CAAA;KAC/D;MACF;KATC,iBAAiB,IASlB,CACN;EACE,CAAA,GAKL,EAAK,SASR,kBAAC,OAAD;EAAK,WAAU;EAA0B,MAAK;YAC3C,EAAK,KAAK,MAAQ;GAGjB,IAAM,IAFQ,EAAI,iBAAiB,CAER,QACxB,MAAS,EAAK,OAAO,OAAO,aAAa,EAAK,OAAO,OAAO,UAC9D,EACK,IAAc,EAAa,IAC3B,IAAY,EAAa,MAAM,EAAE,EACjC,IAAa,EAAI,eAAe;AAEtC,UACE,kBAAC,OAAD;IAEE,MAAK;IACL,WAAW,EACT,0EACA,KAAc,uBACf;cANH,CASE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACZ,KACC,EAAW,EAAY,OAAO,UAAU,MAAM,EAAY,YAAY,CAAC;MACrE,CAAA,EACL,KACC,kBAAC,GAAD;MACE,MAAK;MACL,SAAS;MACT,UAAU,CAAC,EAAI,cAAc;MAC7B,kBAAkB,MAAM,EAAI,eAAe,CAAC,CAAC,EAAE;MAC/C,cAAW;MACX,WAAU;MACV,CAAA,CAEA;QAGL,EAAU,SAAS,KAClB,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAU,KAAK,MAAS;MAEvB,IAAM,IAAO,EAAK,OAAO,UAAU;AAiBnC,aAXI,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;QAIkD,CAAA,EAChE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAW,EAAK,OAAO,UAAU,MAAM,EAAK,YAAY,CAAC;QACrD,CAAA,CACH;SALI,EAAK,GAKT;OAER;KACE,CAAA,CAEJ;MA1DC,EAAI,GA0DL;IAER;EACE,CAAA,GAjFJ,kBAAC,OAAD;EAAK,WAAW,EAAG,wBAAwB,CAAC,KAAc,yBAAyB;YAChF,KAAc,KAAiB;EAC5B,CAAA"}
@@ -22,7 +22,7 @@ function _({ stickyHeader: _ }) {
22
22
  "aria-sort": s ? c === "asc" ? "ascending" : c === "desc" ? "descending" : "none" : void 0,
23
23
  children: a.isPlaceholder ? null : s ? /* @__PURE__ */ u("button", {
24
24
  type: "button",
25
- className: t("flex items-center gap-ds-01 font-medium", "cursor-pointer select-none", "-ml-ds-01 rounded-ds-sm px-ds-01 py-ds-01", "hover:bg-surface-raised transition-colors"),
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 transition-colors"),
26
26
  onClick: a.column.getToggleSortingHandler(),
27
27
  "aria-label": `Sort by ${typeof a.column.columnDef.header == "string" ? a.column.columnDef.header : a.column.id}`,
28
28
  children: [g(a.column.columnDef.header, a.getContext()), /* @__PURE__ */ l(m, {
@@ -91,7 +91,7 @@ function _({ stickyHeader: _ }) {
91
91
  onChange: (t) => e.column.setFilterValue(t.target.value),
92
92
  placeholder: `Filter ${typeof e.column.columnDef.header == "string" ? e.column.columnDef.header : ""}...`,
93
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-ds-md", "border border-surface-border-strong bg-surface-raised-hover", "px-ds-02 text-ds-sm", "text-surface-fg placeholder:text-surface-fg-subtle", "outline-hidden focus:border-accent-7")
94
+ className: t("h-ds-xs-plus w-full rounded-control", "border border-surface-border-strong bg-surface-raised-hover", "px-ds-02 text-ds-sm", "text-surface-fg placeholder:text-surface-fg-subtle", "outline-hidden focus:border-accent-7")
95
95
  })
96
96
  }, `${e.id}-filter`)) }, `${e.id}-filters`))]
97
97
  });
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-header.js","names":[],"sources":["../../src/ui/data-table-header.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconArrowDown,\n IconArrowsSort,\n IconArrowUp,\n} from '@tabler/icons-react'\nimport { flexRender } from '@tanstack/react-table'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport React from 'react'\n\nimport {\n getColumnMetaClasses,\n getPinnedCellStyle,\n useDataTableContext,\n} from './data-table-context'\nimport { Icon } from './icon'\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\nimport { TableHead, TableHeader, TableRow } from './table'\n\n/**\n * Renders the `<TableHeader>` block including sortable column headers\n * and optional per-column filter inputs. Internal — not exported to consumers.\n */\nfunction DataTableHeaderImpl({ stickyHeader }: { stickyHeader?: boolean }) {\n const { table, sortable, filterable, columnPinningState } =\n useDataTableContext()\n\n return (\n <TableHeader\n className={cn(\n stickyHeader && 'sticky top-0 z-10 bg-surface-base',\n )}\n >\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => {\n const canSort = sortable && header.column.getCanSort()\n const sorted = header.column.getIsSorted()\n const pinned = getPinnedCellStyle(\n header.column.id,\n columnPinningState,\n )\n\n return (\n <TableHead\n key={header.id}\n className={cn(\n pinned.className,\n getColumnMetaClasses(\n header.column.columnDef.meta as Record<string, unknown>,\n ),\n )}\n style={pinned.style}\n aria-sort={\n canSort\n ? sorted === 'asc'\n ? 'ascending'\n : sorted === 'desc'\n ? 'descending'\n : 'none'\n : undefined\n }\n >\n {header.isPlaceholder ? null : canSort ? (\n <button\n type=\"button\"\n className={cn(\n 'flex items-center gap-ds-01 font-medium',\n 'cursor-pointer select-none',\n '-ml-ds-01 rounded-ds-sm px-ds-01 py-ds-01',\n 'hover:bg-surface-raised transition-colors',\n )}\n onClick={header.column.getToggleSortingHandler()}\n aria-label={`Sort by ${typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.column.id}`}\n >\n {flexRender(\n header.column.columnDef.header,\n header.getContext(),\n )}\n <AnimatePresence mode=\"wait\" initial={false}>\n {sorted === 'asc' ? (\n <motion.span\n key=\"asc\"\n initial={{ opacity: 0, rotate: 90 }}\n animate={{ opacity: 1, rotate: 0 }}\n exit={{ opacity: 0, rotate: -90 }}\n transition={springs.snappy}\n className=\"inline-flex\"\n >\n <Icon\n icon={IconArrowUp}\n size=\"sm\"\n className=\"text-surface-fg-muted\"\n />\n </motion.span>\n ) : sorted === 'desc' ? (\n <motion.span\n key=\"desc\"\n initial={{ opacity: 0, rotate: -90 }}\n animate={{ opacity: 1, rotate: 0 }}\n exit={{ opacity: 0, rotate: 90 }}\n transition={springs.snappy}\n className=\"inline-flex\"\n >\n <Icon\n icon={IconArrowDown}\n size=\"sm\"\n className=\"text-surface-fg-muted\"\n />\n </motion.span>\n ) : (\n <motion.span\n key=\"unsorted\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={springs.snappy}\n className=\"inline-flex\"\n >\n <Icon\n icon={IconArrowsSort}\n size=\"sm\"\n className=\"text-surface-fg-subtle\"\n />\n </motion.span>\n )}\n </AnimatePresence>\n </button>\n ) : (\n flexRender(\n header.column.columnDef.header,\n header.getContext(),\n )\n )}\n </TableHead>\n )\n })}\n </TableRow>\n ))}\n\n {/* Column filter row */}\n {filterable &&\n table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={`${headerGroup.id}-filters`}>\n {headerGroup.headers.map((header) => (\n <TableHead key={`${header.id}-filter`} className=\"py-ds-01\">\n {header.isPlaceholder ||\n header.column.columnDef.enableColumnFilter === false ? null : (\n <input\n type=\"text\"\n value={\n (header.column.getFilterValue() as string) ?? ''\n }\n onChange={(e) =>\n header.column.setFilterValue(e.target.value)\n }\n placeholder={`Filter ${typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : ''}...`}\n aria-label={`Filter ${typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.column.id}`}\n className={cn(\n 'h-ds-xs-plus w-full rounded-ds-md',\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'px-ds-02 text-ds-sm',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden focus:border-accent-7',\n )}\n />\n )}\n </TableHead>\n ))}\n </TableRow>\n ))}\n </TableHeader>\n )\n}\n\nexport { DataTableHeaderImpl as DataTableHeader }\n"],"mappings":"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"}
1
+ {"version":3,"file":"data-table-header.js","names":[],"sources":["../../src/ui/data-table-header.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconArrowDown,\n IconArrowsSort,\n IconArrowUp,\n} from '@tabler/icons-react'\nimport { flexRender } from '@tanstack/react-table'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport React from 'react'\n\nimport {\n getColumnMetaClasses,\n getPinnedCellStyle,\n useDataTableContext,\n} from './data-table-context'\nimport { Icon } from './icon'\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\nimport { TableHead, TableHeader, TableRow } from './table'\n\n/**\n * Renders the `<TableHeader>` block including sortable column headers\n * and optional per-column filter inputs. Internal — not exported to consumers.\n */\nfunction DataTableHeaderImpl({ stickyHeader }: { stickyHeader?: boolean }) {\n const { table, sortable, filterable, columnPinningState } =\n useDataTableContext()\n\n return (\n <TableHeader\n className={cn(\n stickyHeader && 'sticky top-0 z-10 bg-surface-base',\n )}\n >\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => {\n const canSort = sortable && header.column.getCanSort()\n const sorted = header.column.getIsSorted()\n const pinned = getPinnedCellStyle(\n header.column.id,\n columnPinningState,\n )\n\n return (\n <TableHead\n key={header.id}\n className={cn(\n pinned.className,\n getColumnMetaClasses(\n header.column.columnDef.meta as Record<string, unknown>,\n ),\n )}\n style={pinned.style}\n aria-sort={\n canSort\n ? sorted === 'asc'\n ? 'ascending'\n : sorted === 'desc'\n ? 'descending'\n : 'none'\n : undefined\n }\n >\n {header.isPlaceholder ? null : canSort ? (\n <button\n type=\"button\"\n className={cn(\n 'flex items-center gap-ds-01 font-medium',\n 'cursor-pointer select-none',\n '-ml-ds-01 rounded-control-inner px-ds-01 py-ds-01',\n 'hover:bg-surface-raised transition-colors',\n )}\n onClick={header.column.getToggleSortingHandler()}\n aria-label={`Sort by ${typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.column.id}`}\n >\n {flexRender(\n header.column.columnDef.header,\n header.getContext(),\n )}\n <AnimatePresence mode=\"wait\" initial={false}>\n {sorted === 'asc' ? (\n <motion.span\n key=\"asc\"\n initial={{ opacity: 0, rotate: 90 }}\n animate={{ opacity: 1, rotate: 0 }}\n exit={{ opacity: 0, rotate: -90 }}\n transition={springs.snappy}\n className=\"inline-flex\"\n >\n <Icon\n icon={IconArrowUp}\n size=\"sm\"\n className=\"text-surface-fg-muted\"\n />\n </motion.span>\n ) : sorted === 'desc' ? (\n <motion.span\n key=\"desc\"\n initial={{ opacity: 0, rotate: -90 }}\n animate={{ opacity: 1, rotate: 0 }}\n exit={{ opacity: 0, rotate: 90 }}\n transition={springs.snappy}\n className=\"inline-flex\"\n >\n <Icon\n icon={IconArrowDown}\n size=\"sm\"\n className=\"text-surface-fg-muted\"\n />\n </motion.span>\n ) : (\n <motion.span\n key=\"unsorted\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={springs.snappy}\n className=\"inline-flex\"\n >\n <Icon\n icon={IconArrowsSort}\n size=\"sm\"\n className=\"text-surface-fg-subtle\"\n />\n </motion.span>\n )}\n </AnimatePresence>\n </button>\n ) : (\n flexRender(\n header.column.columnDef.header,\n header.getContext(),\n )\n )}\n </TableHead>\n )\n })}\n </TableRow>\n ))}\n\n {/* Column filter row */}\n {filterable &&\n table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={`${headerGroup.id}-filters`}>\n {headerGroup.headers.map((header) => (\n <TableHead key={`${header.id}-filter`} className=\"py-ds-01\">\n {header.isPlaceholder ||\n header.column.columnDef.enableColumnFilter === false ? null : (\n <input\n type=\"text\"\n value={\n (header.column.getFilterValue() as string) ?? ''\n }\n onChange={(e) =>\n header.column.setFilterValue(e.target.value)\n }\n placeholder={`Filter ${typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : ''}...`}\n aria-label={`Filter ${typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.column.id}`}\n className={cn(\n 'h-ds-xs-plus w-full rounded-control',\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'px-ds-02 text-ds-sm',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden focus:border-accent-7',\n )}\n />\n )}\n </TableHead>\n ))}\n </TableRow>\n ))}\n </TableHeader>\n )\n}\n\nexport { DataTableHeaderImpl as DataTableHeader }\n"],"mappings":"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"}
@@ -20,7 +20,7 @@ function o({ table: o, totalRowCount: s, useServerPagination: c, pageSizeOptions
20
20
  o.setPageSize(Number(e.target.value));
21
21
  },
22
22
  "aria-label": "Rows per page",
23
- className: e("h-ds-sm rounded-ds-md", "border border-surface-border-strong bg-surface-raised-hover", "px-ds-03 text-ds-sm", "text-surface-fg"),
23
+ className: e("h-ds-sm rounded-control", "border border-surface-border-strong bg-surface-raised-hover", "px-ds-03 text-ds-sm", "text-surface-fg"),
24
24
  children: (l ?? [
25
25
  10,
26
26
  20,
@@ -36,7 +36,7 @@ function o({ table: o, totalRowCount: s, useServerPagination: c, pageSizeOptions
36
36
  disabled: !o.getCanPreviousPage(),
37
37
  onClick: () => o.previousPage(),
38
38
  "aria-label": "Previous page",
39
- className: e("h-ds-sm w-ds-sm flex items-center justify-center", "rounded-ds-md border border-surface-border-strong", "enabled:hover:bg-surface-raised", "disabled:opacity-action-disabled disabled:cursor-not-allowed", "transition-colors"),
39
+ className: e("h-ds-sm w-ds-sm flex items-center justify-center", "rounded-control border border-surface-border-strong", "enabled:hover:bg-surface-raised", "disabled:opacity-action-disabled disabled:cursor-not-allowed", "transition-colors"),
40
40
  children: /* @__PURE__ */ n(t, {
41
41
  icon: i,
42
42
  size: "sm"
@@ -57,7 +57,7 @@ function o({ table: o, totalRowCount: s, useServerPagination: c, pageSizeOptions
57
57
  disabled: !o.getCanNextPage(),
58
58
  onClick: () => o.nextPage(),
59
59
  "aria-label": "Next page",
60
- className: e("h-ds-sm w-ds-sm flex items-center justify-center", "rounded-ds-md border border-surface-border-strong", "enabled:hover:bg-surface-raised", "disabled:opacity-action-disabled disabled:cursor-not-allowed", "transition-colors"),
60
+ className: e("h-ds-sm w-ds-sm flex items-center justify-center", "rounded-control border border-surface-border-strong", "enabled:hover:bg-surface-raised", "disabled:opacity-action-disabled disabled:cursor-not-allowed", "transition-colors"),
61
61
  children: /* @__PURE__ */ n(t, {
62
62
  icon: a,
63
63
  size: "sm"
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-pagination.js","names":[],"sources":["../../src/ui/data-table-pagination.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'\nimport { type Table } from '@tanstack/react-table'\nimport React from 'react'\n\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\n/**\n * Pagination controls: page size selector, prev/next buttons, page info.\n * Internal — not exported to consumers.\n */\nexport function DataTablePagination<TData>({\n table,\n totalRowCount,\n useServerPagination,\n pageSizeOptions,\n}: {\n table: Table<TData>\n totalRowCount: number\n useServerPagination: boolean\n pageSizeOptions?: number[]\n}) {\n return (\n <div className=\"flex items-center justify-between px-ds-03 py-ds-04 border-t border-surface-border\">\n <span className=\"text-ds-sm text-surface-fg-muted\">\n {totalRowCount} total rows\n </span>\n <div className=\"flex items-center gap-ds-03\">\n {/* Page size selector */}\n {!useServerPagination && (\n <select\n value={table.getState().pagination.pageSize}\n onChange={(e) => {\n table.setPageSize(Number(e.target.value))\n }}\n aria-label=\"Rows per page\"\n className={cn(\n 'h-ds-sm rounded-ds-md',\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'px-ds-03 text-ds-sm',\n 'text-surface-fg',\n )}\n >\n {(pageSizeOptions ?? [10, 20, 50, 100]).map((size) => (\n <option key={size} value={size}>\n {size} rows\n </option>\n ))}\n </select>\n )}\n\n {/* Previous page button */}\n <button\n type=\"button\"\n disabled={!table.getCanPreviousPage()}\n onClick={() => table.previousPage()}\n aria-label=\"Previous page\"\n className={cn(\n 'h-ds-sm w-ds-sm flex items-center justify-center',\n 'rounded-ds-md border border-surface-border-strong',\n 'enabled:hover:bg-surface-raised',\n 'disabled:opacity-action-disabled disabled:cursor-not-allowed',\n 'transition-colors',\n )}\n >\n <Icon icon={IconChevronLeft} size=\"sm\" />\n </button>\n\n {/* Page info */}\n <span className=\"text-ds-sm text-surface-fg-muted\">\n Page {table.getState().pagination.pageIndex + 1} of{' '}\n {table.getPageCount()}\n </span>\n\n {/* Next page button */}\n <button\n type=\"button\"\n disabled={!table.getCanNextPage()}\n onClick={() => table.nextPage()}\n aria-label=\"Next page\"\n className={cn(\n 'h-ds-sm w-ds-sm flex items-center justify-center',\n 'rounded-ds-md border border-surface-border-strong',\n 'enabled:hover:bg-surface-raised',\n 'disabled:opacity-action-disabled disabled:cursor-not-allowed',\n 'transition-colors',\n )}\n >\n <Icon icon={IconChevronRight} size=\"sm\" />\n </button>\n </div>\n </div>\n )\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,EAA2B,EACzC,UACA,kBACA,wBACA,sBAMC;AACD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACG,GAAc,cACV;MACP,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEG,CAAC,KACA,kBAAC,UAAD;KACE,OAAO,EAAM,UAAU,CAAC,WAAW;KACnC,WAAW,MAAM;AACf,QAAM,YAAY,OAAO,EAAE,OAAO,MAAM,CAAC;;KAE3C,cAAW;KACX,WAAW,EACT,yBACA,+DACA,uBACA,kBACD;gBAEC,KAAmB;MAAC;MAAI;MAAI;MAAI;MAAI,EAAE,KAAK,MAC3C,kBAAC,UAAD;MAAmB,OAAO;gBAA1B,CACG,GAAK,QACC;QAFI,EAEJ,CACT;KACK,CAAA;IAIX,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,CAAC,EAAM,oBAAoB;KACrC,eAAe,EAAM,cAAc;KACnC,cAAW;KACX,WAAW,EACT,oDACA,qDACA,mCACA,gEACA,oBACD;eAED,kBAAC,GAAD;MAAM,MAAM;MAAiB,MAAK;MAAO,CAAA;KAClC,CAAA;IAGT,kBAAC,QAAD;KAAM,WAAU;eAAhB;MAAmD;MAC3C,EAAM,UAAU,CAAC,WAAW,YAAY;MAAE;MAAI;MACnD,EAAM,cAAc;MAChB;;IAGP,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,CAAC,EAAM,gBAAgB;KACjC,eAAe,EAAM,UAAU;KAC/B,cAAW;KACX,WAAW,EACT,oDACA,qDACA,mCACA,gEACA,oBACD;eAED,kBAAC,GAAD;MAAM,MAAM;MAAkB,MAAK;MAAO,CAAA;KACnC,CAAA;IACL;KACF"}
1
+ {"version":3,"file":"data-table-pagination.js","names":[],"sources":["../../src/ui/data-table-pagination.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'\nimport { type Table } from '@tanstack/react-table'\nimport React from 'react'\n\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\n/**\n * Pagination controls: page size selector, prev/next buttons, page info.\n * Internal — not exported to consumers.\n */\nexport function DataTablePagination<TData>({\n table,\n totalRowCount,\n useServerPagination,\n pageSizeOptions,\n}: {\n table: Table<TData>\n totalRowCount: number\n useServerPagination: boolean\n pageSizeOptions?: number[]\n}) {\n return (\n <div className=\"flex items-center justify-between px-ds-03 py-ds-04 border-t border-surface-border\">\n <span className=\"text-ds-sm text-surface-fg-muted\">\n {totalRowCount} total rows\n </span>\n <div className=\"flex items-center gap-ds-03\">\n {/* Page size selector */}\n {!useServerPagination && (\n <select\n value={table.getState().pagination.pageSize}\n onChange={(e) => {\n table.setPageSize(Number(e.target.value))\n }}\n aria-label=\"Rows per page\"\n className={cn(\n 'h-ds-sm rounded-control',\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'px-ds-03 text-ds-sm',\n 'text-surface-fg',\n )}\n >\n {(pageSizeOptions ?? [10, 20, 50, 100]).map((size) => (\n <option key={size} value={size}>\n {size} rows\n </option>\n ))}\n </select>\n )}\n\n {/* Previous page button */}\n <button\n type=\"button\"\n disabled={!table.getCanPreviousPage()}\n onClick={() => table.previousPage()}\n aria-label=\"Previous page\"\n className={cn(\n 'h-ds-sm w-ds-sm flex items-center justify-center',\n 'rounded-control border border-surface-border-strong',\n 'enabled:hover:bg-surface-raised',\n 'disabled:opacity-action-disabled disabled:cursor-not-allowed',\n 'transition-colors',\n )}\n >\n <Icon icon={IconChevronLeft} size=\"sm\" />\n </button>\n\n {/* Page info */}\n <span className=\"text-ds-sm text-surface-fg-muted\">\n Page {table.getState().pagination.pageIndex + 1} of{' '}\n {table.getPageCount()}\n </span>\n\n {/* Next page button */}\n <button\n type=\"button\"\n disabled={!table.getCanNextPage()}\n onClick={() => table.nextPage()}\n aria-label=\"Next page\"\n className={cn(\n 'h-ds-sm w-ds-sm flex items-center justify-center',\n 'rounded-control border border-surface-border-strong',\n 'enabled:hover:bg-surface-raised',\n 'disabled:opacity-action-disabled disabled:cursor-not-allowed',\n 'transition-colors',\n )}\n >\n <Icon icon={IconChevronRight} size=\"sm\" />\n </button>\n </div>\n </div>\n )\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,EAA2B,EACzC,UACA,kBACA,wBACA,sBAMC;AACD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACG,GAAc,cACV;MACP,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEG,CAAC,KACA,kBAAC,UAAD;KACE,OAAO,EAAM,UAAU,CAAC,WAAW;KACnC,WAAW,MAAM;AACf,QAAM,YAAY,OAAO,EAAE,OAAO,MAAM,CAAC;;KAE3C,cAAW;KACX,WAAW,EACT,2BACA,+DACA,uBACA,kBACD;gBAEC,KAAmB;MAAC;MAAI;MAAI;MAAI;MAAI,EAAE,KAAK,MAC3C,kBAAC,UAAD;MAAmB,OAAO;gBAA1B,CACG,GAAK,QACC;QAFI,EAEJ,CACT;KACK,CAAA;IAIX,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,CAAC,EAAM,oBAAoB;KACrC,eAAe,EAAM,cAAc;KACnC,cAAW;KACX,WAAW,EACT,oDACA,uDACA,mCACA,gEACA,oBACD;eAED,kBAAC,GAAD;MAAM,MAAM;MAAiB,MAAK;MAAO,CAAA;KAClC,CAAA;IAGT,kBAAC,QAAD;KAAM,WAAU;eAAhB;MAAmD;MAC3C,EAAM,UAAU,CAAC,WAAW,YAAY;MAAE;MAAI;MACnD,EAAM,cAAc;MAChB;;IAGP,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,CAAC,EAAM,gBAAgB;KACjC,eAAe,EAAM,UAAU;KAC/B,cAAW;KACX,WAAW,EACT,oDACA,uDACA,mCACA,gEACA,oBACD;eAED,kBAAC,GAAD;MAAM,MAAM;MAAkB,MAAK;MAAO,CAAA;KACnC,CAAA;IACL;KACF"}
@@ -14,7 +14,7 @@ var m = {
14
14
  compact: "standard",
15
15
  standard: "comfortable",
16
16
  comfortable: "compact"
17
- }, g = e("h-ds-sm px-ds-03 rounded-ds-md", "border border-surface-border-strong", "hover:bg-surface-raised", "text-ds-sm flex items-center gap-ds-02 transition-colors"), _ = "text-surface-fg-subtle";
17
+ }, g = e("h-ds-sm px-ds-03 rounded-control", "border border-surface-border-strong", "hover:bg-surface-raised", "text-ds-sm flex items-center gap-ds-02 transition-colors"), _ = "text-surface-fg-subtle";
18
18
  function v(e) {
19
19
  let t = e.getAllLeafColumns().filter((e) => e.getIsVisible() && e.id !== "_select").map((e) => {
20
20
  let t = e.columnDef.header;
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-toolbar.js","names":[],"sources":["../../src/ui/data-table-toolbar.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconColumns3,\n IconDownload,\n IconSearch,\n IconTextResize,\n} from '@tabler/icons-react'\nimport { type Table } from '@tanstack/react-table'\nimport * as React from 'react'\n\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from './dropdown-menu'\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\nexport type Density = 'compact' | 'standard' | 'comfortable'\n\nconst densityLabels: Record<Density, string> = {\n compact: 'Compact',\n standard: 'Standard',\n comfortable: 'Comfortable',\n}\n\nconst densityCycle: Record<Density, Density> = {\n compact: 'standard',\n standard: 'comfortable',\n comfortable: 'compact',\n}\n\nexport interface DataTableToolbarProps<TData> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n table: Table<TData>\n globalFilter?: boolean\n globalFilterValue: string\n onGlobalFilterChange: (value: string) => void\n density: Density\n onDensityChange: (density: Density) => void\n enableExport?: boolean\n}\n\nconst toolbarButtonClass = cn(\n 'h-ds-sm px-ds-03 rounded-ds-md',\n 'border border-surface-border-strong',\n 'hover:bg-surface-raised',\n 'text-ds-sm flex items-center gap-ds-02 transition-colors',\n)\n\nconst toolbarIconClass = 'text-surface-fg-subtle'\n\nfunction exportToCsv<TData>(table: Table<TData>) {\n const headers = table\n .getAllLeafColumns()\n .filter((col) => col.getIsVisible() && col.id !== '_select')\n .map((col) => {\n const header = col.columnDef.header\n return typeof header === 'string' ? header : col.id\n })\n\n const rows = table.getFilteredRowModel().rows.map((row) =>\n table\n .getAllLeafColumns()\n .filter((col) => col.getIsVisible() && col.id !== '_select')\n .map((col) => {\n const value = row.getValue(col.id)\n const str = String(value ?? '')\n // Escape CSV: wrap in quotes if it contains comma, quote, or newline\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`\n }\n return str\n }),\n )\n\n const csvContent = [headers.join(','), ...rows.map((r) => r.join(','))].join(\n '\\n',\n )\n\n const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = 'table-export.csv'\n link.click()\n URL.revokeObjectURL(url)\n}\n\nexport function DataTableToolbar<TData>({\n table,\n globalFilter = false,\n globalFilterValue,\n onGlobalFilterChange,\n density,\n onDensityChange,\n enableExport = true,\n className,\n ...props\n}: DataTableToolbarProps<TData>) {\n const toggleableColumns = table\n .getAllColumns()\n .filter((col) => col.getCanHide() && col.id !== '_select')\n\n return (\n <div className={cn('flex items-center gap-ds-03 pb-ds-04', className)} {...props}>\n {/* Global search */}\n {globalFilter && (\n <div className=\"flex flex-1 items-center gap-ds-02\">\n <Icon icon={IconSearch} size=\"sm\" className={toolbarIconClass} />\n <input\n type=\"text\"\n value={globalFilterValue}\n onChange={(e) => onGlobalFilterChange(e.target.value)}\n placeholder=\"Search all columns...\"\n aria-label=\"Search all columns\"\n className={cn(\n 'flex-1 bg-transparent text-ds-md',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden',\n 'h-ds-sm',\n )}\n />\n </div>\n )}\n\n <div className=\"ml-auto flex items-center gap-ds-03\">\n {/* Column visibility dropdown */}\n {toggleableColumns.length > 0 && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={toolbarButtonClass}\n aria-label=\"Toggle column visibility\"\n >\n <Icon icon={IconColumns3} size=\"sm\" className={toolbarIconClass} />\n Columns\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-40\">\n <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>\n <DropdownMenuSeparator />\n {toggleableColumns.map((column) => {\n const headerDef = column.columnDef.header\n const label =\n typeof headerDef === 'string' ? headerDef : column.id\n return (\n <DropdownMenuCheckboxItem\n key={column.id}\n checked={column.getIsVisible()}\n onCheckedChange={(value) =>\n column.toggleVisibility(!!value)\n }\n >\n {label}\n </DropdownMenuCheckboxItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n\n {/* Density toggle */}\n <button\n type=\"button\"\n className={toolbarButtonClass}\n onClick={() => onDensityChange(densityCycle[density])}\n aria-label={`Table density: ${densityLabels[density]}. Click to change.`}\n title={`Density: ${densityLabels[density]}`}\n >\n <Icon icon={IconTextResize} size=\"sm\" className={toolbarIconClass} />\n {densityLabels[density]}\n </button>\n\n {/* CSV Export */}\n {enableExport && (\n <button\n type=\"button\"\n className={toolbarButtonClass}\n onClick={() => exportToCsv(table)}\n aria-label=\"Export table as CSV\"\n >\n <Icon icon={IconDownload} size=\"sm\" className={toolbarIconClass} />\n Export\n </button>\n )}\n </div>\n </div>\n )\n}\nDataTableToolbar.displayName = 'DataTableToolbar'\n"],"mappings":"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"}
1
+ {"version":3,"file":"data-table-toolbar.js","names":[],"sources":["../../src/ui/data-table-toolbar.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconColumns3,\n IconDownload,\n IconSearch,\n IconTextResize,\n} from '@tabler/icons-react'\nimport { type Table } from '@tanstack/react-table'\nimport * as React from 'react'\n\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from './dropdown-menu'\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\nexport type Density = 'compact' | 'standard' | 'comfortable'\n\nconst densityLabels: Record<Density, string> = {\n compact: 'Compact',\n standard: 'Standard',\n comfortable: 'Comfortable',\n}\n\nconst densityCycle: Record<Density, Density> = {\n compact: 'standard',\n standard: 'comfortable',\n comfortable: 'compact',\n}\n\nexport interface DataTableToolbarProps<TData> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n table: Table<TData>\n globalFilter?: boolean\n globalFilterValue: string\n onGlobalFilterChange: (value: string) => void\n density: Density\n onDensityChange: (density: Density) => void\n enableExport?: boolean\n}\n\nconst toolbarButtonClass = cn(\n 'h-ds-sm px-ds-03 rounded-control',\n 'border border-surface-border-strong',\n 'hover:bg-surface-raised',\n 'text-ds-sm flex items-center gap-ds-02 transition-colors',\n)\n\nconst toolbarIconClass = 'text-surface-fg-subtle'\n\nfunction exportToCsv<TData>(table: Table<TData>) {\n const headers = table\n .getAllLeafColumns()\n .filter((col) => col.getIsVisible() && col.id !== '_select')\n .map((col) => {\n const header = col.columnDef.header\n return typeof header === 'string' ? header : col.id\n })\n\n const rows = table.getFilteredRowModel().rows.map((row) =>\n table\n .getAllLeafColumns()\n .filter((col) => col.getIsVisible() && col.id !== '_select')\n .map((col) => {\n const value = row.getValue(col.id)\n const str = String(value ?? '')\n // Escape CSV: wrap in quotes if it contains comma, quote, or newline\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`\n }\n return str\n }),\n )\n\n const csvContent = [headers.join(','), ...rows.map((r) => r.join(','))].join(\n '\\n',\n )\n\n const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = 'table-export.csv'\n link.click()\n URL.revokeObjectURL(url)\n}\n\nexport function DataTableToolbar<TData>({\n table,\n globalFilter = false,\n globalFilterValue,\n onGlobalFilterChange,\n density,\n onDensityChange,\n enableExport = true,\n className,\n ...props\n}: DataTableToolbarProps<TData>) {\n const toggleableColumns = table\n .getAllColumns()\n .filter((col) => col.getCanHide() && col.id !== '_select')\n\n return (\n <div className={cn('flex items-center gap-ds-03 pb-ds-04', className)} {...props}>\n {/* Global search */}\n {globalFilter && (\n <div className=\"flex flex-1 items-center gap-ds-02\">\n <Icon icon={IconSearch} size=\"sm\" className={toolbarIconClass} />\n <input\n type=\"text\"\n value={globalFilterValue}\n onChange={(e) => onGlobalFilterChange(e.target.value)}\n placeholder=\"Search all columns...\"\n aria-label=\"Search all columns\"\n className={cn(\n 'flex-1 bg-transparent text-ds-md',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden',\n 'h-ds-sm',\n )}\n />\n </div>\n )}\n\n <div className=\"ml-auto flex items-center gap-ds-03\">\n {/* Column visibility dropdown */}\n {toggleableColumns.length > 0 && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={toolbarButtonClass}\n aria-label=\"Toggle column visibility\"\n >\n <Icon icon={IconColumns3} size=\"sm\" className={toolbarIconClass} />\n Columns\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-40\">\n <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>\n <DropdownMenuSeparator />\n {toggleableColumns.map((column) => {\n const headerDef = column.columnDef.header\n const label =\n typeof headerDef === 'string' ? headerDef : column.id\n return (\n <DropdownMenuCheckboxItem\n key={column.id}\n checked={column.getIsVisible()}\n onCheckedChange={(value) =>\n column.toggleVisibility(!!value)\n }\n >\n {label}\n </DropdownMenuCheckboxItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n\n {/* Density toggle */}\n <button\n type=\"button\"\n className={toolbarButtonClass}\n onClick={() => onDensityChange(densityCycle[density])}\n aria-label={`Table density: ${densityLabels[density]}. Click to change.`}\n title={`Density: ${densityLabels[density]}`}\n >\n <Icon icon={IconTextResize} size=\"sm\" className={toolbarIconClass} />\n {densityLabels[density]}\n </button>\n\n {/* CSV Export */}\n {enableExport && (\n <button\n type=\"button\"\n className={toolbarButtonClass}\n onClick={() => exportToCsv(table)}\n aria-label=\"Export table as CSV\"\n >\n <Icon icon={IconDownload} size=\"sm\" className={toolbarIconClass} />\n Export\n </button>\n )}\n </div>\n </div>\n )\n}\nDataTableToolbar.displayName = 'DataTableToolbar'\n"],"mappings":";;;;;;;;AAwBA,IAAM,IAAyC;CAC7C,SAAS;CACT,UAAU;CACV,aAAa;CACd,EAEK,IAAyC;CAC7C,SAAS;CACT,UAAU;CACV,aAAa;CACd,EAYK,IAAqB,EACzB,oCACA,uCACA,2BACA,2DACD,EAEK,IAAmB;AAEzB,SAAS,EAAmB,GAAqB;CAC/C,IAAM,IAAU,EACb,mBAAmB,CACnB,QAAQ,MAAQ,EAAI,cAAc,IAAI,EAAI,OAAO,UAAU,CAC3D,KAAK,MAAQ;EACZ,IAAM,IAAS,EAAI,UAAU;AAC7B,SAAO,OAAO,KAAW,WAAW,IAAS,EAAI;GACjD,EAEE,IAAO,EAAM,qBAAqB,CAAC,KAAK,KAAK,MACjD,EACG,mBAAmB,CACnB,QAAQ,MAAQ,EAAI,cAAc,IAAI,EAAI,OAAO,UAAU,CAC3D,KAAK,MAAQ;EACZ,IAAM,IAAQ,EAAI,SAAS,EAAI,GAAG,EAC5B,IAAM,OAAO,KAAS,GAAG;AAK/B,SAHI,EAAI,SAAS,IAAI,IAAI,EAAI,SAAS,KAAI,IAAI,EAAI,SAAS,KAAK,GACvD,IAAI,EAAI,QAAQ,MAAM,OAAK,CAAC,KAE9B;GACP,CACL,EAEK,IAAa,CAAC,EAAQ,KAAK,IAAI,EAAE,GAAG,EAAK,KAAK,MAAM,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,KACtE,KACD,EAEK,IAAO,IAAI,KAAK,CAAC,EAAW,EAAE,EAAE,MAAM,2BAA2B,CAAC,EAClE,IAAM,IAAI,gBAAgB,EAAK,EAC/B,IAAO,SAAS,cAAc,IAAI;AAIxC,CAHA,EAAK,OAAO,GACZ,EAAK,WAAW,oBAChB,EAAK,OAAO,EACZ,IAAI,gBAAgB,EAAI;;AAG1B,SAAgB,EAAwB,EACtC,UACA,kBAAe,IACf,sBACA,yBACA,YACA,oBACA,kBAAe,IACf,cACA,GAAG,KAC4B;CAC/B,IAAM,IAAoB,EACvB,eAAe,CACf,QAAQ,MAAQ,EAAI,YAAY,IAAI,EAAI,OAAO,UAAU;AAE5D,QACE,kBAAC,OAAD;EAAK,WAAW,EAAG,wCAAwC,EAAU;EAAE,GAAI;YAA3E,CAEG,KACC,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IAAM,MAAM;IAAY,MAAK;IAAK,WAAW;IAAoB,CAAA,EACjE,kBAAC,SAAD;IACE,MAAK;IACL,OAAO;IACP,WAAW,MAAM,EAAqB,EAAE,OAAO,MAAM;IACrD,aAAY;IACZ,cAAW;IACX,WAAW,EACT,oCACA,sDACA,kBACA,UACD;IACD,CAAA,CACE;MAGR,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEG,EAAkB,SAAS,KAC1B,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAqB,SAAA;eACnB,kBAAC,UAAD;MACE,MAAK;MACL,WAAW;MACX,cAAW;gBAHb,CAKE,kBAAC,GAAD;OAAM,MAAM;OAAc,MAAK;OAAK,WAAW;OAAoB,CAAA,EAAA,UAE5D;;KACW,CAAA,EACtB,kBAAC,GAAD;KAAqB,OAAM;KAAM,WAAU;eAA3C;MACE,kBAAC,GAAD,EAAA,UAAmB,kBAAkC,CAAA;MACrD,kBAAC,GAAD,EAAyB,CAAA;MACxB,EAAkB,KAAK,MAAW;OACjC,IAAM,IAAY,EAAO,UAAU,QAC7B,IACJ,OAAO,KAAc,WAAW,IAAY,EAAO;AACrD,cACE,kBAAC,GAAD;QAEE,SAAS,EAAO,cAAc;QAC9B,kBAAkB,MAChB,EAAO,iBAAiB,CAAC,CAAC,EAAM;kBAGjC;QACwB,EAPpB,EAAO,GAOa;QAE7B;MACkB;OACT,EAAA,CAAA;IAIjB,kBAAC,UAAD;KACE,MAAK;KACL,WAAW;KACX,eAAe,EAAgB,EAAa,GAAS;KACrD,cAAY,kBAAkB,EAAc,GAAS;KACrD,OAAO,YAAY,EAAc;eALnC,CAOE,kBAAC,GAAD;MAAM,MAAM;MAAgB,MAAK;MAAK,WAAW;MAAoB,CAAA,EACpE,EAAc,GACR;;IAGR,KACC,kBAAC,UAAD;KACE,MAAK;KACL,WAAW;KACX,eAAe,EAAY,EAAM;KACjC,cAAW;eAJb,CAME,kBAAC,GAAD;MAAM,MAAM;MAAc,MAAK;MAAK,WAAW;MAAoB,CAAA,EAAA,SAE5D;;IAEP;KACF;;;AAGV,EAAiB,cAAc"}
@@ -91,7 +91,7 @@ function d({ columns: d, data: f, className: _e, noResultsText: p, sortable: m =
91
91
  type: "button",
92
92
  onClick: () => n.toggleExpanded(),
93
93
  "aria-label": n.getIsExpanded() ? "Collapse row" : "Expand row",
94
- className: "flex items-center justify-center p-ds-01 rounded-ds-sm hover:bg-surface-raised transition-colors",
94
+ className: "flex items-center justify-center p-ds-01 rounded-control-inner hover:bg-surface-raised transition-colors",
95
95
  children: /* @__PURE__ */ l(t, {
96
96
  icon: ce,
97
97
  size: "sm",
@@ -1 +1 @@
1
- {"version":3,"file":"data-table.js","names":[],"sources":["../../src/ui/data-table.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronRight, IconSearch } from '@tabler/icons-react'\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n type ColumnPinningState,\n type ExpandedState,\n getCoreRowModel,\n getExpandedRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type PaginationState,\n type Row,\n type RowData,\n type RowSelectionState,\n type SortingState,\n type TableState,\n type Updater,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport { Checkbox } from './checkbox'\nimport { DataTableBody } from './data-table-body'\nimport { type BulkAction,DataTableBulkActions } from './data-table-bulk-actions'\nimport { DataTableCards } from './data-table-card'\nimport {\n DataTableProvider,\n densityPaddingMap,\n type EditingCell,\n} from './data-table-context'\nimport { DataTableHeader } from './data-table-header'\nimport { DataTablePagination } from './data-table-pagination'\nimport { DataTableToolbar, type Density } from './data-table-toolbar'\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\nimport { Table } from './table'\n\n// Re-export public types so consumers' imports don't break\nexport type { BulkAction } from './data-table-bulk-actions'\n\ndeclare module '@tanstack/react-table' {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n interface ColumnMeta<TData extends RowData, TValue> {\n align?: 'left' | 'center' | 'right'\n hideBelow?: 'sm' | 'md' | 'lg'\n }\n}\n\n/**\n * Props for DataTable — a feature-rich TanStack Table wrapper supporting sorting, filtering,\n * pagination, row selection, inline editing, row expansion, column pinning, and virtualization.\n *\n * All features are opt-in via boolean flags. The component manages its own internal state for\n * sorting, filtering, pagination, and selection — just pass `columns` and `data`.\n *\n * **Feature flags:** `sortable` | `filterable` | `globalFilter` | `paginated` | `selectable` |\n * `toolbar` | `editable` | `expandable` | `virtualRows`\n *\n * **Columns:** Use TanStack Table's `ColumnDef<TData, TValue>` type. Set\n * `meta: { enableEditing: false }` on a column to disable cell editing for that column.\n *\n * @example\n * // Minimal read-only table:\n * const columns: ColumnDef<User, string>[] = [\n * { accessorKey: 'name', header: 'Name' },\n * { accessorKey: 'email', header: 'Email' },\n * ]\n * <DataTable columns={columns} data={users} />\n *\n * @example\n * // Full-featured admin table with sorting, pagination, and selection:\n * <DataTable\n * columns={projectColumns}\n * data={projects}\n * sortable\n * paginated\n * pageSize={20}\n * selectable\n * onSelectionChange={(rows) => setSelectedProjects(rows)}\n * toolbar\n * />\n *\n * @example\n * // Virtualized table for large datasets (10k+ rows):\n * <DataTable\n * columns={logColumns}\n * data={allLogs}\n * virtualRows\n * virtualRowHeight={40}\n * maxHeight={500}\n * />\n *\n * @example\n * // Table with expandable rows for nested detail:\n * <DataTable\n * columns={orderColumns}\n * data={orders}\n * expandable\n * renderExpanded={(order) => <OrderLineItems items={order.lineItems} />}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\n/**\n * A full-featured data table built on TanStack Table with sorting, filtering,\n * pagination, row selection, inline cell editing, expandable rows, column pinning,\n * a toolbar with density/export controls, and optional row virtualization.\n */\nexport interface DataTableProps<TData, TValue> {\n /** Column definitions passed to TanStack Table. */\n columns: ColumnDef<TData, TValue>[]\n /** Row data */\n data: TData[]\n /** Additional class name for the wrapper div */\n className?: string\n /** Text shown when the table has no rows */\n noResultsText?: string\n /** Enable column sorting (click headers to sort) */\n sortable?: boolean\n /** Enable per-column filter inputs below headers */\n filterable?: boolean\n /** Enable a global search input above the table */\n globalFilter?: boolean\n /** Enable pagination controls below the table */\n paginated?: boolean\n /** Number of rows per page when paginated (default 10) */\n pageSize?: number\n /** Options for the page size selector dropdown (default [10, 20, 50, 100]) */\n pageSizeOptions?: number[]\n /** Enable row selection with checkboxes */\n selectable?: boolean\n /** Callback when row selection changes */\n onSelectionChange?: (selectedRows: TData[]) => void\n /** Show toolbar above the table with column visibility, density, and export controls */\n toolbar?: boolean\n /** Row density — controls cell vertical padding */\n density?: Density\n /** Initial column pinning configuration */\n columnPinning?: { left?: string[]; right?: string[] }\n\n // --- Cell Editing ---\n /** Enable inline cell editing (double-click to edit) */\n editable?: boolean\n /** Callback when a cell value is edited */\n onCellEdit?: (rowIndex: number, columnId: string, value: unknown) => void\n\n // --- Row Expansion ---\n /** Enable expandable rows with detail panels */\n expandable?: boolean\n /** Render function for expanded row content */\n renderExpanded?: (row: TData) => React.ReactNode\n\n // --- Virtualization ---\n /** Enable row virtualization for large datasets */\n virtualRows?: boolean\n /** Height of each virtual row in pixels (default 48) */\n virtualRowHeight?: number\n /** Maximum height of the scrollable container in pixels (default 600) */\n maxHeight?: number\n\n // --- Server-side sorting ---\n /** Callback for server-side sorting. When provided, sorting is manual (no client-side sort). */\n onSort?: (key: string, direction: 'asc' | 'desc' | false) => void\n\n // --- Empty state ---\n /** Custom ReactNode to render when data is empty (replaces noResultsText) */\n emptyState?: React.ReactNode\n\n // --- Loading ---\n /** Show shimmer skeleton rows instead of data */\n loading?: boolean\n\n // --- Controlled selection ---\n /** Controlled set of selected row IDs — syncs internal selection state */\n selectedIds?: Set<string>\n /** Per-row filter to determine if a row is selectable */\n selectableFilter?: (row: TData) => boolean\n /** Custom row ID getter */\n getRowId?: (row: TData) => string\n\n // --- Server-side pagination ---\n /** Server-side pagination config. When provided, pagination is manual. */\n pagination?: {\n page: number\n pageSize: number\n total: number\n onPageChange: (page: number) => void\n }\n\n // --- Single-expand mode ---\n /** When true, only one row can be expanded at a time */\n singleExpand?: boolean\n\n // --- Sticky header ---\n /** When true, the table header sticks to the top on scroll */\n stickyHeader?: boolean\n\n // --- Row click ---\n /** Callback when a row is clicked (not fired from interactive elements) */\n onRowClick?: (row: TData) => void\n\n // --- Bulk actions ---\n /** Actions shown in a floating bar when rows are selected */\n bulkActions?: BulkAction<TData>[]\n\n // --- Mobile view ---\n /** Render rows as stacked cards on small screens (below sm breakpoint). Default 'table'. */\n mobileView?: 'card' | 'table'\n}\n\nexport function DataTable<TData, TValue>({\n columns,\n data,\n className,\n noResultsText,\n sortable = false,\n filterable = false,\n globalFilter = false,\n paginated = false,\n pageSize: initialPageSize,\n pageSizeOptions,\n selectable = false,\n onSelectionChange,\n toolbar = false,\n density: initialDensity = 'standard',\n columnPinning: initialColumnPinning,\n editable = false,\n onCellEdit,\n expandable = false,\n renderExpanded,\n virtualRows = false,\n virtualRowHeight = 48,\n maxHeight = 600,\n onSort,\n emptyState,\n loading = false,\n selectedIds,\n selectableFilter,\n getRowId: getRowIdProp,\n pagination: serverPagination,\n singleExpand = false,\n stickyHeader = false,\n onRowClick,\n bulkActions,\n mobileView = 'table',\n}: DataTableProps<TData, TValue>) {\n // Detect below-sm viewport (640px) for card mode — separate from useIsMobile (768px)\n const [isBelowSm, setIsBelowSm] = useState(false)\n useEffect(() => {\n const mql = window.matchMedia('(max-width: 639px)')\n const onChange = () => setIsBelowSm(mql.matches)\n mql.addEventListener('change', onChange)\n setIsBelowSm(mql.matches)\n return () => mql.removeEventListener('change', onChange)\n }, [])\n\n const showCards = mobileView === 'card' && isBelowSm\n\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [globalFilterValue, setGlobalFilterValue] = useState('')\n const [paginationState, setPaginationState] = useState<PaginationState>({\n pageIndex: serverPagination ? serverPagination.page - 1 : 0,\n pageSize: serverPagination?.pageSize ?? initialPageSize ?? 10,\n })\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})\n const [columnPinningState, setColumnPinningState] =\n useState<ColumnPinningState>({\n left: initialColumnPinning?.left ?? [],\n right: initialColumnPinning?.right ?? [],\n })\n const [density, setDensity] = useState<Density>(initialDensity)\n const [editingCell, setEditingCell] = useState<EditingCell>(null)\n const [expanded, setExpanded] = useState<ExpandedState>({})\n\n // Ref for the virtual scroll container\n const scrollContainerRef = useRef<HTMLDivElement>(null)\n\n // Guard to prevent onSelectionChange firing when syncing from selectedIds prop\n const isSyncingFromPropRef = useRef(false)\n\n // Sync controlled selectedIds to internal rowSelection\n useEffect(() => {\n if (selectedIds) {\n isSyncingFromPropRef.current = true\n const newSelection: RowSelectionState = {}\n selectedIds.forEach((id) => {\n newSelection[id] = true\n })\n setRowSelection(newSelection)\n }\n }, [selectedIds])\n\n // Sync server pagination page to internal state\n useEffect(() => {\n if (serverPagination) {\n setPaginationState((prev) => ({\n ...prev,\n pageIndex: serverPagination.page - 1,\n pageSize: serverPagination.pageSize,\n }))\n }\n }, [serverPagination?.page, serverPagination?.pageSize]) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Server-side sorting handler\n const handleSortingChange = useCallback(\n (updater: Updater<SortingState>) => {\n setSorting((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (onSort) {\n if (next.length === 0 && prev.length > 0) {\n // Sorting cleared\n onSort(prev[0].id, false)\n } else if (next.length > 0) {\n onSort(next[0].id, next[0].desc ? 'desc' : 'asc')\n }\n }\n return next\n })\n },\n [onSort],\n )\n\n // Single-expand handler\n const handleExpandedChange = useCallback(\n (updater: Updater<ExpandedState>) => {\n setExpanded((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (!singleExpand) return next\n // If next is boolean true (expand all), just use it\n if (next === true) return next\n if (typeof next !== 'object') return next\n // Determine which row was just toggled on\n const prevKeys = typeof prev === 'object' ? Object.keys(prev).filter((k) => (prev as Record<string, boolean>)[k]) : []\n const nextKeys = Object.keys(next).filter((k) => (next as Record<string, boolean>)[k])\n // Find newly expanded row\n const newlyExpanded = nextKeys.filter((k) => !prevKeys.includes(k))\n if (newlyExpanded.length > 0) {\n // Keep only the most recently expanded row\n return { [newlyExpanded[newlyExpanded.length - 1]]: true } as ExpandedState\n }\n // If no new rows, means a row was collapsed — return as-is\n return next\n })\n },\n [singleExpand],\n )\n\n // Stable ref for server pagination callback to avoid useCallback invalidation\n const onPageChangeRef = useRef(serverPagination?.onPageChange)\n useEffect(() => {\n onPageChangeRef.current = serverPagination?.onPageChange\n }, [serverPagination?.onPageChange])\n\n // Server-side pagination handler\n const handlePaginationChange = useCallback(\n (updater: Updater<PaginationState>) => {\n setPaginationState((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (onPageChangeRef.current) {\n // Only call onPageChange if the page actually changed\n if (next.pageIndex !== prev.pageIndex) {\n onPageChangeRef.current(next.pageIndex + 1)\n }\n }\n return next\n })\n },\n [],\n )\n\n // Checkbox column prepended when selectable is enabled\n const selectColumn: ColumnDef<TData, unknown> = {\n id: '_select',\n header: ({ table: t }) => (\n <Checkbox\n size=\"sm\"\n checked={t.getIsAllPageRowsSelected()}\n indeterminate={t.getIsSomePageRowsSelected()}\n onCheckedChange={(v) => t.toggleAllPageRowsSelected(!!v)}\n aria-label=\"Select all rows\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n size=\"sm\"\n checked={row.getIsSelected()}\n disabled={!row.getCanSelect()}\n onCheckedChange={(v) => row.toggleSelected(!!v)}\n aria-label=\"Select row\"\n />\n ),\n enableSorting: false,\n enableColumnFilter: false,\n enableHiding: false,\n }\n\n // Expand toggle column\n const expandColumn: ColumnDef<TData, unknown> = {\n id: '_expand',\n header: () => null,\n cell: ({ row }) => (\n <button\n type=\"button\"\n onClick={() => row.toggleExpanded()}\n aria-label={row.getIsExpanded() ? 'Collapse row' : 'Expand row'}\n className=\"flex items-center justify-center p-ds-01 rounded-ds-sm hover:bg-surface-raised transition-colors\"\n >\n <Icon\n icon={IconChevronRight}\n size=\"sm\"\n className={cn(\n 'transition-transform duration-moderate-02',\n row.getIsExpanded() && 'rotate-90',\n )}\n />\n </button>\n ),\n enableSorting: false,\n enableColumnFilter: false,\n enableHiding: false,\n }\n\n // Assemble all columns in order: select?, expand?, ...user columns\n const allColumns = [\n ...(selectable ? [selectColumn] : []),\n ...(expandable ? [expandColumn] : []),\n ...columns,\n ]\n\n // Determine if using server-side pagination\n const useServerPagination = !!serverPagination\n const showPagination = paginated || useServerPagination\n\n // Build state object once — sorting and filtering contribute independently\n const tableState: Partial<TableState> = {\n columnVisibility,\n columnPinning: columnPinningState,\n }\n if (sortable) tableState.sorting = sorting\n if (filterable || globalFilter) {\n tableState.columnFilters = columnFilters\n tableState.globalFilter = globalFilterValue\n }\n if (showPagination) tableState.pagination = paginationState\n if (selectable) tableState.rowSelection = rowSelection\n if (expandable) tableState.expanded = expanded\n\n // Determine server-side sort mode\n const isServerSort = sortable && !!onSort\n\n const table = useReactTable({\n data,\n columns: allColumns,\n state: tableState,\n onColumnVisibilityChange: setColumnVisibility,\n onColumnPinningChange: setColumnPinningState,\n getCoreRowModel: getCoreRowModel(),\n ...(sortable && {\n onSortingChange: isServerSort ? handleSortingChange : setSorting,\n ...(isServerSort\n ? { manualSorting: true }\n : { getSortedRowModel: getSortedRowModel() }),\n }),\n ...((filterable || globalFilter) && {\n onColumnFiltersChange: setColumnFilters,\n onGlobalFilterChange: setGlobalFilterValue,\n getFilteredRowModel: getFilteredRowModel(),\n }),\n ...(showPagination && {\n onPaginationChange: useServerPagination\n ? handlePaginationChange\n : setPaginationState,\n ...(useServerPagination\n ? {\n manualPagination: true,\n pageCount: Math.ceil(\n serverPagination!.total / serverPagination!.pageSize,\n ),\n }\n : { getPaginationRowModel: getPaginationRowModel() }),\n }),\n ...(selectable && {\n onRowSelectionChange: setRowSelection,\n enableRowSelection: selectableFilter\n ? (row: Row<TData>) => selectableFilter(row.original)\n : true,\n }),\n ...(expandable && {\n onExpandedChange: singleExpand ? handleExpandedChange : setExpanded,\n getExpandedRowModel: getExpandedRowModel(),\n }),\n ...(getRowIdProp && {\n getRowId: (row: TData) => getRowIdProp(row),\n }),\n })\n\n // Stable refs to avoid effect re-fires from inline callbacks\n const onSelectionChangeRef = useRef(onSelectionChange)\n const getRowIdRef = useRef(getRowIdProp)\n useEffect(() => {\n onSelectionChangeRef.current = onSelectionChange\n getRowIdRef.current = getRowIdProp\n }, [onSelectionChange, getRowIdProp])\n\n // Fire selection callback when row selection changes (skip when syncing from prop)\n useEffect(() => {\n if (isSyncingFromPropRef.current) {\n isSyncingFromPropRef.current = false\n return\n }\n if (!onSelectionChangeRef.current) return\n const selectedRowIds = Object.keys(rowSelection).filter((k) => rowSelection[k])\n const selected = data.filter((_, i) => {\n const id = getRowIdRef.current ? getRowIdRef.current(data[i]) : String(i)\n return selectedRowIds.includes(id)\n })\n onSelectionChangeRef.current(selected)\n }, [rowSelection, data])\n\n const cellPadding = densityPaddingMap[density]\n\n const rows = table.getRowModel().rows\n\n // Virtualizer — always called but only active when virtualRows is true\n const virtualizer = useVirtualizer({\n count: virtualRows ? rows.length : 0,\n getScrollElement: () => scrollContainerRef.current,\n estimateSize: () => virtualRowHeight,\n overscan: 10,\n })\n\n // Number of skeleton rows for loading state\n const skeletonRowCount = serverPagination?.pageSize ?? initialPageSize ?? 5\n\n // Get selected rows for bulk actions (derived from rowSelection + data, not table instance)\n const selectedRows = useMemo(() => {\n if (!bulkActions || !selectable) return []\n const selectedRowIds = Object.keys(rowSelection).filter((k) => rowSelection[k])\n return data.filter((_, i) => {\n const id = getRowIdProp ? getRowIdProp(data[i]) : String(i)\n return selectedRowIds.includes(id)\n })\n }, [bulkActions, selectable, rowSelection, data, getRowIdProp])\n\n const hasSelectedRows = selectedRows.length > 0\n\n // Total rows for pagination display\n const totalRowCount = useServerPagination\n ? serverPagination!.total\n : table.getFilteredRowModel().rows.length\n\n // Build context value for sub-components\n const contextValue = useMemo(\n () => ({\n table,\n allColumns: allColumns.map((col) => ({\n id: (col as { id?: string }).id,\n header: (col as { header?: unknown }).header,\n })),\n cellPadding,\n columnPinningState,\n sortable,\n filterable,\n editable,\n expandable,\n virtualRows,\n selectable,\n mobileView,\n editingCell,\n setEditingCell,\n onCellEdit,\n renderExpanded,\n onRowClick,\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n table,\n allColumns.length,\n cellPadding,\n columnPinningState,\n sortable,\n filterable,\n editable,\n expandable,\n virtualRows,\n selectable,\n mobileView,\n editingCell,\n onCellEdit,\n renderExpanded,\n onRowClick,\n ],\n )\n\n // Virtual items for body\n const virtualItems = virtualRows ? virtualizer.getVirtualItems() : undefined\n const totalVirtualSize = virtualRows ? virtualizer.getTotalSize() : undefined\n\n // Determine if we need a scroll wrapper for virtualization\n const tableContent = (\n <Table aria-busy={loading || undefined}>\n <DataTableHeader stickyHeader={stickyHeader} />\n <DataTableBody\n loading={loading}\n skeletonRowCount={skeletonRowCount}\n noResultsText={noResultsText}\n emptyState={emptyState}\n virtualItems={virtualItems}\n totalVirtualSize={totalVirtualSize}\n />\n </Table>\n )\n\n return (\n <DataTableProvider value={contextValue}>\n <div className={cn(className)}>\n {/* Toolbar */}\n {toolbar && (\n <DataTableToolbar\n table={table}\n globalFilter={globalFilter}\n globalFilterValue={globalFilterValue}\n onGlobalFilterChange={setGlobalFilterValue}\n density={density}\n onDensityChange={setDensity}\n />\n )}\n\n {/* Global search input — only show standalone when toolbar is disabled */}\n {globalFilter && !toolbar && (\n <div className=\"flex items-center gap-ds-03 pb-ds-04 border-b border-surface-border mb-ds-04\">\n <Icon icon={IconSearch} size=\"sm\" className=\"text-surface-fg-subtle\" />\n <input\n type=\"text\"\n value={globalFilterValue}\n onChange={(e) => setGlobalFilterValue(e.target.value)}\n placeholder=\"Search all columns...\"\n aria-label=\"Search all columns\"\n className={cn(\n 'flex-1 bg-transparent text-ds-md',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden',\n )}\n />\n </div>\n )}\n\n {/* Card view on small screens, or standard table */}\n {showCards ? (\n <DataTableCards\n loading={loading}\n skeletonRowCount={skeletonRowCount}\n noResultsText={noResultsText}\n emptyState={emptyState}\n />\n ) : virtualRows ? (\n <div\n ref={scrollContainerRef}\n style={{ maxHeight: `${maxHeight}px`, overflowY: 'auto' }}\n >\n {tableContent}\n </div>\n ) : (\n tableContent\n )}\n\n {/* Pagination controls */}\n {showPagination && (\n <DataTablePagination\n table={table}\n totalRowCount={totalRowCount}\n useServerPagination={useServerPagination}\n pageSizeOptions={pageSizeOptions}\n />\n )}\n\n {/* Bulk action bar */}\n {bulkActions && selectable && hasSelectedRows && (\n <DataTableBulkActions\n table={table}\n selectedRows={selectedRows}\n bulkActions={bulkActions}\n />\n )}\n </div>\n </DataTableProvider>\n )\n}\nDataTable.displayName = 'DataTable'\n"],"mappings":"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"}
1
+ {"version":3,"file":"data-table.js","names":[],"sources":["../../src/ui/data-table.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronRight, IconSearch } from '@tabler/icons-react'\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n type ColumnPinningState,\n type ExpandedState,\n getCoreRowModel,\n getExpandedRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type PaginationState,\n type Row,\n type RowData,\n type RowSelectionState,\n type SortingState,\n type TableState,\n type Updater,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport { Checkbox } from './checkbox'\nimport { DataTableBody } from './data-table-body'\nimport { type BulkAction,DataTableBulkActions } from './data-table-bulk-actions'\nimport { DataTableCards } from './data-table-card'\nimport {\n DataTableProvider,\n densityPaddingMap,\n type EditingCell,\n} from './data-table-context'\nimport { DataTableHeader } from './data-table-header'\nimport { DataTablePagination } from './data-table-pagination'\nimport { DataTableToolbar, type Density } from './data-table-toolbar'\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\nimport { Table } from './table'\n\n// Re-export public types so consumers' imports don't break\nexport type { BulkAction } from './data-table-bulk-actions'\n\ndeclare module '@tanstack/react-table' {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n interface ColumnMeta<TData extends RowData, TValue> {\n align?: 'left' | 'center' | 'right'\n hideBelow?: 'sm' | 'md' | 'lg'\n }\n}\n\n/**\n * Props for DataTable — a feature-rich TanStack Table wrapper supporting sorting, filtering,\n * pagination, row selection, inline editing, row expansion, column pinning, and virtualization.\n *\n * All features are opt-in via boolean flags. The component manages its own internal state for\n * sorting, filtering, pagination, and selection — just pass `columns` and `data`.\n *\n * **Feature flags:** `sortable` | `filterable` | `globalFilter` | `paginated` | `selectable` |\n * `toolbar` | `editable` | `expandable` | `virtualRows`\n *\n * **Columns:** Use TanStack Table's `ColumnDef<TData, TValue>` type. Set\n * `meta: { enableEditing: false }` on a column to disable cell editing for that column.\n *\n * @example\n * // Minimal read-only table:\n * const columns: ColumnDef<User, string>[] = [\n * { accessorKey: 'name', header: 'Name' },\n * { accessorKey: 'email', header: 'Email' },\n * ]\n * <DataTable columns={columns} data={users} />\n *\n * @example\n * // Full-featured admin table with sorting, pagination, and selection:\n * <DataTable\n * columns={projectColumns}\n * data={projects}\n * sortable\n * paginated\n * pageSize={20}\n * selectable\n * onSelectionChange={(rows) => setSelectedProjects(rows)}\n * toolbar\n * />\n *\n * @example\n * // Virtualized table for large datasets (10k+ rows):\n * <DataTable\n * columns={logColumns}\n * data={allLogs}\n * virtualRows\n * virtualRowHeight={40}\n * maxHeight={500}\n * />\n *\n * @example\n * // Table with expandable rows for nested detail:\n * <DataTable\n * columns={orderColumns}\n * data={orders}\n * expandable\n * renderExpanded={(order) => <OrderLineItems items={order.lineItems} />}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\n/**\n * A full-featured data table built on TanStack Table with sorting, filtering,\n * pagination, row selection, inline cell editing, expandable rows, column pinning,\n * a toolbar with density/export controls, and optional row virtualization.\n */\nexport interface DataTableProps<TData, TValue> {\n /** Column definitions passed to TanStack Table. */\n columns: ColumnDef<TData, TValue>[]\n /** Row data */\n data: TData[]\n /** Additional class name for the wrapper div */\n className?: string\n /** Text shown when the table has no rows */\n noResultsText?: string\n /** Enable column sorting (click headers to sort) */\n sortable?: boolean\n /** Enable per-column filter inputs below headers */\n filterable?: boolean\n /** Enable a global search input above the table */\n globalFilter?: boolean\n /** Enable pagination controls below the table */\n paginated?: boolean\n /** Number of rows per page when paginated (default 10) */\n pageSize?: number\n /** Options for the page size selector dropdown (default [10, 20, 50, 100]) */\n pageSizeOptions?: number[]\n /** Enable row selection with checkboxes */\n selectable?: boolean\n /** Callback when row selection changes */\n onSelectionChange?: (selectedRows: TData[]) => void\n /** Show toolbar above the table with column visibility, density, and export controls */\n toolbar?: boolean\n /** Row density — controls cell vertical padding */\n density?: Density\n /** Initial column pinning configuration */\n columnPinning?: { left?: string[]; right?: string[] }\n\n // --- Cell Editing ---\n /** Enable inline cell editing (double-click to edit) */\n editable?: boolean\n /** Callback when a cell value is edited */\n onCellEdit?: (rowIndex: number, columnId: string, value: unknown) => void\n\n // --- Row Expansion ---\n /** Enable expandable rows with detail panels */\n expandable?: boolean\n /** Render function for expanded row content */\n renderExpanded?: (row: TData) => React.ReactNode\n\n // --- Virtualization ---\n /** Enable row virtualization for large datasets */\n virtualRows?: boolean\n /** Height of each virtual row in pixels (default 48) */\n virtualRowHeight?: number\n /** Maximum height of the scrollable container in pixels (default 600) */\n maxHeight?: number\n\n // --- Server-side sorting ---\n /** Callback for server-side sorting. When provided, sorting is manual (no client-side sort). */\n onSort?: (key: string, direction: 'asc' | 'desc' | false) => void\n\n // --- Empty state ---\n /** Custom ReactNode to render when data is empty (replaces noResultsText) */\n emptyState?: React.ReactNode\n\n // --- Loading ---\n /** Show shimmer skeleton rows instead of data */\n loading?: boolean\n\n // --- Controlled selection ---\n /** Controlled set of selected row IDs — syncs internal selection state */\n selectedIds?: Set<string>\n /** Per-row filter to determine if a row is selectable */\n selectableFilter?: (row: TData) => boolean\n /** Custom row ID getter */\n getRowId?: (row: TData) => string\n\n // --- Server-side pagination ---\n /** Server-side pagination config. When provided, pagination is manual. */\n pagination?: {\n page: number\n pageSize: number\n total: number\n onPageChange: (page: number) => void\n }\n\n // --- Single-expand mode ---\n /** When true, only one row can be expanded at a time */\n singleExpand?: boolean\n\n // --- Sticky header ---\n /** When true, the table header sticks to the top on scroll */\n stickyHeader?: boolean\n\n // --- Row click ---\n /** Callback when a row is clicked (not fired from interactive elements) */\n onRowClick?: (row: TData) => void\n\n // --- Bulk actions ---\n /** Actions shown in a floating bar when rows are selected */\n bulkActions?: BulkAction<TData>[]\n\n // --- Mobile view ---\n /** Render rows as stacked cards on small screens (below sm breakpoint). Default 'table'. */\n mobileView?: 'card' | 'table'\n}\n\nexport function DataTable<TData, TValue>({\n columns,\n data,\n className,\n noResultsText,\n sortable = false,\n filterable = false,\n globalFilter = false,\n paginated = false,\n pageSize: initialPageSize,\n pageSizeOptions,\n selectable = false,\n onSelectionChange,\n toolbar = false,\n density: initialDensity = 'standard',\n columnPinning: initialColumnPinning,\n editable = false,\n onCellEdit,\n expandable = false,\n renderExpanded,\n virtualRows = false,\n virtualRowHeight = 48,\n maxHeight = 600,\n onSort,\n emptyState,\n loading = false,\n selectedIds,\n selectableFilter,\n getRowId: getRowIdProp,\n pagination: serverPagination,\n singleExpand = false,\n stickyHeader = false,\n onRowClick,\n bulkActions,\n mobileView = 'table',\n}: DataTableProps<TData, TValue>) {\n // Detect below-sm viewport (640px) for card mode — separate from useIsMobile (768px)\n const [isBelowSm, setIsBelowSm] = useState(false)\n useEffect(() => {\n const mql = window.matchMedia('(max-width: 639px)')\n const onChange = () => setIsBelowSm(mql.matches)\n mql.addEventListener('change', onChange)\n setIsBelowSm(mql.matches)\n return () => mql.removeEventListener('change', onChange)\n }, [])\n\n const showCards = mobileView === 'card' && isBelowSm\n\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [globalFilterValue, setGlobalFilterValue] = useState('')\n const [paginationState, setPaginationState] = useState<PaginationState>({\n pageIndex: serverPagination ? serverPagination.page - 1 : 0,\n pageSize: serverPagination?.pageSize ?? initialPageSize ?? 10,\n })\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})\n const [columnPinningState, setColumnPinningState] =\n useState<ColumnPinningState>({\n left: initialColumnPinning?.left ?? [],\n right: initialColumnPinning?.right ?? [],\n })\n const [density, setDensity] = useState<Density>(initialDensity)\n const [editingCell, setEditingCell] = useState<EditingCell>(null)\n const [expanded, setExpanded] = useState<ExpandedState>({})\n\n // Ref for the virtual scroll container\n const scrollContainerRef = useRef<HTMLDivElement>(null)\n\n // Guard to prevent onSelectionChange firing when syncing from selectedIds prop\n const isSyncingFromPropRef = useRef(false)\n\n // Sync controlled selectedIds to internal rowSelection\n useEffect(() => {\n if (selectedIds) {\n isSyncingFromPropRef.current = true\n const newSelection: RowSelectionState = {}\n selectedIds.forEach((id) => {\n newSelection[id] = true\n })\n setRowSelection(newSelection)\n }\n }, [selectedIds])\n\n // Sync server pagination page to internal state\n useEffect(() => {\n if (serverPagination) {\n setPaginationState((prev) => ({\n ...prev,\n pageIndex: serverPagination.page - 1,\n pageSize: serverPagination.pageSize,\n }))\n }\n }, [serverPagination?.page, serverPagination?.pageSize]) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Server-side sorting handler\n const handleSortingChange = useCallback(\n (updater: Updater<SortingState>) => {\n setSorting((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (onSort) {\n if (next.length === 0 && prev.length > 0) {\n // Sorting cleared\n onSort(prev[0].id, false)\n } else if (next.length > 0) {\n onSort(next[0].id, next[0].desc ? 'desc' : 'asc')\n }\n }\n return next\n })\n },\n [onSort],\n )\n\n // Single-expand handler\n const handleExpandedChange = useCallback(\n (updater: Updater<ExpandedState>) => {\n setExpanded((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (!singleExpand) return next\n // If next is boolean true (expand all), just use it\n if (next === true) return next\n if (typeof next !== 'object') return next\n // Determine which row was just toggled on\n const prevKeys = typeof prev === 'object' ? Object.keys(prev).filter((k) => (prev as Record<string, boolean>)[k]) : []\n const nextKeys = Object.keys(next).filter((k) => (next as Record<string, boolean>)[k])\n // Find newly expanded row\n const newlyExpanded = nextKeys.filter((k) => !prevKeys.includes(k))\n if (newlyExpanded.length > 0) {\n // Keep only the most recently expanded row\n return { [newlyExpanded[newlyExpanded.length - 1]]: true } as ExpandedState\n }\n // If no new rows, means a row was collapsed — return as-is\n return next\n })\n },\n [singleExpand],\n )\n\n // Stable ref for server pagination callback to avoid useCallback invalidation\n const onPageChangeRef = useRef(serverPagination?.onPageChange)\n useEffect(() => {\n onPageChangeRef.current = serverPagination?.onPageChange\n }, [serverPagination?.onPageChange])\n\n // Server-side pagination handler\n const handlePaginationChange = useCallback(\n (updater: Updater<PaginationState>) => {\n setPaginationState((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (onPageChangeRef.current) {\n // Only call onPageChange if the page actually changed\n if (next.pageIndex !== prev.pageIndex) {\n onPageChangeRef.current(next.pageIndex + 1)\n }\n }\n return next\n })\n },\n [],\n )\n\n // Checkbox column prepended when selectable is enabled\n const selectColumn: ColumnDef<TData, unknown> = {\n id: '_select',\n header: ({ table: t }) => (\n <Checkbox\n size=\"sm\"\n checked={t.getIsAllPageRowsSelected()}\n indeterminate={t.getIsSomePageRowsSelected()}\n onCheckedChange={(v) => t.toggleAllPageRowsSelected(!!v)}\n aria-label=\"Select all rows\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n size=\"sm\"\n checked={row.getIsSelected()}\n disabled={!row.getCanSelect()}\n onCheckedChange={(v) => row.toggleSelected(!!v)}\n aria-label=\"Select row\"\n />\n ),\n enableSorting: false,\n enableColumnFilter: false,\n enableHiding: false,\n }\n\n // Expand toggle column\n const expandColumn: ColumnDef<TData, unknown> = {\n id: '_expand',\n header: () => null,\n cell: ({ row }) => (\n <button\n type=\"button\"\n onClick={() => row.toggleExpanded()}\n aria-label={row.getIsExpanded() ? 'Collapse row' : 'Expand row'}\n className=\"flex items-center justify-center p-ds-01 rounded-control-inner hover:bg-surface-raised transition-colors\"\n >\n <Icon\n icon={IconChevronRight}\n size=\"sm\"\n className={cn(\n 'transition-transform duration-moderate-02',\n row.getIsExpanded() && 'rotate-90',\n )}\n />\n </button>\n ),\n enableSorting: false,\n enableColumnFilter: false,\n enableHiding: false,\n }\n\n // Assemble all columns in order: select?, expand?, ...user columns\n const allColumns = [\n ...(selectable ? [selectColumn] : []),\n ...(expandable ? [expandColumn] : []),\n ...columns,\n ]\n\n // Determine if using server-side pagination\n const useServerPagination = !!serverPagination\n const showPagination = paginated || useServerPagination\n\n // Build state object once — sorting and filtering contribute independently\n const tableState: Partial<TableState> = {\n columnVisibility,\n columnPinning: columnPinningState,\n }\n if (sortable) tableState.sorting = sorting\n if (filterable || globalFilter) {\n tableState.columnFilters = columnFilters\n tableState.globalFilter = globalFilterValue\n }\n if (showPagination) tableState.pagination = paginationState\n if (selectable) tableState.rowSelection = rowSelection\n if (expandable) tableState.expanded = expanded\n\n // Determine server-side sort mode\n const isServerSort = sortable && !!onSort\n\n const table = useReactTable({\n data,\n columns: allColumns,\n state: tableState,\n onColumnVisibilityChange: setColumnVisibility,\n onColumnPinningChange: setColumnPinningState,\n getCoreRowModel: getCoreRowModel(),\n ...(sortable && {\n onSortingChange: isServerSort ? handleSortingChange : setSorting,\n ...(isServerSort\n ? { manualSorting: true }\n : { getSortedRowModel: getSortedRowModel() }),\n }),\n ...((filterable || globalFilter) && {\n onColumnFiltersChange: setColumnFilters,\n onGlobalFilterChange: setGlobalFilterValue,\n getFilteredRowModel: getFilteredRowModel(),\n }),\n ...(showPagination && {\n onPaginationChange: useServerPagination\n ? handlePaginationChange\n : setPaginationState,\n ...(useServerPagination\n ? {\n manualPagination: true,\n pageCount: Math.ceil(\n serverPagination!.total / serverPagination!.pageSize,\n ),\n }\n : { getPaginationRowModel: getPaginationRowModel() }),\n }),\n ...(selectable && {\n onRowSelectionChange: setRowSelection,\n enableRowSelection: selectableFilter\n ? (row: Row<TData>) => selectableFilter(row.original)\n : true,\n }),\n ...(expandable && {\n onExpandedChange: singleExpand ? handleExpandedChange : setExpanded,\n getExpandedRowModel: getExpandedRowModel(),\n }),\n ...(getRowIdProp && {\n getRowId: (row: TData) => getRowIdProp(row),\n }),\n })\n\n // Stable refs to avoid effect re-fires from inline callbacks\n const onSelectionChangeRef = useRef(onSelectionChange)\n const getRowIdRef = useRef(getRowIdProp)\n useEffect(() => {\n onSelectionChangeRef.current = onSelectionChange\n getRowIdRef.current = getRowIdProp\n }, [onSelectionChange, getRowIdProp])\n\n // Fire selection callback when row selection changes (skip when syncing from prop)\n useEffect(() => {\n if (isSyncingFromPropRef.current) {\n isSyncingFromPropRef.current = false\n return\n }\n if (!onSelectionChangeRef.current) return\n const selectedRowIds = Object.keys(rowSelection).filter((k) => rowSelection[k])\n const selected = data.filter((_, i) => {\n const id = getRowIdRef.current ? getRowIdRef.current(data[i]) : String(i)\n return selectedRowIds.includes(id)\n })\n onSelectionChangeRef.current(selected)\n }, [rowSelection, data])\n\n const cellPadding = densityPaddingMap[density]\n\n const rows = table.getRowModel().rows\n\n // Virtualizer — always called but only active when virtualRows is true\n const virtualizer = useVirtualizer({\n count: virtualRows ? rows.length : 0,\n getScrollElement: () => scrollContainerRef.current,\n estimateSize: () => virtualRowHeight,\n overscan: 10,\n })\n\n // Number of skeleton rows for loading state\n const skeletonRowCount = serverPagination?.pageSize ?? initialPageSize ?? 5\n\n // Get selected rows for bulk actions (derived from rowSelection + data, not table instance)\n const selectedRows = useMemo(() => {\n if (!bulkActions || !selectable) return []\n const selectedRowIds = Object.keys(rowSelection).filter((k) => rowSelection[k])\n return data.filter((_, i) => {\n const id = getRowIdProp ? getRowIdProp(data[i]) : String(i)\n return selectedRowIds.includes(id)\n })\n }, [bulkActions, selectable, rowSelection, data, getRowIdProp])\n\n const hasSelectedRows = selectedRows.length > 0\n\n // Total rows for pagination display\n const totalRowCount = useServerPagination\n ? serverPagination!.total\n : table.getFilteredRowModel().rows.length\n\n // Build context value for sub-components\n const contextValue = useMemo(\n () => ({\n table,\n allColumns: allColumns.map((col) => ({\n id: (col as { id?: string }).id,\n header: (col as { header?: unknown }).header,\n })),\n cellPadding,\n columnPinningState,\n sortable,\n filterable,\n editable,\n expandable,\n virtualRows,\n selectable,\n mobileView,\n editingCell,\n setEditingCell,\n onCellEdit,\n renderExpanded,\n onRowClick,\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n table,\n allColumns.length,\n cellPadding,\n columnPinningState,\n sortable,\n filterable,\n editable,\n expandable,\n virtualRows,\n selectable,\n mobileView,\n editingCell,\n onCellEdit,\n renderExpanded,\n onRowClick,\n ],\n )\n\n // Virtual items for body\n const virtualItems = virtualRows ? virtualizer.getVirtualItems() : undefined\n const totalVirtualSize = virtualRows ? virtualizer.getTotalSize() : undefined\n\n // Determine if we need a scroll wrapper for virtualization\n const tableContent = (\n <Table aria-busy={loading || undefined}>\n <DataTableHeader stickyHeader={stickyHeader} />\n <DataTableBody\n loading={loading}\n skeletonRowCount={skeletonRowCount}\n noResultsText={noResultsText}\n emptyState={emptyState}\n virtualItems={virtualItems}\n totalVirtualSize={totalVirtualSize}\n />\n </Table>\n )\n\n return (\n <DataTableProvider value={contextValue}>\n <div className={cn(className)}>\n {/* Toolbar */}\n {toolbar && (\n <DataTableToolbar\n table={table}\n globalFilter={globalFilter}\n globalFilterValue={globalFilterValue}\n onGlobalFilterChange={setGlobalFilterValue}\n density={density}\n onDensityChange={setDensity}\n />\n )}\n\n {/* Global search input — only show standalone when toolbar is disabled */}\n {globalFilter && !toolbar && (\n <div className=\"flex items-center gap-ds-03 pb-ds-04 border-b border-surface-border mb-ds-04\">\n <Icon icon={IconSearch} size=\"sm\" className=\"text-surface-fg-subtle\" />\n <input\n type=\"text\"\n value={globalFilterValue}\n onChange={(e) => setGlobalFilterValue(e.target.value)}\n placeholder=\"Search all columns...\"\n aria-label=\"Search all columns\"\n className={cn(\n 'flex-1 bg-transparent text-ds-md',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden',\n )}\n />\n </div>\n )}\n\n {/* Card view on small screens, or standard table */}\n {showCards ? (\n <DataTableCards\n loading={loading}\n skeletonRowCount={skeletonRowCount}\n noResultsText={noResultsText}\n emptyState={emptyState}\n />\n ) : virtualRows ? (\n <div\n ref={scrollContainerRef}\n style={{ maxHeight: `${maxHeight}px`, overflowY: 'auto' }}\n >\n {tableContent}\n </div>\n ) : (\n tableContent\n )}\n\n {/* Pagination controls */}\n {showPagination && (\n <DataTablePagination\n table={table}\n totalRowCount={totalRowCount}\n useServerPagination={useServerPagination}\n pageSizeOptions={pageSizeOptions}\n />\n )}\n\n {/* Bulk action bar */}\n {bulkActions && selectable && hasSelectedRows && (\n <DataTableBulkActions\n table={table}\n selectedRows={selectedRows}\n bulkActions={bulkActions}\n />\n )}\n </div>\n </DataTableProvider>\n )\n}\nDataTable.displayName = 'DataTable'\n"],"mappings":"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"}