@hexclave/dashboard-ui-components 1.0.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 (331) hide show
  1. package/LICENSE +5 -0
  2. package/dist/chunk-BE-pF4vm.js +34 -0
  3. package/dist/components/alert.d.ts +22 -0
  4. package/dist/components/alert.d.ts.map +1 -0
  5. package/dist/components/alert.js +75 -0
  6. package/dist/components/alert.js.map +1 -0
  7. package/dist/components/analytics-chart/analytics-chart-pie.d.ts +67 -0
  8. package/dist/components/analytics-chart/analytics-chart-pie.d.ts.map +1 -0
  9. package/dist/components/analytics-chart/analytics-chart-pie.js +253 -0
  10. package/dist/components/analytics-chart/analytics-chart-pie.js.map +1 -0
  11. package/dist/components/analytics-chart/analytics-chart.d.ts +554 -0
  12. package/dist/components/analytics-chart/analytics-chart.d.ts.map +1 -0
  13. package/dist/components/analytics-chart/analytics-chart.js +1021 -0
  14. package/dist/components/analytics-chart/analytics-chart.js.map +1 -0
  15. package/dist/components/analytics-chart/default-analytics-chart-tooltip.d.ts +66 -0
  16. package/dist/components/analytics-chart/default-analytics-chart-tooltip.d.ts.map +1 -0
  17. package/dist/components/analytics-chart/default-analytics-chart-tooltip.js +179 -0
  18. package/dist/components/analytics-chart/default-analytics-chart-tooltip.js.map +1 -0
  19. package/dist/components/analytics-chart/format.d.ts +13 -0
  20. package/dist/components/analytics-chart/format.d.ts.map +1 -0
  21. package/dist/components/analytics-chart/format.js +138 -0
  22. package/dist/components/analytics-chart/format.js.map +1 -0
  23. package/dist/components/analytics-chart/index.d.ts +8 -0
  24. package/dist/components/analytics-chart/index.js +184 -0
  25. package/dist/components/analytics-chart/palette.d.ts +15 -0
  26. package/dist/components/analytics-chart/palette.d.ts.map +1 -0
  27. package/dist/components/analytics-chart/palette.js +60 -0
  28. package/dist/components/analytics-chart/palette.js.map +1 -0
  29. package/dist/components/analytics-chart/render-data-series.d.ts +28 -0
  30. package/dist/components/analytics-chart/render-data-series.d.ts.map +1 -0
  31. package/dist/components/analytics-chart/render-data-series.js +109 -0
  32. package/dist/components/analytics-chart/render-data-series.js.map +1 -0
  33. package/dist/components/analytics-chart/state.d.ts +54 -0
  34. package/dist/components/analytics-chart/state.d.ts.map +1 -0
  35. package/dist/components/analytics-chart/state.js +142 -0
  36. package/dist/components/analytics-chart/state.js.map +1 -0
  37. package/dist/components/analytics-chart/strings.d.ts +33 -0
  38. package/dist/components/analytics-chart/strings.d.ts.map +1 -0
  39. package/dist/components/analytics-chart/strings.js +37 -0
  40. package/dist/components/analytics-chart/strings.js.map +1 -0
  41. package/dist/components/analytics-chart/types.d.ts +157 -0
  42. package/dist/components/analytics-chart/types.d.ts.map +1 -0
  43. package/dist/components/analytics-chart/types.js +21 -0
  44. package/dist/components/analytics-chart/types.js.map +1 -0
  45. package/dist/components/badge.d.ts +40 -0
  46. package/dist/components/badge.d.ts.map +1 -0
  47. package/dist/components/badge.js +75 -0
  48. package/dist/components/badge.js.map +1 -0
  49. package/dist/components/button.d.ts +46 -0
  50. package/dist/components/button.d.ts.map +1 -0
  51. package/dist/components/button.js +82 -0
  52. package/dist/components/button.js.map +1 -0
  53. package/dist/components/card.d.ts +87 -0
  54. package/dist/components/card.d.ts.map +1 -0
  55. package/dist/components/card.js +161 -0
  56. package/dist/components/card.js.map +1 -0
  57. package/dist/components/chart-card.d.ts +50 -0
  58. package/dist/components/chart-card.d.ts.map +1 -0
  59. package/dist/components/chart-card.js +83 -0
  60. package/dist/components/chart-card.js.map +1 -0
  61. package/dist/components/chart-container.d.ts +51 -0
  62. package/dist/components/chart-container.d.ts.map +1 -0
  63. package/dist/components/chart-container.js +77 -0
  64. package/dist/components/chart-container.js.map +1 -0
  65. package/dist/components/chart-legend.d.ts +11 -0
  66. package/dist/components/chart-legend.d.ts.map +1 -0
  67. package/dist/components/chart-legend.js +37 -0
  68. package/dist/components/chart-legend.js.map +1 -0
  69. package/dist/components/chart-theme.d.ts +26 -0
  70. package/dist/components/chart-theme.d.ts.map +1 -0
  71. package/dist/components/chart-theme.js +64 -0
  72. package/dist/components/chart-theme.js.map +1 -0
  73. package/dist/components/chart-tooltip.d.ts +41 -0
  74. package/dist/components/chart-tooltip.d.ts.map +1 -0
  75. package/dist/components/chart-tooltip.js +89 -0
  76. package/dist/components/chart-tooltip.js.map +1 -0
  77. package/dist/components/cursor-blast-effect.d.ts +27 -0
  78. package/dist/components/cursor-blast-effect.d.ts.map +1 -0
  79. package/dist/components/cursor-blast-effect.js +244 -0
  80. package/dist/components/cursor-blast-effect.js.map +1 -0
  81. package/dist/components/data-grid/data-grid-sizing.d.ts +13 -0
  82. package/dist/components/data-grid/data-grid-sizing.d.ts.map +1 -0
  83. package/dist/components/data-grid/data-grid-sizing.js +44 -0
  84. package/dist/components/data-grid/data-grid-sizing.js.map +1 -0
  85. package/dist/components/data-grid/data-grid-toolbar.d.ts +31 -0
  86. package/dist/components/data-grid/data-grid-toolbar.d.ts.map +1 -0
  87. package/dist/components/data-grid/data-grid-toolbar.js +229 -0
  88. package/dist/components/data-grid/data-grid-toolbar.js.map +1 -0
  89. package/dist/components/data-grid/data-grid.d.ts +47 -0
  90. package/dist/components/data-grid/data-grid.d.ts.map +1 -0
  91. package/dist/components/data-grid/data-grid.js +927 -0
  92. package/dist/components/data-grid/data-grid.js.map +1 -0
  93. package/dist/components/data-grid/data-grid.test.d.ts +1 -0
  94. package/dist/components/data-grid/data-grid.test.js +297 -0
  95. package/dist/components/data-grid/data-grid.test.js.map +1 -0
  96. package/dist/components/data-grid/index.d.ts +9 -0
  97. package/dist/components/data-grid/index.js +148 -0
  98. package/dist/components/data-grid/state.d.ts +34 -0
  99. package/dist/components/data-grid/state.d.ts.map +1 -0
  100. package/dist/components/data-grid/state.js +199 -0
  101. package/dist/components/data-grid/state.js.map +1 -0
  102. package/dist/components/data-grid/strings.d.ts +8 -0
  103. package/dist/components/data-grid/strings.d.ts.map +1 -0
  104. package/dist/components/data-grid/strings.js +42 -0
  105. package/dist/components/data-grid/strings.js.map +1 -0
  106. package/dist/components/data-grid/types.d.ts +278 -0
  107. package/dist/components/data-grid/types.d.ts.map +1 -0
  108. package/dist/components/data-grid/types.js +0 -0
  109. package/dist/components/data-grid/use-data-source.d.ts +85 -0
  110. package/dist/components/data-grid/use-data-source.d.ts.map +1 -0
  111. package/dist/components/data-grid/use-data-source.js +244 -0
  112. package/dist/components/data-grid/use-data-source.js.map +1 -0
  113. package/dist/components/data-grid/use-url-state.d.ts +38 -0
  114. package/dist/components/data-grid/use-url-state.d.ts.map +1 -0
  115. package/dist/components/data-grid/use-url-state.js +214 -0
  116. package/dist/components/data-grid/use-url-state.js.map +1 -0
  117. package/dist/components/data-grid/use-url-state.test.d.ts +1 -0
  118. package/dist/components/data-grid/use-url-state.test.js +91 -0
  119. package/dist/components/data-grid/use-url-state.test.js.map +1 -0
  120. package/dist/components/dialog.d.ts +67 -0
  121. package/dist/components/dialog.d.ts.map +1 -0
  122. package/dist/components/dialog.js +100 -0
  123. package/dist/components/dialog.js.map +1 -0
  124. package/dist/components/edit-mode.d.ts +12 -0
  125. package/dist/components/edit-mode.d.ts.map +1 -0
  126. package/dist/components/edit-mode.js +23 -0
  127. package/dist/components/edit-mode.js.map +1 -0
  128. package/dist/components/empty-state.d.ts +37 -0
  129. package/dist/components/empty-state.d.ts.map +1 -0
  130. package/dist/components/empty-state.js +53 -0
  131. package/dist/components/empty-state.js.map +1 -0
  132. package/dist/components/input.d.ts +18 -0
  133. package/dist/components/input.d.ts.map +1 -0
  134. package/dist/components/input.js +53 -0
  135. package/dist/components/input.js.map +1 -0
  136. package/dist/components/metric-card.d.ts +55 -0
  137. package/dist/components/metric-card.d.ts.map +1 -0
  138. package/dist/components/metric-card.js +112 -0
  139. package/dist/components/metric-card.js.map +1 -0
  140. package/dist/components/pill-toggle.d.ts +33 -0
  141. package/dist/components/pill-toggle.d.ts.map +1 -0
  142. package/dist/components/pill-toggle.js +86 -0
  143. package/dist/components/pill-toggle.js.map +1 -0
  144. package/dist/components/progress-bar.d.ts +35 -0
  145. package/dist/components/progress-bar.d.ts.map +1 -0
  146. package/dist/components/progress-bar.js +54 -0
  147. package/dist/components/progress-bar.js.map +1 -0
  148. package/dist/components/separator.d.ts +23 -0
  149. package/dist/components/separator.d.ts.map +1 -0
  150. package/dist/components/separator.js +29 -0
  151. package/dist/components/separator.js.map +1 -0
  152. package/dist/components/skeleton.d.ts +24 -0
  153. package/dist/components/skeleton.d.ts.map +1 -0
  154. package/dist/components/skeleton.js +30 -0
  155. package/dist/components/skeleton.js.map +1 -0
  156. package/dist/components/table.d.ts +49 -0
  157. package/dist/components/table.d.ts.map +1 -0
  158. package/dist/components/table.js +84 -0
  159. package/dist/components/table.js.map +1 -0
  160. package/dist/components/tabs.d.ts +38 -0
  161. package/dist/components/tabs.d.ts.map +1 -0
  162. package/dist/components/tabs.js +113 -0
  163. package/dist/components/tabs.js.map +1 -0
  164. package/dist/dashboard-ui-components.global.js +25539 -0
  165. package/dist/dashboard-ui-components.global.js.map +7 -0
  166. package/dist/esm/components/alert.d.ts +22 -0
  167. package/dist/esm/components/alert.d.ts.map +1 -0
  168. package/dist/esm/components/alert.js +73 -0
  169. package/dist/esm/components/alert.js.map +1 -0
  170. package/dist/esm/components/analytics-chart/analytics-chart-pie.d.ts +67 -0
  171. package/dist/esm/components/analytics-chart/analytics-chart-pie.d.ts.map +1 -0
  172. package/dist/esm/components/analytics-chart/analytics-chart-pie.js +251 -0
  173. package/dist/esm/components/analytics-chart/analytics-chart-pie.js.map +1 -0
  174. package/dist/esm/components/analytics-chart/analytics-chart.d.ts +554 -0
  175. package/dist/esm/components/analytics-chart/analytics-chart.d.ts.map +1 -0
  176. package/dist/esm/components/analytics-chart/analytics-chart.js +1019 -0
  177. package/dist/esm/components/analytics-chart/analytics-chart.js.map +1 -0
  178. package/dist/esm/components/analytics-chart/default-analytics-chart-tooltip.d.ts +66 -0
  179. package/dist/esm/components/analytics-chart/default-analytics-chart-tooltip.d.ts.map +1 -0
  180. package/dist/esm/components/analytics-chart/default-analytics-chart-tooltip.js +176 -0
  181. package/dist/esm/components/analytics-chart/default-analytics-chart-tooltip.js.map +1 -0
  182. package/dist/esm/components/analytics-chart/format.d.ts +13 -0
  183. package/dist/esm/components/analytics-chart/format.d.ts.map +1 -0
  184. package/dist/esm/components/analytics-chart/format.js +133 -0
  185. package/dist/esm/components/analytics-chart/format.js.map +1 -0
  186. package/dist/esm/components/analytics-chart/index.d.ts +8 -0
  187. package/dist/esm/components/analytics-chart/index.js +9 -0
  188. package/dist/esm/components/analytics-chart/palette.d.ts +15 -0
  189. package/dist/esm/components/analytics-chart/palette.d.ts.map +1 -0
  190. package/dist/esm/components/analytics-chart/palette.js +55 -0
  191. package/dist/esm/components/analytics-chart/palette.js.map +1 -0
  192. package/dist/esm/components/analytics-chart/render-data-series.d.ts +28 -0
  193. package/dist/esm/components/analytics-chart/render-data-series.d.ts.map +1 -0
  194. package/dist/esm/components/analytics-chart/render-data-series.js +107 -0
  195. package/dist/esm/components/analytics-chart/render-data-series.js.map +1 -0
  196. package/dist/esm/components/analytics-chart/state.d.ts +54 -0
  197. package/dist/esm/components/analytics-chart/state.d.ts.map +1 -0
  198. package/dist/esm/components/analytics-chart/state.js +126 -0
  199. package/dist/esm/components/analytics-chart/state.js.map +1 -0
  200. package/dist/esm/components/analytics-chart/strings.d.ts +33 -0
  201. package/dist/esm/components/analytics-chart/strings.d.ts.map +1 -0
  202. package/dist/esm/components/analytics-chart/strings.js +34 -0
  203. package/dist/esm/components/analytics-chart/strings.js.map +1 -0
  204. package/dist/esm/components/analytics-chart/types.d.ts +157 -0
  205. package/dist/esm/components/analytics-chart/types.d.ts.map +1 -0
  206. package/dist/esm/components/analytics-chart/types.js +18 -0
  207. package/dist/esm/components/analytics-chart/types.js.map +1 -0
  208. package/dist/esm/components/badge.d.ts +40 -0
  209. package/dist/esm/components/badge.d.ts.map +1 -0
  210. package/dist/esm/components/badge.js +73 -0
  211. package/dist/esm/components/badge.js.map +1 -0
  212. package/dist/esm/components/button.d.ts +46 -0
  213. package/dist/esm/components/button.d.ts.map +1 -0
  214. package/dist/esm/components/button.js +79 -0
  215. package/dist/esm/components/button.js.map +1 -0
  216. package/dist/esm/components/card.d.ts +87 -0
  217. package/dist/esm/components/card.d.ts.map +1 -0
  218. package/dist/esm/components/card.js +155 -0
  219. package/dist/esm/components/card.js.map +1 -0
  220. package/dist/esm/components/chart-card.d.ts +50 -0
  221. package/dist/esm/components/chart-card.d.ts.map +1 -0
  222. package/dist/esm/components/chart-card.js +80 -0
  223. package/dist/esm/components/chart-card.js.map +1 -0
  224. package/dist/esm/components/chart-container.d.ts +51 -0
  225. package/dist/esm/components/chart-container.d.ts.map +1 -0
  226. package/dist/esm/components/chart-container.js +70 -0
  227. package/dist/esm/components/chart-container.js.map +1 -0
  228. package/dist/esm/components/chart-legend.d.ts +11 -0
  229. package/dist/esm/components/chart-legend.d.ts.map +1 -0
  230. package/dist/esm/components/chart-legend.js +34 -0
  231. package/dist/esm/components/chart-legend.js.map +1 -0
  232. package/dist/esm/components/chart-theme.d.ts +26 -0
  233. package/dist/esm/components/chart-theme.d.ts.map +1 -0
  234. package/dist/esm/components/chart-theme.js +59 -0
  235. package/dist/esm/components/chart-theme.js.map +1 -0
  236. package/dist/esm/components/chart-tooltip.d.ts +41 -0
  237. package/dist/esm/components/chart-tooltip.d.ts.map +1 -0
  238. package/dist/esm/components/chart-tooltip.js +84 -0
  239. package/dist/esm/components/chart-tooltip.js.map +1 -0
  240. package/dist/esm/components/cursor-blast-effect.d.ts +27 -0
  241. package/dist/esm/components/cursor-blast-effect.d.ts.map +1 -0
  242. package/dist/esm/components/cursor-blast-effect.js +242 -0
  243. package/dist/esm/components/cursor-blast-effect.js.map +1 -0
  244. package/dist/esm/components/data-grid/data-grid-sizing.d.ts +13 -0
  245. package/dist/esm/components/data-grid/data-grid-sizing.d.ts.map +1 -0
  246. package/dist/esm/components/data-grid/data-grid-sizing.js +38 -0
  247. package/dist/esm/components/data-grid/data-grid-sizing.js.map +1 -0
  248. package/dist/esm/components/data-grid/data-grid-toolbar.d.ts +31 -0
  249. package/dist/esm/components/data-grid/data-grid-toolbar.d.ts.map +1 -0
  250. package/dist/esm/components/data-grid/data-grid-toolbar.js +226 -0
  251. package/dist/esm/components/data-grid/data-grid-toolbar.js.map +1 -0
  252. package/dist/esm/components/data-grid/data-grid.d.ts +47 -0
  253. package/dist/esm/components/data-grid/data-grid.d.ts.map +1 -0
  254. package/dist/esm/components/data-grid/data-grid.js +923 -0
  255. package/dist/esm/components/data-grid/data-grid.js.map +1 -0
  256. package/dist/esm/components/data-grid/data-grid.test.d.ts +1 -0
  257. package/dist/esm/components/data-grid/data-grid.test.js +297 -0
  258. package/dist/esm/components/data-grid/data-grid.test.js.map +1 -0
  259. package/dist/esm/components/data-grid/index.d.ts +9 -0
  260. package/dist/esm/components/data-grid/index.js +9 -0
  261. package/dist/esm/components/data-grid/state.d.ts +34 -0
  262. package/dist/esm/components/data-grid/state.d.ts.map +1 -0
  263. package/dist/esm/components/data-grid/state.js +187 -0
  264. package/dist/esm/components/data-grid/state.js.map +1 -0
  265. package/dist/esm/components/data-grid/strings.d.ts +8 -0
  266. package/dist/esm/components/data-grid/strings.d.ts.map +1 -0
  267. package/dist/esm/components/data-grid/strings.js +39 -0
  268. package/dist/esm/components/data-grid/strings.js.map +1 -0
  269. package/dist/esm/components/data-grid/types.d.ts +278 -0
  270. package/dist/esm/components/data-grid/types.d.ts.map +1 -0
  271. package/dist/esm/components/data-grid/types.js +1 -0
  272. package/dist/esm/components/data-grid/use-data-source.d.ts +85 -0
  273. package/dist/esm/components/data-grid/use-data-source.d.ts.map +1 -0
  274. package/dist/esm/components/data-grid/use-data-source.js +242 -0
  275. package/dist/esm/components/data-grid/use-data-source.js.map +1 -0
  276. package/dist/esm/components/data-grid/use-url-state.d.ts +38 -0
  277. package/dist/esm/components/data-grid/use-url-state.d.ts.map +1 -0
  278. package/dist/esm/components/data-grid/use-url-state.js +212 -0
  279. package/dist/esm/components/data-grid/use-url-state.js.map +1 -0
  280. package/dist/esm/components/data-grid/use-url-state.test.d.ts +1 -0
  281. package/dist/esm/components/data-grid/use-url-state.test.js +91 -0
  282. package/dist/esm/components/data-grid/use-url-state.test.js.map +1 -0
  283. package/dist/esm/components/dialog.d.ts +67 -0
  284. package/dist/esm/components/dialog.d.ts.map +1 -0
  285. package/dist/esm/components/dialog.js +92 -0
  286. package/dist/esm/components/dialog.js.map +1 -0
  287. package/dist/esm/components/edit-mode.d.ts +12 -0
  288. package/dist/esm/components/edit-mode.d.ts.map +1 -0
  289. package/dist/esm/components/edit-mode.js +20 -0
  290. package/dist/esm/components/edit-mode.js.map +1 -0
  291. package/dist/esm/components/empty-state.d.ts +37 -0
  292. package/dist/esm/components/empty-state.d.ts.map +1 -0
  293. package/dist/esm/components/empty-state.js +50 -0
  294. package/dist/esm/components/empty-state.js.map +1 -0
  295. package/dist/esm/components/input.d.ts +18 -0
  296. package/dist/esm/components/input.d.ts.map +1 -0
  297. package/dist/esm/components/input.js +50 -0
  298. package/dist/esm/components/input.js.map +1 -0
  299. package/dist/esm/components/metric-card.d.ts +55 -0
  300. package/dist/esm/components/metric-card.d.ts.map +1 -0
  301. package/dist/esm/components/metric-card.js +109 -0
  302. package/dist/esm/components/metric-card.js.map +1 -0
  303. package/dist/esm/components/pill-toggle.d.ts +33 -0
  304. package/dist/esm/components/pill-toggle.d.ts.map +1 -0
  305. package/dist/esm/components/pill-toggle.js +84 -0
  306. package/dist/esm/components/pill-toggle.js.map +1 -0
  307. package/dist/esm/components/progress-bar.d.ts +35 -0
  308. package/dist/esm/components/progress-bar.d.ts.map +1 -0
  309. package/dist/esm/components/progress-bar.js +52 -0
  310. package/dist/esm/components/progress-bar.js.map +1 -0
  311. package/dist/esm/components/separator.d.ts +23 -0
  312. package/dist/esm/components/separator.d.ts.map +1 -0
  313. package/dist/esm/components/separator.js +27 -0
  314. package/dist/esm/components/separator.js.map +1 -0
  315. package/dist/esm/components/skeleton.d.ts +24 -0
  316. package/dist/esm/components/skeleton.d.ts.map +1 -0
  317. package/dist/esm/components/skeleton.js +28 -0
  318. package/dist/esm/components/skeleton.js.map +1 -0
  319. package/dist/esm/components/table.d.ts +49 -0
  320. package/dist/esm/components/table.d.ts.map +1 -0
  321. package/dist/esm/components/table.js +76 -0
  322. package/dist/esm/components/table.js.map +1 -0
  323. package/dist/esm/components/tabs.d.ts +38 -0
  324. package/dist/esm/components/tabs.d.ts.map +1 -0
  325. package/dist/esm/components/tabs.js +111 -0
  326. package/dist/esm/components/tabs.js.map +1 -0
  327. package/dist/esm/index.d.ts +24 -0
  328. package/dist/esm/index.js +27 -0
  329. package/dist/index.d.ts +37 -0
  330. package/dist/index.js +291 -0
  331. package/package.json +73 -0
