@exxatdesignux/ui 0.2.19 → 0.3.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 (688) hide show
  1. package/CHANGELOG.md +60 -7
  2. package/bin/sync-extras.mjs +116 -29
  3. package/consumer-extras/README.md +42 -7
  4. package/consumer-extras/cursor-rules/exxat-accessibility.mdc +39 -0
  5. package/consumer-extras/cursor-rules/exxat-board-cards.mdc +26 -0
  6. package/consumer-extras/cursor-rules/exxat-breadcrumbs-no-back.mdc +21 -0
  7. package/consumer-extras/cursor-rules/exxat-card-vs-list-rows.mdc +21 -0
  8. package/consumer-extras/cursor-rules/exxat-centralized-list-dataset.mdc +44 -0
  9. package/consumer-extras/cursor-rules/exxat-collaboration-access.mdc +32 -0
  10. package/consumer-extras/cursor-rules/exxat-command-menu.mdc +22 -0
  11. package/consumer-extras/cursor-rules/exxat-dashboard-view-charts.mdc +53 -0
  12. package/consumer-extras/cursor-rules/exxat-data-tables.mdc +41 -0
  13. package/consumer-extras/cursor-rules/exxat-dedicated-search-surfaces.mdc +25 -0
  14. package/consumer-extras/cursor-rules/exxat-drawer-vs-dialog.mdc +22 -0
  15. package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +56 -0
  16. package/consumer-extras/cursor-rules/exxat-fontawesome-icons.mdc +31 -0
  17. package/consumer-extras/cursor-rules/exxat-kbd-shortcuts.mdc +100 -0
  18. package/consumer-extras/cursor-rules/exxat-kpi-flat-band.mdc +28 -0
  19. package/consumer-extras/cursor-rules/exxat-kpi-max-four.mdc +21 -0
  20. package/consumer-extras/cursor-rules/exxat-kpi-trends.mdc +31 -0
  21. package/consumer-extras/cursor-rules/exxat-list-page-connected-views.mdc +24 -0
  22. package/consumer-extras/cursor-rules/exxat-list-page-view-shells.mdc +31 -0
  23. package/consumer-extras/cursor-rules/exxat-mono-ids.mdc +30 -0
  24. package/consumer-extras/cursor-rules/exxat-no-slds-leakage.mdc +78 -0
  25. package/consumer-extras/cursor-rules/exxat-no-toast.mdc +25 -0
  26. package/consumer-extras/cursor-rules/exxat-page-vs-drawer.mdc +23 -0
  27. package/consumer-extras/cursor-rules/exxat-person-identity-display.mdc +47 -0
  28. package/consumer-extras/cursor-rules/exxat-primary-nav-secondary-panel.mdc +52 -0
  29. package/consumer-extras/cursor-rules/exxat-question-bank-hub-header.mdc +28 -0
  30. package/consumer-extras/cursor-rules/exxat-reuse-before-custom.mdc +34 -0
  31. package/consumer-extras/cursor-rules/exxat-table-properties-drawer.mdc +77 -0
  32. package/consumer-extras/cursor-rules/exxat-token-discipline.mdc +103 -0
  33. package/consumer-extras/cursor-skills/exxat-accessibility/SKILL.md +1 -1
  34. package/consumer-extras/cursor-skills/exxat-board-cards/SKILL.md +2 -2
  35. package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +4 -15
  36. package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +13 -28
  37. package/consumer-extras/cursor-skills/exxat-ds-skill/references/data-table-pattern.md +1 -1
  38. package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +2 -4
  39. package/consumer-extras/handbook/HANDBOOK.md +185 -0
  40. package/consumer-extras/handbook/glossary.md +57 -0
  41. package/consumer-extras/handbook/reference-implementations.md +126 -0
  42. package/consumer-extras/handbook/voice-and-tone.md +262 -0
  43. package/consumer-extras/patterns/command-menu-pattern.md +1 -1
  44. package/consumer-extras/patterns/consumer-upgrade-checklist.md +0 -20
  45. package/consumer-extras/patterns/data-views-pattern.md +17 -54
  46. package/consumer-extras/patterns/shell-surface-elevation-pattern.md +3 -5
  47. package/dist/components/data-table/filter-date-calendar.d.ts +10 -0
  48. package/dist/components/data-table/filter-date-calendar.js +280 -0
  49. package/dist/components/data-table/filter-date-calendar.js.map +1 -0
  50. package/dist/components/data-table/filter-text-value-input.d.ts +15 -0
  51. package/dist/components/data-table/filter-text-value-input.js +561 -0
  52. package/dist/components/data-table/filter-text-value-input.js.map +1 -0
  53. package/dist/components/data-table/index.d.ts +45 -0
  54. package/dist/components/data-table/index.js +3085 -0
  55. package/dist/components/data-table/index.js.map +1 -0
  56. package/dist/components/data-table/pagination.d.ts +28 -0
  57. package/dist/components/data-table/pagination.js +3264 -0
  58. package/dist/components/data-table/pagination.js.map +1 -0
  59. package/dist/components/data-table/types.d.ts +84 -0
  60. package/dist/components/data-table/types.js +3 -0
  61. package/dist/components/data-table/types.js.map +1 -0
  62. package/dist/components/data-table/use-table-state.d.ts +116 -0
  63. package/dist/components/data-table/use-table-state.js +670 -0
  64. package/dist/components/data-table/use-table-state.js.map +1 -0
  65. package/dist/components/data-views/board-card-primitives.d.ts +22 -0
  66. package/dist/components/data-views/board-card-primitives.js +84 -0
  67. package/dist/components/data-views/board-card-primitives.js.map +1 -0
  68. package/dist/components/data-views/data-row-list.d.ts +33 -0
  69. package/dist/components/data-views/data-row-list.js +106 -0
  70. package/dist/components/data-views/data-row-list.js.map +1 -0
  71. package/dist/components/data-views/finder-panel-view.d.ts +54 -0
  72. package/dist/components/data-views/finder-panel-view.js +388 -0
  73. package/dist/components/data-views/finder-panel-view.js.map +1 -0
  74. package/dist/components/data-views/folder-grid-view.d.ts +22 -0
  75. package/dist/components/data-views/folder-grid-view.js +58 -0
  76. package/dist/components/data-views/folder-grid-view.js.map +1 -0
  77. package/dist/components/data-views/hub-table.d.ts +167 -0
  78. package/dist/components/data-views/hub-table.js +5561 -0
  79. package/dist/components/data-views/hub-table.js.map +1 -0
  80. package/dist/components/data-views/index.d.ts +27 -0
  81. package/dist/components/data-views/index.js +6575 -0
  82. package/dist/components/data-views/index.js.map +1 -0
  83. package/dist/components/data-views/list-page-board-card.d.ts +72 -0
  84. package/dist/components/data-views/list-page-board-card.js +264 -0
  85. package/dist/components/data-views/list-page-board-card.js.map +1 -0
  86. package/dist/components/data-views/list-page-board-template.d.ts +24 -0
  87. package/dist/components/data-views/list-page-board-template.js +137 -0
  88. package/dist/components/data-views/list-page-board-template.js.map +1 -0
  89. package/dist/components/data-views/list-page-connected-view-body.d.ts +19 -0
  90. package/dist/components/data-views/list-page-connected-view-body.js +116 -0
  91. package/dist/components/data-views/list-page-connected-view-body.js.map +1 -0
  92. package/dist/components/data-views/list-page-split-details-placeholder.d.ts +14 -0
  93. package/dist/components/data-views/list-page-split-details-placeholder.js +38 -0
  94. package/dist/components/data-views/list-page-split-details-placeholder.js.map +1 -0
  95. package/dist/components/data-views/list-page-split-hub-chrome.d.ts +17 -0
  96. package/dist/components/data-views/list-page-split-hub-chrome.js +54 -0
  97. package/dist/components/data-views/list-page-split-hub-chrome.js.map +1 -0
  98. package/dist/components/data-views/list-page-split-hub-tokens.d.ts +12 -0
  99. package/dist/components/data-views/list-page-split-hub-tokens.js +8 -0
  100. package/dist/components/data-views/list-page-split-hub-tokens.js.map +1 -0
  101. package/dist/components/data-views/list-page-tree-column-header.d.ts +15 -0
  102. package/dist/components/data-views/list-page-tree-column-header.js +22 -0
  103. package/dist/components/data-views/list-page-tree-column-header.js.map +1 -0
  104. package/dist/components/data-views/list-page-tree-panel-shell.d.ts +25 -0
  105. package/dist/components/data-views/list-page-tree-panel-shell.js +146 -0
  106. package/dist/components/data-views/list-page-tree-panel-shell.js.map +1 -0
  107. package/dist/components/data-views/os-folder-glyph.d.ts +35 -0
  108. package/dist/components/data-views/os-folder-glyph.js +104 -0
  109. package/dist/components/data-views/os-folder-glyph.js.map +1 -0
  110. package/dist/components/data-views/outline-tree-menu.d.ts +36 -0
  111. package/dist/components/data-views/outline-tree-menu.js +131 -0
  112. package/dist/components/data-views/outline-tree-menu.js.map +1 -0
  113. package/dist/components/table-properties/column-row.d.ts +22 -0
  114. package/dist/components/table-properties/column-row.js +153 -0
  115. package/dist/components/table-properties/column-row.js.map +1 -0
  116. package/dist/components/table-properties/draggable-list.d.ts +24 -0
  117. package/dist/components/table-properties/draggable-list.js +53 -0
  118. package/dist/components/table-properties/draggable-list.js.map +1 -0
  119. package/dist/components/table-properties/drawer-button.d.ts +110 -0
  120. package/dist/components/table-properties/drawer-button.js +2748 -0
  121. package/dist/components/table-properties/drawer-button.js.map +1 -0
  122. package/dist/components/table-properties/drawer.d.ts +100 -0
  123. package/dist/components/table-properties/drawer.js +2595 -0
  124. package/dist/components/table-properties/drawer.js.map +1 -0
  125. package/dist/components/table-properties/filter-card.d.ts +24 -0
  126. package/dist/components/table-properties/filter-card.js +854 -0
  127. package/dist/components/table-properties/filter-card.js.map +1 -0
  128. package/dist/components/table-properties/index.d.ts +14 -0
  129. package/dist/components/table-properties/index.js +2768 -0
  130. package/dist/components/table-properties/index.js.map +1 -0
  131. package/dist/components/table-properties/sort-card.d.ts +20 -0
  132. package/dist/components/table-properties/sort-card.js +102 -0
  133. package/dist/components/table-properties/sort-card.js.map +1 -0
  134. package/dist/components/templates/dedicated-search-landing-template.d.ts +21 -0
  135. package/dist/components/templates/dedicated-search-landing-template.js +254 -0
  136. package/dist/components/templates/dedicated-search-landing-template.js.map +1 -0
  137. package/dist/components/templates/dedicated-search-results-template.d.ts +15 -0
  138. package/dist/components/templates/dedicated-search-results-template.js +16 -0
  139. package/dist/components/templates/dedicated-search-results-template.js.map +1 -0
  140. package/dist/components/templates/index.d.ts +9 -0
  141. package/dist/components/templates/index.js +2720 -0
  142. package/dist/components/templates/index.js.map +1 -0
  143. package/dist/components/templates/list-page.d.ts +83 -0
  144. package/dist/components/templates/list-page.js +2433 -0
  145. package/dist/components/templates/list-page.js.map +1 -0
  146. package/dist/components/templates/nested-secondary-panel-shell.d.ts +20 -0
  147. package/dist/components/templates/nested-secondary-panel-shell.js +54 -0
  148. package/dist/components/templates/nested-secondary-panel-shell.js.map +1 -0
  149. package/dist/components/ui/accordion.d.ts +10 -0
  150. package/dist/components/ui/accordion.js +74 -0
  151. package/dist/components/ui/accordion.js.map +1 -0
  152. package/dist/components/ui/alert-dialog.d.ts +37 -0
  153. package/dist/components/ui/alert-dialog.js +201 -0
  154. package/dist/components/ui/alert-dialog.js.map +1 -0
  155. package/dist/components/ui/avatar.d.ts +84 -0
  156. package/dist/components/ui/avatar.js +328 -0
  157. package/dist/components/ui/avatar.js.map +1 -0
  158. package/dist/components/ui/badge.d.ts +13 -0
  159. package/dist/components/ui/badge.js +49 -0
  160. package/dist/components/ui/badge.js.map +1 -0
  161. package/dist/components/ui/banner.d.ts +62 -0
  162. package/dist/components/ui/banner.js +364 -0
  163. package/dist/components/ui/banner.js.map +1 -0
  164. package/dist/components/ui/breadcrumb.d.ts +14 -0
  165. package/dist/components/ui/breadcrumb.js +114 -0
  166. package/dist/components/ui/breadcrumb.js.map +1 -0
  167. package/dist/components/ui/button.d.ts +16 -0
  168. package/dist/components/ui/button.js +59 -0
  169. package/dist/components/ui/button.js.map +1 -0
  170. package/dist/components/ui/calendar.d.ts +13 -0
  171. package/dist/components/ui/calendar.js +238 -0
  172. package/dist/components/ui/calendar.js.map +1 -0
  173. package/dist/components/ui/card.d.ts +14 -0
  174. package/dist/components/ui/card.js +102 -0
  175. package/dist/components/ui/card.js.map +1 -0
  176. package/dist/components/ui/chart.d.ts +58 -0
  177. package/dist/components/ui/chart.js +292 -0
  178. package/dist/components/ui/chart.js.map +1 -0
  179. package/dist/components/ui/checkbox.d.ts +23 -0
  180. package/dist/components/ui/checkbox.js +155 -0
  181. package/dist/components/ui/checkbox.js.map +1 -0
  182. package/dist/components/ui/coach-mark.d.ts +27 -0
  183. package/dist/components/ui/coach-mark.js +306 -0
  184. package/dist/components/ui/coach-mark.js.map +1 -0
  185. package/dist/components/ui/collapsible.d.ts +8 -0
  186. package/dist/components/ui/collapsible.js +35 -0
  187. package/dist/components/ui/collapsible.js.map +1 -0
  188. package/dist/components/ui/command.d.ts +36 -0
  189. package/dist/components/ui/command.js +274 -0
  190. package/dist/components/ui/command.js.map +1 -0
  191. package/dist/components/ui/context-menu.d.ts +32 -0
  192. package/dist/components/ui/context-menu.js +245 -0
  193. package/dist/components/ui/context-menu.js.map +1 -0
  194. package/dist/components/ui/date-picker-field.d.ts +38 -0
  195. package/dist/components/ui/date-picker-field.js +550 -0
  196. package/dist/components/ui/date-picker-field.js.map +1 -0
  197. package/dist/components/ui/dialog.d.ts +22 -0
  198. package/dist/components/ui/dialog.js +200 -0
  199. package/dist/components/ui/dialog.js.map +1 -0
  200. package/dist/components/ui/dot-pattern.d.ts +21 -0
  201. package/dist/components/ui/dot-pattern.js +139 -0
  202. package/dist/components/ui/dot-pattern.js.map +1 -0
  203. package/dist/components/ui/drag-handle-grip.d.ts +10 -0
  204. package/dist/components/ui/drag-handle-grip.js +15 -0
  205. package/dist/components/ui/drag-handle-grip.js.map +1 -0
  206. package/dist/components/ui/drawer.d.ts +16 -0
  207. package/dist/components/ui/drawer.js +125 -0
  208. package/dist/components/ui/drawer.js.map +1 -0
  209. package/dist/components/ui/dropdown-menu.d.ts +45 -0
  210. package/dist/components/ui/dropdown-menu.js +353 -0
  211. package/dist/components/ui/dropdown-menu.js.map +1 -0
  212. package/dist/components/ui/export-drawer.d.ts +11 -0
  213. package/dist/components/ui/export-drawer.js +1658 -0
  214. package/dist/components/ui/export-drawer.js.map +1 -0
  215. package/dist/components/ui/field.d.ts +30 -0
  216. package/dist/components/ui/field.js +249 -0
  217. package/dist/components/ui/field.js.map +1 -0
  218. package/dist/components/ui/form.d.ts +28 -0
  219. package/dist/components/ui/form.js +110 -0
  220. package/dist/components/ui/form.js.map +1 -0
  221. package/dist/components/ui/hover-card.d.ts +9 -0
  222. package/dist/components/ui/hover-card.js +43 -0
  223. package/dist/components/ui/hover-card.js.map +1 -0
  224. package/dist/components/ui/input-group.d.ts +20 -0
  225. package/dist/components/ui/input-group.js +219 -0
  226. package/dist/components/ui/input-group.js.map +1 -0
  227. package/dist/components/ui/input-mask.d.ts +39 -0
  228. package/dist/components/ui/input-mask.js +118 -0
  229. package/dist/components/ui/input-mask.js.map +1 -0
  230. package/dist/components/ui/input.d.ts +5 -0
  231. package/dist/components/ui/input.js +30 -0
  232. package/dist/components/ui/input.js.map +1 -0
  233. package/dist/components/ui/kbd.d.ts +20 -0
  234. package/dist/components/ui/kbd.js +45 -0
  235. package/dist/components/ui/kbd.js.map +1 -0
  236. package/dist/components/ui/key-metrics-context.d.ts +19 -0
  237. package/dist/components/ui/key-metrics-context.js +26 -0
  238. package/dist/components/ui/key-metrics-context.js.map +1 -0
  239. package/dist/components/ui/key-metrics.d.ts +131 -0
  240. package/dist/components/ui/key-metrics.js +1015 -0
  241. package/dist/components/ui/key-metrics.js.map +1 -0
  242. package/dist/components/ui/label.d.ts +6 -0
  243. package/dist/components/ui/label.js +28 -0
  244. package/dist/components/ui/label.js.map +1 -0
  245. package/dist/components/ui/list-page-view-frame.d.ts +22 -0
  246. package/dist/components/ui/list-page-view-frame.js +24 -0
  247. package/dist/components/ui/list-page-view-frame.js.map +1 -0
  248. package/dist/components/ui/page-header.d.ts +51 -0
  249. package/dist/components/ui/page-header.js +372 -0
  250. package/dist/components/ui/page-header.js.map +1 -0
  251. package/dist/components/ui/payment-card-fields.d.ts +10 -0
  252. package/dist/components/ui/payment-card-fields.js +80 -0
  253. package/dist/components/ui/payment-card-fields.js.map +1 -0
  254. package/dist/components/ui/popover.d.ts +10 -0
  255. package/dist/components/ui/popover.js +47 -0
  256. package/dist/components/ui/popover.js.map +1 -0
  257. package/dist/components/ui/radio-group.d.ts +29 -0
  258. package/dist/components/ui/radio-group.js +190 -0
  259. package/dist/components/ui/radio-group.js.map +1 -0
  260. package/dist/components/ui/resizable.d.ts +16 -0
  261. package/dist/components/ui/resizable.js +51 -0
  262. package/dist/components/ui/resizable.js.map +1 -0
  263. package/dist/components/ui/scroll-area.d.ts +8 -0
  264. package/dist/components/ui/scroll-area.js +66 -0
  265. package/dist/components/ui/scroll-area.js.map +1 -0
  266. package/dist/components/ui/select.d.ts +18 -0
  267. package/dist/components/ui/select.js +186 -0
  268. package/dist/components/ui/select.js.map +1 -0
  269. package/dist/components/ui/selection-tile-grid.d.ts +52 -0
  270. package/dist/components/ui/selection-tile-grid.js +347 -0
  271. package/dist/components/ui/selection-tile-grid.js.map +1 -0
  272. package/dist/components/ui/separator.d.ts +7 -0
  273. package/dist/components/ui/separator.js +33 -0
  274. package/dist/components/ui/separator.js.map +1 -0
  275. package/dist/components/ui/sheet.d.ts +18 -0
  276. package/dist/components/ui/sheet.js +181 -0
  277. package/dist/components/ui/sheet.js.map +1 -0
  278. package/dist/components/ui/sidebar.d.ts +94 -0
  279. package/dist/components/ui/sidebar.js +805 -0
  280. package/dist/components/ui/sidebar.js.map +1 -0
  281. package/dist/components/ui/skeleton.d.ts +5 -0
  282. package/dist/components/ui/skeleton.js +22 -0
  283. package/dist/components/ui/skeleton.js.map +1 -0
  284. package/dist/components/ui/slider.d.ts +7 -0
  285. package/dist/components/ui/slider.js +66 -0
  286. package/dist/components/ui/slider.js.map +1 -0
  287. package/dist/components/ui/sonner.d.ts +6 -0
  288. package/dist/components/ui/sonner.js +38 -0
  289. package/dist/components/ui/sonner.js.map +1 -0
  290. package/dist/components/ui/status-badge.d.ts +38 -0
  291. package/dist/components/ui/status-badge.js +77 -0
  292. package/dist/components/ui/status-badge.js.map +1 -0
  293. package/dist/components/ui/table.d.ts +13 -0
  294. package/dist/components/ui/table.js +115 -0
  295. package/dist/components/ui/table.js.map +1 -0
  296. package/dist/components/ui/tabs.d.ts +15 -0
  297. package/dist/components/ui/tabs.js +93 -0
  298. package/dist/components/ui/tabs.js.map +1 -0
  299. package/dist/components/ui/textarea.d.ts +6 -0
  300. package/dist/components/ui/textarea.js +25 -0
  301. package/dist/components/ui/textarea.js.map +1 -0
  302. package/dist/components/ui/tip.d.ts +12 -0
  303. package/dist/components/ui/tip.js +61 -0
  304. package/dist/components/ui/tip.js.map +1 -0
  305. package/dist/components/ui/toggle-group.d.ts +14 -0
  306. package/dist/components/ui/toggle-group.js +104 -0
  307. package/dist/components/ui/toggle-group.js.map +1 -0
  308. package/dist/components/ui/toggle-switch.d.ts +10 -0
  309. package/dist/components/ui/toggle-switch.js +33 -0
  310. package/dist/components/ui/toggle-switch.js.map +1 -0
  311. package/dist/components/ui/toggle.d.ts +13 -0
  312. package/dist/components/ui/toggle.js +51 -0
  313. package/dist/components/ui/toggle.js.map +1 -0
  314. package/dist/components/ui/tooltip.d.ts +10 -0
  315. package/dist/components/ui/tooltip.js +68 -0
  316. package/dist/components/ui/tooltip.js.map +1 -0
  317. package/dist/components/ui/view-segmented-control.d.ts +31 -0
  318. package/dist/components/ui/view-segmented-control.js +167 -0
  319. package/dist/components/ui/view-segmented-control.js.map +1 -0
  320. package/dist/data-list-view-registry-CyBoBML4.d.ts +73 -0
  321. package/dist/hooks/use-app-theme.d.ts +24 -0
  322. package/dist/hooks/use-app-theme.js +286 -0
  323. package/dist/hooks/use-app-theme.js.map +1 -0
  324. package/dist/hooks/use-coach-mark.d.ts +86 -0
  325. package/dist/hooks/use-coach-mark.js +218 -0
  326. package/dist/hooks/use-coach-mark.js.map +1 -0
  327. package/dist/hooks/use-mobile.d.ts +3 -0
  328. package/dist/hooks/use-mobile.js +29 -0
  329. package/dist/hooks/use-mobile.js.map +1 -0
  330. package/dist/hooks/use-mod-key-label.d.ts +6 -0
  331. package/dist/hooks/use-mod-key-label.js +25 -0
  332. package/dist/hooks/use-mod-key-label.js.map +1 -0
  333. package/dist/index.d.ts +120 -0
  334. package/dist/index.js +13324 -0
  335. package/dist/index.js.map +1 -0
  336. package/dist/lib/compose-refs.d.ts +6 -0
  337. package/dist/lib/compose-refs.js +17 -0
  338. package/dist/lib/compose-refs.js.map +1 -0
  339. package/dist/lib/conditional-rule-match.d.ts +30 -0
  340. package/dist/lib/conditional-rule-match.js +66 -0
  341. package/dist/lib/conditional-rule-match.js.map +1 -0
  342. package/dist/lib/data-list-display-options.d.ts +26 -0
  343. package/dist/lib/data-list-display-options.js +14 -0
  344. package/dist/lib/data-list-display-options.js.map +1 -0
  345. package/dist/lib/data-list-view-registry.d.ts +2 -0
  346. package/dist/lib/data-list-view-registry.js +102 -0
  347. package/dist/lib/data-list-view-registry.js.map +1 -0
  348. package/dist/lib/data-list-view-surface.d.ts +2 -0
  349. package/dist/lib/data-list-view-surface.js +80 -0
  350. package/dist/lib/data-list-view-surface.js.map +1 -0
  351. package/dist/lib/data-list-view.d.ts +21 -0
  352. package/dist/lib/data-list-view.js +25 -0
  353. package/dist/lib/data-list-view.js.map +1 -0
  354. package/dist/lib/date-filter.d.ts +22 -0
  355. package/dist/lib/date-filter.js +61 -0
  356. package/dist/lib/date-filter.js.map +1 -0
  357. package/dist/lib/dev-log.d.ts +8 -0
  358. package/dist/lib/dev-log.js +10 -0
  359. package/dist/lib/dev-log.js.map +1 -0
  360. package/dist/lib/dropdown-menu-surface.d.ts +14 -0
  361. package/dist/lib/dropdown-menu-surface.js +6 -0
  362. package/dist/lib/dropdown-menu-surface.js.map +1 -0
  363. package/dist/lib/editable-target.d.ts +12 -0
  364. package/dist/lib/editable-target.js +12 -0
  365. package/dist/lib/editable-target.js.map +1 -0
  366. package/dist/lib/list-page-table-properties.d.ts +35 -0
  367. package/dist/lib/list-page-table-properties.js +81 -0
  368. package/dist/lib/list-page-table-properties.js.map +1 -0
  369. package/dist/lib/raf-throttle.d.ts +23 -0
  370. package/dist/lib/raf-throttle.js +27 -0
  371. package/dist/lib/raf-throttle.js.map +1 -0
  372. package/dist/lib/row-height.d.ts +16 -0
  373. package/dist/lib/row-height.js +10 -0
  374. package/dist/lib/row-height.js.map +1 -0
  375. package/dist/lib/table-properties-types.d.ts +83 -0
  376. package/dist/lib/table-properties-types.js +19 -0
  377. package/dist/lib/table-properties-types.js.map +1 -0
  378. package/dist/lib/utils.d.ts +5 -0
  379. package/dist/lib/utils.js +11 -0
  380. package/dist/lib/utils.js.map +1 -0
  381. package/package.json +83 -19
  382. package/src/components/data-table/filter-date-calendar.tsx +38 -0
  383. package/src/components/data-table/filter-text-value-input.tsx +77 -0
  384. package/src/components/data-table/index.tsx +1678 -0
  385. package/src/components/data-table/pagination.tsx +255 -0
  386. package/src/components/data-table/types.ts +96 -0
  387. package/src/components/data-table/use-table-state.ts +767 -0
  388. package/src/components/data-views/board-card-primitives.tsx +93 -0
  389. package/src/components/data-views/data-row-list.tsx +183 -0
  390. package/src/components/data-views/finder-panel-view.tsx +405 -0
  391. package/src/components/data-views/folder-grid-view.tsx +86 -0
  392. package/src/components/data-views/hub-table.tsx +498 -0
  393. package/src/components/data-views/index.ts +28 -0
  394. package/src/components/data-views/list-page-board-card.tsx +192 -0
  395. package/src/components/data-views/list-page-board-template.tsx +122 -0
  396. package/src/components/data-views/list-page-connected-view-body.tsx +66 -0
  397. package/src/components/data-views/list-page-split-details-placeholder.tsx +39 -0
  398. package/src/components/data-views/list-page-split-hub-chrome.tsx +60 -0
  399. package/src/components/data-views/list-page-split-hub-tokens.ts +16 -0
  400. package/src/components/data-views/list-page-tree-column-header.tsx +31 -0
  401. package/src/components/data-views/list-page-tree-panel-shell.tsx +91 -0
  402. package/src/components/data-views/os-folder-glyph.tsx +141 -0
  403. package/src/components/data-views/outline-tree-menu.tsx +157 -0
  404. package/src/components/table-properties/column-row.tsx +90 -0
  405. package/src/components/table-properties/draggable-list.ts +54 -0
  406. package/src/components/table-properties/drawer-button.tsx +300 -0
  407. package/src/components/table-properties/drawer.tsx +1148 -0
  408. package/src/components/table-properties/filter-card.tsx +251 -0
  409. package/src/components/table-properties/index.ts +36 -0
  410. package/src/components/table-properties/sort-card.tsx +63 -0
  411. package/src/components/templates/dedicated-search-landing-template.tsx +124 -0
  412. package/src/components/templates/dedicated-search-results-template.tsx +19 -0
  413. package/src/components/templates/index.ts +33 -0
  414. package/src/components/templates/list-page.tsx +602 -0
  415. package/src/components/templates/nested-secondary-panel-shell.tsx +70 -0
  416. package/src/components/ui/accordion.tsx +92 -0
  417. package/src/components/ui/alert-dialog.tsx +221 -0
  418. package/src/components/ui/avatar.tsx +13 -2
  419. package/src/components/ui/banner.tsx +2 -2
  420. package/src/components/ui/button.tsx +4 -4
  421. package/src/components/ui/calendar.tsx +1 -1
  422. package/src/components/ui/coach-mark.tsx +1 -1
  423. package/src/components/ui/context-menu.tsx +291 -0
  424. package/src/components/ui/date-picker-field.tsx +2 -2
  425. package/src/components/ui/dot-pattern.tsx +183 -0
  426. package/src/components/ui/export-drawer.tsx +375 -0
  427. package/src/components/ui/hover-card.tsx +66 -0
  428. package/src/components/ui/key-metrics-context.tsx +78 -0
  429. package/src/components/ui/key-metrics.tsx +1133 -0
  430. package/src/components/ui/list-page-view-frame.tsx +64 -0
  431. package/src/components/ui/page-header.tsx +244 -0
  432. package/src/components/ui/payment-card-fields.tsx +2 -2
  433. package/src/components/ui/resizable.tsx +68 -0
  434. package/src/components/ui/scroll-area.tsx +72 -0
  435. package/src/components/ui/selection-tile-grid.tsx +9 -2
  436. package/src/components/ui/sidebar.tsx +84 -12
  437. package/src/components/ui/slider.tsx +83 -0
  438. package/src/globals.css +2201 -7
  439. package/src/globals.d.ts +20 -0
  440. package/src/index.ts +68 -1
  441. package/src/lib/conditional-rule-match.ts +119 -0
  442. package/src/lib/data-list-display-options.ts +35 -0
  443. package/src/lib/data-list-view-registry.ts +104 -0
  444. package/src/lib/data-list-view-surface.ts +83 -0
  445. package/src/lib/data-list-view.ts +47 -0
  446. package/src/lib/dev-log.ts +10 -0
  447. package/src/lib/editable-target.ts +20 -0
  448. package/src/lib/list-page-table-properties.ts +48 -0
  449. package/src/lib/raf-throttle.ts +45 -0
  450. package/src/lib/row-height.ts +19 -0
  451. package/src/lib/table-properties-types.ts +98 -0
  452. package/template/.cursor/rules/exxat-command-menu.mdc +1 -1
  453. package/template/.cursor/rules/exxat-dashboard-view-charts.mdc +3 -3
  454. package/template/.cursor/rules/exxat-data-tables.mdc +1 -1
  455. package/template/.cursor/rules/exxat-ds-agents.mdc +2 -2
  456. package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +2 -2
  457. package/template/.cursor/rules/exxat-table-properties-drawer.mdc +1 -1
  458. package/template/AGENTS.md +104 -78
  459. package/template/app/(app)/dashboard/loading.tsx +15 -3
  460. package/template/app/(app)/dashboard/page.tsx +14 -2
  461. package/template/app/(app)/examples/page.tsx +0 -2
  462. package/template/app/(app)/layout.tsx +17 -4
  463. package/template/app/(app)/loading.tsx +18 -1
  464. package/template/app/(app)/question-bank/find/page.tsx +1 -2
  465. package/template/app/(app)/question-bank/layout.tsx +1 -1
  466. package/template/app/(app)/question-bank/library/page.tsx +1 -2
  467. package/template/app/(app)/question-bank/list/page.tsx +1 -2
  468. package/template/app/(app)/question-bank/new/page.tsx +15 -20
  469. package/template/app/(app)/question-bank/page.tsx +1 -2
  470. package/template/app/(app)/settings/page.tsx +5 -4
  471. package/template/app/globals.css +14 -16
  472. package/template/components/ask-leo-sidebar.tsx +5 -1
  473. package/template/components/brand-color-picker.tsx +2 -2
  474. package/template/components/charts-overview.tsx +1 -1
  475. package/template/components/compliance-board-view.tsx +142 -0
  476. package/template/components/compliance-client.tsx +92 -0
  477. package/template/components/compliance-page-header.tsx +89 -0
  478. package/template/components/compliance-table.tsx +468 -0
  479. package/template/components/dashboard-report-charts.tsx +1 -1
  480. package/template/components/dashboard-tabs.tsx +1 -1
  481. package/template/components/data-table/filter-date-calendar.tsx +1 -38
  482. package/template/components/data-table/filter-text-value-input.tsx +1 -77
  483. package/template/components/data-table/index.tsx +1 -1634
  484. package/template/components/data-table/pagination.tsx +1 -255
  485. package/template/components/data-table/types.ts +1 -94
  486. package/template/components/data-table/use-table-state.test.ts +420 -0
  487. package/template/components/data-table/use-table-state.ts +1 -758
  488. package/template/components/data-view-dashboard-charts-compliance.tsx +963 -0
  489. package/template/components/data-view-dashboard-charts-team.tsx +971 -0
  490. package/template/components/data-view-dashboard-charts.tsx +1503 -0
  491. package/template/components/data-views/board-card-primitives.tsx +1 -93
  492. package/template/components/data-views/data-row-list.tsx +1 -183
  493. package/template/components/data-views/finder-panel-view.tsx +1 -405
  494. package/template/components/data-views/folder-grid-view.tsx +1 -86
  495. package/template/components/data-views/hub-table.tsx +1 -0
  496. package/template/components/data-views/index.ts +50 -37
  497. package/template/components/data-views/list-page-board-card.tsx +1 -192
  498. package/template/components/data-views/list-page-board-template.tsx +1 -122
  499. package/template/components/data-views/list-page-connected-view-body.tsx +1 -66
  500. package/template/components/data-views/list-page-split-details-placeholder.tsx +1 -39
  501. package/template/components/data-views/list-page-split-hub-chrome.tsx +1 -68
  502. package/template/components/data-views/list-page-split-hub-tokens.ts +1 -16
  503. package/template/components/data-views/list-page-tree-column-header.tsx +1 -31
  504. package/template/components/data-views/list-page-tree-panel-shell.tsx +1 -91
  505. package/template/components/data-views/list-page-view-frame.tsx +5 -53
  506. package/template/components/data-views/os-folder-glyph.tsx +1 -129
  507. package/template/components/data-views/outline-tree-menu.tsx +1 -157
  508. package/template/components/export-drawer.test.tsx +71 -0
  509. package/template/components/export-drawer.tsx +1 -375
  510. package/template/components/exxat-product-logo.tsx +5 -5
  511. package/template/components/hub-tree-panel-view.tsx +2 -2
  512. package/template/components/invite-collaborators-drawer.tsx +3 -3
  513. package/template/components/key-metrics-ask-leo-bridge.tsx +40 -0
  514. package/template/components/key-metrics.tsx +1 -1063
  515. package/template/components/leo-insight-indicator.tsx +2 -2
  516. package/template/components/new-placement-back-btn.tsx +28 -0
  517. package/template/components/new-placement-form.tsx +942 -0
  518. package/template/components/new-question-composer.tsx +456 -408
  519. package/template/components/onboarding/index.ts +9 -0
  520. package/template/components/onboarding/onboarding-01.tsx +1 -1
  521. package/template/components/onboarding/onboarding-02.tsx +1 -1
  522. package/template/components/onboarding/onboarding-03.tsx +1 -1
  523. package/template/components/onboarding/onboarding-04.tsx +1 -1
  524. package/template/components/page-header.tsx +8 -226
  525. package/template/components/placement-board-card.tsx +250 -0
  526. package/template/components/placement-detail.tsx +438 -0
  527. package/template/components/placements-board-view.tsx +397 -0
  528. package/template/components/placements-client.tsx +220 -0
  529. package/template/components/placements-list-view.tsx +124 -0
  530. package/template/components/placements-page-header.tsx +166 -0
  531. package/template/components/placements-table-cells.test.tsx +22 -0
  532. package/template/components/placements-table-cells.tsx +173 -0
  533. package/template/components/placements-table-columns.tsx +210 -0
  534. package/template/components/placements-table.tsx +934 -0
  535. package/template/components/product-switcher.tsx +3 -4
  536. package/template/components/product-wordmark.tsx +2 -1
  537. package/template/components/question-bank-client.tsx +5 -5
  538. package/template/components/question-bank-hub-client.tsx +1 -1
  539. package/template/components/question-bank-new-folder-sheet.tsx +2 -2
  540. package/template/components/question-bank-secondary-nav.tsx +3 -3
  541. package/template/components/question-bank-table.tsx +541 -431
  542. package/template/components/rotations-empty-state.tsx +50 -0
  543. package/template/components/rotations-panel-activator.tsx +8 -0
  544. package/template/components/settings-appearance-card.tsx +3 -4
  545. package/template/components/settings-client.tsx +15 -59
  546. package/template/components/settings-form-row.tsx +4 -9
  547. package/template/components/{app-sidebar-dynamic.tsx → sidebar/app-sidebar-dynamic.tsx} +1 -1
  548. package/template/components/{app-sidebar.tsx → sidebar/app-sidebar.tsx} +59 -74
  549. package/template/components/sidebar/index.ts +16 -0
  550. package/template/components/{secondary-nav.tsx → sidebar/secondary-nav.tsx} +2 -2
  551. package/template/components/{secondary-panel.tsx → sidebar/secondary-panel.tsx} +50 -7
  552. package/template/components/{sidebar-auto-collapse.tsx → sidebar/sidebar-auto-collapse.tsx} +6 -2
  553. package/template/components/{sidebar-shell.tsx → sidebar/sidebar-shell.tsx} +1 -1
  554. package/template/components/site-header.tsx +1 -1
  555. package/template/components/sites-board-view.tsx +67 -0
  556. package/template/components/sites-client.tsx +154 -0
  557. package/template/components/sites-table.tsx +249 -0
  558. package/template/components/table-properties/column-row.tsx +1 -90
  559. package/template/components/table-properties/draggable-list.ts +1 -49
  560. package/template/components/table-properties/drawer-button.tsx +1 -262
  561. package/template/components/table-properties/drawer.tsx +1 -1166
  562. package/template/components/table-properties/filter-card.tsx +1 -251
  563. package/template/components/table-properties/sort-card.tsx +1 -59
  564. package/template/components/table-properties/types.ts +28 -71
  565. package/template/components/team-board-view.tsx +122 -0
  566. package/template/components/team-client.tsx +100 -0
  567. package/template/components/team-page-header.tsx +92 -0
  568. package/template/components/team-table.tsx +553 -0
  569. package/template/components/templates/dedicated-search-landing-template.tsx +1 -124
  570. package/template/components/templates/dedicated-search-results-template.tsx +1 -19
  571. package/template/components/templates/list-page.tsx +1 -608
  572. package/template/components/templates/nested-secondary-panel-shell.tsx +1 -63
  573. package/template/components/templates/new-focus-template.tsx +659 -0
  574. package/template/components/templates/secondary-panel-hub-template.tsx +1 -1
  575. package/template/components/ui/accordion.tsx +1 -0
  576. package/template/components/ui/alert-dialog.tsx +1 -0
  577. package/template/components/ui/context-menu.tsx +1 -0
  578. package/template/components/ui/dot-pattern.tsx +1 -183
  579. package/template/components/ui/hover-card.tsx +1 -0
  580. package/template/components/ui/resizable.tsx +1 -68
  581. package/template/components/ui/scroll-area.tsx +1 -0
  582. package/template/components/ui/slider.tsx +1 -0
  583. package/template/docs/blueprints/README.md +86 -0
  584. package/template/docs/blueprints/_template.md +91 -0
  585. package/template/docs/blueprints/board-card.md +123 -0
  586. package/template/docs/blueprints/data-table.md +139 -0
  587. package/template/docs/blueprints/key-metrics.md +128 -0
  588. package/template/docs/blueprints/list-page-template.md +123 -0
  589. package/template/docs/blueprints/page-header.md +130 -0
  590. package/template/docs/command-menu-pattern.md +1 -1
  591. package/template/docs/component-selection-guide.md +224 -0
  592. package/template/docs/components-audit-2026-05.md +158 -0
  593. package/template/docs/data-views-pattern.md +17 -54
  594. package/template/docs/drawer-vs-dialog-pattern.md +1 -3
  595. package/template/docs/migrations/0001-brand-deep-alias-stabilization.md +95 -0
  596. package/template/docs/migrations/0002-exxat-token-namespace.md +154 -0
  597. package/template/docs/migrations/0003-globals-css-canonical.md +110 -0
  598. package/template/docs/migrations/README.md +100 -0
  599. package/template/docs/migrations/_template.md +64 -0
  600. package/template/docs/shell-surface-elevation-pattern.md +3 -5
  601. package/template/docs/token-taxonomy.md +416 -0
  602. package/template/eslint.config.mjs +27 -0
  603. package/template/hooks/use-secondary-panel-hub-nav.ts +1 -1
  604. package/template/lib/command-menu-config.ts +0 -1
  605. package/template/lib/command-menu-search-data.ts +27 -11
  606. package/template/lib/compliance-supported-views.ts +10 -0
  607. package/template/lib/conditional-rule-match.ts +6 -97
  608. package/template/lib/data-list-display-options.ts +1 -49
  609. package/template/lib/data-list-view-registry.ts +1 -104
  610. package/template/lib/data-list-view-surface.ts +1 -83
  611. package/template/lib/data-list-view.ts +1 -47
  612. package/template/lib/data-view-dashboard-placements-layout.ts +215 -0
  613. package/template/lib/data-view-dashboard-storage.ts +35 -38
  614. package/template/lib/dev-log.ts +1 -8
  615. package/template/lib/editable-target.ts +1 -10
  616. package/template/lib/list-page-table-properties.ts +1 -48
  617. package/template/lib/list-status-badges.ts +97 -4
  618. package/template/lib/mock/compliance-kpi.ts +61 -0
  619. package/template/lib/mock/compliance.ts +146 -0
  620. package/template/lib/mock/navigation.tsx +0 -9
  621. package/template/lib/mock/placements-kpi.ts +134 -0
  622. package/template/lib/mock/placements.ts +176 -0
  623. package/template/lib/mock/sites-directory.ts +16 -0
  624. package/template/lib/mock/sites-kpi.ts +25 -0
  625. package/template/lib/mock/team-kpi.ts +60 -0
  626. package/template/lib/mock/team.ts +118 -0
  627. package/template/lib/placement-board-card-layout.ts +79 -0
  628. package/template/lib/placements-supported-views.ts +12 -0
  629. package/template/lib/question-bank-supported-views.ts +0 -1
  630. package/template/lib/raf-throttle.ts +1 -45
  631. package/template/lib/row-height.ts +4 -10
  632. package/template/lib/sidebar-state-cookie.ts +11 -2
  633. package/template/lib/sites-supported-views.ts +10 -0
  634. package/template/lib/table-state-lifecycle.ts +2 -2
  635. package/template/lib/team-supported-views.ts +10 -0
  636. package/template/package.json +1 -0
  637. package/template/tests/setup.ts +25 -0
  638. package/consumer-extras/AGENTS.md +0 -76
  639. package/consumer-extras/cursor-skills/exxat-consumer-app/SKILL.md +0 -37
  640. package/consumer-extras/cursor-skills/exxat-focused-workflow-page/SKILL.md +0 -57
  641. package/consumer-extras/patterns/consumer-app-pattern.md +0 -39
  642. package/consumer-extras/patterns/focused-workflow-page-pattern.md +0 -84
  643. package/src/components/ui/button-group.tsx +0 -81
  644. package/src/theme.css +0 -16
  645. package/src/tokens/README.md +0 -15
  646. package/src/tokens/base.css +0 -337
  647. package/src/tokens/high-contrast.css +0 -1195
  648. package/src/tokens/layers.css +0 -224
  649. package/src/tokens/tailwind-bridge.css +0 -118
  650. package/src/tokens/themes.css +0 -201
  651. package/template/app/(app)/data-list/layout.tsx +0 -43
  652. package/template/app/(app)/data-list/page.tsx +0 -10
  653. package/template/app/(app)/examples/focused-workflow/page.tsx +0 -5
  654. package/template/components/app-route-loading.tsx +0 -14
  655. package/template/components/dashboard-onboarding-gallery.tsx +0 -13
  656. package/template/components/dashboard-onboarding.tsx +0 -21
  657. package/template/components/data-views/list-page-calendar-view.tsx +0 -593
  658. package/template/components/data-views/list-page-folder-columns-panel.tsx +0 -345
  659. package/template/components/examples/focused-workflow-showcase.tsx +0 -183
  660. package/template/components/list-hub-board-view.tsx +0 -68
  661. package/template/components/list-hub-client.tsx +0 -186
  662. package/template/components/list-hub-list-view.tsx +0 -36
  663. package/template/components/list-hub-panel-activator.tsx +0 -8
  664. package/template/components/list-hub-secondary-nav.tsx +0 -121
  665. package/template/components/list-hub-table.tsx +0 -336
  666. package/template/components/question-bank-folder-columns-panel.tsx +0 -104
  667. package/template/components/question-bank-list-view.tsx +0 -53
  668. package/template/components/secondary-panel/nav-link-rows.tsx +0 -83
  669. package/template/components/secondary-panels/list-hub-panel.tsx +0 -39
  670. package/template/components/secondary-panels/question-bank-panel.tsx +0 -39
  671. package/template/components/secondary-panels/registry.tsx +0 -15
  672. package/template/components/section-cards.tsx +0 -106
  673. package/template/components/templates/focused-workflow-layouts.tsx +0 -448
  674. package/template/components/templates/focused-workflow-page-template.tsx +0 -69
  675. package/template/components/templates/page-loading-shell.tsx +0 -262
  676. package/template/components/ui/button-group.tsx +0 -1
  677. package/template/docs/consumer-app-pattern.md +0 -39
  678. package/template/docs/focused-workflow-page-pattern.md +0 -84
  679. package/template/lib/list-hub-nav.ts +0 -121
  680. package/template/lib/mock/list-hub-directory.ts +0 -27
  681. package/template/lib/mock/list-hub-kpi.ts +0 -27
  682. package/template/lib/page-loading-variant.ts +0 -40
  683. /package/template/components/{getting-started.tsx → onboarding/getting-started.tsx} +0 -0
  684. /package/template/components/{nav-documents.tsx → sidebar/nav-documents.tsx} +0 -0
  685. /package/template/components/{nav-main.tsx → sidebar/nav-main.tsx} +0 -0
  686. /package/template/components/{nav-secondary.tsx → sidebar/nav-secondary.tsx} +0 -0
  687. /package/template/components/{nav-user.tsx → sidebar/nav-user.tsx} +0 -0
  688. /package/template/components/{sidebar-auto-open.tsx → sidebar/sidebar-auto-open.tsx} +0 -0
@@ -0,0 +1,3085 @@
1
+ "use client";
2
+ import * as React9 from 'react';
3
+ import { useTheme } from 'next-themes';
4
+ import { createPortal } from 'react-dom';
5
+ import { clsx } from 'clsx';
6
+ import { twMerge } from 'tailwind-merge';
7
+ import { cva } from 'class-variance-authority';
8
+ import { Slot, Checkbox as Checkbox$1, Popover as Popover$1, DropdownMenu as DropdownMenu$1, Tooltip as Tooltip$1 } from 'radix-ui';
9
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
+ import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from 'lucide-react';
11
+ import { getDefaultClassNames, DayPicker } from 'react-day-picker';
12
+ import { useMaskInput } from 'use-mask-input';
13
+
14
+ function cn(...inputs) {
15
+ return twMerge(clsx(inputs));
16
+ }
17
+
18
+ // src/lib/raf-throttle.ts
19
+ function rafThrottle(fn) {
20
+ let rafId = 0;
21
+ let lastArgs = null;
22
+ const scheduled = ((...args) => {
23
+ lastArgs = args;
24
+ if (rafId !== 0) return;
25
+ rafId = requestAnimationFrame(() => {
26
+ rafId = 0;
27
+ const a = lastArgs;
28
+ lastArgs = null;
29
+ if (a) fn(...a);
30
+ });
31
+ });
32
+ scheduled.cancel = () => {
33
+ if (rafId !== 0) {
34
+ cancelAnimationFrame(rafId);
35
+ rafId = 0;
36
+ }
37
+ lastArgs = null;
38
+ };
39
+ return scheduled;
40
+ }
41
+ var buttonVariants = cva(
42
+ "group/button inline-flex shrink-0 cursor-pointer items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
43
+ {
44
+ variants: {
45
+ variant: {
46
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
47
+ outline: "border-input bg-background hover:bg-interactive-hover hover:text-interactive-hover-foreground aria-expanded:bg-interactive-hover aria-expanded:text-interactive-hover-foreground dark:bg-input/15 dark:hover:bg-input/25",
48
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
49
+ ghost: "hover:bg-interactive-hover hover:text-interactive-hover-foreground aria-expanded:bg-interactive-hover aria-expanded:text-interactive-hover-foreground dark:hover:bg-interactive-hover-subtle",
50
+ destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
51
+ link: "text-primary underline-offset-4 hover:underline"
52
+ },
53
+ size: {
54
+ default: "h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pe-2.5 has-data-[icon=inline-start]:ps-2.5",
55
+ xs: "h-6 gap-1 px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3",
56
+ sm: "h-8 gap-1 px-3 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2 [&_svg:not([class*='size-'])]:size-3.5",
57
+ lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pe-3.5 has-data-[icon=inline-start]:ps-3.5",
58
+ icon: "size-9",
59
+ "icon-xs": "size-6 in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
60
+ "icon-sm": "size-8 in-data-[slot=button-group]:rounded-lg",
61
+ "icon-lg": "size-10"
62
+ }
63
+ },
64
+ defaultVariants: {
65
+ variant: "default",
66
+ size: "default"
67
+ }
68
+ }
69
+ );
70
+ var Button = React9.forwardRef(({ className, variant = "default", size = "default", asChild = false, ...props }, ref) => {
71
+ const Comp = asChild ? Slot.Root : "button";
72
+ return /* @__PURE__ */ jsx(
73
+ Comp,
74
+ {
75
+ ref,
76
+ "data-slot": "button",
77
+ "data-variant": variant,
78
+ "data-size": size,
79
+ className: cn(buttonVariants({ variant, size }), className),
80
+ ...props
81
+ }
82
+ );
83
+ });
84
+ Button.displayName = "Button";
85
+ var Input = React9.forwardRef(
86
+ function Input2({ className, type, ...props }, ref) {
87
+ return /* @__PURE__ */ jsx(
88
+ "input",
89
+ {
90
+ ref,
91
+ type,
92
+ "data-slot": "input",
93
+ className: cn(
94
+ "h-8 w-full min-w-0 rounded-md border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
95
+ className
96
+ ),
97
+ ...props
98
+ }
99
+ );
100
+ }
101
+ );
102
+ function Kbd({
103
+ className,
104
+ variant = "tile",
105
+ "aria-hidden": ariaHidden,
106
+ ...props
107
+ }) {
108
+ const hidden = ariaHidden ?? (variant === "bare" ? true : void 0);
109
+ return /* @__PURE__ */ jsx(
110
+ "kbd",
111
+ {
112
+ "data-slot": "kbd",
113
+ "data-variant": variant,
114
+ "aria-hidden": hidden,
115
+ className: cn(
116
+ "pointer-events-none inline-flex h-5 min-w-5 select-none items-center justify-center gap-1 px-1 font-sans text-xs font-medium",
117
+ variant === "tile" && "bg-muted text-muted-foreground rounded-sm border",
118
+ variant === "bare" && "text-current/70 px-0",
119
+ className
120
+ ),
121
+ ...props
122
+ }
123
+ );
124
+ }
125
+ function KbdGroup({ className, ...props }) {
126
+ return /* @__PURE__ */ jsx(
127
+ "div",
128
+ {
129
+ "data-slot": "kbd-group",
130
+ className: cn("inline-flex items-center gap-1", className),
131
+ ...props
132
+ }
133
+ );
134
+ }
135
+ function TooltipProvider({
136
+ delayDuration = 0,
137
+ ...props
138
+ }) {
139
+ return /* @__PURE__ */ jsx(
140
+ Tooltip$1.Provider,
141
+ {
142
+ "data-slot": "tooltip-provider",
143
+ delayDuration,
144
+ ...props
145
+ }
146
+ );
147
+ }
148
+ function Tooltip({
149
+ ...props
150
+ }) {
151
+ return /* @__PURE__ */ jsx(Tooltip$1.Root, { "data-slot": "tooltip", ...props });
152
+ }
153
+ function TooltipTrigger({
154
+ className,
155
+ ...props
156
+ }) {
157
+ return /* @__PURE__ */ jsx(
158
+ Tooltip$1.Trigger,
159
+ {
160
+ "data-slot": "tooltip-trigger",
161
+ suppressHydrationWarning: true,
162
+ className: cn("cursor-pointer", className),
163
+ ...props
164
+ }
165
+ );
166
+ }
167
+ function TooltipContent({
168
+ className,
169
+ sideOffset = 0,
170
+ children,
171
+ ...props
172
+ }) {
173
+ return /* @__PURE__ */ jsx(Tooltip$1.Portal, { children: /* @__PURE__ */ jsxs(
174
+ Tooltip$1.Content,
175
+ {
176
+ "data-slot": "tooltip-content",
177
+ sideOffset,
178
+ className: cn(
179
+ "z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pe-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
180
+ className
181
+ ),
182
+ ...props,
183
+ children: [
184
+ children,
185
+ /* @__PURE__ */ jsx(Tooltip$1.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" })
186
+ ]
187
+ }
188
+ ) });
189
+ }
190
+ function Tip({ label, children, side = "top" }) {
191
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
192
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children }),
193
+ /* @__PURE__ */ jsx(TooltipContent, { side, className: "flex flex-wrap items-center gap-1.5", children: label })
194
+ ] });
195
+ }
196
+ function useModKeyLabel() {
197
+ const [mod, setMod] = React9.useState("\u2318");
198
+ React9.useEffect(() => {
199
+ setMod(
200
+ typeof navigator !== "undefined" && /Mac|iPhone|iPod|iPad/i.test(navigator.platform) ? "\u2318" : "Ctrl"
201
+ );
202
+ }, []);
203
+ return mod;
204
+ }
205
+
206
+ // src/lib/editable-target.ts
207
+ function isEditableTarget(target) {
208
+ const el = target;
209
+ if (!el) return false;
210
+ if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement)
211
+ return true;
212
+ return el.getAttribute?.("contenteditable") === "true";
213
+ }
214
+ var checkboxVariants = cva(
215
+ [
216
+ "peer relative box-border flex shrink-0 items-center justify-center self-center rounded-[4px] border border-input",
217
+ "outline-none transition-[color,box-shadow,transform,background-color,border-color] duration-150",
218
+ "motion-reduce:transition-none",
219
+ "group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2",
220
+ "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50",
221
+ "disabled:cursor-not-allowed disabled:opacity-50",
222
+ "aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary",
223
+ "dark:bg-input/15 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40"
224
+ ].join(" "),
225
+ {
226
+ variants: {
227
+ variant: {
228
+ default: [
229
+ "data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary",
230
+ "data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground dark:data-[state=indeterminate]:bg-primary dark:data-[state=indeterminate]:text-primary-foreground"
231
+ ].join(" "),
232
+ outline: [
233
+ "bg-background",
234
+ "data-[state=checked]:border-primary data-[state=checked]:bg-background data-[state=checked]:text-primary data-[state=checked]:ring-2 data-[state=checked]:ring-primary/25",
235
+ "data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-background data-[state=indeterminate]:text-primary data-[state=indeterminate]:ring-2 data-[state=indeterminate]:ring-primary/25"
236
+ ].join(" "),
237
+ secondary: [
238
+ "data-[state=checked]:border-secondary data-[state=checked]:bg-secondary data-[state=checked]:text-secondary-foreground",
239
+ "data-[state=indeterminate]:border-secondary data-[state=indeterminate]:bg-secondary data-[state=indeterminate]:text-secondary-foreground"
240
+ ].join(" "),
241
+ success: [
242
+ "data-[state=checked]:border-chart-2 data-[state=checked]:bg-chart-2 data-[state=checked]:text-primary-foreground",
243
+ "data-[state=indeterminate]:border-chart-2 data-[state=indeterminate]:bg-chart-2 data-[state=indeterminate]:text-primary-foreground"
244
+ ].join(" "),
245
+ destructive: [
246
+ "data-[state=checked]:border-destructive data-[state=checked]:bg-destructive data-[state=checked]:text-destructive-foreground",
247
+ "data-[state=indeterminate]:border-destructive data-[state=indeterminate]:bg-destructive data-[state=indeterminate]:text-destructive-foreground"
248
+ ].join(" "),
249
+ warning: [
250
+ "data-[state=checked]:border-amber-500 data-[state=checked]:bg-amber-500 data-[state=checked]:text-amber-950",
251
+ "data-[state=indeterminate]:border-amber-500 data-[state=indeterminate]:bg-amber-500 data-[state=indeterminate]:text-amber-950"
252
+ ].join(" "),
253
+ muted: [
254
+ "data-[state=checked]:border-muted-foreground/50 data-[state=checked]:bg-muted data-[state=checked]:text-foreground",
255
+ "data-[state=indeterminate]:border-muted-foreground/50 data-[state=indeterminate]:bg-muted data-[state=indeterminate]:text-foreground"
256
+ ].join(" ")
257
+ },
258
+ size: {
259
+ sm: "size-3.5 max-h-3.5 max-w-3.5 min-h-3.5 min-w-3.5 rounded-[3px] [&_[data-slot=checkbox-indicator]_i]:text-[10px]",
260
+ default: "size-4 max-h-4 max-w-4 min-h-4 min-w-4 [&_[data-slot=checkbox-indicator]_i]:text-xs",
261
+ lg: "size-5 max-h-5 max-w-5 min-h-5 min-w-5 rounded-[5px] [&_[data-slot=checkbox-indicator]_i]:text-sm"
262
+ },
263
+ motion: {
264
+ none: "",
265
+ pop: [
266
+ "motion-safe:active:scale-95",
267
+ "data-[state=checked]:motion-safe:scale-[1.04] data-[state=indeterminate]:motion-safe:scale-[1.04]"
268
+ ].join(" "),
269
+ glow: [
270
+ "data-[state=checked]:shadow-[0_0_0_3px] data-[state=checked]:shadow-primary/35",
271
+ "data-[state=indeterminate]:shadow-[0_0_0_3px] data-[state=indeterminate]:shadow-primary/35"
272
+ ].join(" "),
273
+ "pop-glow": [
274
+ "motion-safe:active:scale-95",
275
+ "data-[state=checked]:motion-safe:scale-[1.04] data-[state=indeterminate]:motion-safe:scale-[1.04]",
276
+ "data-[state=checked]:shadow-[0_0_0_3px] data-[state=checked]:shadow-primary/35",
277
+ "data-[state=indeterminate]:shadow-[0_0_0_3px] data-[state=indeterminate]:shadow-primary/35"
278
+ ].join(" ")
279
+ }
280
+ },
281
+ defaultVariants: {
282
+ variant: "default",
283
+ size: "default",
284
+ motion: "none"
285
+ }
286
+ }
287
+ );
288
+ var checkboxIndicatorVariants = cva("grid place-content-center text-current", {
289
+ variants: {
290
+ motion: {
291
+ none: "transition-none",
292
+ pop: "motion-safe:animate-in motion-safe:fade-in-0 motion-safe:zoom-in-95 motion-safe:duration-150",
293
+ glow: "",
294
+ "pop-glow": "motion-safe:animate-in motion-safe:fade-in-0 motion-safe:zoom-in-95 motion-safe:duration-150"
295
+ }
296
+ },
297
+ defaultVariants: {
298
+ motion: "none"
299
+ }
300
+ });
301
+ var Checkbox = React9.forwardRef(
302
+ function Checkbox2({ className, variant, size, motion, checked, ...props }, ref) {
303
+ const m = motion ?? "none";
304
+ return /* @__PURE__ */ jsx(
305
+ Checkbox$1.Root,
306
+ {
307
+ ref,
308
+ "data-slot": "checkbox",
309
+ "data-variant": variant ?? "default",
310
+ "data-motion": m,
311
+ checked,
312
+ className: cn(checkboxVariants({ variant, size, motion: m }), className),
313
+ ...props,
314
+ children: /* @__PURE__ */ jsx(
315
+ Checkbox$1.Indicator,
316
+ {
317
+ "data-slot": "checkbox-indicator",
318
+ className: checkboxIndicatorVariants({ motion: m }),
319
+ children: checked === "indeterminate" ? /* @__PURE__ */ jsx("i", { className: "fa-solid fa-minus text-current", "aria-hidden": "true" }) : /* @__PURE__ */ jsx("i", { className: "fa-solid fa-check text-current", "aria-hidden": "true" })
320
+ }
321
+ )
322
+ }
323
+ );
324
+ }
325
+ );
326
+
327
+ // src/lib/dropdown-menu-surface.ts
328
+ var DROPDOWN_MENU_CONTENT_SURFACE_CLASS = "min-w-52 w-max max-w-[min(24rem,calc(100vw-2rem))]";
329
+ function DropdownMenu({
330
+ ...props
331
+ }) {
332
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Root, { "data-slot": "dropdown-menu", ...props });
333
+ }
334
+ function DropdownMenuTrigger({
335
+ className,
336
+ ...props
337
+ }) {
338
+ return /* @__PURE__ */ jsx(
339
+ DropdownMenu$1.Trigger,
340
+ {
341
+ "data-slot": "dropdown-menu-trigger",
342
+ suppressHydrationWarning: true,
343
+ className: cn("cursor-pointer", className),
344
+ ...props
345
+ }
346
+ );
347
+ }
348
+ function DropdownMenuContent({
349
+ className,
350
+ align = "start",
351
+ sideOffset = 4,
352
+ ...props
353
+ }) {
354
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Portal, { children: /* @__PURE__ */ jsx(
355
+ DropdownMenu$1.Content,
356
+ {
357
+ "data-slot": "dropdown-menu-content",
358
+ sideOffset,
359
+ align,
360
+ className: cn(
361
+ "z-50 max-h-(--radix-dropdown-menu-content-available-height) origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:overflow-hidden data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
362
+ DROPDOWN_MENU_CONTENT_SURFACE_CLASS,
363
+ className
364
+ ),
365
+ ...props
366
+ }
367
+ ) });
368
+ }
369
+ function DropdownMenuItem({
370
+ className,
371
+ inset,
372
+ variant = "default",
373
+ shortcut,
374
+ children,
375
+ asChild,
376
+ ...props
377
+ }) {
378
+ return /* @__PURE__ */ jsx(
379
+ DropdownMenu$1.Item,
380
+ {
381
+ "data-slot": "dropdown-menu-item",
382
+ "data-inset": inset,
383
+ "data-variant": variant,
384
+ asChild,
385
+ className: cn(
386
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:ps-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_i]:pointer-events-none [&_svg]:shrink-0 [&_i]:shrink-0 [&_svg:not([data-product-logo]):not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
387
+ className
388
+ ),
389
+ ...props,
390
+ children: asChild ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
391
+ children,
392
+ shortcut ? /* @__PURE__ */ jsx(DropdownMenuShortcut, { children: shortcut }) : null
393
+ ] })
394
+ }
395
+ );
396
+ }
397
+ function DropdownMenuLabel({
398
+ className,
399
+ inset,
400
+ ...props
401
+ }) {
402
+ return /* @__PURE__ */ jsx(
403
+ DropdownMenu$1.Label,
404
+ {
405
+ "data-slot": "dropdown-menu-label",
406
+ "data-inset": inset,
407
+ className: cn(
408
+ "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:ps-7",
409
+ className
410
+ ),
411
+ ...props
412
+ }
413
+ );
414
+ }
415
+ function DropdownMenuSeparator({
416
+ className,
417
+ ...props
418
+ }) {
419
+ return /* @__PURE__ */ jsx(
420
+ DropdownMenu$1.Separator,
421
+ {
422
+ "data-slot": "dropdown-menu-separator",
423
+ className: cn("-mx-1 my-1 h-px bg-border", className),
424
+ ...props
425
+ }
426
+ );
427
+ }
428
+ function DropdownMenuShortcut({
429
+ className,
430
+ ...props
431
+ }) {
432
+ return /* @__PURE__ */ jsx(
433
+ "span",
434
+ {
435
+ "data-slot": "dropdown-menu-shortcut",
436
+ className: cn(
437
+ "ms-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground",
438
+ className
439
+ ),
440
+ ...props
441
+ }
442
+ );
443
+ }
444
+ function Popover({ ...props }) {
445
+ return /* @__PURE__ */ jsx(Popover$1.Root, { ...props });
446
+ }
447
+ function PopoverTrigger({ className, ...props }) {
448
+ return /* @__PURE__ */ jsx(Popover$1.Trigger, { className: cn("cursor-pointer", className), ...props });
449
+ }
450
+ function PopoverAnchor({ ...props }) {
451
+ return /* @__PURE__ */ jsx(Popover$1.Anchor, { ...props });
452
+ }
453
+ function PopoverContent({
454
+ className,
455
+ align = "start",
456
+ sideOffset = 4,
457
+ ...props
458
+ }) {
459
+ return /* @__PURE__ */ jsx(Popover$1.Portal, { children: /* @__PURE__ */ jsx(
460
+ Popover$1.Content,
461
+ {
462
+ "data-slot": "popover-content",
463
+ align,
464
+ sideOffset,
465
+ className: cn(
466
+ "z-50 rounded-lg border border-border bg-popover shadow-md outline-none",
467
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
468
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
469
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
470
+ "data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2",
471
+ "data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2",
472
+ className
473
+ ),
474
+ ...props
475
+ }
476
+ ) });
477
+ }
478
+
479
+ // src/lib/table-properties-types.ts
480
+ var OPERATOR_LABELS = {
481
+ is: "is",
482
+ is_not: "is not",
483
+ contains: "contains",
484
+ not_contains: "does not contain"
485
+ };
486
+
487
+ // src/lib/conditional-rule-match.ts
488
+ function rowValueForRule(row, rule, columns) {
489
+ const col = columns?.find((c) => c.key === rule.fieldKey);
490
+ const dataKey = col?.sortKey ?? rule.fieldKey;
491
+ return String(row[dataKey] ?? "");
492
+ }
493
+ function ruleHasActiveValues(rule, columns) {
494
+ if (rule.values.length === 0) return false;
495
+ const col = columns?.find((c) => c.key === rule.fieldKey);
496
+ if (col?.filter?.type === "text")
497
+ return (rule.values[0] ?? "").trim().length > 0;
498
+ return true;
499
+ }
500
+ function conditionalTextMatches(cellVal, needle, op, textMask) {
501
+ const v = cellVal.trim();
502
+ const n = needle.trim();
503
+ if (!n) return op === "not_contains";
504
+ if (textMask === "phone" || textMask === "zip") {
505
+ const nd = n.replace(/\D/g, "");
506
+ const hay = v.replace(/\D/g, "");
507
+ if (!nd) return op === "not_contains";
508
+ const hit2 = hay.includes(nd);
509
+ return op === "contains" ? hit2 : !hit2;
510
+ }
511
+ const hit = v.toLowerCase().includes(n.toLowerCase());
512
+ return op === "contains" ? hit : !hit;
513
+ }
514
+ function conditionalRuleMatchesRow(row, rule, columns) {
515
+ if (!ruleHasActiveValues(rule, columns)) return false;
516
+ const v = rowValueForRule(row, rule, columns).trim();
517
+ const col = columns?.find((c) => c.key === rule.fieldKey);
518
+ const textMask = col?.filter?.type === "text" ? col.filter.textMask : void 0;
519
+ switch (rule.operator) {
520
+ case "is":
521
+ return rule.values.includes(v);
522
+ case "is_not":
523
+ return !rule.values.includes(v);
524
+ case "contains":
525
+ return rule.values.some(
526
+ (val) => conditionalTextMatches(v, val, "contains", textMask)
527
+ );
528
+ case "not_contains":
529
+ return !rule.values.some(
530
+ (val) => conditionalTextMatches(v, val, "contains", textMask)
531
+ );
532
+ default:
533
+ return false;
534
+ }
535
+ }
536
+ function getConditionalCellBackground(row, colKey, rules, columns) {
537
+ if (!rules?.length) return void 0;
538
+ const rule = rules.find((r) => r.fieldKey === colKey);
539
+ if (!rule || !conditionalRuleMatchesRow(row, rule, columns)) return void 0;
540
+ return rule.bgColor;
541
+ }
542
+
543
+ // src/lib/date-filter.ts
544
+ function formatDateFromDate(raw) {
545
+ if (!raw || Number.isNaN(raw.getTime())) return "\u2014";
546
+ const m = String(raw.getMonth() + 1).padStart(2, "0");
547
+ const day = String(raw.getDate()).padStart(2, "0");
548
+ const y = raw.getFullYear();
549
+ return `${m}/${day}/${y}`;
550
+ }
551
+ function parseRowDateToYmd(raw) {
552
+ const t = raw.trim();
553
+ if (!t || t === "\u2014" || t === "-") return null;
554
+ const d = new Date(t);
555
+ if (Number.isNaN(d.getTime())) return null;
556
+ const y = d.getFullYear();
557
+ const m = String(d.getMonth() + 1).padStart(2, "0");
558
+ const day = String(d.getDate()).padStart(2, "0");
559
+ return `${y}-${m}-${day}`;
560
+ }
561
+ function formatYmdForDisplay(ymd) {
562
+ const d = ymdToLocalDate(ymd);
563
+ if (!d) return ymd;
564
+ return formatDateFromDate(d);
565
+ }
566
+ function ymdToLocalDate(ymd) {
567
+ if (!ymd || !/^\d{4}-\d{2}-\d{2}$/.test(ymd)) return void 0;
568
+ const [y, m, d] = ymd.split("-").map(Number);
569
+ return new Date(y, m - 1, d, 12, 0, 0, 0);
570
+ }
571
+ function localDateToYmd(d) {
572
+ const y = d.getFullYear();
573
+ const m = String(d.getMonth() + 1).padStart(2, "0");
574
+ const day = String(d.getDate()).padStart(2, "0");
575
+ return `${y}-${m}-${day}`;
576
+ }
577
+ function Calendar({
578
+ className,
579
+ classNames,
580
+ showOutsideDays = true,
581
+ captionLayout = "label",
582
+ buttonVariant = "ghost",
583
+ formatters,
584
+ components,
585
+ ...props
586
+ }) {
587
+ const defaultClassNames = getDefaultClassNames();
588
+ return /* @__PURE__ */ jsx(
589
+ DayPicker,
590
+ {
591
+ showOutsideDays,
592
+ className: cn(
593
+ "group/calendar bg-background p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
594
+ String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
595
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
596
+ className
597
+ ),
598
+ captionLayout,
599
+ formatters: {
600
+ formatMonthDropdown: (date) => date.toLocaleString("default", { month: "short" }),
601
+ ...formatters
602
+ },
603
+ classNames: {
604
+ root: cn("w-fit", defaultClassNames.root),
605
+ months: cn(
606
+ "relative flex flex-col gap-4 md:flex-row",
607
+ defaultClassNames.months
608
+ ),
609
+ month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
610
+ nav: cn(
611
+ "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
612
+ defaultClassNames.nav
613
+ ),
614
+ button_previous: cn(
615
+ buttonVariants({ variant: buttonVariant }),
616
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
617
+ defaultClassNames.button_previous
618
+ ),
619
+ button_next: cn(
620
+ buttonVariants({ variant: buttonVariant }),
621
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
622
+ defaultClassNames.button_next
623
+ ),
624
+ month_caption: cn(
625
+ "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
626
+ defaultClassNames.month_caption
627
+ ),
628
+ dropdowns: cn(
629
+ "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
630
+ defaultClassNames.dropdowns
631
+ ),
632
+ dropdown_root: cn(
633
+ "relative rounded-md border border-input shadow-xs has-focus:border-ring has-focus:ring-[3px] has-focus:ring-ring/50",
634
+ defaultClassNames.dropdown_root
635
+ ),
636
+ dropdown: cn(
637
+ "absolute inset-0 bg-popover opacity-0",
638
+ defaultClassNames.dropdown
639
+ ),
640
+ caption_label: cn(
641
+ "font-medium select-none",
642
+ captionLayout === "label" ? "text-sm" : "flex h-8 items-center gap-1 rounded-md pe-1 ps-2 text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
643
+ defaultClassNames.caption_label
644
+ ),
645
+ table: "w-full border-collapse",
646
+ weekdays: cn("flex", defaultClassNames.weekdays),
647
+ weekday: cn(
648
+ "flex-1 rounded-md text-[0.8rem] font-normal text-muted-foreground select-none",
649
+ defaultClassNames.weekday
650
+ ),
651
+ week: cn("mt-2 flex w-full", defaultClassNames.week),
652
+ week_number_header: cn(
653
+ "w-(--cell-size) select-none",
654
+ defaultClassNames.week_number_header
655
+ ),
656
+ week_number: cn(
657
+ "text-[0.8rem] text-muted-foreground select-none",
658
+ defaultClassNames.week_number
659
+ ),
660
+ day: cn(
661
+ "group/day relative aspect-square h-full w-full p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-md",
662
+ props.showWeekNumber ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-md" : "[&:first-child[data-selected=true]_button]:rounded-l-md",
663
+ defaultClassNames.day
664
+ ),
665
+ range_start: cn(
666
+ "rounded-l-md bg-accent",
667
+ defaultClassNames.range_start
668
+ ),
669
+ range_middle: cn("rounded-none", defaultClassNames.range_middle),
670
+ range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
671
+ today: cn(
672
+ "rounded-md bg-accent text-accent-foreground data-[selected=true]:rounded-none",
673
+ defaultClassNames.today
674
+ ),
675
+ outside: cn(
676
+ "text-muted-foreground aria-selected:text-muted-foreground",
677
+ defaultClassNames.outside
678
+ ),
679
+ disabled: cn(
680
+ "text-muted-foreground opacity-50",
681
+ defaultClassNames.disabled
682
+ ),
683
+ hidden: cn("invisible", defaultClassNames.hidden),
684
+ ...classNames
685
+ },
686
+ components: {
687
+ Root: ({ className: className2, rootRef, ...props2 }) => {
688
+ return /* @__PURE__ */ jsx(
689
+ "div",
690
+ {
691
+ "data-slot": "calendar",
692
+ ref: rootRef,
693
+ className: cn(className2),
694
+ ...props2
695
+ }
696
+ );
697
+ },
698
+ Chevron: ({ className: className2, orientation, ...props2 }) => {
699
+ if (orientation === "left") {
700
+ return /* @__PURE__ */ jsx(ChevronLeftIcon, { className: cn("size-4", className2), ...props2 });
701
+ }
702
+ if (orientation === "right") {
703
+ return /* @__PURE__ */ jsx(
704
+ ChevronRightIcon,
705
+ {
706
+ className: cn("size-4", className2),
707
+ ...props2
708
+ }
709
+ );
710
+ }
711
+ return /* @__PURE__ */ jsx(ChevronDownIcon, { className: cn("size-4", className2), ...props2 });
712
+ },
713
+ DayButton: CalendarDayButton,
714
+ WeekNumber: ({ children, ...props2 }) => {
715
+ return /* @__PURE__ */ jsx("td", { ...props2, children: /* @__PURE__ */ jsx("div", { className: "flex size-(--cell-size) items-center justify-center text-center", children }) });
716
+ },
717
+ ...components
718
+ },
719
+ ...props
720
+ }
721
+ );
722
+ }
723
+ function CalendarDayButton({
724
+ className,
725
+ day,
726
+ modifiers,
727
+ ...props
728
+ }) {
729
+ const defaultClassNames = getDefaultClassNames();
730
+ const ref = React9.useRef(null);
731
+ React9.useEffect(() => {
732
+ if (modifiers.focused) ref.current?.focus();
733
+ }, [modifiers.focused]);
734
+ return /* @__PURE__ */ jsx(
735
+ Button,
736
+ {
737
+ ref,
738
+ variant: "ghost",
739
+ size: "icon",
740
+ "data-day": day.date.toLocaleDateString(),
741
+ "data-selected-single": modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle,
742
+ "data-range-start": modifiers.range_start,
743
+ "data-range-end": modifiers.range_end,
744
+ "data-range-middle": modifiers.range_middle,
745
+ className: cn(
746
+ "flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-accent-foreground [&>span]:text-xs [&>span]:opacity-70",
747
+ defaultClassNames.day,
748
+ className
749
+ ),
750
+ ...props
751
+ }
752
+ );
753
+ }
754
+ function FilterDateCalendar({
755
+ valueYmd,
756
+ onChangeYmd,
757
+ label
758
+ }) {
759
+ const [timeZone, setTimeZone] = React9.useState();
760
+ React9.useEffect(() => {
761
+ setTimeZone(Intl.DateTimeFormat().resolvedOptions().timeZone);
762
+ }, []);
763
+ return /* @__PURE__ */ jsx(
764
+ "div",
765
+ {
766
+ className: "rounded-lg border border-border overflow-hidden",
767
+ role: "group",
768
+ "aria-label": label,
769
+ children: /* @__PURE__ */ jsx(
770
+ Calendar,
771
+ {
772
+ mode: "single",
773
+ selected: ymdToLocalDate(valueYmd),
774
+ onSelect: (d) => onChangeYmd(d ? localDateToYmd(d) : void 0),
775
+ captionLayout: "dropdown",
776
+ timeZone,
777
+ className: "rounded-lg border-0"
778
+ }
779
+ )
780
+ }
781
+ );
782
+ }
783
+ function InputGroup({ className, ...props }) {
784
+ return /* @__PURE__ */ jsx(
785
+ "div",
786
+ {
787
+ "data-slot": "input-group",
788
+ role: "group",
789
+ className: cn(
790
+ "group/input-group relative flex h-8 w-full min-w-0 items-center rounded-md border border-input transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pe-1.5 has-[>[data-align=inline-start]]:[&>input]:ps-1.5",
791
+ className
792
+ ),
793
+ ...props
794
+ }
795
+ );
796
+ }
797
+ var inputGroupAddonVariants = cva(
798
+ "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
799
+ {
800
+ variants: {
801
+ align: {
802
+ "inline-start": "order-first ps-2 has-[>button]:ms-[-0.3rem] has-[>kbd]:ms-[-0.15rem]",
803
+ "inline-end": "order-last pe-2 has-[>button]:me-[-0.3rem] has-[>kbd]:me-[-0.15rem]",
804
+ "block-start": "order-first w-full justify-start px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2",
805
+ "block-end": "order-last w-full justify-start px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2"
806
+ }
807
+ },
808
+ defaultVariants: {
809
+ align: "inline-start"
810
+ }
811
+ }
812
+ );
813
+ function InputGroupAddon({
814
+ className,
815
+ align = "inline-start",
816
+ ...props
817
+ }) {
818
+ return /* @__PURE__ */ jsx(
819
+ "div",
820
+ {
821
+ role: "group",
822
+ "data-slot": "input-group-addon",
823
+ "data-align": align,
824
+ className: cn(inputGroupAddonVariants({ align }), className),
825
+ onClick: (e) => {
826
+ if (e.target.closest("button")) {
827
+ return;
828
+ }
829
+ e.currentTarget.parentElement?.querySelector("input")?.focus();
830
+ },
831
+ ...props
832
+ }
833
+ );
834
+ }
835
+ var inputGroupButtonVariants = cva(
836
+ "flex items-center gap-2 text-sm shadow-none",
837
+ {
838
+ variants: {
839
+ size: {
840
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-3px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
841
+ sm: "",
842
+ "icon-xs": "size-6 rounded-[calc(var(--radius)-3px)] p-0 has-[>svg]:p-0",
843
+ "icon-sm": "size-8 p-0 has-[>svg]:p-0"
844
+ }
845
+ },
846
+ defaultVariants: {
847
+ size: "xs"
848
+ }
849
+ }
850
+ );
851
+ function InputGroupButton({
852
+ className,
853
+ type = "button",
854
+ variant = "ghost",
855
+ size = "xs",
856
+ ...props
857
+ }) {
858
+ return /* @__PURE__ */ jsx(
859
+ Button,
860
+ {
861
+ type,
862
+ "data-size": size,
863
+ variant,
864
+ className: cn(inputGroupButtonVariants({ size }), className),
865
+ ...props
866
+ }
867
+ );
868
+ }
869
+
870
+ // src/lib/compose-refs.ts
871
+ function composeRefs(...refs) {
872
+ return (node) => {
873
+ for (const ref of refs) {
874
+ if (ref == null) continue;
875
+ if (typeof ref === "function") {
876
+ ref(node);
877
+ } else {
878
+ ref.current = node;
879
+ }
880
+ }
881
+ };
882
+ }
883
+ var exxatInputMaskDefaults = {
884
+ placeholder: "_",
885
+ showMaskOnHover: false
886
+ };
887
+ var exxatMaskPatterns = {
888
+ /** US NANP 10-digit display */
889
+ phoneUS: "(999) 999-9999",
890
+ /** US ZIP or ZIP+4 */
891
+ zipUS: "99999[-9999]",
892
+ /** Calendar-style date (validate separately). */
893
+ dateMDY: "99/99/9999"};
894
+ var MaskedInput = React9.forwardRef(function MaskedInput2({ mask, maskOptions, className, type = "text", ...props }, ref) {
895
+ const maskRef = useMaskInput({
896
+ mask,
897
+ options: { ...exxatInputMaskDefaults, ...maskOptions }
898
+ });
899
+ return /* @__PURE__ */ jsx(
900
+ Input,
901
+ {
902
+ ref: composeRefs(ref, maskRef),
903
+ type,
904
+ className: cn(className),
905
+ ...props
906
+ }
907
+ );
908
+ });
909
+ var DATE_PICKER_ICON_CLASS = "fa-light fa-calendar";
910
+ function parseMdyToLocalDate(raw) {
911
+ const match = raw.trim().match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
912
+ if (!match) return void 0;
913
+ const month = Number(match[1]);
914
+ const day = Number(match[2]);
915
+ const year = Number(match[3]);
916
+ if (month < 1 || month > 12 || day < 1 || day > 31) return void 0;
917
+ const date = new Date(year, month - 1, day, 12, 0, 0, 0);
918
+ if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) return void 0;
919
+ return date;
920
+ }
921
+ function formatLocalDateToMdy(date) {
922
+ const month = String(date.getMonth() + 1).padStart(2, "0");
923
+ const day = String(date.getDate()).padStart(2, "0");
924
+ const year = String(date.getFullYear());
925
+ return `${month}/${day}/${year}`;
926
+ }
927
+ function DateTextInputField({
928
+ value,
929
+ onValueChange,
930
+ "aria-label": ariaLabel,
931
+ id,
932
+ placeholder = "MM/DD/YYYY",
933
+ className,
934
+ inputClassName,
935
+ autoFocus,
936
+ disabled,
937
+ fromYear = 2020,
938
+ toYear = 2032,
939
+ iconButtonVariant = "ghost",
940
+ popoverAlign = "end",
941
+ popoverClassName
942
+ }) {
943
+ return /* @__PURE__ */ jsxs(InputGroup, { className, children: [
944
+ /* @__PURE__ */ jsx(
945
+ MaskedInput,
946
+ {
947
+ "data-slot": "input-group-control",
948
+ id,
949
+ mask: exxatMaskPatterns.dateMDY,
950
+ "aria-label": ariaLabel,
951
+ placeholder,
952
+ value,
953
+ onChange: (event) => onValueChange(event.target.value),
954
+ className: cn(
955
+ "flex-1 rounded-none border-0 bg-transparent shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent",
956
+ inputClassName
957
+ ),
958
+ autoFocus,
959
+ disabled
960
+ }
961
+ ),
962
+ /* @__PURE__ */ jsx(InputGroupAddon, { align: "inline-end", children: /* @__PURE__ */ jsxs(Popover, { children: [
963
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
964
+ InputGroupButton,
965
+ {
966
+ type: "button",
967
+ variant: iconButtonVariant,
968
+ size: "icon-xs",
969
+ disabled,
970
+ "aria-label": `${ariaLabel} pick date`,
971
+ children: /* @__PURE__ */ jsx("i", { className: DATE_PICKER_ICON_CLASS, "aria-hidden": "true" })
972
+ }
973
+ ) }),
974
+ /* @__PURE__ */ jsx(
975
+ PopoverContent,
976
+ {
977
+ className: cn("z-[80] w-auto p-0", popoverClassName),
978
+ align: popoverAlign,
979
+ sideOffset: 6,
980
+ children: /* @__PURE__ */ jsx(
981
+ Calendar,
982
+ {
983
+ mode: "single",
984
+ selected: parseMdyToLocalDate(value),
985
+ onSelect: (next) => onValueChange(next ? formatLocalDateToMdy(next) : ""),
986
+ initialFocus: true,
987
+ fromYear,
988
+ toYear,
989
+ captionLayout: "dropdown"
990
+ }
991
+ )
992
+ }
993
+ )
994
+ ] }) })
995
+ ] });
996
+ }
997
+ var MASK_BY_KIND = {
998
+ phone: exxatMaskPatterns.phoneUS,
999
+ zip: exxatMaskPatterns.zipUS,
1000
+ dateMDY: exxatMaskPatterns.dateMDY
1001
+ };
1002
+ function FilterTextValueInput({
1003
+ id,
1004
+ mask,
1005
+ value,
1006
+ onValueChange,
1007
+ "aria-label": ariaLabel,
1008
+ placeholder,
1009
+ className,
1010
+ autoFocus
1011
+ }) {
1012
+ if (mask === "dateMDY") {
1013
+ return /* @__PURE__ */ jsx(
1014
+ DateTextInputField,
1015
+ {
1016
+ id,
1017
+ value,
1018
+ onValueChange,
1019
+ "aria-label": ariaLabel,
1020
+ placeholder,
1021
+ inputClassName: className,
1022
+ autoFocus,
1023
+ iconButtonVariant: "ghost",
1024
+ popoverAlign: "end"
1025
+ }
1026
+ );
1027
+ }
1028
+ if (mask) {
1029
+ return /* @__PURE__ */ jsx(
1030
+ MaskedInput,
1031
+ {
1032
+ id,
1033
+ mask: MASK_BY_KIND[mask],
1034
+ "aria-label": ariaLabel,
1035
+ placeholder,
1036
+ value,
1037
+ onChange: (e) => onValueChange(e.target.value),
1038
+ className,
1039
+ autoFocus
1040
+ }
1041
+ );
1042
+ }
1043
+ return /* @__PURE__ */ jsx(
1044
+ Input,
1045
+ {
1046
+ id,
1047
+ type: "text",
1048
+ "aria-label": ariaLabel,
1049
+ placeholder,
1050
+ value,
1051
+ onChange: (e) => onValueChange(e.target.value),
1052
+ className,
1053
+ autoFocus
1054
+ }
1055
+ );
1056
+ }
1057
+ var _filterId = 0;
1058
+ function nextFilterId() {
1059
+ return `f-${++_filterId}`;
1060
+ }
1061
+ var REFLOW_VIEWPORT_MQ = "(max-height: 640px)";
1062
+ function subscribeReflowViewport(callback) {
1063
+ if (typeof window === "undefined") return () => {
1064
+ };
1065
+ const mql = window.matchMedia(REFLOW_VIEWPORT_MQ);
1066
+ mql.addEventListener("change", callback);
1067
+ return () => mql.removeEventListener("change", callback);
1068
+ }
1069
+ function getReflowViewportSnapshot() {
1070
+ if (typeof window === "undefined") return false;
1071
+ return window.matchMedia(REFLOW_VIEWPORT_MQ).matches;
1072
+ }
1073
+ function getServerReflowViewportSnapshot() {
1074
+ return false;
1075
+ }
1076
+ function digitsOnly(s) {
1077
+ return s.replace(/\D/g, "");
1078
+ }
1079
+ function buildDefaultWidths(columns) {
1080
+ const map = {};
1081
+ for (const col of columns) {
1082
+ if (col.width !== void 0) map[col.key] = col.width;
1083
+ }
1084
+ return map;
1085
+ }
1086
+ function buildDefaultPins(columns) {
1087
+ const map = {};
1088
+ for (const col of columns) {
1089
+ if (col.defaultPin) map[col.key] = col.defaultPin;
1090
+ }
1091
+ return map;
1092
+ }
1093
+ function compareUnknownSort(a, b) {
1094
+ if (a === b) return 0;
1095
+ if (a == null && b == null) return 0;
1096
+ if (a == null) return 1;
1097
+ if (b == null) return -1;
1098
+ if (typeof a === "number" && typeof b === "number") return a < b ? -1 : a > b ? 1 : 0;
1099
+ if (typeof a === "string" && typeof b === "string") return a < b ? -1 : a > b ? 1 : 0;
1100
+ const as = String(a);
1101
+ const bs = String(b);
1102
+ return as < bs ? -1 : as > bs ? 1 : 0;
1103
+ }
1104
+ function buildLockedPins(columns) {
1105
+ const map = {};
1106
+ for (const col of columns) {
1107
+ if (col.lockPin && col.defaultPin) map[col.key] = col.defaultPin;
1108
+ }
1109
+ return map;
1110
+ }
1111
+ function useTableState(data, columns, defaultSort, paginationOverride, syncedSearchFromUrl) {
1112
+ const [sortRules, setSortRules] = React9.useState(() => {
1113
+ if (defaultSort) {
1114
+ return [{ id: "sort-default", fieldKey: defaultSort.key, direction: defaultSort.dir }];
1115
+ }
1116
+ return [];
1117
+ });
1118
+ const primarySort = sortRules[0] ?? null;
1119
+ const sortKey = primarySort?.fieldKey ?? "";
1120
+ const sortDir = primarySort?.direction ?? "asc";
1121
+ const addSortRule = React9.useCallback((fieldKey) => {
1122
+ setSortRules((prev) => {
1123
+ if (prev.some((r) => r.fieldKey === fieldKey)) return prev;
1124
+ return [{ id: `sort-${Date.now()}`, fieldKey, direction: "asc" }, ...prev];
1125
+ });
1126
+ }, [setSortRules]);
1127
+ const removeSortRule = React9.useCallback((id) => {
1128
+ setSortRules((prev) => prev.filter((r) => r.id !== id));
1129
+ }, [setSortRules]);
1130
+ const toggleSortDir = React9.useCallback((id) => {
1131
+ setSortRules((prev) => prev.map(
1132
+ (r) => r.id === id ? { ...r, direction: r.direction === "asc" ? "desc" : "asc" } : r
1133
+ ));
1134
+ }, [setSortRules]);
1135
+ const handleSortByKey = React9.useCallback((colKey) => {
1136
+ setSortRules((prev) => {
1137
+ const idx = prev.findIndex((r) => r.fieldKey === colKey);
1138
+ if (idx === 0) {
1139
+ return prev.map((r, i) => i === 0 ? { ...r, direction: r.direction === "asc" ? "desc" : "asc" } : r);
1140
+ }
1141
+ const filtered = prev.filter((r) => r.fieldKey !== colKey);
1142
+ return [{ id: `sort-${Date.now()}`, fieldKey: colKey, direction: "asc" }, ...filtered];
1143
+ });
1144
+ }, [setSortRules]);
1145
+ const [search, setSearch] = React9.useState(
1146
+ () => ""
1147
+ );
1148
+ const [searchOpen, setSearchOpen] = React9.useState(
1149
+ () => syncedSearchFromUrl !== void 0
1150
+ );
1151
+ const searchRef = React9.useRef(null);
1152
+ const [activeFilters, setActiveFilters] = React9.useState([]);
1153
+ const [filterConnectors, setFilterConnectors] = React9.useState({});
1154
+ const [openFilterId, setOpenFilterId] = React9.useState(null);
1155
+ const [filterBarVisible, setFilterBarVisible] = React9.useState(true);
1156
+ const [drawerExpandedFilters, setDrawerExpandedFilters] = React9.useState(/* @__PURE__ */ new Set());
1157
+ React9.useEffect(() => {
1158
+ return;
1159
+ }, [syncedSearchFromUrl]);
1160
+ const toggleConnector = React9.useCallback((leftId) => {
1161
+ setFilterConnectors((prev) => ({ ...prev, [leftId]: prev[leftId] === "or" ? "and" : "or" }));
1162
+ }, [setFilterConnectors]);
1163
+ function getConnector(leftId) {
1164
+ return filterConnectors[leftId] ?? "and";
1165
+ }
1166
+ const addFilter = React9.useCallback((fieldKey, fromDrawer = false) => {
1167
+ const col = columns.find((c) => c.key === fieldKey);
1168
+ if (!col?.filter) return;
1169
+ const id = nextFilterId();
1170
+ const f = col.filter;
1171
+ const firstOperator = (() => {
1172
+ if (f.type === "select" || f.type === "date") {
1173
+ const pick = f.operators?.find((o) => o === "is" || o === "is_not");
1174
+ return pick ?? "is";
1175
+ }
1176
+ return f.operators?.[0] ?? "contains";
1177
+ })();
1178
+ const newFilter = { id, fieldKey, operator: firstOperator, values: [] };
1179
+ setActiveFilters((prev) => [...prev, newFilter]);
1180
+ if (fromDrawer) {
1181
+ setDrawerExpandedFilters(() => /* @__PURE__ */ new Set([id]));
1182
+ } else {
1183
+ setOpenFilterId(id);
1184
+ setFilterBarVisible(true);
1185
+ }
1186
+ }, [columns, setActiveFilters, setDrawerExpandedFilters, setOpenFilterId, setFilterBarVisible]);
1187
+ const updateFilter = React9.useCallback((id, patch) => {
1188
+ let shouldShowFilterBar = false;
1189
+ setActiveFilters((prev) => {
1190
+ const next = prev.map((f) => {
1191
+ if (f.id !== id) return f;
1192
+ const merged = { ...f, ...patch };
1193
+ const col = columns.find((c) => c.key === merged.fieldKey);
1194
+ if (merged.values.length > 0) {
1195
+ shouldShowFilterBar = col?.filter?.type === "text" ? (merged.values[0] ?? "").trim().length > 0 : true;
1196
+ }
1197
+ return merged;
1198
+ });
1199
+ return next;
1200
+ });
1201
+ if (shouldShowFilterBar) setFilterBarVisible(true);
1202
+ }, [columns, setActiveFilters, setFilterBarVisible]);
1203
+ const removeFilter = React9.useCallback((id) => {
1204
+ setActiveFilters((prev) => {
1205
+ const idx = prev.findIndex((f) => f.id === id);
1206
+ const next = prev.filter((f) => f.id !== id);
1207
+ setFilterConnectors((prevC) => {
1208
+ const c = { ...prevC };
1209
+ if (idx > 0 && next.length > 0) {
1210
+ const leftId = prev[idx - 1].id;
1211
+ c[leftId] = prevC[id] ?? prevC[leftId] ?? "and";
1212
+ }
1213
+ delete c[id];
1214
+ return c;
1215
+ });
1216
+ return next;
1217
+ });
1218
+ setOpenFilterId((prev) => prev === id ? null : prev);
1219
+ }, [setActiveFilters, setFilterConnectors, setOpenFilterId]);
1220
+ const [groupBy, setGroupBy] = React9.useState(null);
1221
+ const [colMenuSearch, setColMenuSearch] = React9.useState({});
1222
+ const [selected, setSelected] = React9.useState(/* @__PURE__ */ new Set());
1223
+ const [colWidths, setColWidths] = React9.useState(() => buildDefaultWidths(columns));
1224
+ const resizeRef = React9.useRef(null);
1225
+ const [colOrder, setColOrder] = React9.useState(() => columns.map((c) => c.key));
1226
+ const [colPins, setColPins] = React9.useState(() => buildDefaultPins(columns));
1227
+ const lockedPins = React9.useMemo(() => buildLockedPins(columns), [columns]);
1228
+ const [colWrap, setColWrap] = React9.useState({});
1229
+ const [sheetOpen, setSheetOpen] = React9.useState(false);
1230
+ const [sheetInitialPanel, setSheetInitialPanel] = React9.useState(null);
1231
+ const [showGridlines, setShowGridlines] = React9.useState(true);
1232
+ const [rowHeight, setRowHeight] = React9.useState("default");
1233
+ const [hiddenCols, setHiddenCols] = React9.useState(/* @__PURE__ */ new Set());
1234
+ const toggleColVisibility = React9.useCallback((key) => {
1235
+ setHiddenCols((prev) => {
1236
+ const next = new Set(prev);
1237
+ if (next.has(key)) next.delete(key);
1238
+ else next.add(key);
1239
+ return next;
1240
+ });
1241
+ }, [setHiddenCols]);
1242
+ const moveCol = React9.useCallback((key, dir) => {
1243
+ setColOrder((prev) => {
1244
+ const lockedLeft = columns.filter((c) => c.lockPin && c.defaultPin === "left").map((c) => c.key);
1245
+ const lockedRight = columns.filter((c) => c.lockPin && c.defaultPin === "right").map((c) => c.key);
1246
+ const orderable = prev.filter((k) => !lockedLeft.includes(k) && !lockedRight.includes(k));
1247
+ const idx = orderable.indexOf(key);
1248
+ if (dir === "up" && idx <= 0) return prev;
1249
+ if (dir === "down" && idx >= orderable.length - 1) return prev;
1250
+ const next = [...orderable];
1251
+ const swap = dir === "up" ? idx - 1 : idx + 1;
1252
+ [next[idx], next[swap]] = [next[swap], next[idx]];
1253
+ return [...lockedLeft, ...next, ...lockedRight];
1254
+ });
1255
+ }, [columns, setColOrder]);
1256
+ const draggedKey = React9.useRef(null);
1257
+ const [dragOverKey, setDragOverKey] = React9.useState(null);
1258
+ const scrollRef = React9.useRef(null);
1259
+ const [scrolled, setScrolled] = React9.useState(false);
1260
+ const [scrollEnd, setScrollEnd] = React9.useState(false);
1261
+ const [isOverflowing, setIsOverflowing] = React9.useState(false);
1262
+ const isReflowViewport = React9.useSyncExternalStore(
1263
+ subscribeReflowViewport,
1264
+ getReflowViewportSnapshot,
1265
+ getServerReflowViewportSnapshot
1266
+ );
1267
+ const [hoveredRow, setHoveredRow] = React9.useState(null);
1268
+ const columnsByKey = React9.useMemo(() => {
1269
+ const map = /* @__PURE__ */ new Map();
1270
+ for (const col of columns) map.set(col.key, col);
1271
+ return map;
1272
+ }, [columns]);
1273
+ const searchableTextCache = React9.useRef(/* @__PURE__ */ new WeakMap());
1274
+ const getSearchableText = React9.useCallback((row) => {
1275
+ const cache = searchableTextCache.current;
1276
+ const cached = cache.get(row);
1277
+ if (cached !== void 0) return cached;
1278
+ let blob = "";
1279
+ for (const v of Object.values(row)) {
1280
+ if (v == null) continue;
1281
+ blob += String(v).toLowerCase() + "\n";
1282
+ }
1283
+ cache.set(row, blob);
1284
+ return blob;
1285
+ }, []);
1286
+ const lowerValueCache = React9.useRef(/* @__PURE__ */ new WeakMap());
1287
+ const getLowerValue = React9.useCallback((row, key) => {
1288
+ const wm = lowerValueCache.current;
1289
+ let perRow = wm.get(row);
1290
+ if (!perRow) {
1291
+ perRow = /* @__PURE__ */ new Map();
1292
+ wm.set(row, perRow);
1293
+ }
1294
+ const cached = perRow.get(key);
1295
+ if (cached !== void 0) return cached;
1296
+ const computed = String(row[key] ?? "").toLowerCase();
1297
+ perRow.set(key, computed);
1298
+ return computed;
1299
+ }, []);
1300
+ React9.useEffect(() => {
1301
+ searchableTextCache.current = /* @__PURE__ */ new WeakMap();
1302
+ lowerValueCache.current = /* @__PURE__ */ new WeakMap();
1303
+ }, [data]);
1304
+ const rows = React9.useMemo(() => {
1305
+ let result = data.slice();
1306
+ const q = search.trim().toLowerCase();
1307
+ if (q) {
1308
+ result = result.filter((r) => getSearchableText(r).includes(q));
1309
+ }
1310
+ const activeWithValues = activeFilters.filter((f) => {
1311
+ if (f.values.length === 0) return false;
1312
+ const col = columnsByKey.get(f.fieldKey);
1313
+ if (col?.filter?.type === "text") {
1314
+ return (f.values[0] ?? "").trim().length > 0;
1315
+ }
1316
+ return true;
1317
+ });
1318
+ if (activeWithValues.length > 0) {
1319
+ const compiled = [];
1320
+ for (const f of activeWithValues) {
1321
+ const col = columnsByKey.get(f.fieldKey);
1322
+ if (!col?.filter) continue;
1323
+ if (col.filter.type === "select") {
1324
+ compiled.push({
1325
+ col,
1326
+ id: f.id,
1327
+ type: "select",
1328
+ operator: f.operator,
1329
+ selectValues: new Set(f.values)
1330
+ });
1331
+ } else if (col.filter.type === "date") {
1332
+ compiled.push({
1333
+ col,
1334
+ id: f.id,
1335
+ type: "date",
1336
+ operator: f.operator,
1337
+ dateTarget: f.values[0]
1338
+ });
1339
+ } else {
1340
+ const raw = f.values[0] ?? "";
1341
+ const isDigitsMask = col.filter.textMask === "phone" || col.filter.textMask === "zip";
1342
+ compiled.push({
1343
+ col,
1344
+ id: f.id,
1345
+ type: "text",
1346
+ operator: f.operator,
1347
+ isDigitsMask,
1348
+ digitsNeedle: isDigitsMask ? digitsOnly(raw) : void 0,
1349
+ textNeedle: !isDigitsMask ? raw.toLowerCase() : void 0
1350
+ });
1351
+ }
1352
+ }
1353
+ const matchesCompiled = (r, f) => {
1354
+ const rowVal = String(r[f.col.key] ?? "");
1355
+ if (f.type === "select") {
1356
+ const hit = f.selectValues.has(rowVal);
1357
+ return f.operator === "is" ? hit : !hit;
1358
+ }
1359
+ if (f.type === "date") {
1360
+ if (!f.dateTarget) return true;
1361
+ const rowYmd = parseRowDateToYmd(rowVal);
1362
+ const op = f.operator === "is_not" ? "is_not" : "is";
1363
+ if (rowYmd === null) return op === "is_not";
1364
+ return op === "is" ? rowYmd === f.dateTarget : rowYmd !== f.dateTarget;
1365
+ }
1366
+ if (f.isDigitsMask) {
1367
+ if (!f.digitsNeedle) return true;
1368
+ const hay2 = digitsOnly(rowVal);
1369
+ return f.operator === "contains" ? hay2.includes(f.digitsNeedle) : !hay2.includes(f.digitsNeedle);
1370
+ }
1371
+ if (!f.textNeedle) return true;
1372
+ const hay = getLowerValue(r, f.col.key);
1373
+ return f.operator === "contains" ? hay.includes(f.textNeedle) : !hay.includes(f.textNeedle);
1374
+ };
1375
+ if (compiled.length > 0) {
1376
+ result = result.filter((r) => {
1377
+ let res = matchesCompiled(r, compiled[0]);
1378
+ for (let i = 1; i < compiled.length; i++) {
1379
+ const connector = filterConnectors[compiled[i - 1].id] ?? "and";
1380
+ const match = matchesCompiled(r, compiled[i]);
1381
+ res = connector === "and" ? res && match : res || match;
1382
+ }
1383
+ return res;
1384
+ });
1385
+ }
1386
+ }
1387
+ const colMenuEntries = [];
1388
+ for (const [key, raw] of Object.entries(colMenuSearch)) {
1389
+ const trimmed = raw.trim();
1390
+ if (trimmed) colMenuEntries.push({ key, lower: trimmed.toLowerCase() });
1391
+ }
1392
+ if (colMenuEntries.length > 0) {
1393
+ result = result.filter((r) => {
1394
+ for (const { key, lower } of colMenuEntries) {
1395
+ if (!getLowerValue(r, key).includes(lower)) return false;
1396
+ }
1397
+ return true;
1398
+ });
1399
+ }
1400
+ if (sortRules.length > 0) {
1401
+ const resolved = [];
1402
+ for (const rule of sortRules) {
1403
+ const col = columnsByKey.get(rule.fieldKey);
1404
+ const sk = col?.sortKey ?? col?.key;
1405
+ if (sk) resolved.push({ sk, dir: rule.direction });
1406
+ }
1407
+ if (resolved.length > 0) {
1408
+ result.sort((a, b) => {
1409
+ for (let i = 0; i < resolved.length; i++) {
1410
+ const { sk, dir } = resolved[i];
1411
+ const cmp = compareUnknownSort(a[sk], b[sk]);
1412
+ if (cmp !== 0) return dir === "asc" ? cmp : -cmp;
1413
+ }
1414
+ return 0;
1415
+ });
1416
+ }
1417
+ }
1418
+ return result;
1419
+ }, [
1420
+ data,
1421
+ search,
1422
+ activeFilters,
1423
+ filterConnectors,
1424
+ colMenuSearch,
1425
+ sortRules,
1426
+ columnsByKey,
1427
+ getSearchableText,
1428
+ getLowerValue
1429
+ ]);
1430
+ const pagedRows = React9.useMemo(() => {
1431
+ if (!paginationOverride || paginationOverride.pageSize <= 0) return rows;
1432
+ const { page, pageSize } = paginationOverride;
1433
+ const safePage = Math.max(1, page);
1434
+ return rows.slice((safePage - 1) * pageSize, safePage * pageSize);
1435
+ }, [rows, paginationOverride?.page, paginationOverride?.pageSize]);
1436
+ const groupedRows = React9.useMemo(() => {
1437
+ if (!groupBy) return [{ groupKey: null, groupLabel: null, rows }];
1438
+ const groups = /* @__PURE__ */ new Map();
1439
+ rows.forEach((row) => {
1440
+ const val = String(row[groupBy] ?? "\u2014");
1441
+ if (!groups.has(val)) groups.set(val, []);
1442
+ groups.get(val).push(row);
1443
+ });
1444
+ return [...groups.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([key, groupRows]) => ({ groupKey: key, groupLabel: key, rows: groupRows }));
1445
+ }, [rows, groupBy]);
1446
+ const LOCKED_KEYS = React9.useMemo(() => new Set(Object.keys(lockedPins)), [lockedPins]);
1447
+ const effectivePins = React9.useMemo(() => {
1448
+ if (isReflowViewport || !isOverflowing) return {};
1449
+ const result = {};
1450
+ for (const [key, pin] of Object.entries(colPins)) {
1451
+ result[key] = pin;
1452
+ }
1453
+ return result;
1454
+ }, [colPins, isOverflowing, isReflowViewport]);
1455
+ const displayCols = React9.useMemo(() => {
1456
+ const leftPinned = [];
1457
+ const free = [];
1458
+ const rightPinned = [];
1459
+ for (const k of colOrder) {
1460
+ const pin = colPins[k];
1461
+ if (pin === "left") leftPinned.push(k);
1462
+ else if (pin === "right") rightPinned.push(k);
1463
+ else free.push(k);
1464
+ }
1465
+ const ordered = [...leftPinned, ...free, ...rightPinned];
1466
+ const out = [];
1467
+ for (const k of ordered) {
1468
+ if (hiddenCols.has(k)) continue;
1469
+ const col = columnsByKey.get(k);
1470
+ if (col) out.push(col);
1471
+ }
1472
+ return out;
1473
+ }, [colOrder, colPins, hiddenCols, columnsByKey]);
1474
+ function startResize(key, e) {
1475
+ e.preventDefault();
1476
+ e.stopPropagation();
1477
+ const minW = columns.find((c) => c.key === key)?.minWidth ?? 60;
1478
+ const startW = colWidths[key] ?? (columns.find((c) => c.key === key)?.width ?? 100);
1479
+ resizeRef.current = { key, startX: e.clientX, startW };
1480
+ const onMove = (ev) => {
1481
+ if (!resizeRef.current) return;
1482
+ const { key: k, startX, startW: sw } = resizeRef.current;
1483
+ setColWidths((p) => ({ ...p, [k]: Math.max(minW, sw + ev.clientX - startX) }));
1484
+ };
1485
+ const onUp = () => {
1486
+ resizeRef.current = null;
1487
+ document.removeEventListener("mousemove", onMove);
1488
+ document.removeEventListener("mouseup", onUp);
1489
+ };
1490
+ document.addEventListener("mousemove", onMove);
1491
+ document.addEventListener("mouseup", onUp);
1492
+ }
1493
+ function handleDragStart(key, e) {
1494
+ draggedKey.current = key;
1495
+ e.dataTransfer.effectAllowed = "move";
1496
+ }
1497
+ function handleDragOver(key, e) {
1498
+ e.preventDefault();
1499
+ e.dataTransfer.dropEffect = "move";
1500
+ if (draggedKey.current && draggedKey.current !== key) setDragOverKey(key);
1501
+ }
1502
+ function handleDrop(key) {
1503
+ if (!draggedKey.current || draggedKey.current === key) {
1504
+ setDragOverKey(null);
1505
+ return;
1506
+ }
1507
+ const order = [...colOrder];
1508
+ const from = order.indexOf(draggedKey.current);
1509
+ const to = order.indexOf(key);
1510
+ order.splice(from, 1);
1511
+ order.splice(to, 0, draggedKey.current);
1512
+ setColOrder(order);
1513
+ draggedKey.current = null;
1514
+ setDragOverKey(null);
1515
+ }
1516
+ function handleDragEnd() {
1517
+ draggedKey.current = null;
1518
+ setDragOverKey(null);
1519
+ }
1520
+ function pinColumn(key, pin) {
1521
+ setColPins((p) => ({ ...p, [key]: pin }));
1522
+ }
1523
+ function unpinColumn(key) {
1524
+ if (lockedPins[key]) return;
1525
+ setColPins((p) => {
1526
+ const n = { ...p };
1527
+ delete n[key];
1528
+ return n;
1529
+ });
1530
+ }
1531
+ function toggleWrap(key) {
1532
+ setColWrap((p) => ({ ...p, [key]: !p[key] }));
1533
+ }
1534
+ function checkOverflow() {
1535
+ const el = scrollRef.current;
1536
+ if (!el) return;
1537
+ setIsOverflowing(el.scrollWidth > el.clientWidth + 1);
1538
+ }
1539
+ function handleScroll() {
1540
+ const el = scrollRef.current;
1541
+ if (!el) return;
1542
+ setScrolled(el.scrollLeft > 1);
1543
+ setScrollEnd(el.scrollLeft >= el.scrollWidth - el.clientWidth - 1);
1544
+ setIsOverflowing(el.scrollWidth > el.clientWidth + 1);
1545
+ }
1546
+ function getRowId(row, index, getIdFn) {
1547
+ return getIdFn ? getIdFn(row, index) : row.id ?? index;
1548
+ }
1549
+ const toggleRow = React9.useCallback((id) => {
1550
+ setSelected((prev) => {
1551
+ const next = new Set(prev);
1552
+ if (next.has(id)) next.delete(id);
1553
+ else next.add(id);
1554
+ return next;
1555
+ });
1556
+ }, [setSelected]);
1557
+ const toggleAll = React9.useCallback((allRowIds) => {
1558
+ setSelected((prev) => prev.size === allRowIds.length ? /* @__PURE__ */ new Set() : new Set(allRowIds));
1559
+ }, [setSelected]);
1560
+ const stickyOffsets = React9.useMemo(() => {
1561
+ const left = /* @__PURE__ */ new Map();
1562
+ const right = /* @__PURE__ */ new Map();
1563
+ let leftOffset = 0;
1564
+ for (const col of displayCols) {
1565
+ if (effectivePins[col.key] !== "left") break;
1566
+ left.set(col.key, leftOffset);
1567
+ leftOffset += colWidths[col.key] ?? col.width ?? 100;
1568
+ }
1569
+ let rightOffset = 0;
1570
+ for (let i = displayCols.length - 1; i >= 0; i--) {
1571
+ const col = displayCols[i];
1572
+ if (effectivePins[col.key] !== "right") break;
1573
+ right.set(col.key, rightOffset);
1574
+ rightOffset += colWidths[col.key] ?? col.width ?? 100;
1575
+ }
1576
+ return { left, right };
1577
+ }, [displayCols, effectivePins, colWidths]);
1578
+ const getStickyLeft = React9.useCallback((key) => {
1579
+ return stickyOffsets.left.get(key) ?? 0;
1580
+ }, [stickyOffsets]);
1581
+ const getStickyRight = React9.useCallback((key) => {
1582
+ return stickyOffsets.right.get(key) ?? 0;
1583
+ }, [stickyOffsets]);
1584
+ const stickyStyle = React9.useCallback(
1585
+ (key, isHeader = false) => {
1586
+ if (isReflowViewport) return {};
1587
+ const pin = effectivePins[key];
1588
+ if (pin === "left") {
1589
+ return isHeader ? { position: "sticky", left: stickyOffsets.left.get(key) ?? 0, top: 0 } : { position: "sticky", left: stickyOffsets.left.get(key) ?? 0 };
1590
+ }
1591
+ if (pin === "right") {
1592
+ return isHeader ? { position: "sticky", right: stickyOffsets.right.get(key) ?? 0, top: 0 } : { position: "sticky", right: stickyOffsets.right.get(key) ?? 0 };
1593
+ }
1594
+ return isHeader ? { position: "sticky", top: 0 } : {};
1595
+ },
1596
+ [effectivePins, isReflowViewport, stickyOffsets]
1597
+ );
1598
+ const totalWidth = React9.useMemo(
1599
+ () => displayCols.reduce((s, c) => s + (colWidths[c.key] ?? c.width ?? 100), 0),
1600
+ [displayCols, colWidths]
1601
+ );
1602
+ return {
1603
+ // Sort
1604
+ sortRules,
1605
+ setSortRules,
1606
+ sortKey,
1607
+ sortDir,
1608
+ addSortRule,
1609
+ removeSortRule,
1610
+ toggleSortDir,
1611
+ handleSortByKey,
1612
+ // Filters
1613
+ search,
1614
+ setSearch,
1615
+ searchOpen,
1616
+ setSearchOpen,
1617
+ searchRef,
1618
+ activeFilters,
1619
+ setActiveFilters,
1620
+ filterConnectors,
1621
+ setFilterConnectors,
1622
+ toggleConnector,
1623
+ getConnector,
1624
+ openFilterId,
1625
+ setOpenFilterId,
1626
+ filterBarVisible,
1627
+ setFilterBarVisible,
1628
+ drawerExpandedFilters,
1629
+ setDrawerExpandedFilters,
1630
+ addFilter,
1631
+ updateFilter,
1632
+ removeFilter,
1633
+ // Group
1634
+ groupBy,
1635
+ setGroupBy,
1636
+ // Column quick-search
1637
+ colMenuSearch,
1638
+ setColMenuSearch,
1639
+ // Selection
1640
+ selected,
1641
+ setSelected,
1642
+ toggleRow,
1643
+ toggleAll,
1644
+ getRowId,
1645
+ // Column widths / order / pins / wrap
1646
+ colWidths,
1647
+ setColWidths,
1648
+ resizeRef,
1649
+ startResize,
1650
+ colOrder,
1651
+ setColOrder,
1652
+ moveCol,
1653
+ colPins,
1654
+ setColPins,
1655
+ lockedPins,
1656
+ LOCKED_KEYS,
1657
+ pinColumn,
1658
+ unpinColumn,
1659
+ colWrap,
1660
+ setColWrap,
1661
+ toggleWrap,
1662
+ // Drag-to-reorder
1663
+ draggedKey,
1664
+ dragOverKey,
1665
+ handleDragStart,
1666
+ handleDragOver,
1667
+ handleDrop,
1668
+ handleDragEnd,
1669
+ // Scroll
1670
+ scrollRef,
1671
+ scrolled,
1672
+ scrollEnd,
1673
+ isOverflowing,
1674
+ checkOverflow,
1675
+ handleScroll,
1676
+ // Hover
1677
+ hoveredRow,
1678
+ setHoveredRow,
1679
+ // Derived
1680
+ rows,
1681
+ pagedRows,
1682
+ groupedRows,
1683
+ effectivePins,
1684
+ displayCols,
1685
+ isReflowViewport,
1686
+ getStickyLeft,
1687
+ getStickyRight,
1688
+ stickyStyle,
1689
+ totalWidth,
1690
+ // Display settings
1691
+ sheetOpen,
1692
+ setSheetOpen,
1693
+ sheetInitialPanel,
1694
+ setSheetInitialPanel,
1695
+ showGridlines,
1696
+ setShowGridlines,
1697
+ rowHeight,
1698
+ setRowHeight,
1699
+ hiddenCols,
1700
+ setHiddenCols,
1701
+ toggleColVisibility
1702
+ };
1703
+ }
1704
+ function defaultColumnHeaderLabel(key) {
1705
+ switch (key) {
1706
+ case "select":
1707
+ return "Select";
1708
+ case "actions":
1709
+ return "Actions";
1710
+ default:
1711
+ return void 0;
1712
+ }
1713
+ }
1714
+ function resolvedColumnLabel(col) {
1715
+ const t = col.label?.trim();
1716
+ if (t) return t;
1717
+ return defaultColumnHeaderLabel(col.key) ?? col.key;
1718
+ }
1719
+ var SortChevron = React9.memo(function SortChevron2({ dir }) {
1720
+ return /* @__PURE__ */ jsx("i", { className: `fa-solid fa-arrow-${dir === "asc" ? "up" : "down"} ms-1 text-xs`, "aria-hidden": "true" });
1721
+ });
1722
+ function FilterPillBase({
1723
+ filter,
1724
+ columns,
1725
+ defaultOpen = false,
1726
+ onUpdate,
1727
+ onRemove,
1728
+ renderOptionValue
1729
+ }) {
1730
+ const [open, setOpen] = React9.useState(false);
1731
+ const [optSearch, setOptSearch] = React9.useState("");
1732
+ const justAutoOpenedRef = React9.useRef(false);
1733
+ React9.useEffect(() => {
1734
+ if (defaultOpen) {
1735
+ justAutoOpenedRef.current = true;
1736
+ const t = setTimeout(() => {
1737
+ setOpen(true);
1738
+ setTimeout(() => {
1739
+ justAutoOpenedRef.current = false;
1740
+ }, 400);
1741
+ }, 0);
1742
+ return () => clearTimeout(t);
1743
+ }
1744
+ }, []);
1745
+ const col = columns.find((c) => c.key === filter.fieldKey);
1746
+ const filterDef = col?.filter;
1747
+ React9.useEffect(() => {
1748
+ if (!filterDef) return;
1749
+ if (filterDef.type !== "select" && filterDef.type !== "date") return;
1750
+ if (filter.operator !== "is" && filter.operator !== "is_not") {
1751
+ onUpdate(filter.id, { operator: "is" });
1752
+ }
1753
+ }, [filter.id, filterDef, filter.operator, onUpdate]);
1754
+ if (!filterDef) return null;
1755
+ const options = filterDef.options ?? [];
1756
+ const showSearch = options.length > 8;
1757
+ const filteredOpts = optSearch ? options.filter((o) => o.label.toLowerCase().includes(optSearch.toLowerCase())) : options;
1758
+ const operators = filterDef.operators ?? (filterDef.type === "select" || filterDef.type === "date" ? ["is", "is_not"] : ["contains", "not_contains"]);
1759
+ const valueLabel = (() => {
1760
+ if (filterDef.type === "select") {
1761
+ if (filter.values.length === 0) return "\u2026";
1762
+ if (filter.values.length === 1) {
1763
+ return options.find((o) => o.value === filter.values[0])?.label ?? filter.values[0];
1764
+ }
1765
+ return `${filter.values.length} selected`;
1766
+ }
1767
+ if (filterDef.type === "date") {
1768
+ const ymd = filter.values[0];
1769
+ return ymd ? formatYmdForDisplay(ymd) : "\u2026";
1770
+ }
1771
+ return filter.values[0] || "\u2026";
1772
+ })();
1773
+ function toggleValue(val) {
1774
+ const next = filter.values.includes(val) ? filter.values.filter((v) => v !== val) : [...filter.values, val];
1775
+ onUpdate(filter.id, { values: next });
1776
+ }
1777
+ function cycleOperator() {
1778
+ const idx = operators.indexOf(filter.operator);
1779
+ const i = idx === -1 ? 0 : idx;
1780
+ onUpdate(filter.id, { operator: operators[(i + 1) % operators.length] });
1781
+ }
1782
+ const isActive = filterDef.type === "date" ? Boolean(filter.values[0]) : filter.values.length > 0;
1783
+ const hasSelection = filter.values.length > 0;
1784
+ const iconClass = filterDef.icon ? `fa-light ${filterDef.icon}` : "fa-light fa-filter";
1785
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
1786
+ /* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs(
1787
+ "div",
1788
+ {
1789
+ className: cn(
1790
+ "inline-flex cursor-pointer items-center rounded border text-xs transition-colors",
1791
+ isActive ? "border-brand/45 bg-brand/10" : "border-input bg-background"
1792
+ ),
1793
+ children: [
1794
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1795
+ "button",
1796
+ {
1797
+ type: "button",
1798
+ className: cn(
1799
+ "inline-flex cursor-pointer items-center gap-1 h-6 ps-2 pe-1.5 rounded-s transition-colors",
1800
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset",
1801
+ isActive ? "hover:bg-brand/15" : "hover:bg-interactive-hover"
1802
+ ),
1803
+ children: [
1804
+ /* @__PURE__ */ jsx(
1805
+ "i",
1806
+ {
1807
+ className: cn(iconClass, "text-xs", isActive ? "text-brand" : "text-muted-foreground"),
1808
+ "aria-hidden": "true"
1809
+ }
1810
+ ),
1811
+ /* @__PURE__ */ jsx("span", { className: "text-foreground", children: col.label }),
1812
+ isActive && /* @__PURE__ */ jsx("span", { className: "text-foreground font-medium", children: valueLabel })
1813
+ ]
1814
+ }
1815
+ ) }),
1816
+ /* @__PURE__ */ jsx(
1817
+ "button",
1818
+ {
1819
+ type: "button",
1820
+ "aria-label": `Remove ${col.label} filter`,
1821
+ onClick: () => onRemove(filter.id),
1822
+ className: cn(
1823
+ "inline-flex cursor-pointer items-center justify-center h-6 w-5 rounded-e transition-colors",
1824
+ "text-muted-foreground hover:text-destructive",
1825
+ isActive ? "hover:bg-brand/15" : "hover:bg-interactive-hover",
1826
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset"
1827
+ ),
1828
+ children: /* @__PURE__ */ jsx("i", { className: "fa-light fa-xmark text-xs", "aria-hidden": "true" })
1829
+ }
1830
+ )
1831
+ ]
1832
+ }
1833
+ ) }),
1834
+ /* @__PURE__ */ jsxs(
1835
+ PopoverContent,
1836
+ {
1837
+ className: cn(
1838
+ "p-0",
1839
+ filterDef.type === "date" ? "w-auto max-w-[min(calc(100vw-2rem),22rem)]" : "w-64"
1840
+ ),
1841
+ align: "start",
1842
+ onFocusOutside: (e) => e.preventDefault(),
1843
+ onInteractOutside: (e) => {
1844
+ if (justAutoOpenedRef.current) {
1845
+ e.preventDefault();
1846
+ justAutoOpenedRef.current = false;
1847
+ }
1848
+ },
1849
+ children: [
1850
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-border", children: [
1851
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-sm text-foreground", children: [
1852
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: col.label }),
1853
+ /* @__PURE__ */ jsxs(
1854
+ "button",
1855
+ {
1856
+ type: "button",
1857
+ onClick: cycleOperator,
1858
+ className: "inline-flex items-center gap-0.5 text-muted-foreground hover:text-interactive-hover-foreground transition-colors rounded px-1 py-0.5 hover:bg-interactive-hover",
1859
+ children: [
1860
+ OPERATOR_LABELS[filter.operator],
1861
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-chevron-down text-xs", "aria-hidden": "true" })
1862
+ ]
1863
+ }
1864
+ )
1865
+ ] }),
1866
+ /* @__PURE__ */ jsx(
1867
+ "button",
1868
+ {
1869
+ type: "button",
1870
+ "aria-label": "Remove filter",
1871
+ onClick: () => onRemove(filter.id),
1872
+ className: "text-muted-foreground hover:text-destructive transition-colors p-1 rounded hover:bg-interactive-hover",
1873
+ children: /* @__PURE__ */ jsx("i", { className: "fa-light fa-trash text-xs", "aria-hidden": "true" })
1874
+ }
1875
+ )
1876
+ ] }),
1877
+ filterDef.type === "date" && /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
1878
+ FilterDateCalendar,
1879
+ {
1880
+ label: `${col.label} \u2014 choose date`,
1881
+ valueYmd: filter.values[0],
1882
+ onChangeYmd: (ymd) => onUpdate(filter.id, { values: ymd ? [ymd] : [] })
1883
+ }
1884
+ ) }),
1885
+ filterDef.type === "select" && /* @__PURE__ */ jsxs("div", { className: "py-1 max-h-64 overflow-y-auto", children: [
1886
+ showSearch && /* @__PURE__ */ jsx("div", { className: "px-2 pt-1 pb-1", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1887
+ /* @__PURE__ */ jsx(
1888
+ Input,
1889
+ {
1890
+ type: "text",
1891
+ placeholder: "Search options\u2026",
1892
+ value: optSearch,
1893
+ onChange: (e) => setOptSearch(e.target.value),
1894
+ className: cn("h-7 text-xs", optSearch ? "pe-8" : "pe-2"),
1895
+ autoFocus: true
1896
+ }
1897
+ ),
1898
+ optSearch ? /* @__PURE__ */ jsx(
1899
+ "button",
1900
+ {
1901
+ type: "button",
1902
+ "aria-label": "Clear option search",
1903
+ onClick: () => setOptSearch(""),
1904
+ className: "absolute end-1 top-1/2 -translate-y-1/2 inline-flex size-6 items-center justify-center rounded text-muted-foreground transition-colors hover:text-interactive-hover-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1905
+ children: /* @__PURE__ */ jsx("i", { className: "fa-light fa-xmark text-xs", "aria-hidden": "true" })
1906
+ }
1907
+ ) : null
1908
+ ] }) }),
1909
+ filteredOpts.map((opt) => {
1910
+ const checked = filter.values.includes(opt.value);
1911
+ return /* @__PURE__ */ jsxs(
1912
+ "div",
1913
+ {
1914
+ role: "option",
1915
+ "aria-selected": checked,
1916
+ tabIndex: 0,
1917
+ onClick: () => toggleValue(opt.value),
1918
+ onKeyDown: (e) => {
1919
+ if (e.key === "Enter" || e.key === " ") {
1920
+ e.preventDefault();
1921
+ toggleValue(opt.value);
1922
+ }
1923
+ },
1924
+ className: "flex w-full items-center gap-2.5 px-3 py-1.5 text-sm hover:bg-interactive-hover transition-colors cursor-pointer select-none focus-visible:outline-none focus-visible:bg-interactive-hover",
1925
+ children: [
1926
+ /* @__PURE__ */ jsx(
1927
+ "span",
1928
+ {
1929
+ "aria-hidden": "true",
1930
+ "data-slot": "checkbox",
1931
+ "data-state": checked ? "checked" : "unchecked",
1932
+ className: cn(
1933
+ "inline-flex items-center justify-center size-3.5 shrink-0 rounded-[4px] border transition-colors",
1934
+ checked ? "bg-primary border-primary text-primary-foreground" : "border-input bg-background"
1935
+ ),
1936
+ children: checked && /* @__PURE__ */ jsx("i", { className: "fa-solid fa-check text-current", style: { fontSize: "8px" } })
1937
+ }
1938
+ ),
1939
+ renderOptionValue ? renderOptionValue(filter.fieldKey, opt.value) : /* @__PURE__ */ jsx("span", { className: "text-foreground", children: opt.label })
1940
+ ]
1941
+ },
1942
+ opt.value
1943
+ );
1944
+ }),
1945
+ filteredOpts.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-3 py-2 text-xs text-muted-foreground", children: "No options found" })
1946
+ ] }),
1947
+ filterDef.type === "text" && /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
1948
+ FilterTextValueInput,
1949
+ {
1950
+ mask: filterDef.textMask,
1951
+ placeholder: `Enter ${col.label.toLowerCase()}\u2026`,
1952
+ value: filter.values[0] ?? "",
1953
+ onValueChange: (next) => onUpdate(filter.id, { values: [next] }),
1954
+ "aria-label": `${col.label} filter value`,
1955
+ className: "h-8 text-xs focus-visible:border-ring focus-visible:ring-ring/50",
1956
+ autoFocus: true
1957
+ }
1958
+ ) }),
1959
+ hasSelection ? /* @__PURE__ */ jsx("div", { className: "sticky bottom-0 border-t border-border bg-popover p-2", children: /* @__PURE__ */ jsxs(
1960
+ Button,
1961
+ {
1962
+ type: "button",
1963
+ variant: "outline",
1964
+ size: "sm",
1965
+ onClick: () => onUpdate(filter.id, { values: [] }),
1966
+ className: "w-full justify-center gap-1.5 text-xs text-muted-foreground",
1967
+ children: [
1968
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-xmark text-xs", "aria-hidden": "true" }),
1969
+ "Clear selection"
1970
+ ]
1971
+ }
1972
+ ) }) : null
1973
+ ]
1974
+ }
1975
+ )
1976
+ ] });
1977
+ }
1978
+ var FilterPill = React9.memo(FilterPillBase);
1979
+ function stickyShadow(pin) {
1980
+ if (!pin) return "";
1981
+ const base = "after:content-[''] after:absolute after:top-0 after:bottom-0 after:w-3 after:pointer-events-none";
1982
+ if (pin === "left") {
1983
+ return cn(
1984
+ base,
1985
+ "after:start-full",
1986
+ "after:bg-[linear-gradient(to_right,var(--sticky-edge-fade),transparent)]"
1987
+ );
1988
+ }
1989
+ return cn(
1990
+ base,
1991
+ "after:end-full",
1992
+ "after:bg-[linear-gradient(to_left,var(--sticky-edge-fade),transparent)]"
1993
+ );
1994
+ }
1995
+ function DataTableToolbar({
1996
+ state,
1997
+ columns,
1998
+ searchable = true,
1999
+ /** When false, hides filter pills, search, and filter controls (e.g. dashboard canvas edit mode). */
2000
+ showQueryControls = true,
2001
+ renderFilterOptionValue,
2002
+ toolbarSlot,
2003
+ searchAriaLabel = "Search table"
2004
+ }) {
2005
+ const {
2006
+ search,
2007
+ setSearch,
2008
+ searchOpen,
2009
+ setSearchOpen,
2010
+ searchRef,
2011
+ activeFilters,
2012
+ setActiveFilters,
2013
+ openFilterId,
2014
+ filterBarVisible,
2015
+ setFilterBarVisible,
2016
+ addFilter,
2017
+ updateFilter,
2018
+ removeFilter
2019
+ } = state;
2020
+ const filterableCols = columns.filter((c) => c.filter);
2021
+ const searchModLabel = useModKeyLabel();
2022
+ const effectiveSearchable = showQueryControls && searchable;
2023
+ React9.useEffect(() => {
2024
+ if (!effectiveSearchable) return;
2025
+ function onGlobalKeyDown(e) {
2026
+ if (!e.metaKey && !e.ctrlKey) return;
2027
+ if (e.altKey) return;
2028
+ if (e.key.toLowerCase() !== "k") return;
2029
+ if (isEditableTarget(e.target)) return;
2030
+ e.preventDefault();
2031
+ setSearchOpen(true);
2032
+ queueMicrotask(() => searchRef.current?.focus());
2033
+ }
2034
+ document.addEventListener("keydown", onGlobalKeyDown);
2035
+ return () => document.removeEventListener("keydown", onGlobalKeyDown);
2036
+ }, [effectiveSearchable, setSearchOpen, searchRef]);
2037
+ return /* @__PURE__ */ jsxs(
2038
+ "div",
2039
+ {
2040
+ className: cn(
2041
+ "flex items-center gap-1.5 px-4 lg:px-6",
2042
+ showQueryControls ? "min-h-10 pt-2 pb-2" : "min-h-0 justify-end py-1.5"
2043
+ ),
2044
+ children: [
2045
+ showQueryControls && filterBarVisible && filterableCols.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5 flex-1 min-w-0", children: [
2046
+ activeFilters.map((filter) => /* @__PURE__ */ jsx(React9.Fragment, { children: /* @__PURE__ */ jsx(
2047
+ FilterPill,
2048
+ {
2049
+ filter,
2050
+ columns,
2051
+ defaultOpen: filter.id === openFilterId,
2052
+ onUpdate: updateFilter,
2053
+ onRemove: removeFilter,
2054
+ renderOptionValue: renderFilterOptionValue
2055
+ }
2056
+ ) }, filter.id)),
2057
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2058
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
2059
+ "button",
2060
+ {
2061
+ type: "button",
2062
+ className: "inline-flex cursor-pointer items-center gap-1 h-6 px-2 rounded text-xs text-muted-foreground hover:text-interactive-hover-foreground border border-dashed border-input/70 hover:border-input hover:bg-interactive-hover-subtle transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
2063
+ children: [
2064
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-plus text-xs", "aria-hidden": "true" }),
2065
+ "Add filter"
2066
+ ]
2067
+ }
2068
+ ) }),
2069
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", children: [
2070
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-xs", children: "Filter by field" }),
2071
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2072
+ filterableCols.map((c) => /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => addFilter(c.key), children: [
2073
+ c.filter?.icon && /* @__PURE__ */ jsx("i", { className: `fa-light ${c.filter.icon}`, "aria-hidden": "true" }),
2074
+ c.label
2075
+ ] }, c.key))
2076
+ ] })
2077
+ ] }),
2078
+ activeFilters.length > 0 && /* @__PURE__ */ jsx(
2079
+ "button",
2080
+ {
2081
+ type: "button",
2082
+ onClick: () => setActiveFilters([]),
2083
+ className: "cursor-pointer text-xs text-muted-foreground hover:text-interactive-hover-foreground transition-colors px-1",
2084
+ children: "Clear all"
2085
+ }
2086
+ )
2087
+ ] }),
2088
+ /* @__PURE__ */ jsxs(
2089
+ "div",
2090
+ {
2091
+ className: cn(
2092
+ "flex items-center gap-1 shrink-0",
2093
+ showQueryControls && "ms-auto"
2094
+ ),
2095
+ children: [
2096
+ effectiveSearchable && (searchOpen ? /* @__PURE__ */ jsxs("div", { className: "relative flex items-center", children: [
2097
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-magnifying-glass absolute start-2.5 top-1/2 -translate-y-1/2 text-muted-foreground text-xs pointer-events-none", "aria-hidden": "true" }),
2098
+ /* @__PURE__ */ jsx(
2099
+ Input,
2100
+ {
2101
+ ref: searchRef,
2102
+ type: "text",
2103
+ role: "searchbox",
2104
+ inputMode: "search",
2105
+ autoComplete: "off",
2106
+ placeholder: "Search\u2026",
2107
+ value: search,
2108
+ onChange: (e) => setSearch(e.target.value),
2109
+ onBlur: () => {
2110
+ if (!search) setSearchOpen(false);
2111
+ },
2112
+ onKeyDown: (e) => {
2113
+ if (e.key === "Escape") {
2114
+ setSearch("");
2115
+ setSearchOpen(false);
2116
+ }
2117
+ },
2118
+ className: cn("h-8 w-48 ps-7 text-xs", search ? "pe-8" : "pe-2"),
2119
+ "aria-label": searchAriaLabel
2120
+ }
2121
+ ),
2122
+ search ? /* @__PURE__ */ jsx(
2123
+ "button",
2124
+ {
2125
+ type: "button",
2126
+ "aria-label": "Clear search",
2127
+ onClick: () => setSearch(""),
2128
+ className: "absolute end-1.5 top-1/2 -translate-y-1/2 inline-flex cursor-pointer size-6 items-center justify-center rounded text-muted-foreground transition-colors hover:text-interactive-hover-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
2129
+ children: /* @__PURE__ */ jsx("i", { className: "fa-light fa-xmark text-xs", "aria-hidden": "true" })
2130
+ }
2131
+ ) : null
2132
+ ] }) : /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
2133
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
2134
+ "button",
2135
+ {
2136
+ type: "button",
2137
+ "aria-label": "Search",
2138
+ onClick: () => {
2139
+ setSearchOpen(true);
2140
+ setTimeout(() => searchRef.current?.focus(), 10);
2141
+ },
2142
+ className: "inline-flex shrink-0 cursor-pointer items-center justify-center size-8 rounded-md text-muted-foreground hover:text-interactive-hover-foreground hover:bg-interactive-hover transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
2143
+ children: /* @__PURE__ */ jsx("i", { className: "fa-light fa-magnifying-glass text-[13px]", "aria-hidden": "true" })
2144
+ }
2145
+ ) }),
2146
+ /* @__PURE__ */ jsxs(TooltipContent, { side: "bottom", children: [
2147
+ /* @__PURE__ */ jsx("span", { children: searchAriaLabel }),
2148
+ /* @__PURE__ */ jsxs(KbdGroup, { children: [
2149
+ /* @__PURE__ */ jsx(Kbd, { children: searchModLabel }),
2150
+ /* @__PURE__ */ jsx(Kbd, { children: "K" })
2151
+ ] })
2152
+ ] })
2153
+ ] }) })),
2154
+ showQueryControls && filterableCols.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
2155
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-border/70", "aria-hidden": "true" }),
2156
+ activeFilters.length > 0 ? /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
2157
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
2158
+ "button",
2159
+ {
2160
+ type: "button",
2161
+ "aria-label": filterBarVisible ? "Hide filters" : "Show filters",
2162
+ onClick: () => setFilterBarVisible((v) => !v),
2163
+ className: cn(
2164
+ "inline-flex shrink-0 cursor-pointer items-center gap-1 size-8 justify-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
2165
+ filterBarVisible ? "bg-accent text-accent-foreground hover:bg-accent/90" : "text-muted-foreground hover:text-interactive-hover-foreground hover:bg-interactive-hover"
2166
+ ),
2167
+ children: [
2168
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-filter text-[13px]", "aria-hidden": "true" }),
2169
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold tabular-nums", children: activeFilters.length })
2170
+ ]
2171
+ }
2172
+ ) }),
2173
+ /* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: filterBarVisible ? "Hide filters" : "Show filters" })
2174
+ ] }) }) : (
2175
+ // NOTE: Tooltip MUST wrap DropdownMenuTrigger directly (not the
2176
+ // surrounding <DropdownMenu> wrapper). Radix `asChild` Slot needs
2177
+ // a real DOM child — `<DropdownMenu>` is a logical wrapper, so
2178
+ // putting it inside TooltipTrigger swallows the tooltip handlers
2179
+ // and the hover hint silently disappears.
2180
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2181
+ /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
2182
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
2183
+ "button",
2184
+ {
2185
+ type: "button",
2186
+ "aria-label": "Add filter",
2187
+ onClick: () => setFilterBarVisible(true),
2188
+ className: "inline-flex shrink-0 cursor-pointer items-center justify-center size-8 rounded-md text-muted-foreground hover:text-interactive-hover-foreground hover:bg-interactive-hover transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
2189
+ children: /* @__PURE__ */ jsx("i", { className: "fa-light fa-filter text-[13px]", "aria-hidden": "true" })
2190
+ }
2191
+ ) }) }),
2192
+ /* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: "Add filter" })
2193
+ ] }) }),
2194
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
2195
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-xs", children: "Filter by field" }),
2196
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2197
+ filterableCols.map((c) => /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => addFilter(c.key), children: [
2198
+ c.filter?.icon && /* @__PURE__ */ jsx("i", { className: `fa-light ${c.filter.icon}`, "aria-hidden": "true" }),
2199
+ c.label
2200
+ ] }, c.key))
2201
+ ] })
2202
+ ] })
2203
+ )
2204
+ ] }),
2205
+ toolbarSlot && toolbarSlot(state)
2206
+ ]
2207
+ }
2208
+ )
2209
+ ]
2210
+ }
2211
+ );
2212
+ }
2213
+ var BULK_BAR_MAX_PX = 448;
2214
+ var BULK_BAR_ON_LIGHT_STRIP = cn(
2215
+ "[&_button[data-variant=default]]:bg-zinc-900 [&_button[data-variant=default]]:text-zinc-50",
2216
+ "hover:[&_button[data-variant=default]]:bg-zinc-800",
2217
+ "[&_button[data-variant=outline]]:border-zinc-300/80 [&_button[data-variant=outline]]:bg-white [&_button[data-variant=outline]]:text-zinc-900",
2218
+ "hover:[&_button[data-variant=outline]]:bg-zinc-100",
2219
+ "[&_button[data-variant=destructive]]:border-rose-200/80 [&_button[data-variant=destructive]]:bg-rose-100 [&_button[data-variant=destructive]]:text-rose-800",
2220
+ "hover:[&_button[data-variant=destructive]]:bg-rose-200/40",
2221
+ "[&_button[data-variant=ghost]]:text-zinc-600 hover:[&_button[data-variant=ghost]]:bg-zinc-200/70 hover:[&_button[data-variant=ghost]]:text-zinc-900"
2222
+ );
2223
+ function useBulkBarFixedToTableScrollEl(scrollRef, active, fullWidth) {
2224
+ const [style, setStyle] = React9.useState(void 0);
2225
+ React9.useLayoutEffect(() => {
2226
+ if (!active) {
2227
+ setStyle(void 0);
2228
+ return;
2229
+ }
2230
+ const el = scrollRef.current;
2231
+ if (!el) {
2232
+ setStyle(void 0);
2233
+ return;
2234
+ }
2235
+ const apply = () => {
2236
+ const r = el.getBoundingClientRect();
2237
+ let left = r.left;
2238
+ let width = r.width;
2239
+ if (!fullWidth) {
2240
+ const w = Math.min(r.width, BULK_BAR_MAX_PX);
2241
+ left = r.left + (r.width - w) / 2;
2242
+ width = w;
2243
+ }
2244
+ setStyle({
2245
+ position: "fixed",
2246
+ left,
2247
+ width,
2248
+ bottom: "max(0.5rem, env(safe-area-inset-bottom, 0px))",
2249
+ zIndex: 50,
2250
+ boxSizing: "border-box",
2251
+ margin: 0,
2252
+ right: "auto"
2253
+ });
2254
+ };
2255
+ apply();
2256
+ const scheduled = rafThrottle(apply);
2257
+ const ro = new ResizeObserver(scheduled);
2258
+ ro.observe(el);
2259
+ window.addEventListener("resize", scheduled, { passive: true });
2260
+ window.addEventListener("scroll", scheduled, { passive: true, capture: true });
2261
+ return () => {
2262
+ scheduled.cancel();
2263
+ ro.disconnect();
2264
+ window.removeEventListener("resize", scheduled);
2265
+ window.removeEventListener("scroll", scheduled, { capture: true });
2266
+ };
2267
+ }, [active, fullWidth, scrollRef]);
2268
+ return style;
2269
+ }
2270
+ function DataTableInner({
2271
+ // `data` / `defaultSort` flow into `useTableState` upstream; the inner table
2272
+ // reads them via `state` and never directly here. Keep the prop slots so
2273
+ // the public `DataTable<TData>` API stays unchanged.
2274
+ data: _data,
2275
+ columns,
2276
+ getRowId: getRowIdProp,
2277
+ getRowSelectionLabel,
2278
+ selectable = true,
2279
+ searchable = true,
2280
+ emptyState,
2281
+ onRowClick,
2282
+ defaultSort: _defaultSort,
2283
+ toolbarSlot,
2284
+ bulkActionsSlot,
2285
+ addRowLabel = false,
2286
+ renderFilterOptionValue,
2287
+ hasFooter = false,
2288
+ conditionalRules,
2289
+ showColumnHeaders = true,
2290
+ state
2291
+ }) {
2292
+ const {
2293
+ setSortRules,
2294
+ sortKey,
2295
+ sortDir,
2296
+ handleSortByKey,
2297
+ addFilter,
2298
+ groupBy,
2299
+ setGroupBy,
2300
+ colMenuSearch,
2301
+ setColMenuSearch,
2302
+ selected,
2303
+ setSelected,
2304
+ toggleRow,
2305
+ toggleAll,
2306
+ getRowId,
2307
+ colWidths,
2308
+ startResize,
2309
+ colPins,
2310
+ lockedPins,
2311
+ pinColumn,
2312
+ unpinColumn,
2313
+ colWrap,
2314
+ toggleWrap,
2315
+ draggedKey,
2316
+ dragOverKey,
2317
+ handleDragStart,
2318
+ handleDragOver,
2319
+ handleDrop,
2320
+ handleDragEnd,
2321
+ scrollRef,
2322
+ handleScroll,
2323
+ checkOverflow,
2324
+ isOverflowing,
2325
+ setHoveredRow,
2326
+ rows,
2327
+ pagedRows,
2328
+ groupedRows,
2329
+ effectivePins,
2330
+ displayCols,
2331
+ isReflowViewport,
2332
+ stickyStyle,
2333
+ totalWidth,
2334
+ rowHeight,
2335
+ showGridlines,
2336
+ setSheetOpen,
2337
+ setSheetInitialPanel
2338
+ } = state;
2339
+ React9.useEffect(() => {
2340
+ const syncScrollport = () => {
2341
+ const el2 = scrollRef.current;
2342
+ if (el2) {
2343
+ el2.style.setProperty("--dt-scrollport-width", `${el2.clientWidth}px`);
2344
+ }
2345
+ checkOverflow();
2346
+ };
2347
+ syncScrollport();
2348
+ const el = scrollRef.current;
2349
+ if (!el) return;
2350
+ const ro = new ResizeObserver(syncScrollport);
2351
+ ro.observe(el);
2352
+ return () => ro.disconnect();
2353
+ }, []);
2354
+ const columnMenuPendingActionRef = React9.useRef(null);
2355
+ const pinnedScrollHintDoneRef = React9.useRef(false);
2356
+ React9.useEffect(() => {
2357
+ if (!isOverflowing || isReflowViewport || Object.keys(colPins).length === 0) return;
2358
+ if (pinnedScrollHintDoneRef.current) return;
2359
+ const el = scrollRef.current;
2360
+ if (!el) return;
2361
+ if (el.scrollLeft > 2) return;
2362
+ const maxScroll = el.scrollWidth - el.clientWidth;
2363
+ if (maxScroll < 16) return;
2364
+ if (typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
2365
+ pinnedScrollHintDoneRef.current = true;
2366
+ return;
2367
+ }
2368
+ pinnedScrollHintDoneRef.current = true;
2369
+ const delta = Math.min(96, Math.max(28, Math.round(maxScroll * 0.14)));
2370
+ const startDelayMs = 320;
2371
+ const dwellMs = 520;
2372
+ const t1 = window.setTimeout(() => {
2373
+ el.scrollTo({ left: delta, behavior: "smooth" });
2374
+ }, startDelayMs);
2375
+ const t2 = window.setTimeout(() => {
2376
+ el.scrollTo({ left: 0, behavior: "smooth" });
2377
+ }, startDelayMs + dwellMs);
2378
+ return () => {
2379
+ window.clearTimeout(t1);
2380
+ window.clearTimeout(t2);
2381
+ };
2382
+ }, [isOverflowing, isReflowViewport, colPins, scrollRef]);
2383
+ const lastLeftPinKey = [...displayCols].reverse().find((c) => effectivePins[c.key] === "left")?.key;
2384
+ const firstRightPinKey = displayCols.find((c) => effectivePins[c.key] === "right")?.key;
2385
+ function floatingHeaderPinnedStyle(key) {
2386
+ const pin = effectivePins[key];
2387
+ if (!pin) return void 0;
2388
+ const visibleWidth = typeof floatingHeaderStyle?.width === "number" ? floatingHeaderStyle.width : tableWrapRef.current?.clientWidth ?? floatingHeaderTableWidth;
2389
+ const maxScroll = Math.max(0, floatingHeaderTableWidth - visibleWidth);
2390
+ const translateX = pin === "left" ? headerScrollLeft : headerScrollLeft - maxScroll;
2391
+ return { position: "relative", transform: `translateX(${translateX}px)` };
2392
+ }
2393
+ const allRowIds = rows.map((r, i) => getRowId(r, i, getRowIdProp));
2394
+ const allSelected = rows.length > 0 && selected.size === rows.length;
2395
+ const someSelected = selected.size > 0 && !allSelected;
2396
+ const anySelected = selected.size > 0;
2397
+ const { resolvedTheme } = useTheme();
2398
+ const isAppDark = resolvedTheme === "dark";
2399
+ const bulkBarUseFixedLayout = anySelected;
2400
+ const bulkBarFixedStyle = useBulkBarFixedToTableScrollEl(
2401
+ scrollRef,
2402
+ bulkBarUseFixedLayout,
2403
+ isReflowViewport
2404
+ );
2405
+ const tableWrapRef = React9.useRef(null);
2406
+ const tableHeadRef = React9.useRef(null);
2407
+ const [headerIsStuck, setHeaderIsStuck] = React9.useState(false);
2408
+ const [headerScrollLeft, setHeaderScrollLeft] = React9.useState(0);
2409
+ const [floatingHeaderStyle, setFloatingHeaderStyle] = React9.useState(void 0);
2410
+ const [floatingHeaderTableWidth, setFloatingHeaderTableWidth] = React9.useState(totalWidth);
2411
+ const [isClient, setIsClient] = React9.useState(false);
2412
+ React9.useEffect(() => {
2413
+ setIsClient(true);
2414
+ }, []);
2415
+ React9.useEffect(() => {
2416
+ const wrapEl = tableWrapRef.current;
2417
+ const headEl = tableHeadRef.current;
2418
+ if (!wrapEl || !headEl || !showColumnHeaders) {
2419
+ setHeaderIsStuck(false);
2420
+ return;
2421
+ }
2422
+ const update = () => {
2423
+ const wrapRect = wrapEl.getBoundingClientRect();
2424
+ const headHeight = headEl.getBoundingClientRect().height || 0;
2425
+ const rootStyle = getComputedStyle(document.documentElement);
2426
+ const headerOffset = Number.parseFloat(rootStyle.getPropertyValue("--header-height")) || 0;
2427
+ const stuck = wrapRect.top <= headerOffset && wrapRect.bottom > headHeight + headerOffset + 1;
2428
+ setHeaderIsStuck((prev) => prev === stuck ? prev : stuck);
2429
+ };
2430
+ update();
2431
+ const scheduled = rafThrottle(update);
2432
+ window.addEventListener("scroll", scheduled, { passive: true, capture: true });
2433
+ window.addEventListener("resize", scheduled, { passive: true });
2434
+ return () => {
2435
+ scheduled.cancel();
2436
+ window.removeEventListener("scroll", scheduled, { capture: true });
2437
+ window.removeEventListener("resize", scheduled);
2438
+ };
2439
+ }, [showColumnHeaders, rows.length, displayCols.length]);
2440
+ React9.useLayoutEffect(() => {
2441
+ if (!headerIsStuck || !showColumnHeaders) {
2442
+ setFloatingHeaderStyle(void 0);
2443
+ return;
2444
+ }
2445
+ const wrapEl = tableWrapRef.current;
2446
+ if (!wrapEl) {
2447
+ setFloatingHeaderStyle(void 0);
2448
+ return;
2449
+ }
2450
+ const apply = () => {
2451
+ const rect = wrapEl.getBoundingClientRect();
2452
+ const rootStyle = getComputedStyle(document.documentElement);
2453
+ const headerOffset = Number.parseFloat(rootStyle.getPropertyValue("--header-height")) || 0;
2454
+ const cs = getComputedStyle(wrapEl);
2455
+ const borderLeft = parseFloat(cs.borderLeftWidth) || 0;
2456
+ const borderRight = parseFloat(cs.borderRightWidth) || 0;
2457
+ const visibleWidth = Math.max(0, wrapEl.clientWidth - borderLeft - borderRight);
2458
+ const renderedTableWidth = Math.max(
2459
+ totalWidth,
2460
+ visibleWidth,
2461
+ wrapEl.querySelector("table")?.getBoundingClientRect().width ?? 0
2462
+ );
2463
+ setFloatingHeaderStyle({
2464
+ position: "fixed",
2465
+ top: headerOffset,
2466
+ left: rect.left + borderLeft,
2467
+ width: visibleWidth,
2468
+ zIndex: 50
2469
+ });
2470
+ setFloatingHeaderTableWidth(renderedTableWidth);
2471
+ setHeaderScrollLeft(wrapEl.scrollLeft);
2472
+ };
2473
+ apply();
2474
+ const scheduled = rafThrottle(apply);
2475
+ const ro = new ResizeObserver(scheduled);
2476
+ ro.observe(wrapEl);
2477
+ window.addEventListener("scroll", scheduled, { passive: true, capture: true });
2478
+ window.addEventListener("resize", scheduled, { passive: true });
2479
+ return () => {
2480
+ scheduled.cancel();
2481
+ ro.disconnect();
2482
+ window.removeEventListener("scroll", scheduled, { capture: true });
2483
+ window.removeEventListener("resize", scheduled);
2484
+ };
2485
+ }, [headerIsStuck, showColumnHeaders, totalWidth, displayCols.length]);
2486
+ function ariaSortAttr(colKey) {
2487
+ return sortKey !== colKey ? "none" : sortDir === "asc" ? "ascending" : "descending";
2488
+ }
2489
+ function cellStyle(key) {
2490
+ return stickyStyle(key);
2491
+ }
2492
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 w-full flex-col gap-0", children: [
2493
+ /* @__PURE__ */ jsx(
2494
+ DataTableToolbar,
2495
+ {
2496
+ state,
2497
+ columns,
2498
+ searchable,
2499
+ renderFilterOptionValue,
2500
+ toolbarSlot,
2501
+ searchAriaLabel: "Search table"
2502
+ }
2503
+ ),
2504
+ isClient && showColumnHeaders && headerIsStuck && floatingHeaderStyle ? createPortal(
2505
+ /* @__PURE__ */ jsx(
2506
+ "div",
2507
+ {
2508
+ style: floatingHeaderStyle,
2509
+ className: "pointer-events-auto",
2510
+ children: /* @__PURE__ */ jsx("div", { className: "overflow-hidden border border-border bg-dt-header-bg shadow-[0_10px_18px_-14px_rgba(15,23,42,0.5)] dark:shadow-[0_12px_20px_-14px_rgba(0,0,0,0.75)]", children: /* @__PURE__ */ jsx("div", { style: { transform: `translateX(${-headerScrollLeft}px)` }, children: /* @__PURE__ */ jsxs(
2511
+ "table",
2512
+ {
2513
+ className: "w-full text-sm border-separate border-spacing-0",
2514
+ style: { tableLayout: "fixed", width: floatingHeaderTableWidth },
2515
+ children: [
2516
+ /* @__PURE__ */ jsx("colgroup", { children: displayCols.map((col) => /* @__PURE__ */ jsx("col", { style: { width: colWidths[col.key] ?? col.width ?? 100 } }, col.key)) }),
2517
+ /* @__PURE__ */ jsx("thead", { className: "bg-dt-header-bg", children: /* @__PURE__ */ jsx("tr", { children: displayCols.map((col) => {
2518
+ const isPinned = !!effectivePins[col.key];
2519
+ const isEdgePinCol = col.key === lastLeftPinKey || col.key === firstRightPinKey;
2520
+ return /* @__PURE__ */ jsx(
2521
+ "th",
2522
+ {
2523
+ scope: "col",
2524
+ style: floatingHeaderPinnedStyle(col.key),
2525
+ className: cn(
2526
+ "h-9 px-3 text-start align-middle select-none",
2527
+ "text-xs font-medium text-muted-foreground tracking-wide",
2528
+ "bg-dt-header-bg border-b border-border",
2529
+ showGridlines && (!isEdgePinCol ? "border-e border-border last:border-e-0" : "last:border-e-0"),
2530
+ isPinned ? "z-40" : "z-30",
2531
+ isPinned && "relative",
2532
+ isEdgePinCol && stickyShadow(effectivePins[col.key])
2533
+ ),
2534
+ children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between gap-1 min-w-0", children: /* @__PURE__ */ jsx("div", { className: "flex items-center min-w-0 flex-1", children: col.key === "select" ? selectable && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center justify-center self-center", children: [
2535
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: resolvedColumnLabel(col) }),
2536
+ /* @__PURE__ */ jsx(
2537
+ Checkbox,
2538
+ {
2539
+ checked: allSelected ? true : someSelected ? "indeterminate" : false,
2540
+ onCheckedChange: () => toggleAll(allRowIds),
2541
+ "aria-label": "Select all rows"
2542
+ }
2543
+ )
2544
+ ] }) : col.sortable && col.sortKey ? /* @__PURE__ */ jsxs(
2545
+ "button",
2546
+ {
2547
+ type: "button",
2548
+ onClick: () => handleSortByKey(col.key),
2549
+ className: cn(
2550
+ "inline-flex items-center hover:text-interactive-hover-foreground transition-colors whitespace-nowrap",
2551
+ sortKey === col.key && "text-foreground"
2552
+ ),
2553
+ children: [
2554
+ col.label?.trim() ? col.label : resolvedColumnLabel(col),
2555
+ sortKey === col.key ? /* @__PURE__ */ jsx(SortChevron, { dir: sortDir }) : null
2556
+ ]
2557
+ }
2558
+ ) : /* @__PURE__ */ jsx("span", { className: "truncate whitespace-nowrap", children: col.label?.trim() ? col.label : defaultColumnHeaderLabel(col.key) ?? col.key }) }) })
2559
+ },
2560
+ col.key
2561
+ );
2562
+ }) }) })
2563
+ ]
2564
+ }
2565
+ ) }) })
2566
+ }
2567
+ ),
2568
+ document.body
2569
+ ) : null,
2570
+ /* @__PURE__ */ jsx(
2571
+ "div",
2572
+ {
2573
+ ref: (el) => {
2574
+ tableWrapRef.current = el;
2575
+ scrollRef.current = el;
2576
+ },
2577
+ onScroll: (e) => {
2578
+ handleScroll();
2579
+ setHeaderScrollLeft(e.currentTarget.scrollLeft);
2580
+ },
2581
+ className: cn(
2582
+ "mx-4 lg:mx-6 overflow-x-auto border border-border",
2583
+ hasFooter ? "rounded-t-lg" : "rounded-lg"
2584
+ ),
2585
+ children: /* @__PURE__ */ jsxs(
2586
+ "table",
2587
+ {
2588
+ className: "w-full text-sm border-separate border-spacing-0",
2589
+ style: {
2590
+ tableLayout: "fixed",
2591
+ minWidth: totalWidth,
2592
+ width: headerIsStuck ? floatingHeaderTableWidth : void 0
2593
+ },
2594
+ children: [
2595
+ /* @__PURE__ */ jsx("colgroup", { children: displayCols.map((col) => /* @__PURE__ */ jsx("col", { style: { width: colWidths[col.key] ?? col.width ?? 100 } }, col.key)) }),
2596
+ /* @__PURE__ */ jsx(
2597
+ "thead",
2598
+ {
2599
+ ref: tableHeadRef,
2600
+ className: cn(
2601
+ "bg-dt-header-bg",
2602
+ headerIsStuck && "invisible",
2603
+ !showColumnHeaders && "hidden"
2604
+ ),
2605
+ children: /* @__PURE__ */ jsx("tr", { children: displayCols.map((col) => {
2606
+ const isPinned = !!effectivePins[col.key];
2607
+ const isLocked = !!lockedPins[col.key];
2608
+ const isFree = !colPins[col.key];
2609
+ const isResizable = !isLocked || col.key !== "select";
2610
+ const isEdgePinCol = col.key === lastLeftPinKey || col.key === firstRightPinKey;
2611
+ return /* @__PURE__ */ jsxs(
2612
+ "th",
2613
+ {
2614
+ scope: "col",
2615
+ "aria-sort": col.sortable && col.sortKey ? ariaSortAttr(col.sortKey) : void 0,
2616
+ draggable: isFree,
2617
+ onDragStart: isFree ? (e) => handleDragStart(col.key, e) : void 0,
2618
+ onDragOver: isFree ? (e) => handleDragOver(col.key, e) : void 0,
2619
+ onDrop: isFree ? () => handleDrop(col.key) : void 0,
2620
+ onDragEnd: isFree ? handleDragEnd : void 0,
2621
+ style: stickyStyle(col.key, false),
2622
+ className: cn(
2623
+ "group/th relative h-9 px-3 text-start align-middle select-none",
2624
+ "text-xs font-medium text-muted-foreground tracking-wide",
2625
+ "bg-dt-header-bg border-b border-border",
2626
+ showGridlines && (!isEdgePinCol ? "border-e border-border last:border-e-0" : "last:border-e-0"),
2627
+ isPinned ? "z-40" : "z-30",
2628
+ isFree && "cursor-grab active:cursor-grabbing",
2629
+ dragOverKey === col.key && draggedKey.current !== col.key && "bg-accent/40",
2630
+ isEdgePinCol && stickyShadow(effectivePins[col.key])
2631
+ ),
2632
+ children: [
2633
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-1 min-w-0", children: [
2634
+ /* @__PURE__ */ jsx("div", { className: "flex items-center min-w-0 flex-1", children: col.header ? col.header() : col.key === "select" ? selectable && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center justify-center self-center", children: [
2635
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: resolvedColumnLabel(col) }),
2636
+ /* @__PURE__ */ jsx(
2637
+ Checkbox,
2638
+ {
2639
+ checked: allSelected ? true : someSelected ? "indeterminate" : false,
2640
+ onCheckedChange: () => toggleAll(allRowIds),
2641
+ "aria-label": "Select all rows"
2642
+ }
2643
+ )
2644
+ ] }) : col.sortable && col.sortKey ? /* @__PURE__ */ jsx(Tip, { label: `Sort by ${resolvedColumnLabel(col)}`, side: "top", children: /* @__PURE__ */ jsxs(
2645
+ "button",
2646
+ {
2647
+ type: "button",
2648
+ onClick: () => handleSortByKey(col.key),
2649
+ className: cn(
2650
+ "inline-flex items-center hover:text-interactive-hover-foreground transition-colors whitespace-nowrap",
2651
+ sortKey === col.key && "text-foreground"
2652
+ ),
2653
+ children: [
2654
+ col.label?.trim() ? col.label : resolvedColumnLabel(col),
2655
+ sortKey === col.key && /* @__PURE__ */ jsx(SortChevron, { dir: sortDir })
2656
+ ]
2657
+ }
2658
+ ) }) : /* @__PURE__ */ jsx(Tip, { label: resolvedColumnLabel(col), side: "top", children: /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap", children: col.label?.trim() ? col.label : defaultColumnHeaderLabel(col.key) ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: defaultColumnHeaderLabel(col.key) }) : /* @__PURE__ */ jsx("span", { className: "sr-only", children: col.key }) }) }) }),
2659
+ col.key !== "select" && !lockedPins[col.key]?.includes("right") && col.key !== columns.find((c) => c.lockPin && c.defaultPin === "right")?.key && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2660
+ /* @__PURE__ */ jsx(Tip, { label: "Column options", side: "top", children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
2661
+ "button",
2662
+ {
2663
+ type: "button",
2664
+ "aria-label": `${resolvedColumnLabel(col)} column options`,
2665
+ onClick: (e) => e.stopPropagation(),
2666
+ className: cn(
2667
+ "opacity-0 group-hover/th:opacity-100 group-focus-within/th:opacity-100",
2668
+ "inline-flex shrink-0 items-center justify-center size-7 rounded-md",
2669
+ "text-muted-foreground hover:text-interactive-hover-foreground hover:bg-interactive-hover-row",
2670
+ "transition-opacity focus-visible:opacity-100",
2671
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
2672
+ ),
2673
+ children: /* @__PURE__ */ jsx("i", { className: "fa-light fa-ellipsis-vertical text-xs", "aria-hidden": "true" })
2674
+ }
2675
+ ) }) }),
2676
+ /* @__PURE__ */ jsxs(
2677
+ DropdownMenuContent,
2678
+ {
2679
+ align: "start",
2680
+ onCloseAutoFocus: () => {
2681
+ const action = columnMenuPendingActionRef.current;
2682
+ if (!action) return;
2683
+ columnMenuPendingActionRef.current = null;
2684
+ action();
2685
+ },
2686
+ children: [
2687
+ /* @__PURE__ */ jsx("div", { className: "px-2 pt-2 pb-1", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2688
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-magnifying-glass absolute start-2 top-1/2 -translate-y-1/2 text-muted-foreground text-xs pointer-events-none", "aria-hidden": "true" }),
2689
+ /* @__PURE__ */ jsx(
2690
+ Input,
2691
+ {
2692
+ placeholder: `Search ${resolvedColumnLabel(col)}\u2026`,
2693
+ value: colMenuSearch[col.key] ?? "",
2694
+ onChange: (e) => setColMenuSearch((prev) => ({ ...prev, [col.key]: e.target.value })),
2695
+ onKeyDown: (e) => e.stopPropagation(),
2696
+ className: "h-7 ps-6 text-xs"
2697
+ }
2698
+ ),
2699
+ colMenuSearch[col.key] && /* @__PURE__ */ jsx(
2700
+ "button",
2701
+ {
2702
+ type: "button",
2703
+ "aria-label": "Clear search",
2704
+ onClick: () => setColMenuSearch((prev) => ({ ...prev, [col.key]: "" })),
2705
+ className: "absolute end-1.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-interactive-hover-foreground transition-colors",
2706
+ children: /* @__PURE__ */ jsx("i", { className: "fa-light fa-xmark text-xs", "aria-hidden": "true" })
2707
+ }
2708
+ )
2709
+ ] }) }),
2710
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2711
+ !isLocked && /* @__PURE__ */ jsxs(Fragment, { children: [
2712
+ /* @__PURE__ */ jsxs(
2713
+ DropdownMenuItem,
2714
+ {
2715
+ onClick: () => pinColumn(col.key, "left"),
2716
+ disabled: colPins[col.key] === "left",
2717
+ children: [
2718
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-arrow-left-to-line", "aria-hidden": "true" }),
2719
+ "Pin Left"
2720
+ ]
2721
+ }
2722
+ ),
2723
+ /* @__PURE__ */ jsxs(
2724
+ DropdownMenuItem,
2725
+ {
2726
+ onClick: () => pinColumn(col.key, "right"),
2727
+ disabled: colPins[col.key] === "right",
2728
+ children: [
2729
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-arrow-right-to-line", "aria-hidden": "true" }),
2730
+ "Pin Right"
2731
+ ]
2732
+ }
2733
+ ),
2734
+ colPins[col.key] && /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => unpinColumn(col.key), children: [
2735
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-thumbtack-slash", "aria-hidden": "true" }),
2736
+ "Unpin"
2737
+ ] }),
2738
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {})
2739
+ ] }),
2740
+ col.sortable && col.sortKey && /* @__PURE__ */ jsxs(Fragment, { children: [
2741
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setSortRules((prev) => {
2742
+ const filtered = prev.filter((r) => r.fieldKey !== col.key);
2743
+ return [{ id: `sort-${Date.now()}`, fieldKey: col.key, direction: "asc" }, ...filtered];
2744
+ }), children: [
2745
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-arrow-up-a-z text-xs shrink-0", "aria-hidden": "true" }),
2746
+ "Sort Ascending"
2747
+ ] }),
2748
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setSortRules((prev) => {
2749
+ const filtered = prev.filter((r) => r.fieldKey !== col.key);
2750
+ return [{ id: `sort-${Date.now()}`, fieldKey: col.key, direction: "desc" }, ...filtered];
2751
+ }), children: [
2752
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-arrow-down-a-z text-xs shrink-0", "aria-hidden": "true" }),
2753
+ "Sort Descending"
2754
+ ] }),
2755
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {})
2756
+ ] }),
2757
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => toggleWrap(col.key), children: [
2758
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-text-width", "aria-hidden": "true" }),
2759
+ colWrap[col.key] ? "Unwrap Text" : "Wrap Text"
2760
+ ] }),
2761
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2762
+ col.filter && /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => addFilter(col.key), children: [
2763
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-filter", "aria-hidden": "true" }),
2764
+ "Filter by this column"
2765
+ ] }),
2766
+ /* @__PURE__ */ jsxs(
2767
+ DropdownMenuItem,
2768
+ {
2769
+ onClick: () => setGroupBy(groupBy === col.key ? null : col.key),
2770
+ children: [
2771
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-layer-group", "aria-hidden": "true" }),
2772
+ groupBy === col.key ? "Remove Grouping" : "Group by this Column"
2773
+ ]
2774
+ }
2775
+ ),
2776
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2777
+ /* @__PURE__ */ jsxs(
2778
+ DropdownMenuItem,
2779
+ {
2780
+ onSelect: () => {
2781
+ columnMenuPendingActionRef.current = () => {
2782
+ setSheetInitialPanel("conditional-rules");
2783
+ setSheetOpen(true);
2784
+ };
2785
+ },
2786
+ children: [
2787
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-palette", "aria-hidden": "true" }),
2788
+ "Add Conditional Rule"
2789
+ ]
2790
+ }
2791
+ )
2792
+ ]
2793
+ }
2794
+ )
2795
+ ] })
2796
+ ] }),
2797
+ isResizable && col.key !== "select" && /* @__PURE__ */ jsx(
2798
+ "div",
2799
+ {
2800
+ role: "separator",
2801
+ "aria-label": `Resize ${resolvedColumnLabel(col)} column`,
2802
+ "aria-orientation": "vertical",
2803
+ onMouseDown: (e) => startResize(col.key, e),
2804
+ className: "absolute end-0 top-1 bottom-1 w-1.5 cursor-col-resize rounded-full hover:bg-interactive-hover-foreground/50 active:bg-muted-foreground/70 transition-colors"
2805
+ }
2806
+ )
2807
+ ]
2808
+ },
2809
+ col.key
2810
+ );
2811
+ }) })
2812
+ }
2813
+ ),
2814
+ /* @__PURE__ */ jsxs("tbody", { children: [
2815
+ (pagedRows !== rows ? [{ groupKey: null, groupLabel: null, rows: pagedRows }] : groupedRows).map(({ groupKey, groupLabel, rows: groupRows }) => /* @__PURE__ */ jsxs(React9.Fragment, { children: [
2816
+ groupLabel && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: displayCols.length, className: "p-0 border-b border-border bg-dt-group-bg", children: /* @__PURE__ */ jsxs(
2817
+ "div",
2818
+ {
2819
+ className: cn(
2820
+ "sticky start-0 z-[25] px-4 py-1.5 text-xs font-semibold text-muted-foreground tracking-wide bg-dt-group-bg select-none",
2821
+ !isReflowViewport && "shadow-[4px_0_8px_-4px_var(--sticky-edge-fade)]"
2822
+ ),
2823
+ style: { width: "var(--dt-scrollport-width, 100%)" },
2824
+ children: [
2825
+ groupLabel,
2826
+ /* @__PURE__ */ jsxs("span", { className: "ms-2 font-normal normal-case opacity-60 tracking-normal", children: [
2827
+ groupRows.length,
2828
+ " record",
2829
+ groupRows.length !== 1 ? "s" : ""
2830
+ ] })
2831
+ ]
2832
+ }
2833
+ ) }) }),
2834
+ groupRows.map((row, rowIndex) => {
2835
+ const rowId = getRowId(row, rowIndex, getRowIdProp);
2836
+ const isSelected = selected.has(rowId);
2837
+ const rowClickable = Boolean(onRowClick) || selectable;
2838
+ function handleRowClick(e) {
2839
+ if (!rowClickable) return;
2840
+ const el = e.target;
2841
+ if (!el) return;
2842
+ if (el.closest("button, a, input, textarea, select, label, [role='checkbox']")) return;
2843
+ if (onRowClick) {
2844
+ onRowClick(row);
2845
+ return;
2846
+ }
2847
+ if (selectable) {
2848
+ toggleRow(rowId);
2849
+ }
2850
+ }
2851
+ return /* @__PURE__ */ jsx(
2852
+ "tr",
2853
+ {
2854
+ "data-state": isSelected ? "selected" : void 0,
2855
+ onMouseEnter: () => setHoveredRow(rowId),
2856
+ onMouseLeave: () => setHoveredRow(null),
2857
+ onClick: rowClickable ? handleRowClick : void 0,
2858
+ "data-new": Boolean(row.isNew) || void 0,
2859
+ className: cn(
2860
+ "group/row transition-colors",
2861
+ "hover:bg-dt-row-hover",
2862
+ isSelected && "bg-dt-row-selected text-dt-row-selected-fg",
2863
+ rowClickable && "cursor-pointer",
2864
+ Boolean(row.isNew) && "bg-dt-new-row-bg border-s-2 border-s-dt-new-row-border"
2865
+ ),
2866
+ children: displayCols.map((col) => {
2867
+ const isPinned = !!effectivePins[col.key];
2868
+ const wrap = colWrap[col.key];
2869
+ const isEdgePin = col.key === lastLeftPinKey || col.key === firstRightPinKey;
2870
+ const rowPy = rowHeight === "compact" ? "py-1" : rowHeight === "comfortable" ? "py-4" : "py-2.5";
2871
+ const cs = cellStyle(col.key);
2872
+ const tdBase = cn(
2873
+ `px-3 ${rowPy} align-middle`,
2874
+ showGridlines && !isEdgePin && "border-e border-border last:border-e-0",
2875
+ "border-b border-border group-last/row:border-b-0",
2876
+ isPinned && [
2877
+ "z-20 pinned-cell",
2878
+ "bg-dt-row-bg",
2879
+ "group-data-[state=selected]/row:bg-dt-row-selected",
2880
+ "group-hover/row:bg-dt-row-hover",
2881
+ isEdgePin && stickyShadow(effectivePins[col.key])
2882
+ ]
2883
+ );
2884
+ const conditionalBg = getConditionalCellBackground(
2885
+ row,
2886
+ col.key,
2887
+ conditionalRules,
2888
+ columns
2889
+ );
2890
+ const tdStyle = conditionalBg ? { ...cs, background: conditionalBg } : cs;
2891
+ if (col.key === "select") {
2892
+ const selectionLabel = getRowSelectionLabel?.(row, rowIndex);
2893
+ const ariaLabel = selectionLabel ? `Select row, ${selectionLabel}` : `Select row ${rowIndex + 1}`;
2894
+ return /* @__PURE__ */ jsx("td", { className: cn(tdBase, "text-center"), style: tdStyle, children: selectable && // inline-flex: inline elements inside <td> are never
2895
+ // stretched by table-cell height in Chrome/Safari/Firefox.
2896
+ // Block-level flex/grid always inherits full cell height at zoom.
2897
+ /* @__PURE__ */ jsx(
2898
+ "span",
2899
+ {
2900
+ className: cn(
2901
+ "inline-flex items-center justify-center transition-opacity",
2902
+ anySelected ? "opacity-100" : "opacity-0 group-hover/row:opacity-100 group-focus-within/row:opacity-100"
2903
+ ),
2904
+ onClick: (e) => e.stopPropagation(),
2905
+ children: /* @__PURE__ */ jsx(
2906
+ Checkbox,
2907
+ {
2908
+ checked: isSelected,
2909
+ onCheckedChange: () => toggleRow(rowId),
2910
+ "aria-label": ariaLabel,
2911
+ onClick: (e) => e.stopPropagation()
2912
+ }
2913
+ )
2914
+ }
2915
+ ) }, "select");
2916
+ }
2917
+ if (col.cell) {
2918
+ return /* @__PURE__ */ jsx(
2919
+ "td",
2920
+ {
2921
+ className: cn(
2922
+ tdBase,
2923
+ // When wrap is on, override truncate/overflow on any descendant
2924
+ wrap && "[&_.truncate]:!whitespace-normal [&_.truncate]:!overflow-visible [&_.truncate]:!text-clip"
2925
+ ),
2926
+ style: tdStyle,
2927
+ children: col.cell(row, {
2928
+ rowIndex,
2929
+ selected: isSelected,
2930
+ onSelect: (checked) => checked ? setSelected((prev) => /* @__PURE__ */ new Set([...prev, rowId])) : toggleRow(rowId)
2931
+ })
2932
+ },
2933
+ col.key
2934
+ );
2935
+ }
2936
+ const rawVal = String(row[col.key] ?? "");
2937
+ return /* @__PURE__ */ jsx("td", { className: cn(tdBase, "text-sm text-foreground/80"), style: tdStyle, children: /* @__PURE__ */ jsx("span", { className: wrap ? "whitespace-normal" : "block truncate", title: !wrap ? rawVal : void 0, children: rawVal }) }, col.key);
2938
+ })
2939
+ },
2940
+ String(rowId)
2941
+ );
2942
+ })
2943
+ ] }, groupKey ?? "__all__")),
2944
+ rows.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: displayCols.length, className: "h-24 px-3 text-center text-sm text-muted-foreground", children: emptyState ?? "No results match your filters." }) }),
2945
+ addRowLabel !== false && /* @__PURE__ */ jsx(
2946
+ "tr",
2947
+ {
2948
+ role: "button",
2949
+ tabIndex: 0,
2950
+ onKeyDown: (e) => {
2951
+ if (e.key === "Enter" || e.key === " ") e.preventDefault();
2952
+ },
2953
+ className: "cursor-pointer hover:bg-dt-row-hover transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset",
2954
+ "aria-label": `Add new ${addRowLabel}`,
2955
+ children: /* @__PURE__ */ jsx("td", { colSpan: displayCols.length, className: "px-3 py-2.5 align-middle", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-sm text-muted-foreground", children: [
2956
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-plus text-xs", "aria-hidden": "true" }),
2957
+ addRowLabel
2958
+ ] }) })
2959
+ }
2960
+ )
2961
+ ] })
2962
+ ]
2963
+ }
2964
+ )
2965
+ }
2966
+ ),
2967
+ anySelected && /* @__PURE__ */ jsxs(
2968
+ "div",
2969
+ {
2970
+ role: "status",
2971
+ "aria-live": "polite",
2972
+ "aria-label": `${selected.size} row${selected.size !== 1 ? "s" : ""} selected`,
2973
+ "data-exxat-bulk-bar": "",
2974
+ style: bulkBarFixedStyle,
2975
+ className: cn(
2976
+ "flex min-w-0 max-w-full items-stretch overflow-hidden",
2977
+ isAppDark ? "rounded-lg border border-zinc-300/80 bg-zinc-100 text-zinc-900 shadow-lg" : "rounded-lg border border-zinc-800 bg-zinc-900 text-zinc-100 shadow-lg",
2978
+ "animate-in fade-in-0 duration-150",
2979
+ "w-auto max-w-none"
2980
+ ),
2981
+ children: [
2982
+ /* @__PURE__ */ jsxs(
2983
+ "div",
2984
+ {
2985
+ className: cn(
2986
+ "flex shrink-0 items-center gap-2 border-e py-2.5 ps-3 pe-2",
2987
+ isAppDark ? "border-zinc-300/50" : "border-zinc-600/50"
2988
+ ),
2989
+ "aria-hidden": "true",
2990
+ children: [
2991
+ /* @__PURE__ */ jsx(
2992
+ "span",
2993
+ {
2994
+ className: cn(
2995
+ "inline-flex size-8 items-center justify-center rounded-md",
2996
+ isAppDark ? "text-zinc-500" : "text-zinc-400"
2997
+ ),
2998
+ "aria-hidden": "true",
2999
+ children: /* @__PURE__ */ jsx("i", { className: "fa-light fa-clipboard-list text-[1.1rem] leading-none" })
3000
+ }
3001
+ ),
3002
+ /* @__PURE__ */ jsx(
3003
+ "span",
3004
+ {
3005
+ className: cn(
3006
+ "min-w-6 rounded-md px-1.5 py-0.5 text-center text-xs font-semibold leading-none tabular-nums",
3007
+ isAppDark ? "bg-zinc-200/90 text-zinc-900" : "bg-zinc-800 text-zinc-100"
3008
+ ),
3009
+ children: selected.size
3010
+ }
3011
+ )
3012
+ ]
3013
+ }
3014
+ ),
3015
+ /* @__PURE__ */ jsxs(
3016
+ "div",
3017
+ {
3018
+ className: cn(
3019
+ "flex min-w-0 min-h-0 flex-1 items-stretch",
3020
+ !isAppDark && "dark",
3021
+ isAppDark && BULK_BAR_ON_LIGHT_STRIP
3022
+ ),
3023
+ children: [
3024
+ /* @__PURE__ */ jsx(
3025
+ "div",
3026
+ {
3027
+ className: cn(
3028
+ "min-w-0 flex-1 self-center",
3029
+ "overflow-x-auto overscroll-x-contain [scrollbar-width:thin] [touch-action:pan-x]"
3030
+ ),
3031
+ children: /* @__PURE__ */ jsx("div", { className: "flex w-max min-w-0 max-w-full flex-nowrap items-center gap-2 py-2.5 ps-2 pe-2", children: bulkActionsSlot ? bulkActionsSlot(selected, rows) : /* @__PURE__ */ jsxs(Fragment, { children: [
3032
+ /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "outline", className: "shrink-0", children: [
3033
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-arrow-down-to-line", "aria-hidden": "true" }),
3034
+ " Export"
3035
+ ] }),
3036
+ /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "destructive", className: "shrink-0", children: [
3037
+ /* @__PURE__ */ jsx("i", { className: "fa-light fa-trash", "aria-hidden": "true" }),
3038
+ " Delete"
3039
+ ] })
3040
+ ] }) })
3041
+ }
3042
+ ),
3043
+ /* @__PURE__ */ jsx(
3044
+ "div",
3045
+ {
3046
+ className: cn(
3047
+ "flex shrink-0 items-center border-e py-2.5 ps-2 pe-2.5",
3048
+ isAppDark ? "border-zinc-300/50" : "border-zinc-600/50"
3049
+ ),
3050
+ children: /* @__PURE__ */ jsx(Tip, { label: "Clear selection", side: "top", children: /* @__PURE__ */ jsx(
3051
+ Button,
3052
+ {
3053
+ type: "button",
3054
+ size: "icon-sm",
3055
+ variant: "ghost",
3056
+ "aria-label": "Clear selection",
3057
+ onClick: () => setSelected(/* @__PURE__ */ new Set()),
3058
+ className: "shrink-0",
3059
+ children: /* @__PURE__ */ jsx("i", { className: "fa-light fa-xmark", "aria-hidden": "true" })
3060
+ }
3061
+ ) })
3062
+ }
3063
+ )
3064
+ ]
3065
+ }
3066
+ )
3067
+ ]
3068
+ }
3069
+ )
3070
+ ] });
3071
+ }
3072
+ function DataTableWithInternalState(props) {
3073
+ const state = useTableState(props.data, props.columns, props.defaultSort, props.paginationOverride);
3074
+ return /* @__PURE__ */ jsx(DataTableInner, { ...props, state });
3075
+ }
3076
+ function DataTable(props) {
3077
+ if (props.state) {
3078
+ return /* @__PURE__ */ jsx(DataTableInner, { ...props, state: props.state });
3079
+ }
3080
+ return /* @__PURE__ */ jsx(DataTableWithInternalState, { ...props });
3081
+ }
3082
+
3083
+ export { DataTable, DataTableToolbar };
3084
+ //# sourceMappingURL=index.js.map
3085
+ //# sourceMappingURL=index.js.map