@@ -0,0 +1,923 @@
1
+ "use client";
2
+
3
+ import { ArrowDown, ArrowUp, CaretDown, CaretUp, CheckSquare, MinusSquare, Square } from "@phosphor-icons/react";
4
+ import { cn } from "@hexclave/ui";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
7
+ import { exportToCsv, formatGridDate, resolveColumnValue } from "./state.js";
8
+ import { resolveDataGridStrings } from "./strings.js";
9
+ import { throwErr } from "@hexclave/shared/dist/utils/errors";
10
+ import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
11
+ import { useVirtualizer } from "@tanstack/react-virtual";
12
+ import { DesignSkeleton } from "../skeleton.js";
13
+ import { DEFAULT_COL_WIDTH, clampColumnWidth, getEffectiveMaxWidth, getEffectiveMinWidth } from "./data-grid-sizing.js";
14
+ import { DataGridToolbar } from "./data-grid-toolbar.js";
15
+
16
+ //#region src/components/data-grid/data-grid.tsx
17
+ function getEventTargetElement(target) {
18
+ if (target instanceof Element) return target;
19
+ if (target instanceof Node) return target.parentElement;
20
+ return null;
21
+ }
22
+ function isDataGridInteractiveRowClickTarget(target) {
23
+ return getEventTargetElement(target)?.closest([
24
+ "a",
25
+ "button",
26
+ "input",
27
+ "select",
28
+ "textarea",
29
+ "[role=\"button\"]",
30
+ "[role=\"menuitem\"]",
31
+ "[contenteditable]:not([contenteditable=\"false\"])",
32
+ "[data-no-row-click]"
33
+ ].join(",")) != null;
34
+ }
35
+ function shouldIgnoreRowClick(event) {
36
+ return event.defaultPrevented || isDataGridInteractiveRowClickTarget(event.target);
37
+ }
38
+ function toTanstackSorting(sorting) {
39
+ return sorting.map((s) => ({
40
+ id: s.columnId,
41
+ desc: s.direction === "desc"
42
+ }));
43
+ }
44
+ function fromTanstackSorting(sorting) {
45
+ return sorting.map((s) => ({
46
+ columnId: s.id,
47
+ direction: s.desc ? "desc" : "asc"
48
+ }));
49
+ }
50
+ function toTanstackRowSelection(ids) {
51
+ const out = {};
52
+ for (const id of ids) out[id] = true;
53
+ return out;
54
+ }
55
+ function resolveUpdater(updater, current) {
56
+ return typeof updater === "function" ? updater(current) : updater;
57
+ }
58
+ function distributeFlexWidths(sizes, visibleColumns, available) {
59
+ const flexCols = visibleColumns.filter((c) => c.flex != null && c.flex > 0);
60
+ if (flexCols.length === 0 || available <= 0) return;
61
+ const totalFlex = flexCols.reduce((acc, c) => acc + (c.flex ?? 0), 0);
62
+ let remaining = available;
63
+ flexCols.forEach((col, i) => {
64
+ const share = i === flexCols.length - 1 ? remaining : Math.floor(available * ((col.flex ?? 0) / totalFlex));
65
+ const max = col.maxWidth ?? Infinity;
66
+ const add = Math.max(0, Math.min(share, max - sizes[col.id]));
67
+ sizes[col.id] += add;
68
+ remaining -= add;
69
+ });
70
+ }
71
+ function selectSingle(current, rowId) {
72
+ const isSelected = current.selectedIds.has(rowId);
73
+ return {
74
+ selectedIds: isSelected ? /* @__PURE__ */ new Set() : new Set([rowId]),
75
+ anchorId: isSelected ? null : rowId
76
+ };
77
+ }
78
+ function selectRange(current, rowId, allRowIds, additive) {
79
+ if (current.anchorId == null) return null;
80
+ const anchorIdx = allRowIds.indexOf(current.anchorId);
81
+ const currentIdx = allRowIds.indexOf(rowId);
82
+ if (anchorIdx < 0 || currentIdx < 0) return null;
83
+ const start = Math.min(anchorIdx, currentIdx);
84
+ const end = Math.max(anchorIdx, currentIdx);
85
+ const next = additive ? new Set(current.selectedIds) : /* @__PURE__ */ new Set();
86
+ for (let i = start; i <= end; i++) next.add(allRowIds[i]);
87
+ return {
88
+ selectedIds: next,
89
+ anchorId: current.anchorId
90
+ };
91
+ }
92
+ function selectToggle(current, rowId) {
93
+ const next = new Set(current.selectedIds);
94
+ if (next.has(rowId)) next.delete(rowId);
95
+ else next.add(rowId);
96
+ return {
97
+ selectedIds: next,
98
+ anchorId: rowId
99
+ };
100
+ }
101
+ function nextSelection(input) {
102
+ const { current, rowId, mode, modifiers, allRowIds } = input;
103
+ if (mode === "single") return selectSingle(current, rowId);
104
+ if (modifiers.shift) {
105
+ const range = selectRange(current, rowId, allRowIds, modifiers.ctrl);
106
+ if (range != null) return range;
107
+ }
108
+ if (modifiers.ctrl) return selectToggle(current, rowId);
109
+ return {
110
+ selectedIds: new Set([rowId]),
111
+ anchorId: rowId
112
+ };
113
+ }
114
+ function HeaderCell({ header, col, resizable }) {
115
+ const sorted = header.column.getIsSorted();
116
+ const sortIndex = header.column.getSortIndex();
117
+ const totalSorts = header.column.getCanMultiSort() ? header.getContext().table.getState().sorting.length : 0;
118
+ const ctx = {
119
+ columnId: col.id,
120
+ columnDef: col,
121
+ isSorted: sorted === false ? false : sorted,
122
+ sortIndex: totalSorts > 1 && sortIndex >= 0 ? sortIndex + 1 : null
123
+ };
124
+ const label = typeof col.header === "function" ? col.header(ctx) : col.header;
125
+ const sortable = header.column.getCanSort();
126
+ const canResize = resizable && header.column.getCanResize();
127
+ const isResizing = header.column.getIsResizing();
128
+ return /* @__PURE__ */ jsxs("div", {
129
+ className: cn("group/header relative flex items-center gap-1.5 px-3 select-none bg-transparent overflow-hidden", "border-r border-black/[0.04] dark:border-white/[0.04] last:border-r-0", sortable && "cursor-pointer"),
130
+ style: { width: `calc(var(--col-${col.id}-size) * 1px)` },
131
+ "data-col-id": col.id,
132
+ onClick: sortable ? header.column.getToggleSortingHandler() : void 0,
133
+ role: "columnheader",
134
+ "aria-sort": sorted === "asc" ? "ascending" : sorted === "desc" ? "descending" : "none",
135
+ children: [
136
+ /* @__PURE__ */ jsx("span", {
137
+ className: cn("flex-1 min-w-0 truncate text-xs font-semibold uppercase tracking-wider text-muted-foreground", col.align === "center" && "text-center", col.align === "right" && "text-right"),
138
+ children: label
139
+ }),
140
+ sorted && /* @__PURE__ */ jsxs("span", {
141
+ className: "flex items-center gap-0.5 text-foreground/60",
142
+ children: [sorted === "asc" ? /* @__PURE__ */ jsx(ArrowUp, {
143
+ className: "h-3 w-3",
144
+ weight: "bold"
145
+ }) : /* @__PURE__ */ jsx(ArrowDown, {
146
+ className: "h-3 w-3",
147
+ weight: "bold"
148
+ }), ctx.sortIndex != null && /* @__PURE__ */ jsx("span", {
149
+ className: "text-[10px] font-medium tabular-nums",
150
+ children: ctx.sortIndex
151
+ })]
152
+ }),
153
+ !sorted && sortable && /* @__PURE__ */ jsxs("span", {
154
+ className: "hidden group-hover/header:flex items-center text-foreground/20",
155
+ children: [/* @__PURE__ */ jsx(CaretUp, {
156
+ className: "h-2.5 w-2.5 -mb-[1px]",
157
+ weight: "bold"
158
+ }), /* @__PURE__ */ jsx(CaretDown, {
159
+ className: "h-2.5 w-2.5 -mt-[1px]",
160
+ weight: "bold"
161
+ })]
162
+ }),
163
+ canResize && /* @__PURE__ */ jsx("div", {
164
+ onMouseDown: header.getResizeHandler(),
165
+ onTouchStart: header.getResizeHandler(),
166
+ onClick: (e) => {
167
+ e.preventDefault();
168
+ e.stopPropagation();
169
+ },
170
+ className: cn("absolute right-0 top-0 bottom-0 z-10 w-[5px] cursor-col-resize touch-none", "group-hover/header:bg-foreground/[0.06] hover:!bg-blue-500/30", "transition-colors duration-100", isResizing && "bg-blue-500/40")
171
+ })
172
+ ]
173
+ });
174
+ }
175
+ function DataCell({ col, row, rowId, rowIndex, isSelected, dateDisplay }) {
176
+ const value = resolveColumnValue(col, row);
177
+ const ctx = {
178
+ row,
179
+ rowId,
180
+ rowIndex,
181
+ value,
182
+ columnId: col.id,
183
+ isSelected,
184
+ dateDisplay
185
+ };
186
+ const isDateCol = col.type === "date" || col.type === "dateTime";
187
+ let content;
188
+ if (col.renderCell) content = col.renderCell(ctx);
189
+ else if (isDateCol) content = renderDateCell(value, dateDisplay, col);
190
+ else content = formatCellValue(value);
191
+ const hasCellClick = col.onCellClick || col.onCellDoubleClick;
192
+ const isWrap = col.cellOverflow === "wrap";
193
+ return /* @__PURE__ */ jsx("div", {
194
+ className: cn("flex px-3 bg-transparent overflow-hidden", "border-r border-black/[0.04] dark:border-white/[0.04] last:border-r-0", "text-sm text-foreground", isWrap ? "items-start py-2" : "items-center", col.align === "center" && "justify-center", col.align === "right" && "justify-end", hasCellClick && "cursor-pointer"),
195
+ style: { width: `calc(var(--col-${col.id}-size) * 1px)` },
196
+ "data-col-id": col.id,
197
+ role: "gridcell",
198
+ onClick: col.onCellClick ? (e) => {
199
+ e.stopPropagation();
200
+ col.onCellClick(ctx, e);
201
+ } : void 0,
202
+ onDoubleClick: col.onCellDoubleClick ? (e) => {
203
+ e.stopPropagation();
204
+ col.onCellDoubleClick(ctx, e);
205
+ } : void 0,
206
+ children: /* @__PURE__ */ jsx("div", {
207
+ className: cn("min-w-0", isWrap ? "flex-1" : "truncate"),
208
+ children: content
209
+ })
210
+ });
211
+ }
212
+ function formatCellValue(value) {
213
+ if (value == null) return /* @__PURE__ */ jsx("span", {
214
+ className: "text-muted-foreground/40",
215
+ children: "-"
216
+ });
217
+ if (typeof value === "boolean") return /* @__PURE__ */ jsx("span", {
218
+ className: cn("inline-flex items-center px-1.5 py-0.5 rounded-md text-xs font-medium", value ? "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400" : "bg-foreground/[0.04] text-muted-foreground"),
219
+ children: value ? "Yes" : "No"
220
+ });
221
+ if (value instanceof Date) return /* @__PURE__ */ jsx("span", {
222
+ className: "tabular-nums text-muted-foreground",
223
+ children: value.toLocaleDateString()
224
+ });
225
+ return /* @__PURE__ */ jsx("span", {
226
+ className: "truncate",
227
+ children: String(value)
228
+ });
229
+ }
230
+ function renderDateCell(value, dateDisplay, col) {
231
+ const { display, tooltip } = formatGridDate(value, dateDisplay, {
232
+ parseValue: col.parseValue,
233
+ dateFormat: col.dateFormat
234
+ });
235
+ if (display == null) return /* @__PURE__ */ jsx("span", {
236
+ className: "text-muted-foreground/40",
237
+ children: "-"
238
+ });
239
+ return /* @__PURE__ */ jsx("span", {
240
+ className: "tabular-nums text-muted-foreground truncate cursor-help",
241
+ title: tooltip ?? void 0,
242
+ children: display
243
+ });
244
+ }
245
+ function hashStringToInt(value) {
246
+ let hash = 0;
247
+ for (let i = 0; i < value.length; i++) hash = (hash << 5) - hash + value.charCodeAt(i) | 0;
248
+ return Math.abs(hash);
249
+ }
250
+ function SkeletonRow({ columns, height, showCheckbox }) {
251
+ return /* @__PURE__ */ jsxs("div", {
252
+ className: "flex",
253
+ style: { height },
254
+ role: "row",
255
+ children: [showCheckbox && /* @__PURE__ */ jsx("div", {
256
+ className: "flex items-center justify-center border-r border-black/[0.04] dark:border-white/[0.04]",
257
+ style: { width: 44 },
258
+ children: /* @__PURE__ */ jsx(DesignSkeleton, { className: "h-4 w-4 rounded" })
259
+ }), columns.map((col) => /* @__PURE__ */ jsx("div", {
260
+ className: "flex items-center px-3 border-r border-black/[0.04] dark:border-white/[0.04] last:border-r-0",
261
+ style: { width: `calc(var(--col-${col.id}-size) * 1px)` },
262
+ children: /* @__PURE__ */ jsx(DesignSkeleton, {
263
+ className: "h-3.5 rounded-md",
264
+ style: { width: `${40 + hashStringToInt(col.id) % 40}%` }
265
+ })
266
+ }, col.id))]
267
+ });
268
+ }
269
+ function SelectionCheckbox({ checked, indeterminate, onChange, ariaLabel, title }) {
270
+ const Icon = indeterminate ? MinusSquare : checked ? CheckSquare : Square;
271
+ return /* @__PURE__ */ jsx("button", {
272
+ className: cn("flex items-center justify-center w-full h-full", "hover:bg-foreground/[0.04] transition-colors duration-75", checked || indeterminate ? "text-blue-600 dark:text-blue-400" : "text-muted-foreground/40 hover:text-muted-foreground/60"),
273
+ onClick: (e) => {
274
+ e.stopPropagation();
275
+ onChange(e);
276
+ },
277
+ "aria-label": ariaLabel,
278
+ title: title ?? ariaLabel,
279
+ role: "checkbox",
280
+ "aria-checked": indeterminate ? "mixed" : checked,
281
+ children: /* @__PURE__ */ jsx(Icon, {
282
+ className: "h-4 w-4",
283
+ weight: checked || indeterminate ? "fill" : "regular"
284
+ })
285
+ });
286
+ }
287
+ const NOOP = () => {};
288
+ function InfiniteScrollSentinel({ onIntersect, isLoading, rootRef, strings }) {
289
+ const ref = useRef(null);
290
+ useEffect(() => {
291
+ const el = ref.current;
292
+ if (!el) return;
293
+ const observer = new IntersectionObserver((entries) => {
294
+ if (entries[0]?.isIntersecting) onIntersect();
295
+ }, {
296
+ root: rootRef?.current ?? null,
297
+ rootMargin: "200px"
298
+ });
299
+ observer.observe(el);
300
+ return () => observer.disconnect();
301
+ }, [onIntersect, rootRef]);
302
+ return /* @__PURE__ */ jsx("div", {
303
+ ref,
304
+ className: "flex items-center justify-center py-4",
305
+ children: isLoading && /* @__PURE__ */ jsxs("div", {
306
+ className: "flex items-center gap-2 text-xs text-muted-foreground",
307
+ children: [/* @__PURE__ */ jsx("div", { className: "h-3 w-3 rounded-full border-2 border-current border-t-transparent animate-spin" }), strings.loadingMore]
308
+ })
309
+ });
310
+ }
311
+ function DefaultFooter({ ctx, pagination, onChange }) {
312
+ const { state, totalRowCount, visibleRowCount, selectedRowCount, strings } = ctx;
313
+ const totalPages = totalRowCount != null ? Math.max(1, Math.ceil(totalRowCount / state.pagination.pageSize)) : void 0;
314
+ const setPage = (pageIndex) => onChange((s) => ({
315
+ ...s,
316
+ pagination: {
317
+ ...s.pagination,
318
+ pageIndex
319
+ }
320
+ }));
321
+ const setPageSize = (pageSize) => onChange((s) => ({
322
+ ...s,
323
+ pagination: {
324
+ ...s.pagination,
325
+ pageSize,
326
+ pageIndex: 0
327
+ }
328
+ }));
329
+ return /* @__PURE__ */ jsxs("div", {
330
+ className: "flex items-center justify-between px-4 py-2.5 border-t border-foreground/[0.06] text-xs text-muted-foreground",
331
+ children: [/* @__PURE__ */ jsxs("div", {
332
+ className: "flex items-center gap-3",
333
+ children: [selectedRowCount > 0 && /* @__PURE__ */ jsx("span", {
334
+ className: "font-medium text-foreground",
335
+ children: strings.rowsSelected(selectedRowCount)
336
+ }), totalRowCount != null && /* @__PURE__ */ jsxs("span", { children: [
337
+ visibleRowCount,
338
+ " of ",
339
+ totalRowCount,
340
+ " rows"
341
+ ] })]
342
+ }), pagination !== "infinite" && totalPages != null && /* @__PURE__ */ jsxs("div", {
343
+ className: "flex items-center gap-3",
344
+ children: [/* @__PURE__ */ jsxs("div", {
345
+ className: "flex items-center gap-1.5",
346
+ children: [/* @__PURE__ */ jsx("span", { children: strings.rowsPerPage }), /* @__PURE__ */ jsx("select", {
347
+ className: cn("h-7 rounded-lg border border-black/[0.08] dark:border-white/[0.08] bg-background px-1.5", "text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]", "cursor-pointer"),
348
+ value: state.pagination.pageSize,
349
+ onChange: (e) => setPageSize(Number(e.target.value)),
350
+ children: [
351
+ 10,
352
+ 25,
353
+ 50,
354
+ 100
355
+ ].map((size) => /* @__PURE__ */ jsx("option", {
356
+ value: size,
357
+ children: size
358
+ }, size))
359
+ })]
360
+ }), /* @__PURE__ */ jsxs("div", {
361
+ className: "flex items-center gap-1",
362
+ children: [
363
+ /* @__PURE__ */ jsx("button", {
364
+ className: cn("h-7 w-7 flex items-center justify-center rounded-lg", "hover:bg-foreground/[0.04] disabled:opacity-30 disabled:cursor-not-allowed", "transition-colors duration-75"),
365
+ onClick: () => setPage(state.pagination.pageIndex - 1),
366
+ disabled: state.pagination.pageIndex === 0,
367
+ "aria-label": "Previous page",
368
+ children: /* @__PURE__ */ jsx(CaretUp, {
369
+ className: "h-3.5 w-3.5 -rotate-90",
370
+ weight: "bold"
371
+ })
372
+ }),
373
+ /* @__PURE__ */ jsx("span", {
374
+ className: "px-2 tabular-nums font-medium",
375
+ children: strings.pageOf(state.pagination.pageIndex + 1, totalPages)
376
+ }),
377
+ /* @__PURE__ */ jsx("button", {
378
+ className: cn("h-7 w-7 flex items-center justify-center rounded-lg", "hover:bg-foreground/[0.04] disabled:opacity-30 disabled:cursor-not-allowed", "transition-colors duration-75"),
379
+ onClick: () => setPage(state.pagination.pageIndex + 1),
380
+ disabled: state.pagination.pageIndex >= totalPages - 1,
381
+ "aria-label": "Next page",
382
+ children: /* @__PURE__ */ jsx(CaretDown, {
383
+ className: "h-3.5 w-3.5 -rotate-90",
384
+ weight: "bold"
385
+ })
386
+ })
387
+ ]
388
+ })]
389
+ })]
390
+ });
391
+ }
392
+ /**
393
+ * Interactive table built on TanStack Table v8. Sorting, column sizing,
394
+ * visibility, ordering, and pinning are owned by the table instance; we
395
+ * layer virtualization, sticky toolbar/header/footer, infinite scroll,
396
+ * quick search, CSV export, and date-format toggling on top.
397
+ *
398
+ * The grid is display-only — it does not fetch or page data itself. Pair
399
+ * with `useDataSource` for client- or server-side data and pass the
400
+ * already-processed slice through `rows`.
401
+ *
402
+ * ```tsx
403
+ * const columns = useMemo(() => [...], []);
404
+ * const [gridState, setGridState] = useState(() => createDefaultDataGridState(columns));
405
+ * const gridData = useDataSource({
406
+ * data: users, columns, getRowId: (r) => r.id,
407
+ * sorting: gridState.sorting,
408
+ * quickSearch: gridState.quickSearch,
409
+ * pagination: gridState.pagination,
410
+ * paginationMode: "client",
411
+ * });
412
+ *
413
+ * <DataGrid
414
+ * columns={columns}
415
+ * rows={gridData.rows}
416
+ * getRowId={(r) => r.id}
417
+ * totalRowCount={gridData.totalRowCount}
418
+ * isLoading={gridData.isLoading}
419
+ * state={gridState}
420
+ * onChange={setGridState}
421
+ * />
422
+ * ```
423
+ *
424
+ * Iron rules:
425
+ * - `rows` is always `gridData.rows`, never your raw array.
426
+ * - Columns must be stable (define outside the component or wrap in `useMemo`).
427
+ * - Initialize state with `createDefaultDataGridState(columns)`.
428
+ * - `renderCell` must be a pure function — no React hooks inside.
429
+ */
430
+ function DataGrid(props) {
431
+ const { columns: allColumns, rows, getRowId, totalRowCount, isLoading = false, isRefetching = false, hasMore = false, isLoadingMore = false, onLoadMore, state, onChange, paginationMode = "paginated", selectionMode = "none", resizable = true, rowHeight: rowHeightProp = 44, estimatedRowHeight: estimatedRowHeightProp, headerHeight = 44, overscan = 5, maxHeight, fillHeight = true, stickyTop, toolbar, toolbarExtra, emptyState, loadingState, footer, footerExtra, exportFilename = "export", strings: stringsOverride, className, onRowClick, onRowDoubleClick, onSelectionChange, onSortChange, onColumnResize, onColumnVisibilityChange } = props;
432
+ const isDynamicRowHeight = rowHeightProp === "auto";
433
+ const fixedRowHeight = isDynamicRowHeight ? void 0 : rowHeightProp;
434
+ const estimatedRowHeight = estimatedRowHeightProp ?? fixedRowHeight ?? 44;
435
+ const strings = useMemo(() => resolveDataGridStrings(stringsOverride), [stringsOverride]);
436
+ const tableColumns = useMemo(() => allColumns.map((col) => ({
437
+ id: col.id,
438
+ accessorFn: (row) => resolveColumnValue(col, row),
439
+ header: typeof col.header === "string" ? col.header : col.id,
440
+ size: col.width ?? DEFAULT_COL_WIDTH,
441
+ minSize: getEffectiveMinWidth(col),
442
+ maxSize: getEffectiveMaxWidth(col),
443
+ enableSorting: col.sortable !== false,
444
+ enableHiding: col.hideable !== false,
445
+ enableResizing: col.resizable !== false,
446
+ enableMultiSort: true
447
+ })), [allColumns]);
448
+ const tanstackSorting = useMemo(() => toTanstackSorting(state.sorting), [state.sorting]);
449
+ const tanstackRowSelection = useMemo(() => toTanstackRowSelection(state.selection.selectedIds), [state.selection.selectedIds]);
450
+ const tanstackColumnPinning = useMemo(() => ({
451
+ left: [...state.columnPinning.left],
452
+ right: [...state.columnPinning.right]
453
+ }), [state.columnPinning]);
454
+ const tanstackColumnOrder = useMemo(() => [...state.columnOrder], [state.columnOrder]);
455
+ const allColumnsRef = useRef(allColumns);
456
+ allColumnsRef.current = allColumns;
457
+ const handleSortingChange = useCallback((updater) => {
458
+ const ours = fromTanstackSorting(resolveUpdater(updater, toTanstackSorting(state.sorting))).map((s) => ({ ...s }));
459
+ onChange((s) => ({
460
+ ...s,
461
+ sorting: ours,
462
+ pagination: {
463
+ ...s.pagination,
464
+ pageIndex: 0
465
+ }
466
+ }));
467
+ onSortChange?.(ours);
468
+ }, [
469
+ onChange,
470
+ onSortChange,
471
+ state.sorting
472
+ ]);
473
+ const handleColumnSizingChange = useCallback((updater) => {
474
+ const next = resolveUpdater(updater, state.columnWidths);
475
+ const clamped = {};
476
+ for (const [id, w] of Object.entries(next)) {
477
+ const col = allColumnsRef.current.find((c) => c.id === id);
478
+ clamped[id] = col ? clampColumnWidth(col, w) : w;
479
+ }
480
+ onChange((s) => ({
481
+ ...s,
482
+ columnWidths: clamped
483
+ }));
484
+ if (onColumnResize) {
485
+ for (const [id, w] of Object.entries(clamped)) if (state.columnWidths[id] !== w) onColumnResize(id, w);
486
+ }
487
+ }, [
488
+ onChange,
489
+ onColumnResize,
490
+ state.columnWidths
491
+ ]);
492
+ const handleVisibilityChange = useCallback((updater) => {
493
+ const next = resolveUpdater(updater, state.columnVisibility);
494
+ onChange((s) => ({
495
+ ...s,
496
+ columnVisibility: next
497
+ }));
498
+ onColumnVisibilityChange?.(next);
499
+ }, [
500
+ onChange,
501
+ onColumnVisibilityChange,
502
+ state.columnVisibility
503
+ ]);
504
+ const handleColumnOrderChange = useCallback((updater) => {
505
+ const next = resolveUpdater(updater, [...state.columnOrder]);
506
+ onChange((s) => ({
507
+ ...s,
508
+ columnOrder: next
509
+ }));
510
+ }, [onChange, state.columnOrder]);
511
+ const handleColumnPinningChange = useCallback((updater) => {
512
+ const next = resolveUpdater(updater, {
513
+ left: [...state.columnPinning.left],
514
+ right: [...state.columnPinning.right]
515
+ });
516
+ onChange((s) => ({
517
+ ...s,
518
+ columnPinning: {
519
+ left: next.left ?? [],
520
+ right: next.right ?? []
521
+ }
522
+ }));
523
+ }, [onChange, state.columnPinning]);
524
+ const table = useReactTable({
525
+ data: rows,
526
+ columns: tableColumns,
527
+ getRowId: (row) => getRowId(row),
528
+ getCoreRowModel: getCoreRowModel(),
529
+ state: {
530
+ sorting: tanstackSorting,
531
+ columnVisibility: state.columnVisibility,
532
+ columnSizing: state.columnWidths,
533
+ columnOrder: tanstackColumnOrder,
534
+ columnPinning: tanstackColumnPinning,
535
+ rowSelection: tanstackRowSelection
536
+ },
537
+ onSortingChange: handleSortingChange,
538
+ onColumnSizingChange: handleColumnSizingChange,
539
+ onColumnVisibilityChange: handleVisibilityChange,
540
+ onColumnOrderChange: handleColumnOrderChange,
541
+ onColumnPinningChange: handleColumnPinningChange,
542
+ columnResizeMode: "onEnd",
543
+ enableRowSelection: selectionMode !== "none",
544
+ enableMultiRowSelection: selectionMode === "multiple",
545
+ enableColumnResizing: resizable,
546
+ manualSorting: true,
547
+ manualPagination: true,
548
+ manualFiltering: true
549
+ });
550
+ const visibleColumns = useMemo(() => {
551
+ const colMap = new Map(allColumns.map((c) => [c.id, c]));
552
+ return table.getVisibleLeafColumns().map((c) => colMap.get(c.id)).filter(Boolean);
553
+ }, [
554
+ allColumns,
555
+ table,
556
+ state.columnOrder,
557
+ state.columnVisibility
558
+ ]);
559
+ const rowIds = useMemo(() => rows.map(getRowId), [rows, getRowId]);
560
+ const [containerWidth, setContainerWidth] = useState(0);
561
+ useLayoutEffect(() => {
562
+ const grid = gridRef.current;
563
+ const scroller = scrollContainerRef.current;
564
+ if (!grid) return;
565
+ const update = () => {
566
+ const w = scroller?.clientWidth ?? grid.clientWidth;
567
+ if (w > 0) setContainerWidth(w);
568
+ };
569
+ update();
570
+ const observer = new ResizeObserver(update);
571
+ observer.observe(grid);
572
+ if (scroller) observer.observe(scroller);
573
+ return () => observer.disconnect();
574
+ }, []);
575
+ const columnSizingInfo = table.getState().columnSizingInfo;
576
+ const columnSizes = useMemo(() => {
577
+ const sizes = {};
578
+ let baseTotal = selectionMode !== "none" ? 44 : 0;
579
+ const resizingId = columnSizingInfo.isResizingColumn || null;
580
+ const deltaOffset = columnSizingInfo.deltaOffset ?? 0;
581
+ for (const col of visibleColumns) {
582
+ const baseSize = table.getColumn(col.id)?.getSize() ?? col.width ?? DEFAULT_COL_WIDTH;
583
+ const liveSize = resizingId === col.id ? clampColumnWidth(col, baseSize + deltaOffset) : baseSize;
584
+ sizes[col.id] = liveSize;
585
+ baseTotal += liveSize;
586
+ }
587
+ distributeFlexWidths(sizes, visibleColumns, containerWidth - baseTotal);
588
+ return sizes;
589
+ }, [
590
+ visibleColumns,
591
+ table,
592
+ columnSizingInfo,
593
+ state.columnWidths,
594
+ containerWidth,
595
+ selectionMode
596
+ ]);
597
+ const totalContentWidth = useMemo(() => {
598
+ let total = selectionMode !== "none" ? 44 : 0;
599
+ for (const col of visibleColumns) total += columnSizes[col.id] ?? 0;
600
+ return total;
601
+ }, [
602
+ visibleColumns,
603
+ columnSizes,
604
+ selectionMode
605
+ ]);
606
+ const cssVars = useMemo(() => {
607
+ const vars = { "--grid-total-w": `${totalContentWidth}px` };
608
+ for (const col of visibleColumns) vars[`--col-${col.id}-size`] = columnSizes[col.id];
609
+ return vars;
610
+ }, [
611
+ visibleColumns,
612
+ columnSizes,
613
+ totalContentWidth
614
+ ]);
615
+ const fireSelection = useCallback((next) => {
616
+ onChange((s) => ({
617
+ ...s,
618
+ selection: next
619
+ }));
620
+ if (onSelectionChange) {
621
+ const idSet = next.selectedIds;
622
+ onSelectionChange(idSet, rows.filter((r) => idSet.has(getRowId(r))));
623
+ }
624
+ }, [
625
+ onChange,
626
+ onSelectionChange,
627
+ rows,
628
+ getRowId
629
+ ]);
630
+ const handleRowClick = useCallback((row, rowId, event) => {
631
+ if (selectionMode !== "none") fireSelection(nextSelection({
632
+ current: state.selection,
633
+ rowId,
634
+ mode: selectionMode,
635
+ modifiers: {
636
+ shift: event.shiftKey,
637
+ ctrl: event.metaKey || event.ctrlKey
638
+ },
639
+ allRowIds: rowIds
640
+ }));
641
+ onRowClick?.(row, rowId, event);
642
+ }, [
643
+ selectionMode,
644
+ state.selection,
645
+ rowIds,
646
+ fireSelection,
647
+ onRowClick
648
+ ]);
649
+ const handleSelectAll = useCallback(() => {
650
+ fireSelection(rowIds.length > 0 && rowIds.every((id) => state.selection.selectedIds.has(id)) ? {
651
+ selectedIds: /* @__PURE__ */ new Set(),
652
+ anchorId: null
653
+ } : {
654
+ selectedIds: new Set(rowIds),
655
+ anchorId: null
656
+ });
657
+ }, [
658
+ rowIds,
659
+ state.selection.selectedIds,
660
+ fireSelection
661
+ ]);
662
+ const handleExportCsv = useCallback(() => {
663
+ if (typeof window !== "undefined" && rows.length > 0) {
664
+ const totalSuffix = totalRowCount != null && totalRowCount > rows.length ? ` of ${totalRowCount} total — load more rows first to include them` : "";
665
+ if (!window.confirm(`Export ${rows.length.toLocaleString()} loaded row${rows.length === 1 ? "" : "s"}${totalSuffix}?`)) return;
666
+ }
667
+ exportToCsv(rows, visibleColumns, exportFilename);
668
+ }, [
669
+ rows,
670
+ visibleColumns,
671
+ exportFilename,
672
+ totalRowCount
673
+ ]);
674
+ const scrollContainerRef = useRef(null);
675
+ const headerScrollRef = useRef(null);
676
+ const stickyChromeRef = useRef(null);
677
+ const rowsClipRef = useRef(null);
678
+ const gridRef = useRef(null);
679
+ const measureElementFn = useCallback((el) => el.getBoundingClientRect().height, []);
680
+ const rowVirtualizer = useVirtualizer({
681
+ count: rows.length,
682
+ getScrollElement: () => scrollContainerRef.current,
683
+ estimateSize: () => estimatedRowHeight,
684
+ overscan,
685
+ getItemKey: (index) => {
686
+ const row = rows[index];
687
+ return row != null ? String(getRowId(row)) : index;
688
+ },
689
+ ...isDynamicRowHeight ? { measureElement: measureElementFn } : {}
690
+ });
691
+ useLayoutEffect(() => {
692
+ const gridEl = gridRef.current;
693
+ const stickyEl = stickyChromeRef.current;
694
+ const bodyEl = scrollContainerRef.current;
695
+ const clipEl = rowsClipRef.current;
696
+ if (!gridEl || !stickyEl || !bodyEl || !clipEl) return;
697
+ const updateClip = () => {
698
+ const stickyRect = stickyEl.getBoundingClientRect();
699
+ const clipRect = clipEl.getBoundingClientRect();
700
+ const overlap = Math.max(0, stickyRect.bottom - clipRect.top);
701
+ clipEl.style.setProperty("--data-grid-sticky-overlap", `${overlap}px`);
702
+ };
703
+ updateClip();
704
+ bodyEl.addEventListener("scroll", updateClip);
705
+ window.addEventListener("scroll", updateClip, true);
706
+ window.addEventListener("resize", updateClip);
707
+ const observer = new ResizeObserver(updateClip);
708
+ observer.observe(gridEl);
709
+ observer.observe(stickyEl);
710
+ observer.observe(bodyEl);
711
+ return () => {
712
+ bodyEl.removeEventListener("scroll", updateClip);
713
+ window.removeEventListener("scroll", updateClip, true);
714
+ window.removeEventListener("resize", updateClip);
715
+ observer.disconnect();
716
+ };
717
+ }, []);
718
+ const handleBodyScroll = useCallback(() => {
719
+ const body = scrollContainerRef.current;
720
+ const header = headerScrollRef.current;
721
+ if (body && header) header.scrollLeft = body.scrollLeft;
722
+ }, []);
723
+ const toolbarCtx = useMemo(() => ({
724
+ state,
725
+ onChange,
726
+ columns: allColumns,
727
+ visibleColumns,
728
+ totalRowCount,
729
+ selectedRowCount: state.selection.selectedIds.size,
730
+ strings,
731
+ exportCsv: handleExportCsv
732
+ }), [
733
+ state,
734
+ onChange,
735
+ allColumns,
736
+ visibleColumns,
737
+ totalRowCount,
738
+ strings,
739
+ handleExportCsv
740
+ ]);
741
+ const footerCtx = useMemo(() => ({
742
+ state,
743
+ totalRowCount,
744
+ visibleRowCount: rows.length,
745
+ selectedRowCount: state.selection.selectedIds.size,
746
+ paginationMode,
747
+ strings
748
+ }), [
749
+ state,
750
+ totalRowCount,
751
+ rows.length,
752
+ paginationMode,
753
+ strings
754
+ ]);
755
+ const allSelected = rowIds.length > 0 && rowIds.every((id) => state.selection.selectedIds.has(id));
756
+ const someSelected = !allSelected && rowIds.some((id) => state.selection.selectedIds.has(id));
757
+ const infiniteScrollRootRef = paginationMode === "infinite" && (fillHeight || maxHeight != null) ? scrollContainerRef : void 0;
758
+ const headers = useMemo(() => table.getHeaderGroups()[0]?.headers.filter((h) => visibleColumns.some((c) => c.id === h.column.id)) ?? [], [table, visibleColumns]);
759
+ const headerByColId = useMemo(() => {
760
+ const m = /* @__PURE__ */ new Map();
761
+ for (const h of headers) m.set(h.column.id, h);
762
+ return m;
763
+ }, [headers]);
764
+ const isBounded = fillHeight || maxHeight != null;
765
+ return /* @__PURE__ */ jsxs("div", {
766
+ ref: gridRef,
767
+ className: cn("isolate flex w-full min-w-0 max-w-full flex-col bg-transparent rounded-[calc(var(--radius)*2)]", fillHeight ? "min-h-0 h-full" : "min-h-0 h-auto", isBounded && "overflow-hidden", className),
768
+ style: maxHeight != null ? {
769
+ ...cssVars,
770
+ maxHeight
771
+ } : cssVars,
772
+ role: "grid",
773
+ "aria-rowcount": totalRowCount ?? rows.length,
774
+ "aria-colcount": visibleColumns.length,
775
+ children: [
776
+ /* @__PURE__ */ jsxs("div", {
777
+ ref: stickyChromeRef,
778
+ className: "sticky z-30 w-full min-w-0 shrink-0 overflow-visible rounded-t-[calc(var(--radius)*2)] bg-white/90 dark:bg-background/60 backdrop-blur-xl",
779
+ style: { top: stickyTop ?? (maxHeight != null ? 0 : "var(--data-grid-sticky-top, 0px)") },
780
+ children: [toolbar !== false && /* @__PURE__ */ jsx("div", {
781
+ className: "relative bg-transparent",
782
+ children: toolbar ? toolbar(toolbarCtx) : /* @__PURE__ */ jsx(DataGridToolbar, {
783
+ ctx: toolbarCtx,
784
+ extra: typeof toolbarExtra === "function" ? toolbarExtra(toolbarCtx) : toolbarExtra
785
+ })
786
+ }), /* @__PURE__ */ jsxs("div", {
787
+ className: "relative",
788
+ children: [isRefetching && /* @__PURE__ */ jsx("div", {
789
+ className: "absolute top-0 left-0 right-0 h-0.5 z-30 bg-foreground/[0.04] overflow-hidden",
790
+ children: /* @__PURE__ */ jsx("div", { className: "h-full w-1/3 bg-blue-500/60 rounded-full animate-pulse" })
791
+ }), /* @__PURE__ */ jsx("div", {
792
+ ref: headerScrollRef,
793
+ className: "w-full min-w-0 shrink-0 overflow-hidden border-b border-foreground/[0.06]",
794
+ children: /* @__PURE__ */ jsxs("div", {
795
+ className: "flex",
796
+ style: {
797
+ height: headerHeight,
798
+ minWidth: totalContentWidth
799
+ },
800
+ role: "row",
801
+ children: [selectionMode !== "none" && /* @__PURE__ */ jsx("div", {
802
+ className: "flex items-center justify-center border-r border-foreground/[0.04]",
803
+ style: { width: 44 },
804
+ children: selectionMode === "multiple" && /* @__PURE__ */ jsx(SelectionCheckbox, {
805
+ checked: allSelected,
806
+ indeterminate: someSelected,
807
+ onChange: handleSelectAll,
808
+ ariaLabel: "Select all rows on this page",
809
+ title: "Select all rows on this page"
810
+ })
811
+ }), visibleColumns.map((col) => {
812
+ const header = headerByColId.get(col.id);
813
+ if (!header) return null;
814
+ return /* @__PURE__ */ jsx(HeaderCell, {
815
+ header,
816
+ col,
817
+ resizable
818
+ }, col.id);
819
+ })]
820
+ })
821
+ })]
822
+ })]
823
+ }),
824
+ /* @__PURE__ */ jsx("div", {
825
+ ref: scrollContainerRef,
826
+ className: cn("relative z-0 w-full min-w-0 overflow-auto bg-transparent", isBounded ? "min-h-0 flex-1" : "flex-none", "[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar]:h-1.5", "[&::-webkit-scrollbar-track]:bg-transparent", "[&::-webkit-scrollbar-thumb]:bg-foreground/[0.08] [&::-webkit-scrollbar-thumb]:rounded-full", "[&::-webkit-scrollbar-thumb]:hover:bg-foreground/[0.15]"),
827
+ onScroll: handleBodyScroll,
828
+ children: /* @__PURE__ */ jsxs("div", {
829
+ ref: rowsClipRef,
830
+ "data-data-grid-rows-clip": "",
831
+ className: "relative z-0",
832
+ style: {
833
+ minWidth: totalContentWidth,
834
+ clipPath: "inset(var(--data-grid-sticky-overlap, 0px) 0 0 0)"
835
+ },
836
+ children: [
837
+ isLoading && /* @__PURE__ */ jsx("div", {
838
+ style: { minWidth: totalContentWidth },
839
+ children: loadingState ?? Array.from({ length: 8 }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, {
840
+ columns: visibleColumns,
841
+ height: estimatedRowHeight,
842
+ showCheckbox: selectionMode !== "none"
843
+ }, i))
844
+ }),
845
+ !isLoading && rows.length === 0 && /* @__PURE__ */ jsx("div", {
846
+ className: "flex items-center justify-center py-16 text-sm text-muted-foreground",
847
+ style: { minWidth: totalContentWidth },
848
+ children: emptyState ?? strings.noData
849
+ }),
850
+ !isLoading && rows.length > 0 && /* @__PURE__ */ jsx("div", {
851
+ style: {
852
+ height: rowVirtualizer.getTotalSize(),
853
+ width: "100%",
854
+ minWidth: totalContentWidth,
855
+ position: "relative"
856
+ },
857
+ children: rowVirtualizer.getVirtualItems().map((virtualRow) => {
858
+ const row = rows[virtualRow.index] ?? throwErr(`DataGrid: virtualized row index ${virtualRow.index} out of range (rows.length=${rows.length})`);
859
+ const rowId = getRowId(row);
860
+ const isSelected = state.selection.selectedIds.has(rowId);
861
+ const isOddRow = virtualRow.index % 2 === 1;
862
+ return /* @__PURE__ */ jsxs("div", {
863
+ ref: isDynamicRowHeight ? rowVirtualizer.measureElement : void 0,
864
+ "data-index": virtualRow.index,
865
+ className: cn("absolute left-0 w-full flex", "border-b border-black/[0.03] dark:border-white/[0.03]", "transition-colors duration-75", isSelected ? "bg-blue-500/[0.06] dark:bg-blue-400/[0.08] hover:bg-blue-500/[0.08] dark:hover:bg-blue-400/[0.1]" : isOddRow ? "bg-foreground/[0.02] dark:bg-foreground/[0.03] hover:bg-foreground/[0.04] dark:hover:bg-foreground/[0.06]" : "hover:bg-foreground/[0.025] dark:hover:bg-foreground/[0.04]", (selectionMode !== "none" || onRowClick) && "cursor-pointer"),
866
+ style: {
867
+ ...isDynamicRowHeight ? { minHeight: estimatedRowHeight } : { height: fixedRowHeight },
868
+ transform: `translateY(${virtualRow.start}px)`
869
+ },
870
+ onClick: (e) => {
871
+ if (!shouldIgnoreRowClick(e)) handleRowClick(row, rowId, e);
872
+ },
873
+ onDoubleClick: (e) => {
874
+ if (!shouldIgnoreRowClick(e)) onRowDoubleClick?.(row, rowId, e);
875
+ },
876
+ role: "row",
877
+ "aria-rowindex": virtualRow.index + 2,
878
+ "aria-selected": isSelected,
879
+ "data-row-id": rowId,
880
+ "data-state": isSelected ? "selected" : void 0,
881
+ children: [selectionMode !== "none" && /* @__PURE__ */ jsx("div", {
882
+ className: "flex items-center justify-center border-r border-black/[0.04] dark:border-white/[0.04]",
883
+ style: { width: 44 },
884
+ children: /* @__PURE__ */ jsx(SelectionCheckbox, {
885
+ checked: isSelected,
886
+ onChange: (event) => handleRowClick(row, rowId, event),
887
+ ariaLabel: `Select row ${rowId}`
888
+ })
889
+ }), visibleColumns.map((col) => /* @__PURE__ */ jsx(DataCell, {
890
+ col,
891
+ row,
892
+ rowId,
893
+ rowIndex: virtualRow.index,
894
+ isSelected,
895
+ dateDisplay: state.dateDisplay
896
+ }, col.id))]
897
+ }, rowId);
898
+ })
899
+ }),
900
+ paginationMode === "infinite" && hasMore && !isLoading && /* @__PURE__ */ jsx(InfiniteScrollSentinel, {
901
+ onIntersect: onLoadMore ?? NOOP,
902
+ isLoading: isLoadingMore,
903
+ rootRef: infiniteScrollRootRef,
904
+ strings
905
+ })
906
+ ]
907
+ })
908
+ }),
909
+ footer !== false && /* @__PURE__ */ jsxs("div", {
910
+ className: "sticky bottom-0 z-30 shrink-0 overflow-hidden rounded-b-[calc(var(--radius)*2)] bg-white/90 dark:bg-background/60 backdrop-blur-xl",
911
+ children: [footer ? footer(footerCtx) : /* @__PURE__ */ jsx(DefaultFooter, {
912
+ ctx: footerCtx,
913
+ pagination: paginationMode,
914
+ onChange
915
+ }), footerExtra && (typeof footerExtra === "function" ? footerExtra(footerCtx) : footerExtra)]
916
+ })
917
+ ]
918
+ });
919
+ }
920
+
921
+ //#endregion
922
+ export { DataGrid, isDataGridInteractiveRowClickTarget };
923
+ //# sourceMappingURL=data-grid.js.map