@crewlethq/ui 0.2.0 → 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 (497) hide show
  1. package/README.md +1714 -14
  2. package/dist/Accordion/Accordion.d.ts +54 -0
  3. package/dist/Accordion/index.d.ts +4 -0
  4. package/dist/Accordion/index.js +6 -0
  5. package/dist/Accordion-ZI2WLD5C.css +87 -0
  6. package/dist/AddPill/AddPill.d.ts +114 -0
  7. package/dist/AddPill/index.d.ts +3 -0
  8. package/dist/AddPill/index.js +3 -0
  9. package/dist/AddPill-DFWXYLIQ.css +434 -0
  10. package/dist/Announcer/Announcer.d.ts +15 -0
  11. package/dist/Announcer/index.d.ts +2 -0
  12. package/dist/Announcer/index.js +3 -0
  13. package/dist/AppShell/AppShell.d.ts +193 -0
  14. package/dist/AppShell/index.d.ts +3 -0
  15. package/dist/AppShell/index.js +6 -0
  16. package/dist/AppShell-NVE6LHNI.css +395 -0
  17. package/dist/Avatar/Avatar.d.ts +104 -0
  18. package/dist/Avatar/index.d.ts +3 -0
  19. package/dist/Avatar/index.js +2 -0
  20. package/dist/Avatar-P2KRQM2B.css +156 -0
  21. package/dist/BrandLockup/BrandLockup.d.ts +41 -0
  22. package/dist/BrandLockup/index.d.ts +3 -0
  23. package/dist/BrandLockup/index.js +2 -0
  24. package/dist/BrandLockup-6ISDEHPJ.css +108 -0
  25. package/dist/Button/Button.d.ts +88 -0
  26. package/dist/Button/index.d.ts +3 -0
  27. package/dist/Button/index.js +3 -0
  28. package/dist/Button-D4J6B4MA.css +302 -0
  29. package/dist/CalendarGrid/CalendarGrid.d.ts +87 -0
  30. package/dist/CalendarGrid/index.d.ts +3 -0
  31. package/dist/CalendarGrid/index.js +2 -0
  32. package/dist/CalendarGrid-V6TQ5QKS.css +128 -0
  33. package/dist/Callout/Callout.d.ts +47 -0
  34. package/dist/Callout/index.d.ts +3 -0
  35. package/dist/Callout/index.js +2 -0
  36. package/dist/Callout-S7QDWHDL.css +111 -0
  37. package/dist/Canvas/Canvas.d.ts +234 -0
  38. package/dist/Canvas/geometry.d.ts +249 -0
  39. package/dist/Canvas/index.d.ts +5 -0
  40. package/dist/Canvas/index.js +8 -0
  41. package/dist/Canvas/layerNode.d.ts +20 -0
  42. package/dist/Canvas-Q6JETCWR.css +315 -0
  43. package/dist/Card/Card.d.ts +142 -0
  44. package/dist/Card/headerSlot.d.ts +65 -0
  45. package/dist/Card/index.d.ts +5 -0
  46. package/dist/Card/index.js +6 -0
  47. package/dist/Card-AHX3Q2JD.css +428 -0
  48. package/dist/Charts/ActivityStrip.d.ts +45 -0
  49. package/dist/Charts/BarList.d.ts +51 -0
  50. package/dist/Charts/Legend.d.ts +32 -0
  51. package/dist/Charts/StackedBar.d.ts +38 -0
  52. package/dist/Charts/TimeSeries.d.ts +92 -0
  53. package/dist/Charts/dataColor.d.ts +20 -0
  54. package/dist/Charts/index.d.ts +12 -0
  55. package/dist/Charts/index.js +3 -0
  56. package/dist/Charts-D7G2BSXH.css +277 -0
  57. package/dist/Checkbox/Checkbox.d.ts +45 -0
  58. package/dist/Checkbox/index.d.ts +3 -0
  59. package/dist/Checkbox/index.js +2 -0
  60. package/dist/Checkbox-VGW26YLQ.css +111 -0
  61. package/dist/CodeBlock/CodeBlock.d.ts +60 -0
  62. package/dist/CodeBlock/index.d.ts +3 -0
  63. package/dist/CodeBlock/index.js +7 -0
  64. package/dist/CodeBlock-U2W6NNVC.css +153 -0
  65. package/dist/Combobox/Combobox.d.ts +89 -0
  66. package/dist/Combobox/index.d.ts +3 -0
  67. package/dist/Combobox/index.js +8 -0
  68. package/dist/Combobox-4FUVYIE7.css +80 -0
  69. package/dist/CommandPalette/CommandPalette.d.ts +77 -0
  70. package/dist/CommandPalette/index.d.ts +3 -0
  71. package/dist/CommandPalette/index.js +11 -0
  72. package/dist/CommandPalette-CSJDUCQA.css +115 -0
  73. package/dist/Container/Container.d.ts +17 -0
  74. package/dist/Container/index.d.ts +3 -0
  75. package/dist/Container/index.js +2 -0
  76. package/dist/Container-3TSKMGNI.css +52 -0
  77. package/dist/Copyable/CopyButton.d.ts +54 -0
  78. package/dist/Copyable/Copyable.d.ts +34 -0
  79. package/dist/Copyable/index.d.ts +5 -0
  80. package/dist/Copyable/index.js +6 -0
  81. package/dist/Copyable-5PNRFOLS.css +125 -0
  82. package/dist/Count/Count.d.ts +24 -0
  83. package/dist/Count/index.d.ts +3 -0
  84. package/dist/Count/index.js +3 -0
  85. package/dist/Count-ZVCJ6VPD.css +20 -0
  86. package/dist/DataTable/CopyableCell.d.ts +12 -0
  87. package/dist/DataTable/DataTable.d.ts +615 -0
  88. package/dist/DataTable/RowActionsMenu.d.ts +7 -0
  89. package/dist/DataTable/index.d.ts +7 -0
  90. package/dist/DataTable/index.js +14 -0
  91. package/dist/DataTable-ITNACQ2X.css +2020 -0
  92. package/dist/DataView/DataView.d.ts +109 -0
  93. package/dist/DataView/DataViewToolbar.d.ts +87 -0
  94. package/dist/DataView/FilterAxisBar.d.ts +103 -0
  95. package/dist/DataView/columns.d.ts +35 -0
  96. package/dist/DataView/filters.d.ts +184 -0
  97. package/dist/DataView/index.d.ts +11 -0
  98. package/dist/DataView/index.js +25 -0
  99. package/dist/DataView-256YF32J.css +441 -0
  100. package/dist/DateTimePicker/DateTimePicker.d.ts +91 -0
  101. package/dist/DateTimePicker/index.d.ts +3 -0
  102. package/dist/DateTimePicker/index.js +9 -0
  103. package/dist/DateTimePicker-22VNXRWC.css +199 -0
  104. package/dist/DescriptionList/DescriptionList.d.ts +36 -0
  105. package/dist/DescriptionList/index.d.ts +3 -0
  106. package/dist/DescriptionList/index.js +2 -0
  107. package/dist/DescriptionList-YYY3V3O6.css +59 -0
  108. package/dist/DiffList/DiffList.d.ts +47 -0
  109. package/dist/DiffList/index.d.ts +3 -0
  110. package/dist/DiffList/index.js +3 -0
  111. package/dist/DiffList-3EX64AAE.css +94 -0
  112. package/dist/Disclosure/Disclosure.d.ts +56 -0
  113. package/dist/Disclosure/anatomy.d.ts +43 -0
  114. package/dist/Disclosure/index.d.ts +5 -0
  115. package/dist/Disclosure/index.js +6 -0
  116. package/dist/Disclosure-VKBJJIZ7.css +176 -0
  117. package/dist/EmptyState/EmptyState.d.ts +39 -0
  118. package/dist/EmptyState/index.d.ts +3 -0
  119. package/dist/EmptyState/index.js +3 -0
  120. package/dist/EmptyState-C6HRBGT7.css +73 -0
  121. package/dist/EmptyValue/EmptyValue.d.ts +31 -0
  122. package/dist/EmptyValue/index.d.ts +3 -0
  123. package/dist/EmptyValue/index.js +3 -0
  124. package/dist/EmptyValue-4B6ODXHT.css +12 -0
  125. package/dist/EntityChip/EntityChip.d.ts +40 -0
  126. package/dist/EntityChip/index.d.ts +3 -0
  127. package/dist/EntityChip/index.js +3 -0
  128. package/dist/EntityChip-LUCPZBBG.css +64 -0
  129. package/dist/ErrorBoundary/ErrorBoundary.d.ts +58 -0
  130. package/dist/ErrorBoundary/index.d.ts +3 -0
  131. package/dist/ErrorBoundary/index.js +4 -0
  132. package/dist/ErrorBoundary-ME36CQTA.css +59 -0
  133. package/dist/Eyebrow/Eyebrow.d.ts +18 -0
  134. package/dist/Eyebrow/index.d.ts +3 -0
  135. package/dist/Eyebrow/index.js +2 -0
  136. package/dist/Eyebrow-5NREGHQH.css +46 -0
  137. package/dist/FilterChip/FilterChip.d.ts +68 -0
  138. package/dist/FilterChip/index.d.ts +3 -0
  139. package/dist/FilterChip/index.js +3 -0
  140. package/dist/FilterChip-GTGLLOXE.css +107 -0
  141. package/dist/Fullscreen/index.d.ts +2 -0
  142. package/dist/Fullscreen/index.js +1 -0
  143. package/dist/Fullscreen/useFullscreen.d.ts +32 -0
  144. package/dist/IconButton/IconButton.d.ts +45 -0
  145. package/dist/IconButton/index.d.ts +3 -0
  146. package/dist/IconButton/index.js +3 -0
  147. package/dist/IconButton-VQGNMJDI.css +158 -0
  148. package/dist/ImageUpload/ImageUpload.d.ts +37 -0
  149. package/dist/ImageUpload/index.d.ts +3 -0
  150. package/dist/ImageUpload/index.js +3 -0
  151. package/dist/ImageUpload-HKFIZR6D.css +193 -0
  152. package/dist/InlineCode/InlineCode.d.ts +37 -0
  153. package/dist/InlineCode/index.d.ts +3 -0
  154. package/dist/InlineCode/index.js +2 -0
  155. package/dist/InlineCode-6WSR5COL.css +65 -0
  156. package/dist/Input/FormField.d.ts +61 -0
  157. package/dist/Input/FormRow.d.ts +6 -0
  158. package/dist/Input/FormSection.d.ts +28 -0
  159. package/dist/Input/Input.d.ts +98 -0
  160. package/dist/Input/Label.d.ts +31 -0
  161. package/dist/Input/ReadOnlyField.d.ts +30 -0
  162. package/dist/Input/Textarea.d.ts +16 -0
  163. package/dist/Input/index.d.ts +15 -0
  164. package/dist/Input/index.js +5 -0
  165. package/dist/Input-2PU5CPKK.css +616 -0
  166. package/dist/Kbd/Kbd.d.ts +40 -0
  167. package/dist/Kbd/index.d.ts +3 -0
  168. package/dist/Kbd/index.js +3 -0
  169. package/dist/Kbd-W66MXQI5.css +61 -0
  170. package/dist/Layer/LayerHost.d.ts +23 -0
  171. package/dist/Layer/index.d.ts +7 -0
  172. package/dist/Layer/index.js +3 -0
  173. package/dist/Layer/place.d.ts +63 -0
  174. package/dist/Layer/stack.d.ts +159 -0
  175. package/dist/Layer-NAFSGCFA.css +23 -0
  176. package/dist/Layout/Layout.d.ts +104 -0
  177. package/dist/Layout/index.d.ts +3 -0
  178. package/dist/Layout/index.js +2 -0
  179. package/dist/Layout-2ZCV3IGF.css +171 -0
  180. package/dist/Link/Link.d.ts +45 -0
  181. package/dist/Link/index.d.ts +3 -0
  182. package/dist/Link/index.js +3 -0
  183. package/dist/Link-6BEFNMN2.css +80 -0
  184. package/dist/List/List.d.ts +73 -0
  185. package/dist/List/index.d.ts +3 -0
  186. package/dist/List/index.js +3 -0
  187. package/dist/List-XTHESXLR.css +161 -0
  188. package/dist/ListInput/ListInput.d.ts +68 -0
  189. package/dist/ListInput/index.d.ts +3 -0
  190. package/dist/ListInput/index.js +10 -0
  191. package/dist/ListInput-O7LJKOIG.css +147 -0
  192. package/dist/Listbox/index.d.ts +5 -0
  193. package/dist/Listbox/index.js +2 -0
  194. package/dist/Listbox/useListbox.d.ts +97 -0
  195. package/dist/Listbox/useOptionKeys.d.ts +64 -0
  196. package/dist/Listbox-X2DOTSQA.css +110 -0
  197. package/dist/Menu/Menu.d.ts +118 -0
  198. package/dist/Menu/index.d.ts +3 -0
  199. package/dist/Menu/index.js +7 -0
  200. package/dist/Menu-6DE7I66I.css +222 -0
  201. package/dist/Meter/Meter.d.ts +49 -0
  202. package/dist/Meter/index.d.ts +3 -0
  203. package/dist/Meter/index.js +3 -0
  204. package/dist/Meter-SKOOXQBC.css +87 -0
  205. package/dist/Modal/ConfirmModal.d.ts +74 -0
  206. package/dist/Modal/Modal.d.ts +154 -0
  207. package/dist/Modal/index.d.ts +5 -0
  208. package/dist/Modal/index.js +8 -0
  209. package/dist/Modal-XYQJ4BL6.css +484 -0
  210. package/dist/NewItemsNotice/NewItemsNotice.d.ts +28 -0
  211. package/dist/NewItemsNotice/index.d.ts +3 -0
  212. package/dist/NewItemsNotice/index.js +4 -0
  213. package/dist/NewItemsNotice-T4DSSPVV.css +60 -0
  214. package/dist/OrgLabel/OrgLabel.d.ts +117 -0
  215. package/dist/OrgLabel/index.d.ts +3 -0
  216. package/dist/OrgLabel/index.js +2 -0
  217. package/dist/OrgLabel-D7U6QJZD.css +293 -0
  218. package/dist/OrgNode/OrgNode.d.ts +103 -0
  219. package/dist/OrgNode/index.d.ts +3 -0
  220. package/dist/OrgNode/index.js +3 -0
  221. package/dist/OrgNode-BT7T2Q2X.css +214 -0
  222. package/dist/OrgTable/OrgTable.d.ts +113 -0
  223. package/dist/OrgTable/index.d.ts +3 -0
  224. package/dist/OrgTable/index.js +11 -0
  225. package/dist/OrgTable-VWMFC3TB.css +360 -0
  226. package/dist/PageHeader/PageHeader.d.ts +35 -0
  227. package/dist/PageHeader/index.d.ts +3 -0
  228. package/dist/PageHeader/index.js +3 -0
  229. package/dist/PageHeader-6EYWQXRE.css +88 -0
  230. package/dist/Popover/Popover.d.ts +91 -0
  231. package/dist/Popover/index.d.ts +3 -0
  232. package/dist/Popover/index.js +4 -0
  233. package/dist/Popover-WJGCF3ZQ.css +185 -0
  234. package/dist/PricingCard/PricingCard.d.ts +56 -0
  235. package/dist/PricingCard/index.d.ts +3 -0
  236. package/dist/PricingCard/index.js +4 -0
  237. package/dist/PricingCard-JFI7RYXP.css +278 -0
  238. package/dist/Prose/Prose.d.ts +33 -0
  239. package/dist/Prose/index.d.ts +3 -0
  240. package/dist/Prose/index.js +2 -0
  241. package/dist/Prose-BTXNFT2Q.css +99 -0
  242. package/dist/RelativeTime/RelativeTime.d.ts +31 -0
  243. package/dist/RelativeTime/clock.d.ts +9 -0
  244. package/dist/RelativeTime/format.d.ts +38 -0
  245. package/dist/RelativeTime/index.d.ts +6 -0
  246. package/dist/RelativeTime/index.js +4 -0
  247. package/dist/RelativeTime-EBAQPGO2.css +10 -0
  248. package/dist/SearchTrigger/SearchTrigger.d.ts +29 -0
  249. package/dist/SearchTrigger/index.d.ts +3 -0
  250. package/dist/SearchTrigger/index.js +2 -0
  251. package/dist/SearchTrigger-QXOYAUUY.css +79 -0
  252. package/dist/Section/Section.d.ts +41 -0
  253. package/dist/Section/index.d.ts +3 -0
  254. package/dist/Section/index.js +3 -0
  255. package/dist/Section-QRUPRIQ2.css +127 -0
  256. package/dist/SegmentedControl/SegmentedControl.d.ts +68 -0
  257. package/dist/SegmentedControl/index.d.ts +4 -0
  258. package/dist/SegmentedControl/index.js +5 -0
  259. package/dist/SegmentedControl-X3BI3XU4.css +68 -0
  260. package/dist/Select/Select.d.ts +138 -0
  261. package/dist/Select/index.d.ts +3 -0
  262. package/dist/Select/index.js +5 -0
  263. package/dist/Select-2X77FSWR.css +350 -0
  264. package/dist/Shortcut/index.d.ts +2 -0
  265. package/dist/Shortcut/index.js +4 -0
  266. package/dist/Shortcut/useShortcut.d.ts +68 -0
  267. package/dist/SidebarNav/SidebarNav.d.ts +117 -0
  268. package/dist/SidebarNav/index.d.ts +3 -0
  269. package/dist/SidebarNav/index.js +3 -0
  270. package/dist/SidebarNav-QGSFKZYA.css +319 -0
  271. package/dist/Skeleton/Skeleton.d.ts +50 -0
  272. package/dist/Skeleton/index.d.ts +3 -0
  273. package/dist/Skeleton/index.js +3 -0
  274. package/dist/Skeleton-V735HRGM.css +421 -0
  275. package/dist/StatCard/StatCard.d.ts +56 -0
  276. package/dist/StatCard/index.d.ts +3 -0
  277. package/dist/StatCard/index.js +3 -0
  278. package/dist/StatCard-KYPKZUWX.css +111 -0
  279. package/dist/StatGroup/StatGroup.d.ts +20 -0
  280. package/dist/StatGroup/index.d.ts +3 -0
  281. package/dist/StatGroup/index.js +2 -0
  282. package/dist/StatGroup-TGB6AEKM.css +80 -0
  283. package/dist/StatusDot/StatusDot.d.ts +25 -0
  284. package/dist/StatusDot/index.d.ts +3 -0
  285. package/dist/StatusDot/index.js +2 -0
  286. package/dist/StatusDot-HA2L2FSX.css +84 -0
  287. package/dist/Switch/Switch.d.ts +38 -0
  288. package/dist/Switch/index.d.ts +3 -0
  289. package/dist/Switch/index.js +2 -0
  290. package/dist/Switch-U4OWK4CL.css +169 -0
  291. package/dist/Table/Table.d.ts +51 -0
  292. package/dist/Table/index.d.ts +3 -0
  293. package/dist/Table/index.js +3 -0
  294. package/dist/Table-MDOLVUAW.css +159 -0
  295. package/dist/Tabs/Tabs.d.ts +97 -0
  296. package/dist/Tabs/index.d.ts +3 -0
  297. package/dist/Tabs/index.js +4 -0
  298. package/dist/Tabs/roving.d.ts +36 -0
  299. package/dist/Tabs-VLICJFVB.css +275 -0
  300. package/dist/Tag/Tag.d.ts +107 -0
  301. package/dist/Tag/index.d.ts +3 -0
  302. package/dist/Tag/index.js +3 -0
  303. package/dist/Tag-VNZEYLB6.css +406 -0
  304. package/dist/TagGroup/TagGroup.d.ts +41 -0
  305. package/dist/TagGroup/index.d.ts +3 -0
  306. package/dist/TagGroup/index.js +4 -0
  307. package/dist/TagGroup-APC2EFH4.css +75 -0
  308. package/dist/TagsInput/TagsInput.d.ts +112 -0
  309. package/dist/TagsInput/index.d.ts +3 -0
  310. package/dist/TagsInput/index.js +10 -0
  311. package/dist/TagsInput-W4P36PRJ.css +168 -0
  312. package/dist/Text/Text.d.ts +67 -0
  313. package/dist/Text/index.d.ts +3 -0
  314. package/dist/Text/index.js +2 -0
  315. package/dist/Text-XIPYYZX2.css +154 -0
  316. package/dist/ThemeSwitcher/ThemeSwitcher.d.ts +47 -0
  317. package/dist/ThemeSwitcher/index.d.ts +4 -0
  318. package/dist/ThemeSwitcher/index.js +6 -0
  319. package/dist/ThemeSwitcher/preferences.d.ts +51 -0
  320. package/dist/TimeWindowPicker/TimeWindowPicker.d.ts +231 -0
  321. package/dist/TimeWindowPicker/index.d.ts +3 -0
  322. package/dist/TimeWindowPicker/index.js +13 -0
  323. package/dist/TimeWindowPicker/mask.d.ts +82 -0
  324. package/dist/TimeWindowPicker-7I7KWCMU.css +403 -0
  325. package/dist/Timeline/Timeline.d.ts +51 -0
  326. package/dist/Timeline/index.d.ts +3 -0
  327. package/dist/Timeline/index.js +3 -0
  328. package/dist/Timeline-27SYKOFX.css +144 -0
  329. package/dist/Toaster/Toaster.d.ts +108 -0
  330. package/dist/Toaster/index.d.ts +3 -0
  331. package/dist/Toaster/index.js +5 -0
  332. package/dist/Toaster-NVDCEIP5.css +306 -0
  333. package/dist/Toolbar/Toolbar.d.ts +62 -0
  334. package/dist/Toolbar/index.d.ts +3 -0
  335. package/dist/Toolbar/index.js +4 -0
  336. package/dist/Toolbar-IP6LXN45.css +48 -0
  337. package/dist/Tooltip/Tooltip.d.ts +51 -0
  338. package/dist/Tooltip/index.d.ts +3 -0
  339. package/dist/Tooltip/index.js +4 -0
  340. package/dist/Tooltip-LKQF7CE4.css +71 -0
  341. package/dist/Tree/index.d.ts +8 -0
  342. package/dist/Tree/index.js +1 -0
  343. package/dist/Tree/layout.d.ts +160 -0
  344. package/dist/Tree/model.d.ts +110 -0
  345. package/dist/Tree/useMeasuredSizes.d.ts +61 -0
  346. package/dist/Tree/useTreeState.d.ts +89 -0
  347. package/dist/TreeCanvas/TreeCanvas.d.ts +384 -0
  348. package/dist/TreeCanvas/index.d.ts +3 -0
  349. package/dist/TreeCanvas/index.js +10 -0
  350. package/dist/TreeCanvas/motion.d.ts +59 -0
  351. package/dist/TreeCanvas-WBNQPHC7.css +1098 -0
  352. package/dist/TreeGrid/TreeGrid.d.ts +142 -0
  353. package/dist/TreeGrid/index.d.ts +3 -0
  354. package/dist/TreeGrid/index.js +8 -0
  355. package/dist/TreeGrid-NSW7VMOX.css +132 -0
  356. package/dist/VisuallyHidden/VisuallyHidden.d.ts +23 -0
  357. package/dist/VisuallyHidden/index.d.ts +3 -0
  358. package/dist/VisuallyHidden/index.js +2 -0
  359. package/dist/VisuallyHidden-L552H7OA.css +21 -0
  360. package/dist/chunk-22O7LAW2.js +41 -0
  361. package/dist/chunk-23DHIMJA.js +38 -0
  362. package/dist/chunk-2EOKFKHX.js +263 -0
  363. package/dist/chunk-2PRH365R.js +74 -0
  364. package/dist/chunk-2ZQMA2WB.js +57 -0
  365. package/dist/chunk-3CZ7XAVY.js +139 -0
  366. package/dist/chunk-3EYF6HKB.js +135 -0
  367. package/dist/chunk-3ZP55QZE.js +40 -0
  368. package/dist/chunk-53DVJCVW.js +14 -0
  369. package/dist/chunk-5C5YMZQU.js +51 -0
  370. package/dist/chunk-5EKIWVOR.js +132 -0
  371. package/dist/chunk-5IMACPJS.js +495 -0
  372. package/dist/chunk-5KPQ6D7N.js +54 -0
  373. package/dist/chunk-5SDBMKUO.js +297 -0
  374. package/dist/chunk-5WS6L6FA.js +114 -0
  375. package/dist/chunk-7EM5T4ME.js +39 -0
  376. package/dist/chunk-7FZ53WDJ.js +163 -0
  377. package/dist/chunk-7HPRF5XN.js +525 -0
  378. package/dist/chunk-7RPGY3JE.js +43 -0
  379. package/dist/chunk-A2UXBCLO.js +48 -0
  380. package/dist/chunk-ARMRX2YV.js +96 -0
  381. package/dist/chunk-AV2DXAEL.js +27 -0
  382. package/dist/chunk-BHHIIK3M.js +17 -0
  383. package/dist/chunk-BZFWDIV6.js +9 -0
  384. package/dist/chunk-BZYDZBAN.js +123 -0
  385. package/dist/chunk-CMEE37QJ.js +628 -0
  386. package/dist/chunk-D3OADIM6.js +112 -0
  387. package/dist/chunk-DD5BBGBE.js +162 -0
  388. package/dist/chunk-EHMQQHYR.js +1652 -0
  389. package/dist/chunk-EN6K2IFA.js +256 -0
  390. package/dist/chunk-EPOOQZYA.js +118 -0
  391. package/dist/chunk-ESCO4XYW.js +144 -0
  392. package/dist/chunk-EUCC37WY.js +14 -0
  393. package/dist/chunk-EV6IMYJ6.js +62 -0
  394. package/dist/chunk-F27EPQ7D.js +68 -0
  395. package/dist/chunk-F4PJZ4ED.js +245 -0
  396. package/dist/chunk-F6OE5FH3.js +49 -0
  397. package/dist/chunk-FBZAKNSX.js +263 -0
  398. package/dist/chunk-FEFTGVMF.js +46 -0
  399. package/dist/chunk-G2QFRTJ2.js +823 -0
  400. package/dist/chunk-GHYY2WPF.js +907 -0
  401. package/dist/chunk-GTOUGQQK.js +147 -0
  402. package/dist/chunk-GUIF6Q6N.js +143 -0
  403. package/dist/chunk-GXQ3B46I.js +216 -0
  404. package/dist/chunk-H4FBTAYS.js +130 -0
  405. package/dist/chunk-HOXGBLEY.js +37 -0
  406. package/dist/chunk-HQNHV7D6.js +54 -0
  407. package/dist/chunk-HTDFCRJZ.js +92 -0
  408. package/dist/chunk-HZ5XZNPS.js +98 -0
  409. package/dist/chunk-IAJLHVUA.js +28 -0
  410. package/dist/chunk-IJ7QXNIJ.js +1 -0
  411. package/dist/chunk-ITHXJHBB.js +280 -0
  412. package/dist/chunk-JCSA3XVH.js +32 -0
  413. package/dist/chunk-KLJCCMF3.js +97 -0
  414. package/dist/chunk-LGCPQIOZ.js +49 -0
  415. package/dist/chunk-LWKJQTOM.js +77 -0
  416. package/dist/chunk-MNAXYY3R.js +215 -0
  417. package/dist/chunk-NN62JQLR.js +29 -0
  418. package/dist/chunk-NPZY6YYL.js +251 -0
  419. package/dist/chunk-NTRZGNEX.js +529 -0
  420. package/dist/chunk-O6232G37.js +273 -0
  421. package/dist/chunk-O67VF5MS.js +58 -0
  422. package/dist/chunk-ODEQTPFM.js +6 -0
  423. package/dist/chunk-PNFASD6F.js +98 -0
  424. package/dist/chunk-PQADV6P6.js +19 -0
  425. package/dist/chunk-PZSWF74H.js +15 -0
  426. package/dist/chunk-Q4ZPPART.js +26 -0
  427. package/dist/chunk-QNCVHRZL.js +17 -0
  428. package/dist/chunk-QVE4GJAT.js +15 -0
  429. package/dist/chunk-QYOFACSP.js +36 -0
  430. package/dist/chunk-RA2ULG6H.js +29 -0
  431. package/dist/chunk-RDGD7Z7I.js +350 -0
  432. package/dist/chunk-RK4XPHVG.js +16 -0
  433. package/dist/chunk-RSAQOKH3.js +38 -0
  434. package/dist/chunk-S2XHHEW4.js +84 -0
  435. package/dist/chunk-S4GZWSKR.js +137 -0
  436. package/dist/chunk-SFZOKW2G.js +52 -0
  437. package/dist/chunk-T7FKOJKW.js +221 -0
  438. package/dist/chunk-UG46QBLT.js +325 -0
  439. package/dist/chunk-UOGSZKLT.js +134 -0
  440. package/dist/chunk-V2XMNLMS.js +52 -0
  441. package/dist/chunk-V663QU4R.js +51 -0
  442. package/dist/chunk-W4ENKCXJ.js +40 -0
  443. package/dist/chunk-W5J7R5EB.js +107 -0
  444. package/dist/chunk-WNI2WSJF.js +27 -0
  445. package/dist/chunk-XDTYBF2F.js +36 -0
  446. package/dist/chunk-XN4JBAN3.js +32 -0
  447. package/dist/chunk-XV6WRMBC.js +211 -0
  448. package/dist/chunk-YLYOWZ4V.js +33 -0
  449. package/dist/chunk-YMWONFSI.js +170 -0
  450. package/dist/chunk-ZCR6YGQ4.js +1 -0
  451. package/dist/generated/index.d.ts +83 -0
  452. package/dist/generated/index.js +91 -0
  453. package/dist/index.d.ts +1 -1217
  454. package/dist/index.js +91 -4518
  455. package/dist/styles.css +14841 -4274
  456. package/dist/utils/cx.d.ts +10 -0
  457. package/dist/utils/headingLevel.d.ts +16 -0
  458. package/dist/utils/index.d.ts +6 -0
  459. package/dist/utils/index.js +4 -0
  460. package/dist/utils/tone.d.ts +25 -0
  461. package/dist/utils/useClipboard.d.ts +30 -0
  462. package/package.json +18 -10
  463. package/scripts/bundle-css.mjs +25 -0
  464. package/scripts/check-css-literals.mjs +166 -0
  465. package/scripts/check-css-variables.mjs +184 -0
  466. package/scripts/check-css.mjs +27 -0
  467. package/scripts/css-source.mjs +67 -0
  468. package/scripts/write-barrel.mjs +60 -0
  469. package/dist/Accordion-NIMJQIOI.css +0 -88
  470. package/dist/AppShell-ZW3NSFBP.css +0 -51
  471. package/dist/Avatar-V6NG6Q45.css +0 -67
  472. package/dist/Button-XGCTXXYP.css +0 -174
  473. package/dist/Callout-LEGDIMAM.css +0 -52
  474. package/dist/Card-BOZGBML7.css +0 -86
  475. package/dist/Checkbox-OCUICIIZ.css +0 -58
  476. package/dist/CodeBlock-IEMBNIQC.css +0 -90
  477. package/dist/Container-LTKBA2FW.css +0 -21
  478. package/dist/Copyable-IB57OTHZ.css +0 -123
  479. package/dist/DataTable-3GALZUW2.css +0 -1593
  480. package/dist/DateTimePicker-NMSSGVPK.css +0 -312
  481. package/dist/Eyebrow-AVBORAS2.css +0 -30
  482. package/dist/IconButton-GB4PJDG2.css +0 -82
  483. package/dist/ImageUpload-3HQDF2KC.css +0 -158
  484. package/dist/Input-ZHUTN7CU.css +0 -210
  485. package/dist/Kbd-Q77CDZY7.css +0 -23
  486. package/dist/Modal-FJVG66S4.css +0 -138
  487. package/dist/Popover-FUFULUE2.css +0 -123
  488. package/dist/PricingCard-NKYV3JHA.css +0 -238
  489. package/dist/Section-665ZIPG6.css +0 -20
  490. package/dist/Select-GPRF7PRB.css +0 -294
  491. package/dist/Skeleton-3WEFLRDN.css +0 -378
  492. package/dist/StatCard-RTJIVTRB.css +0 -50
  493. package/dist/Table-AR3TRY2E.css +0 -89
  494. package/dist/Tabs-XZ4JIH3E.css +0 -153
  495. package/dist/Tag-R5QDJLYJ.css +0 -163
  496. package/dist/TimeWindowPicker-L3G5Q7UT.css +0 -629
  497. package/dist/Toaster-2O65VOR4.css +0 -264
@@ -0,0 +1,1652 @@
1
+ import { Menu } from './chunk-FBZAKNSX.js';
2
+ import { EmptyValue } from './chunk-EUCC37WY.js';
3
+ import { Modal } from './chunk-2EOKFKHX.js';
4
+ import { useCardHeaderSlot } from './chunk-AV2DXAEL.js';
5
+ import { Checkbox } from './chunk-2PRH365R.js';
6
+ import { useClipboard } from './chunk-V663QU4R.js';
7
+ import { IconButton } from './chunk-F27EPQ7D.js';
8
+ import { Button } from './chunk-BZYDZBAN.js';
9
+ import { VisuallyHidden } from './chunk-BZFWDIV6.js';
10
+ import { cx } from './chunk-ODEQTPFM.js';
11
+ import './DataTable-ITNACQ2X.css';
12
+ import React, { useState, useCallback, useMemo, useRef, useLayoutEffect, useEffect, useId } from 'react';
13
+ import { createPortal } from 'react-dom';
14
+ import { CheckGlyph, ErrorGlyph, ContentCopyGlyph, KeyboardDoubleArrowLeftGlyph, ChevronLeftGlyph, ChevronRightGlyph, KeyboardDoubleArrowRightGlyph, SettingsGlyph, DragIndicatorGlyph, KeyboardArrowUpGlyph, KeyboardArrowDownGlyph, DeleteGlyph, ArrowUpwardGlyph, ArrowDownwardGlyph, UnfoldMoreGlyph, SettingsBackupRestoreGlyph } from '@crewlethq/icons/glyphs';
15
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
16
+
17
+ var CopyableCell = ({
18
+ value,
19
+ children,
20
+ ariaLabel,
21
+ copiedLabel = "Copied",
22
+ failedLabel = "Copy failed"
23
+ }) => {
24
+ const text = value === void 0 || value === null ? "" : String(value);
25
+ const clipboard = useClipboard();
26
+ const onCopy = (event) => {
27
+ event.stopPropagation();
28
+ if (!text) return;
29
+ void clipboard.copy(text);
30
+ };
31
+ return /* @__PURE__ */ jsxs("span", { className: "crewlet-data-table__copy-cell", children: [
32
+ /* @__PURE__ */ jsx("span", { className: "crewlet-data-table__copy-cell-value", children }),
33
+ text && /* @__PURE__ */ jsxs(Fragment, { children: [
34
+ /* @__PURE__ */ jsx(
35
+ "button",
36
+ {
37
+ type: "button",
38
+ className: `crewlet-data-table__copy-cell-button${clipboard.state === "copied" ? " is-copied" : ""}${clipboard.state === "failed" ? " is-failed" : ""}`,
39
+ onClick: onCopy,
40
+ "aria-label": ariaLabel || "Copy to clipboard",
41
+ title: ariaLabel || "Copy to clipboard",
42
+ children: clipboard.state === "copied" ? /* @__PURE__ */ jsx(CheckGlyph, { size: "sm" }) : clipboard.state === "failed" ? /* @__PURE__ */ jsx(ErrorGlyph, { size: "sm" }) : /* @__PURE__ */ jsx(ContentCopyGlyph, { size: "sm" })
43
+ }
44
+ ),
45
+ /* @__PURE__ */ jsx("span", { role: "status", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: clipboard.state === "copied" ? copiedLabel : clipboard.state === "failed" ? failedLabel : "" }) })
46
+ ] })
47
+ ] });
48
+ };
49
+ function entriesFor(action, index) {
50
+ const key = `${index}:${action.label}`;
51
+ const item = {
52
+ key,
53
+ label: action.label,
54
+ icon: action.icon,
55
+ // An action with nothing to do still draws, because `disabled` is what
56
+ // says why it cannot be pressed; an empty handler is never called.
57
+ onSelect: action.onClick ?? (() => {
58
+ }),
59
+ disabled: action.disabled,
60
+ danger: action.danger,
61
+ description: action.description
62
+ };
63
+ return [
64
+ ...action.divider === "before" ? [{ kind: "separator", key: `${key}:before` }] : [],
65
+ item,
66
+ ...action.divider === "after" ? [{ kind: "separator", key: `${key}:after` }] : []
67
+ ];
68
+ }
69
+ var RowActionsMenu = ({ actions, label = "Row actions" }) => {
70
+ const items = (actions || []).filter((action) => !!action && action.visible !== false).flatMap(entriesFor);
71
+ if (items.length === 0) return null;
72
+ return /* @__PURE__ */ jsx(Menu, { label, items, align: "end", className: "crewlet-data-table__row-actions" });
73
+ };
74
+ function cellValue(row, key) {
75
+ return row?.[key];
76
+ }
77
+ function readStored(storageKey, name) {
78
+ if (!storageKey) return null;
79
+ try {
80
+ return globalThis.localStorage?.getItem(`${storageKey}_${name}`) ?? null;
81
+ } catch {
82
+ return null;
83
+ }
84
+ }
85
+ function writeStored(storageKey, name, value) {
86
+ if (!storageKey) return;
87
+ try {
88
+ globalThis.localStorage?.setItem(`${storageKey}_${name}`, value);
89
+ } catch {
90
+ }
91
+ }
92
+ function removeStored(storageKey, name) {
93
+ if (!storageKey) return;
94
+ try {
95
+ globalThis.localStorage?.removeItem(`${storageKey}_${name}`);
96
+ } catch {
97
+ }
98
+ }
99
+ function readStoredJson(storageKey, name, valid) {
100
+ const raw = readStored(storageKey, name);
101
+ if (raw === null) return null;
102
+ try {
103
+ const parsed = JSON.parse(raw);
104
+ return valid(parsed) ? parsed : null;
105
+ } catch {
106
+ return null;
107
+ }
108
+ }
109
+ function isPlainObject(value) {
110
+ return typeof value === "object" && value !== null && !Array.isArray(value);
111
+ }
112
+ function isNumberRecord(value) {
113
+ return isPlainObject(value) && Object.values(value).every((entry) => typeof entry === "number");
114
+ }
115
+ function isBooleanRecord(value) {
116
+ return isPlainObject(value) && Object.values(value).every((entry) => typeof entry === "boolean");
117
+ }
118
+ function isStringArray(value) {
119
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
120
+ }
121
+ function isAbsent(value) {
122
+ return value === null || value === void 0 || typeof value === "number" && Number.isNaN(value);
123
+ }
124
+ function compareValues(a, b) {
125
+ if (typeof a === "number" && typeof b === "number") return a < b ? -1 : a > b ? 1 : 0;
126
+ if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
127
+ return String(a).localeCompare(String(b), void 0, { numeric: true, sensitivity: "base" });
128
+ }
129
+ function reconcileOrder(current, declared) {
130
+ const known = new Set(declared);
131
+ const kept = current.filter((key) => known.has(key));
132
+ if (kept.length === declared.length) return kept;
133
+ const out = [...kept];
134
+ declared.forEach((key, index) => {
135
+ if (out.includes(key)) return;
136
+ let at = 0;
137
+ for (let earlier = index - 1; earlier >= 0; earlier -= 1) {
138
+ const where = out.indexOf(declared[earlier]);
139
+ if (where >= 0) {
140
+ at = where + 1;
141
+ break;
142
+ }
143
+ }
144
+ out.splice(at, 0, key);
145
+ });
146
+ return out;
147
+ }
148
+ var ALL_ITEMS = "all";
149
+ var DATA_TABLE_LABELS = {
150
+ settings: "Table settings",
151
+ /*
152
+ * THE WORDS THE PRODUCT ALREADY SHIPS. The frame's title, its column
153
+ * section, that section's hint and the reset button are the four strings an
154
+ * operator reads on every table in the product today, so they are spelt here
155
+ * exactly as they are spelt there. `Reset to Default` is also the more
156
+ * accurate of the two: the button puts the page size, the wrapping, the sort
157
+ * and the widths back as well as the columns, which `Reset columns` says
158
+ * less than half of.
159
+ */
160
+ resetColumns: "Reset to Default",
161
+ resetConfirmed: "Settings reset to default",
162
+ cancel: "Cancel",
163
+ apply: "Apply",
164
+ settingsTitle: "Table Settings",
165
+ itemsPerPage: "Items per page",
166
+ allItems: "All",
167
+ allItemsCount: (rows) => `${rows.toLocaleString()} rows`,
168
+ wrapLines: "Wrap lines",
169
+ wrapLinesHint: "Wrap the content of a cell instead of truncating it.",
170
+ columnsSection: "Column Order & Visibility",
171
+ /*
172
+ * THE HINT IS THE POINTER'S, AND THE KEYBOARD'S PATH IS ON THE CONTROLS
173
+ * THEMSELVES. Naming Move up and Move down here read as the only way in for
174
+ * somebody who could see the row, and said nothing to a reader who cannot:
175
+ * a paragraph above a list is not where a screen reader looks for what a
176
+ * control does. The handle's own name and `reorderHint` carry it now, so
177
+ * the keyboard path arrives at the control it belongs to.
178
+ */
179
+ columnsHint: "Drag to reorder, check/uncheck to show/hide",
180
+ moveUp: (column) => `Move ${column} up`,
181
+ moveDown: (column) => `Move ${column} down`,
182
+ atTop: (column) => `${column} is already first`,
183
+ atBottom: (column) => `${column} is already last`,
184
+ reorder: (column) => `Reorder ${column}`,
185
+ reorderHint: "Press the up or down arrow key to move this column.",
186
+ columnMoved: (column, position, of) => `${column} moved to position ${position} of ${of}`,
187
+ columnAlwaysShown: "This column is always shown.",
188
+ columnLastShown: "At least one column stays shown.",
189
+ pagination: "Pagination",
190
+ firstPage: "First page",
191
+ previousPage: "Previous page",
192
+ nextPage: "Next page",
193
+ lastPage: "Last page",
194
+ page: (page, of) => `Page ${page} of ${of}`,
195
+ pageRange: (from, to, total) => `Rows ${from} to ${to} of ${total}`,
196
+ expandRow: "Expand row",
197
+ collapseRow: "Collapse row",
198
+ expandAll: "Expand all rows",
199
+ collapseAll: "Collapse all rows",
200
+ resize: (column) => `Resize ${column}`,
201
+ resizeWidth: (pixels) => `${pixels} pixels`,
202
+ copyCell: (column) => `Copy ${column}`,
203
+ rowActions: "Row actions",
204
+ actions: "Actions",
205
+ archivedRow: (label) => `This row is ${label}`,
206
+ absent: "Not reported",
207
+ loading: "Loading rows",
208
+ tone: { info: "Active", warning: "Needs attention", danger: "Failed" }
209
+ };
210
+ var DataTable = ({
211
+ data = [],
212
+ columns = {},
213
+ storageKey,
214
+ defaultColumnOrder = null,
215
+ columnOrder: columnOrderProp,
216
+ onColumnOrderChange,
217
+ defaultItemsPerPage = 10,
218
+ itemsPerPage: itemsPerPageProp,
219
+ onItemsPerPageChange,
220
+ page: pageProp,
221
+ onPageChange,
222
+ pageCount,
223
+ minColumnWidth = 80,
224
+ resizable = true,
225
+ itemsPerPageOptions = [5, 10, 20, 50, 100],
226
+ onRowAction = null,
227
+ actionLabel = "Delete",
228
+ actionIcon = /* @__PURE__ */ jsx(DeleteGlyph, { size: "md" }),
229
+ getRowKey,
230
+ rowKey,
231
+ emptyMessage = "No data available",
232
+ endMessage,
233
+ showActions = true,
234
+ className = "",
235
+ variant = "default",
236
+ density = "compact",
237
+ maxBodyHeight,
238
+ sort: sortProp,
239
+ onSortChange,
240
+ defaultSort = null,
241
+ sortCycle = "asc-desc-none",
242
+ stableOrder = false,
243
+ rowActions,
244
+ archivedPredicate,
245
+ archivedLabel = "archived",
246
+ loading = false,
247
+ skeletonRows = 5,
248
+ error = null,
249
+ paginated = true,
250
+ showSettings = true,
251
+ onRowClick,
252
+ getRowHref,
253
+ rowTone,
254
+ isSelected,
255
+ renderAccessoryRow,
256
+ renderToolbar,
257
+ renderFilterBar,
258
+ onClearFilters,
259
+ filtersActive = false,
260
+ clearFiltersLabel = "Clear filters",
261
+ filterKey,
262
+ visibleColumns: visibleColumnsProp,
263
+ onVisibleColumnsChange,
264
+ renderExpandedRow,
265
+ defaultExpandedKey = null,
266
+ hasMore = false,
267
+ onLoadMore,
268
+ loadingMore = false,
269
+ loadMoreLabel = "Load more",
270
+ title,
271
+ description,
272
+ icon,
273
+ defaultWrapLines,
274
+ labels: labelOverrides
275
+ }) => {
276
+ const labels = labelOverrides ? { ...DATA_TABLE_LABELS, ...labelOverrides, tone: { ...DATA_TABLE_LABELS.tone, ...labelOverrides.tone } } : DATA_TABLE_LABELS;
277
+ const effectiveDefaultWrapLines = defaultWrapLines ?? true;
278
+ const resolveRowKey = (row) => {
279
+ if (getRowKey) return getRowKey(row);
280
+ if (rowKey) return cellValue(row, rowKey);
281
+ return cellValue(row, "id");
282
+ };
283
+ const isCompact = variant === "compact";
284
+ const hasActionColumn = !!rowActions || showActions && !!onRowAction;
285
+ const expandable = !!renderExpandedRow;
286
+ const settingsEnabled = showSettings;
287
+ const paginationEnabled = paginated;
288
+ const settingsInHeader = settingsEnabled && !isCompact;
289
+ const hasChromeColumn = hasActionColumn || settingsInHeader;
290
+ const generateDefaultColumnWidths = () => {
291
+ const widths = {};
292
+ Object.keys(columns).forEach((key) => {
293
+ const col = columns[key];
294
+ const rawExplicit = col?.width ?? col?.defaultWidth;
295
+ let px = null;
296
+ if (rawExplicit != null) {
297
+ const parsed = typeof rawExplicit === "number" ? rawExplicit : parseInt(String(rawExplicit), 10);
298
+ if (Number.isFinite(parsed)) px = parsed;
299
+ }
300
+ if (px == null) {
301
+ const labelStr = typeof col?.label === "string" ? col.label : key;
302
+ const estimated = Math.ceil(labelStr.length * 7.5) + 56;
303
+ px = Math.max(120, estimated);
304
+ }
305
+ widths[key] = Math.max(minColumnWidth, px);
306
+ });
307
+ if (showActions) {
308
+ widths.__actions = 60;
309
+ }
310
+ return widths;
311
+ };
312
+ const generateDefaultVisibleColumns = () => {
313
+ const visible = {};
314
+ Object.keys(columns).forEach((key) => {
315
+ visible[key] = columns[key]?.defaultVisible !== false;
316
+ });
317
+ return visible;
318
+ };
319
+ const generateDefaultColumnOrder = () => {
320
+ return defaultColumnOrder || Object.keys(columns);
321
+ };
322
+ const defaultColumnWidths = generateDefaultColumnWidths();
323
+ const defaultVisibleColumns = generateDefaultVisibleColumns();
324
+ const defaultOrder = generateDefaultColumnOrder();
325
+ const readResizedColumns = () => {
326
+ const saved = readStoredJson(storageKey, "resizedColumns", isNumberRecord);
327
+ if (!saved) return {};
328
+ const kept = {};
329
+ Object.entries(saved).forEach(([key, px]) => {
330
+ if (!Number.isFinite(px)) return;
331
+ const col = columns[key];
332
+ if (!col || col.width != null) return;
333
+ kept[key] = Math.max(minColumnWidth, px);
334
+ });
335
+ return kept;
336
+ };
337
+ const [columnWidths, setColumnWidths] = useState(
338
+ () => ({ ...defaultColumnWidths, ...readResizedColumns() })
339
+ );
340
+ const [resizedColumns, setResizedColumns] = useState(
341
+ () => Object.fromEntries(Object.keys(readResizedColumns()).map((key) => [key, true]))
342
+ );
343
+ const markResized = useCallback((columnKey) => {
344
+ setResizedColumns((was) => was[columnKey] ? was : { ...was, [columnKey]: true });
345
+ }, []);
346
+ const [ownItemsPerPage, setOwnItemsPerPage] = useState(() => {
347
+ if (itemsPerPageProp !== void 0) return defaultItemsPerPage;
348
+ const saved = readStored(storageKey, "itemsPerPage");
349
+ if (saved === ALL_ITEMS) return ALL_ITEMS;
350
+ const count = Number.parseInt(saved ?? "", 10);
351
+ return Number.isFinite(count) && count > 0 ? count : defaultItemsPerPage;
352
+ });
353
+ const itemsPerPage = itemsPerPageProp ?? ownItemsPerPage;
354
+ const commitItemsPerPage = (next) => {
355
+ if (itemsPerPageProp === void 0) setOwnItemsPerPage(next);
356
+ onItemsPerPageChange?.(next);
357
+ };
358
+ const [ownVisibleColumns, setOwnVisibleColumns] = useState(() => {
359
+ const saved = visibleColumnsProp === void 0 ? readStoredJson(storageKey, "visibleColumns", isBooleanRecord) : null;
360
+ if (!saved) return defaultVisibleColumns;
361
+ const valid = {};
362
+ Object.keys(columns).forEach((key) => {
363
+ valid[key] = Object.prototype.hasOwnProperty.call(saved, key) ? saved[key] : columns[key]?.defaultVisible !== false;
364
+ });
365
+ return valid;
366
+ });
367
+ const visibleColumns = visibleColumnsProp ?? ownVisibleColumns;
368
+ const isColumnVisible = (key) => visibleColumns[key] !== false;
369
+ const commitVisibleColumns = (next) => {
370
+ if (visibleColumnsProp === void 0) setOwnVisibleColumns(next);
371
+ onVisibleColumnsChange?.(next);
372
+ };
373
+ const [ownColumnOrder, setOwnColumnOrder] = useState(() => {
374
+ const saved = columnOrderProp === void 0 ? readStoredJson(storageKey, "columnOrder", isStringArray) : null;
375
+ if (!saved) return defaultOrder;
376
+ const validOrder = saved.filter((key) => Object.prototype.hasOwnProperty.call(columns, key));
377
+ const newColumns = defaultOrder.filter((key) => !validOrder.includes(key));
378
+ return validOrder.length > 0 ? [...validOrder, ...newColumns] : defaultOrder;
379
+ });
380
+ const declaredOrder = defaultOrder.join("\0");
381
+ const arrangedOrder = columnOrderProp ?? ownColumnOrder;
382
+ const columnOrder = useMemo(
383
+ () => reconcileOrder(arrangedOrder, declaredOrder === "" ? [] : declaredOrder.split("\0")),
384
+ [arrangedOrder, declaredOrder]
385
+ );
386
+ const commitColumnOrder = (next) => {
387
+ if (columnOrderProp === void 0) setOwnColumnOrder(next);
388
+ onColumnOrderChange?.(next);
389
+ };
390
+ const [sortConfig, setSortConfig] = useState(
391
+ () => ({ key: defaultSort?.key ?? null, direction: defaultSort?.direction ?? null })
392
+ );
393
+ const [tableSettingsOpen, setTableSettingsOpen] = useState(false);
394
+ const [wrapLines, setWrapLines] = useState(() => {
395
+ if (!storageKey) return effectiveDefaultWrapLines;
396
+ const saved = readStored(storageKey, "wrapLines");
397
+ return saved == null ? effectiveDefaultWrapLines : saved === "true";
398
+ });
399
+ const [draftItemsPerPage, setDraftItemsPerPage] = useState(0);
400
+ const [draftWrapLines, setDraftWrapLines] = useState(effectiveDefaultWrapLines);
401
+ const [draftColumnWidths, setDraftColumnWidths] = useState({});
402
+ const [draftVisibleColumns, setDraftVisibleColumns] = useState({});
403
+ const [draftColumnOrder, setDraftColumnOrder] = useState([]);
404
+ const [draftSortConfig, setDraftSortConfig] = useState(
405
+ { key: null, direction: null }
406
+ );
407
+ const [resetConfirmed, setResetConfirmed] = useState(false);
408
+ const resetConfirmTimer = useRef(null);
409
+ const pendingFitOnApplyRef = useRef(false);
410
+ const [expandedKeys, setExpandedKeys] = useState(
411
+ () => defaultExpandedKey != null ? /* @__PURE__ */ new Set([defaultExpandedKey]) : /* @__PURE__ */ new Set()
412
+ );
413
+ const toggleExpanded = (key) => {
414
+ setExpandedKeys((prev) => {
415
+ const next = new Set(prev);
416
+ if (next.has(key)) {
417
+ next.delete(key);
418
+ } else {
419
+ next.add(key);
420
+ }
421
+ return next;
422
+ });
423
+ };
424
+ const [draggedColumn, setDraggedColumn] = useState(null);
425
+ const [resizingColumn, setResizingColumn] = useState(null);
426
+ const [startX, setStartX] = useState(0);
427
+ const [startWidth, setStartWidth] = useState(0);
428
+ const dragTimeoutRef = useRef(null);
429
+ const settingsButtonRef = useRef(null);
430
+ const scrollRef = useRef(null);
431
+ const [fitRequests, setFitRequests] = useState(0);
432
+ const requestFit = useCallback(() => setFitRequests((n) => n + 1), []);
433
+ const emptyCellRef = useRef(null);
434
+ const [emptySaid, setEmptySaid] = useState("");
435
+ const resetToDefault = () => {
436
+ const newDefaultWidths = generateDefaultColumnWidths();
437
+ const newDefaultVisible = generateDefaultVisibleColumns();
438
+ const newDefaultOrder = generateDefaultColumnOrder();
439
+ setColumnWidths(newDefaultWidths);
440
+ setResizedColumns({});
441
+ commitVisibleColumns(newDefaultVisible);
442
+ commitColumnOrder(newDefaultOrder);
443
+ commitItemsPerPage(defaultItemsPerPage);
444
+ setSortConfig({ key: defaultSort?.key ?? null, direction: defaultSort?.direction ?? null });
445
+ requestFit();
446
+ for (const name of ["resizedColumns", "visibleColumns", "columnOrder", "itemsPerPage"]) {
447
+ removeStored(storageKey, name);
448
+ }
449
+ };
450
+ const fitInputs = useRef({
451
+ columns,
452
+ columnOrder,
453
+ visibleColumns,
454
+ columnWidths,
455
+ resizedColumns,
456
+ expandable,
457
+ hasChromeColumn,
458
+ isCompact,
459
+ minColumnWidth
460
+ });
461
+ fitInputs.current = {
462
+ columns,
463
+ columnOrder,
464
+ visibleColumns,
465
+ columnWidths,
466
+ resizedColumns,
467
+ expandable,
468
+ hasChromeColumn,
469
+ isCompact,
470
+ minColumnWidth
471
+ };
472
+ useLayoutEffect(() => {
473
+ const { columns: columns2, columnOrder: columnOrder2, visibleColumns: visibleColumns2, columnWidths: columnWidths2, resizedColumns: resizedColumns2, expandable: expandable2, hasChromeColumn: hasChromeColumn2, isCompact: isCompact2, minColumnWidth: minColumnWidth2 } = fitInputs.current;
474
+ const el = scrollRef.current;
475
+ if (!el) return;
476
+ const box = el.getBoundingClientRect();
477
+ const edges = Math.max(0, el.offsetWidth - el.clientWidth);
478
+ const measured = box.width - edges;
479
+ const containerWidth = measured > 0 ? Math.floor(measured) : el.clientWidth;
480
+ if (containerWidth <= 0) return;
481
+ const visibleAllKeys = columnOrder2.filter((key) => visibleColumns2[key] !== false);
482
+ const isFixedWidthColumn = (key) => {
483
+ const col = columns2[key];
484
+ if (!col) return false;
485
+ if (col.sticky === "right") return false;
486
+ return col.width != null || resizedColumns2[key] === true;
487
+ };
488
+ const visibleStickyKeys = visibleAllKeys.filter((key) => columns2[key]?.sticky === "right");
489
+ const visibleFixedKeys = visibleAllKeys.filter((key) => isFixedWidthColumn(key));
490
+ const visibleDataKeys = visibleAllKeys.filter(
491
+ (key) => columns2[key]?.sticky !== "right" && !isFixedWidthColumn(key)
492
+ );
493
+ if (visibleDataKeys.length === 0) return;
494
+ let chromeWidth = 0;
495
+ if (expandable2) chromeWidth += 32;
496
+ if (hasChromeColumn2) chromeWidth += isCompact2 ? 48 : columnWidths2.__actions ?? 60;
497
+ chromeWidth += visibleStickyKeys.reduce(
498
+ (sum, key) => sum + (columnWidths2[key] ?? minColumnWidth2),
499
+ 0
500
+ );
501
+ chromeWidth += visibleFixedKeys.reduce(
502
+ (sum, key) => sum + (columnWidths2[key] ?? minColumnWidth2),
503
+ 0
504
+ );
505
+ if (visibleStickyKeys.length > 0) {
506
+ const spacer = el.querySelector(".crewlet-data-table__th--spacer");
507
+ const drawn = spacer ? spacer.getBoundingClientRect().width : 0;
508
+ chromeWidth += drawn > 0 ? drawn : 24;
509
+ }
510
+ const dataTotal = visibleDataKeys.reduce(
511
+ (sum, key) => sum + (columnWidths2[key] ?? minColumnWidth2),
512
+ 0
513
+ );
514
+ const available = containerWidth - chromeWidth;
515
+ const leftover = available - dataTotal;
516
+ if (leftover >= 0 && leftover <= 1) return;
517
+ const next = { ...columnWidths2 };
518
+ const widthOf = (key) => next[key] ?? minColumnWidth2;
519
+ visibleDataKeys.forEach((key) => {
520
+ next[key] = widthOf(key);
521
+ });
522
+ let outstanding = leftover;
523
+ let pool = visibleDataKeys;
524
+ while (pool.length > 0 && outstanding !== 0) {
525
+ const poolTotal = pool.reduce((sum, key) => sum + widthOf(key), 0);
526
+ if (poolTotal <= 0) break;
527
+ const roomLeft = [];
528
+ let moved = 0;
529
+ pool.forEach((key, idx) => {
530
+ const current = widthOf(key);
531
+ const rawShare = idx === pool.length - 1 ? outstanding - moved : Math.round(outstanding * (current / poolTotal));
532
+ const clamped = Math.max(minColumnWidth2, current + rawShare);
533
+ moved += clamped - current;
534
+ next[key] = clamped;
535
+ if (clamped > minColumnWidth2) roomLeft.push(key);
536
+ });
537
+ if (moved === 0) break;
538
+ outstanding -= moved;
539
+ pool = roomLeft;
540
+ }
541
+ setColumnWidths(next);
542
+ }, [fitRequests]);
543
+ const fittedColumnKeys = columnOrder.filter((key) => visibleColumns[key] !== false).join(",");
544
+ const fittedColumnKeysRef = useRef(fittedColumnKeys);
545
+ useLayoutEffect(() => {
546
+ if (fittedColumnKeysRef.current === fittedColumnKeys) return;
547
+ fittedColumnKeysRef.current = fittedColumnKeys;
548
+ requestFit();
549
+ }, [fittedColumnKeys, requestFit]);
550
+ useEffect(() => {
551
+ const el = scrollRef.current;
552
+ if (!el) return;
553
+ let lastWidth = el.clientWidth;
554
+ const observer = new ResizeObserver(() => {
555
+ const w = el.clientWidth;
556
+ if (w > 0 && w !== lastWidth) {
557
+ lastWidth = w;
558
+ requestFit();
559
+ }
560
+ });
561
+ observer.observe(el);
562
+ return () => observer.disconnect();
563
+ }, [requestFit]);
564
+ useEffect(() => {
565
+ const chosen = Object.keys(resizedColumns);
566
+ if (chosen.length === 0) {
567
+ removeStored(storageKey, "resizedColumns");
568
+ return;
569
+ }
570
+ writeStored(storageKey, "resizedColumns", JSON.stringify(
571
+ Object.fromEntries(chosen.map((key) => [key, columnWidths[key] ?? minColumnWidth]))
572
+ ));
573
+ }, [columnWidths, resizedColumns, storageKey, minColumnWidth]);
574
+ useEffect(() => {
575
+ removeStored(storageKey, "columnWidths");
576
+ }, [storageKey]);
577
+ useEffect(() => {
578
+ if (itemsPerPageProp === void 0) {
579
+ writeStored(storageKey, "itemsPerPage", String(ownItemsPerPage));
580
+ }
581
+ }, [ownItemsPerPage, storageKey, itemsPerPageProp]);
582
+ useEffect(() => {
583
+ if (visibleColumnsProp === void 0) {
584
+ writeStored(storageKey, "visibleColumns", JSON.stringify(ownVisibleColumns));
585
+ }
586
+ }, [ownVisibleColumns, storageKey, visibleColumnsProp]);
587
+ useEffect(() => {
588
+ if (columnOrderProp === void 0) {
589
+ writeStored(storageKey, "columnOrder", JSON.stringify(columnOrder));
590
+ }
591
+ }, [columnOrder, storageKey, columnOrderProp]);
592
+ useEffect(() => {
593
+ writeStored(storageKey, "wrapLines", String(wrapLines));
594
+ }, [wrapLines, storageKey]);
595
+ const handleMouseDownResize = (e, columnKey) => {
596
+ e.preventDefault();
597
+ e.stopPropagation();
598
+ setResizingColumn(columnKey);
599
+ setStartX(e.clientX);
600
+ setStartWidth(columnWidths[columnKey] ?? minColumnWidth);
601
+ };
602
+ const KEYBOARD_RESIZE_STEP = 16;
603
+ const resizerState = (columnKey) => {
604
+ const width = Math.round(columnWidths[columnKey] ?? minColumnWidth);
605
+ return {
606
+ role: "separator",
607
+ "aria-orientation": "vertical",
608
+ "aria-label": labels.resize(columnName(columnKey)),
609
+ "aria-valuenow": width,
610
+ "aria-valuemin": minColumnWidth,
611
+ "aria-valuetext": labels.resizeWidth(width)
612
+ };
613
+ };
614
+ const nudgeColumnWidth = (e, columnKey) => {
615
+ const step = e.key === "ArrowLeft" ? -KEYBOARD_RESIZE_STEP : e.key === "ArrowRight" ? KEYBOARD_RESIZE_STEP : 0;
616
+ if (step === 0) return;
617
+ e.preventDefault();
618
+ e.stopPropagation();
619
+ setColumnWidths((was) => ({
620
+ ...was,
621
+ [columnKey]: Math.max(minColumnWidth, (was[columnKey] ?? minColumnWidth) + step)
622
+ }));
623
+ markResized(columnKey);
624
+ };
625
+ useEffect(() => {
626
+ const handleMouseMove = (e) => {
627
+ if (resizingColumn) {
628
+ const diff = e.clientX - startX;
629
+ const newWidth = Math.max(minColumnWidth, startWidth + diff);
630
+ setColumnWidths((prev) => ({
631
+ ...prev,
632
+ [resizingColumn]: newWidth
633
+ }));
634
+ markResized(resizingColumn);
635
+ }
636
+ };
637
+ const handleMouseUp = () => {
638
+ if (resizingColumn) {
639
+ setResizingColumn(null);
640
+ }
641
+ };
642
+ if (resizingColumn) {
643
+ document.body.classList.add("crewlet-data-table-resizing");
644
+ document.addEventListener("mousemove", handleMouseMove);
645
+ document.addEventListener("mouseup", handleMouseUp);
646
+ return () => {
647
+ document.body.classList.remove("crewlet-data-table-resizing");
648
+ document.removeEventListener("mousemove", handleMouseMove);
649
+ document.removeEventListener("mouseup", handleMouseUp);
650
+ };
651
+ }
652
+ return void 0;
653
+ }, [resizingColumn, startX, startWidth, minColumnWidth, markResized]);
654
+ const controlledSort = sortProp !== void 0;
655
+ const effectiveSort = controlledSort ? sortProp ? { key: sortProp.key, direction: sortProp.direction } : { key: null, direction: null } : sortConfig;
656
+ const handleSort = (columnKey) => {
657
+ const column = columns[columnKey];
658
+ if (column?.sortable === false) return;
659
+ const first = column?.firstDirection ?? "asc";
660
+ const other = first === "asc" ? "desc" : "asc";
661
+ let next;
662
+ if (effectiveSort.key !== columnKey || effectiveSort.direction === null) {
663
+ next = { key: columnKey, direction: first };
664
+ } else if (effectiveSort.direction === first) {
665
+ next = { key: columnKey, direction: other };
666
+ } else {
667
+ next = sortCycle === "asc-desc" ? { key: columnKey, direction: first } : null;
668
+ }
669
+ if (controlledSort) {
670
+ onSortChange?.(next);
671
+ } else {
672
+ setSortConfig({ key: next?.key ?? null, direction: next?.direction ?? null });
673
+ }
674
+ };
675
+ const heldOrder = useRef(null);
676
+ const getSortedData = () => {
677
+ const sortKey = effectiveSort.key;
678
+ const direction = effectiveSort.direction;
679
+ if (!sortKey || !direction) {
680
+ heldOrder.current = null;
681
+ return [...data];
682
+ }
683
+ const column = columns[sortKey];
684
+ const accessor = column?.sortValue ?? ((row) => cellValue(row, sortKey));
685
+ const sorted = data.map((row, index) => ({ row, index })).sort((left, right) => {
686
+ const a = accessor(left.row);
687
+ const b = accessor(right.row);
688
+ const aAbsent = isAbsent(a);
689
+ const bAbsent = isAbsent(b);
690
+ if (aAbsent || bAbsent) {
691
+ if (aAbsent && bAbsent) return left.index - right.index;
692
+ return aAbsent ? 1 : -1;
693
+ }
694
+ const difference = compareValues(a, b);
695
+ if (difference !== 0) return direction === "asc" ? difference : -difference;
696
+ return left.index - right.index;
697
+ }).map((decorated) => decorated.row);
698
+ if (!stableOrder) {
699
+ heldOrder.current = null;
700
+ return sorted;
701
+ }
702
+ const signature = `${sortKey}:${direction}`;
703
+ const held = heldOrder.current;
704
+ if (!held || held.signature !== signature) {
705
+ heldOrder.current = {
706
+ signature,
707
+ rank: new Map(sorted.map((row, index) => [resolveRowKey(row), index]))
708
+ };
709
+ return sorted;
710
+ }
711
+ const { rank } = held;
712
+ return sorted.map((row, index) => ({ row, index })).sort((left, right) => {
713
+ const a = rank.get(resolveRowKey(left.row));
714
+ const b = rank.get(resolveRowKey(right.row));
715
+ if (a === void 0 && b === void 0) return left.index - right.index;
716
+ if (a === void 0) return 1;
717
+ if (b === void 0) return -1;
718
+ return a - b;
719
+ }).map((decorated) => decorated.row);
720
+ };
721
+ const [ownPage, setOwnPage] = useState(1);
722
+ const currentPage = pageProp ?? ownPage;
723
+ const goToPage = (next) => {
724
+ if (pageProp === void 0) setOwnPage(next);
725
+ onPageChange?.(next);
726
+ };
727
+ const sortedDataMemo = getSortedData();
728
+ const totalPages = paginationEnabled ? itemsPerPage === ALL_ITEMS ? 1 : Math.max(1, Math.ceil(sortedDataMemo.length / Math.max(1, itemsPerPage))) : Math.max(1, pageCount ?? 1);
729
+ const pageBoundKnown = paginationEnabled || pageCount !== void 0;
730
+ useEffect(() => {
731
+ if (!pageBoundKnown) return;
732
+ if (currentPage > totalPages) goToPage(totalPages);
733
+ else if (currentPage < 1) goToPage(1);
734
+ }, [totalPages, currentPage, pageBoundKnown]);
735
+ const pagedFrom = useRef(null);
736
+ useEffect(() => {
737
+ const signature = `${effectiveSort.key}:${effectiveSort.direction}:${String(filterKey)}:${filtersActive}`;
738
+ const was = pagedFrom.current;
739
+ pagedFrom.current = signature;
740
+ if (was === null || was === signature) return;
741
+ if (currentPage !== 1) goToPage(1);
742
+ }, [effectiveSort.key, effectiveSort.direction, filterKey, filtersActive]);
743
+ const getDisplayedData = () => {
744
+ if (!paginationEnabled || itemsPerPage === ALL_ITEMS) return sortedDataMemo;
745
+ const start = (currentPage - 1) * itemsPerPage;
746
+ return sortedDataMemo.slice(start, start + itemsPerPage);
747
+ };
748
+ const columnName = (columnKey) => {
749
+ const label = columns[columnKey]?.label;
750
+ return typeof label === "string" && label.trim() !== "" ? label : columnKey;
751
+ };
752
+ const whyFixed = (columnKey, shown) => {
753
+ if (columns[columnKey]?.hideable === false) return labels.columnAlwaysShown;
754
+ const others = Object.keys(columns).filter((key) => key !== columnKey && shown[key] !== false);
755
+ return others.length === 0 ? labels.columnLastShown : null;
756
+ };
757
+ const [settingsSaid, setSettingsSaid] = useState("");
758
+ const instanceId = useId();
759
+ const reorderHintId = `${instanceId}-reorder`;
760
+ const columnLabelId = (columnKey) => (
761
+ // Whitespace out of the key: `aria-labelledby` is a SPACE-SEPARATED list
762
+ // of ids, so a column keyed "created at" would point the cell at two ids
763
+ // that do not exist and leave the header with no name at all.
764
+ `${instanceId}-col-${columnKey.replace(/\s+/g, "_")}`
765
+ );
766
+ const handleToggleColumn = (columnKey) => {
767
+ if (whyFixed(columnKey, draftVisibleColumns) !== null && draftVisibleColumns[columnKey] !== false) return;
768
+ setDraftVisibleColumns((prev) => ({ ...prev, [columnKey]: !prev[columnKey] }));
769
+ };
770
+ const moveColumn = (columnKey, by) => {
771
+ const at = draftColumnOrder.indexOf(columnKey);
772
+ const to = at + by;
773
+ if (at < 0 || to < 0 || to >= draftColumnOrder.length) return;
774
+ const next = [...draftColumnOrder];
775
+ next.splice(at, 1);
776
+ next.splice(to, 0, columnKey);
777
+ setDraftColumnOrder(next);
778
+ setSettingsSaid(labels.columnMoved(columnName(columnKey), to + 1, next.length));
779
+ };
780
+ const handleItemsPerPageChange = (value) => {
781
+ setDraftItemsPerPage(value);
782
+ };
783
+ const handleResetTableSettings = () => {
784
+ setDraftColumnWidths(generateDefaultColumnWidths());
785
+ setDraftItemsPerPage(defaultItemsPerPage);
786
+ setDraftVisibleColumns(generateDefaultVisibleColumns());
787
+ setDraftColumnOrder(generateDefaultColumnOrder());
788
+ setDraftWrapLines(effectiveDefaultWrapLines);
789
+ setDraftSortConfig({ key: defaultSort?.key ?? null, direction: defaultSort?.direction ?? null });
790
+ pendingFitOnApplyRef.current = true;
791
+ setResetConfirmed(true);
792
+ setSettingsSaid(labels.resetConfirmed);
793
+ if (resetConfirmTimer.current) clearTimeout(resetConfirmTimer.current);
794
+ resetConfirmTimer.current = setTimeout(() => setResetConfirmed(false), 1500);
795
+ };
796
+ const openTableSettings = () => {
797
+ setDraftColumnWidths({ ...columnWidths });
798
+ setDraftItemsPerPage(itemsPerPage);
799
+ setDraftVisibleColumns({ ...visibleColumns });
800
+ setDraftColumnOrder([...columnOrder]);
801
+ setDraftWrapLines(wrapLines);
802
+ setDraftSortConfig({ key: effectiveSort.key, direction: effectiveSort.direction });
803
+ setResetConfirmed(false);
804
+ setSettingsSaid("");
805
+ pendingFitOnApplyRef.current = false;
806
+ if (resetConfirmTimer.current) {
807
+ clearTimeout(resetConfirmTimer.current);
808
+ resetConfirmTimer.current = null;
809
+ }
810
+ setTableSettingsOpen(true);
811
+ };
812
+ const applyTableSettings = () => {
813
+ setColumnWidths(draftColumnWidths);
814
+ commitItemsPerPage(draftItemsPerPage);
815
+ commitVisibleColumns(draftVisibleColumns);
816
+ commitColumnOrder(draftColumnOrder);
817
+ setWrapLines(draftWrapLines);
818
+ if (controlledSort) {
819
+ onSortChange?.(
820
+ draftSortConfig.key && draftSortConfig.direction ? { key: draftSortConfig.key, direction: draftSortConfig.direction } : null
821
+ );
822
+ } else {
823
+ setSortConfig(draftSortConfig);
824
+ }
825
+ if (pendingFitOnApplyRef.current) {
826
+ pendingFitOnApplyRef.current = false;
827
+ setResizedColumns({});
828
+ requestFit();
829
+ }
830
+ setTableSettingsOpen(false);
831
+ };
832
+ const cancelTableSettings = () => {
833
+ pendingFitOnApplyRef.current = false;
834
+ setTableSettingsOpen(false);
835
+ };
836
+ const handleDragStart = (e, columnKey) => {
837
+ setDraggedColumn(columnKey);
838
+ e.dataTransfer.effectAllowed = "move";
839
+ };
840
+ const handleDragOver = (e, columnKey) => {
841
+ e.preventDefault();
842
+ e.dataTransfer.dropEffect = "move";
843
+ if (columnKey && draggedColumn && draggedColumn !== columnKey) {
844
+ if (dragTimeoutRef.current) {
845
+ clearTimeout(dragTimeoutRef.current);
846
+ }
847
+ dragTimeoutRef.current = setTimeout(() => {
848
+ setDraftColumnOrder((prev) => {
849
+ const newOrder = [...prev];
850
+ const draggedIndex = newOrder.indexOf(draggedColumn);
851
+ const targetIndex = newOrder.indexOf(columnKey);
852
+ if (draggedIndex === -1 || targetIndex === -1 || draggedIndex === targetIndex) {
853
+ return prev;
854
+ }
855
+ newOrder.splice(draggedIndex, 1);
856
+ newOrder.splice(targetIndex, 0, draggedColumn);
857
+ return newOrder;
858
+ });
859
+ }, 5);
860
+ }
861
+ };
862
+ const handleDrop = (e, _targetColumnKey) => {
863
+ e.preventDefault();
864
+ setDraggedColumn(null);
865
+ };
866
+ const handleDragEnd = () => {
867
+ if (dragTimeoutRef.current) {
868
+ clearTimeout(dragTimeoutRef.current);
869
+ }
870
+ setDraggedColumn(null);
871
+ };
872
+ const renderCellContent = (row, columnKey) => {
873
+ const column = columns[columnKey];
874
+ const value = cellValue(row, columnKey);
875
+ if (column?.render) {
876
+ return column.render(row, value);
877
+ }
878
+ return value !== null && value !== void 0 ? value : /* @__PURE__ */ jsx(EmptyValue, { label: labels.absent });
879
+ };
880
+ const columnClasses = (column) => cx(
881
+ column.align === "right" && "crewlet-data-table__cell--right",
882
+ column.align === "center" && "crewlet-data-table__cell--center",
883
+ column.shrink && "crewlet-data-table__cell--shrink"
884
+ );
885
+ const renderBodyCell = (row, columnKey, lead = {}) => {
886
+ const column = columns[columnKey];
887
+ if (!column) return null;
888
+ const style = {};
889
+ if (isCompact) {
890
+ if (columnWidths[columnKey] != null) {
891
+ style.width = `${columnWidths[columnKey]}px`;
892
+ }
893
+ } else {
894
+ style.width = `${columnWidths[columnKey]}px`;
895
+ }
896
+ const rendered = renderCellContent(row, columnKey);
897
+ let content = rendered;
898
+ if (lead.href) {
899
+ content = /* @__PURE__ */ jsx("a", { className: "crewlet-data-table__row-link", href: lead.href, children: content });
900
+ }
901
+ if (isCompact && column.copyable) {
902
+ const raw = column.copyValue ? column.copyValue(row) : cellValue(row, columnKey);
903
+ const copyText = raw !== void 0 && raw !== null ? String(raw) : "";
904
+ content = /* @__PURE__ */ jsx(CopyableCell, { value: copyText, ariaLabel: labels.copyCell(columnName(columnKey)), children: rendered });
905
+ }
906
+ const tdClassName = cx(
907
+ columnClasses(column),
908
+ column.mono && "crewlet-data-table__cell--mono",
909
+ isCompact && column.sticky === "right" && "crewlet-data-table__td--sticky-right"
910
+ );
911
+ return /* @__PURE__ */ jsxs("td", { style, className: tdClassName || void 0, children: [
912
+ lead.tone,
913
+ content
914
+ ] }, columnKey);
915
+ };
916
+ const renderHeaderCell = (columnKey) => {
917
+ if (!isColumnVisible(columnKey)) return null;
918
+ const column = columns[columnKey];
919
+ if (!column) return null;
920
+ const isSortable = column.sortable !== false;
921
+ const isActive = effectiveSort.key === columnKey && effectiveSort.direction !== null;
922
+ const arrow = !isSortable ? null : isActive ? effectiveSort.direction === "asc" ? /* @__PURE__ */ jsx(ArrowUpwardGlyph, { size: "sm" }) : /* @__PURE__ */ jsx(ArrowDownwardGlyph, { size: "sm" }) : /* @__PURE__ */ jsx(UnfoldMoreGlyph, { size: "sm" });
923
+ const ariaSort = isActive ? effectiveSort.direction === "asc" ? "ascending" : "descending" : void 0;
924
+ const isSticky = column.sticky === "right";
925
+ if (isCompact) {
926
+ const style = {};
927
+ if (columnWidths[columnKey] != null) {
928
+ style.width = `${columnWidths[columnKey]}px`;
929
+ }
930
+ const visibleStickyExists = columnOrder.some(
931
+ (k) => columns[k]?.sticky === "right" && isColumnVisible(k)
932
+ );
933
+ const suppressResizer = !resizable || isSticky || visibleStickyExists;
934
+ const resizer = suppressResizer ? null : /* @__PURE__ */ jsx(
935
+ "button",
936
+ {
937
+ type: "button",
938
+ className: "crewlet-data-table__resizer",
939
+ ...resizerState(columnKey),
940
+ onMouseDown: (e) => {
941
+ e.stopPropagation();
942
+ handleMouseDownResize(e, columnKey);
943
+ },
944
+ onClick: (e) => e.stopPropagation(),
945
+ onKeyDown: (e) => nudgeColumnWidth(e, columnKey)
946
+ }
947
+ );
948
+ const thClass = cx(
949
+ columnClasses(column),
950
+ isSortable && "crewlet-data-table__th--sortable",
951
+ isSortable && isActive && "is-active",
952
+ isSticky && "crewlet-data-table__th--sticky-right"
953
+ );
954
+ return /* @__PURE__ */ jsxs(
955
+ "th",
956
+ {
957
+ scope: "col",
958
+ style,
959
+ "aria-sort": ariaSort,
960
+ "aria-labelledby": columnLabelId(columnKey),
961
+ className: thClass || void 0,
962
+ children: [
963
+ isSortable ? /* @__PURE__ */ jsxs(
964
+ "button",
965
+ {
966
+ type: "button",
967
+ className: "crewlet-data-table__sort-button",
968
+ onClick: () => handleSort(columnKey),
969
+ children: [
970
+ /* @__PURE__ */ jsx("span", { id: columnLabelId(columnKey), children: column.label }),
971
+ arrow
972
+ ]
973
+ }
974
+ ) : /* @__PURE__ */ jsx("span", { id: columnLabelId(columnKey), children: column.label }),
975
+ resizer
976
+ ]
977
+ },
978
+ columnKey
979
+ );
980
+ }
981
+ return /* @__PURE__ */ jsxs(
982
+ "th",
983
+ {
984
+ scope: "col",
985
+ style: { width: `${columnWidths[columnKey]}px` },
986
+ "aria-sort": ariaSort,
987
+ "aria-labelledby": columnLabelId(columnKey),
988
+ className: cx(columnClasses(column), isSortable && "crewlet-data-table__th--sortable") || void 0,
989
+ children: [
990
+ isSortable ? /* @__PURE__ */ jsxs(
991
+ "button",
992
+ {
993
+ type: "button",
994
+ className: "crewlet-data-table__sort-button crewlet-data-table__header-content",
995
+ onClick: () => handleSort(columnKey),
996
+ children: [
997
+ /* @__PURE__ */ jsx("span", { id: columnLabelId(columnKey), children: column.label }),
998
+ /* @__PURE__ */ jsx("span", { className: cx("crewlet-data-table__sort-icon", isActive && "is-active"), children: arrow })
999
+ ]
1000
+ }
1001
+ ) : /* @__PURE__ */ jsx("div", { className: "crewlet-data-table__header-content", children: /* @__PURE__ */ jsx("span", { id: columnLabelId(columnKey), children: column.label }) }),
1002
+ resizable && /* @__PURE__ */ jsx(
1003
+ "button",
1004
+ {
1005
+ type: "button",
1006
+ className: "crewlet-data-table__column-resizer",
1007
+ ...resizerState(columnKey),
1008
+ onMouseDown: (e) => handleMouseDownResize(e, columnKey),
1009
+ onClick: (e) => e.stopPropagation(),
1010
+ onKeyDown: (e) => nudgeColumnWidth(e, columnKey)
1011
+ }
1012
+ )
1013
+ ]
1014
+ },
1015
+ columnKey
1016
+ );
1017
+ };
1018
+ const renderActionsHeader = () => {
1019
+ if (!hasChromeColumn) return null;
1020
+ if (!settingsInHeader) {
1021
+ return /* @__PURE__ */ jsx(
1022
+ "th",
1023
+ {
1024
+ scope: "col",
1025
+ className: "crewlet-data-table__th--chrome crewlet-data-table__th--actions",
1026
+ style: { width: 1 },
1027
+ children: /* @__PURE__ */ jsx(VisuallyHidden, { children: labels.actions })
1028
+ },
1029
+ "__actions"
1030
+ );
1031
+ }
1032
+ return (
1033
+ /*
1034
+ * NO POSITION HERE. The two buttons above hang off this cell, so it has
1035
+ * to be their containing block, and it used to say so inline. The header
1036
+ * cells are `sticky` now, which is a positioned value and is already
1037
+ * that containing block; the inline `relative` merely OUTRANKED it, so
1038
+ * on a bounded table every column name stayed put while this one column
1039
+ * scrolled its heading away.
1040
+ */
1041
+ /* @__PURE__ */ jsxs("th", { scope: "col", style: { width: `${columnWidths.__actions}px` }, children: [
1042
+ labels.actions,
1043
+ /* @__PURE__ */ jsx(
1044
+ "button",
1045
+ {
1046
+ type: "button",
1047
+ className: "crewlet-data-table__header-btn crewlet-data-table__header-btn--reset",
1048
+ onClick: (e) => {
1049
+ e.stopPropagation();
1050
+ resetToDefault();
1051
+ },
1052
+ "aria-label": labels.resetColumns,
1053
+ title: labels.resetColumns,
1054
+ children: /* @__PURE__ */ jsx(SettingsBackupRestoreGlyph, { size: "md" })
1055
+ }
1056
+ ),
1057
+ /* @__PURE__ */ jsx(
1058
+ "button",
1059
+ {
1060
+ type: "button",
1061
+ ref: settingsButtonRef,
1062
+ className: "crewlet-data-table__header-btn crewlet-data-table__header-btn--settings",
1063
+ onClick: (e) => {
1064
+ e.stopPropagation();
1065
+ openTableSettings();
1066
+ },
1067
+ "aria-label": labels.settings,
1068
+ title: labels.settings,
1069
+ children: /* @__PURE__ */ jsx(SettingsGlyph, { size: "md" })
1070
+ }
1071
+ )
1072
+ ] }, "__actions")
1073
+ );
1074
+ };
1075
+ const renderActionsCell = (row) => {
1076
+ if (!hasChromeColumn) return null;
1077
+ if (!hasActionColumn) {
1078
+ return /* @__PURE__ */ jsx("td", { className: "crewlet-data-table__td--actions" }, "__actions");
1079
+ }
1080
+ if (rowActions) {
1081
+ const actions = rowActions(row);
1082
+ return /* @__PURE__ */ jsx(
1083
+ "td",
1084
+ {
1085
+ className: "crewlet-data-table__td--actions",
1086
+ style: { textAlign: "right", width: 1 },
1087
+ children: /* @__PURE__ */ jsx(RowActionsMenu, { actions, label: labels.rowActions })
1088
+ },
1089
+ "__actions"
1090
+ );
1091
+ }
1092
+ return /* @__PURE__ */ jsx(
1093
+ "td",
1094
+ {
1095
+ className: "crewlet-data-table__td--actions",
1096
+ style: { width: `${columnWidths.__actions}px`, textAlign: "center" },
1097
+ children: /* @__PURE__ */ jsx(
1098
+ IconButton,
1099
+ {
1100
+ size: "sm",
1101
+ className: "crewlet-data-table__action-btn",
1102
+ onClick: () => onRowAction(row),
1103
+ label: actionLabel,
1104
+ title: actionLabel,
1105
+ icon: actionIcon
1106
+ }
1107
+ )
1108
+ },
1109
+ "__actions"
1110
+ );
1111
+ };
1112
+ const displayedData = getDisplayedData();
1113
+ const bodyHoldsRows = loading && displayedData.length === 0 || !error && displayedData.length > 0;
1114
+ const visibleColumnKeys = columnOrder.filter(isColumnVisible);
1115
+ const firstVisibleKey = columnOrder.find(
1116
+ (key) => columns[key]?.sticky !== "right" && isColumnVisible(key)
1117
+ );
1118
+ const spacerCols = isCompact ? 1 : 0;
1119
+ const colSpan = visibleColumnKeys.length + (hasChromeColumn ? 1 : 0) + spacerCols;
1120
+ const wrapLinesClass = wrapLines ? " crewlet-data-table--wrap-lines" : "";
1121
+ const boundedBody = maxBodyHeight !== void 0;
1122
+ const stickyHeadClass = boundedBody ? " crewlet-data-table--sticky-head" : "";
1123
+ const rootClass = isCompact ? `crewlet-data-table crewlet-data-table--compact crewlet-data-table--density-${density}${wrapLinesClass}${stickyHeadClass} ${className}`.trim() : `crewlet-data-table crewlet-data-table--default${wrapLinesClass}${stickyHeadClass} ${className}`.trim();
1124
+ const expandColSpan = colSpan + (expandable ? 1 : 0);
1125
+ const visibleRowKeys = displayedData.map((row) => resolveRowKey(row));
1126
+ const allExpanded = expandable && visibleRowKeys.length > 0 && visibleRowKeys.every((k) => expandedKeys.has(k));
1127
+ const toggleExpandAll = () => {
1128
+ setExpandedKeys(() => allExpanded ? /* @__PURE__ */ new Set() : new Set(visibleRowKeys));
1129
+ };
1130
+ const renderExpandHeader = () => {
1131
+ if (!expandable) return null;
1132
+ return /* @__PURE__ */ jsx(
1133
+ "th",
1134
+ {
1135
+ className: "crewlet-data-table__expand-header",
1136
+ style: { width: 32 },
1137
+ children: /* @__PURE__ */ jsx(
1138
+ "button",
1139
+ {
1140
+ type: "button",
1141
+ className: "crewlet-data-table__expand-all-btn",
1142
+ onClick: toggleExpandAll,
1143
+ "aria-label": allExpanded ? labels.collapseAll : labels.expandAll,
1144
+ "aria-expanded": allExpanded,
1145
+ title: allExpanded ? labels.collapseAll : labels.expandAll,
1146
+ children: /* @__PURE__ */ jsx(
1147
+ ChevronRightGlyph,
1148
+ {
1149
+ className: `crewlet-data-table__chevron${allExpanded ? " is-open" : ""}`,
1150
+ size: "md"
1151
+ }
1152
+ )
1153
+ }
1154
+ )
1155
+ },
1156
+ "__expand"
1157
+ );
1158
+ };
1159
+ const renderExpandCell = (rowIsOpen, canExpand, onToggle) => {
1160
+ if (!expandable) return null;
1161
+ return /* @__PURE__ */ jsx("td", { className: "crewlet-data-table__expand-cell", style: { width: 32 }, children: canExpand && /* @__PURE__ */ jsx(
1162
+ "button",
1163
+ {
1164
+ type: "button",
1165
+ className: "crewlet-data-table__expand-btn",
1166
+ "aria-expanded": rowIsOpen,
1167
+ "aria-label": rowIsOpen ? labels.collapseRow : labels.expandRow,
1168
+ onClick: (event) => {
1169
+ event.stopPropagation();
1170
+ onToggle();
1171
+ },
1172
+ children: /* @__PURE__ */ jsx(ChevronRightGlyph, { className: cx("crewlet-data-table__chevron", rowIsOpen && "is-open"), size: "md" })
1173
+ }
1174
+ ) }, "__expand");
1175
+ };
1176
+ const callerPages = onPageChange !== void 0 && pageCount !== void 0;
1177
+ const pagerVisible = paginationEnabled || callerPages;
1178
+ const pageSizeOffered = paginationEnabled || onItemsPerPageChange !== void 0;
1179
+ const pageRange = (() => {
1180
+ const total = sortedDataMemo.length;
1181
+ if (total === 0) return { from: 0, to: 0, total: 0 };
1182
+ const sliced = paginationEnabled && itemsPerPage !== ALL_ITEMS;
1183
+ const from = sliced ? (currentPage - 1) * itemsPerPage + 1 : 1;
1184
+ return { from, to: Math.min(total, from + displayedData.length - 1), total };
1185
+ })();
1186
+ useEffect(() => {
1187
+ setEmptySaid(emptyCellRef.current?.textContent ?? "");
1188
+ }, [emptyMessage, loading, error, displayedData.length]);
1189
+ const cogInChromeRow = settingsEnabled && isCompact;
1190
+ const topControlsVisible = pagerVisible || cogInChromeRow;
1191
+ const headerVisible = title != null || description != null || icon != null;
1192
+ const cardHeader = useCardHeaderSlot(topControlsVisible && !headerVisible);
1193
+ const renderTopControls = topControlsVisible ? /* @__PURE__ */ jsxs("div", { className: "crewlet-data-table__chrome", children: [
1194
+ pagerVisible && /*
1195
+ * A NAMED GROUP, because `aria-label` on a plain div names nothing: a
1196
+ * generic element has no role for a name to attach to, so the label
1197
+ * this cluster has always carried was read by nobody.
1198
+ *
1199
+ * A GROUP AND NOT A LANDMARK. `<nav aria-label="Pagination">` is the
1200
+ * shape a page-level pager takes, and it comes with a rule this
1201
+ * component cannot keep: where there is more than one of them on a
1202
+ * page, each needs a name of its own. A table does not know how many
1203
+ * tables it is on screen with, and the engine draws three on a single
1204
+ * route, so a landmark here fills a reader's landmark list with
1205
+ * identical entries for chrome that belongs inside a table rather than
1206
+ * to the document. A group carries the name and adds nothing to that
1207
+ * list.
1208
+ */
1209
+ /* @__PURE__ */ jsxs("div", { role: "group", className: "crewlet-data-table__pagination", "aria-label": labels.pagination, children: [
1210
+ /* @__PURE__ */ jsx(
1211
+ IconButton,
1212
+ {
1213
+ size: "sm",
1214
+ className: "crewlet-data-table__page-btn",
1215
+ onClick: () => goToPage(1),
1216
+ disabled: currentPage <= 1,
1217
+ label: labels.firstPage,
1218
+ icon: /* @__PURE__ */ jsx(KeyboardDoubleArrowLeftGlyph, { size: "md" })
1219
+ }
1220
+ ),
1221
+ /* @__PURE__ */ jsx(
1222
+ IconButton,
1223
+ {
1224
+ size: "sm",
1225
+ className: "crewlet-data-table__page-btn",
1226
+ onClick: () => goToPage(Math.max(1, currentPage - 1)),
1227
+ disabled: currentPage <= 1,
1228
+ label: labels.previousPage,
1229
+ icon: /* @__PURE__ */ jsx(ChevronLeftGlyph, { size: "md" })
1230
+ }
1231
+ ),
1232
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-data-table__page-number", "aria-live": "polite", children: [
1233
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: currentPage }),
1234
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: `${labels.page(currentPage, totalPages)}. ${labels.pageRange(
1235
+ pageRange.from,
1236
+ pageRange.to,
1237
+ pageRange.total
1238
+ )}` })
1239
+ ] }),
1240
+ /* @__PURE__ */ jsx(
1241
+ IconButton,
1242
+ {
1243
+ size: "sm",
1244
+ className: "crewlet-data-table__page-btn",
1245
+ onClick: () => goToPage(Math.min(totalPages, currentPage + 1)),
1246
+ disabled: currentPage >= totalPages,
1247
+ label: labels.nextPage,
1248
+ icon: /* @__PURE__ */ jsx(ChevronRightGlyph, { size: "md" })
1249
+ }
1250
+ ),
1251
+ /* @__PURE__ */ jsx(
1252
+ IconButton,
1253
+ {
1254
+ size: "sm",
1255
+ className: "crewlet-data-table__page-btn",
1256
+ onClick: () => goToPage(totalPages),
1257
+ disabled: currentPage >= totalPages,
1258
+ label: labels.lastPage,
1259
+ icon: /* @__PURE__ */ jsx(KeyboardDoubleArrowRightGlyph, { size: "md" })
1260
+ }
1261
+ )
1262
+ ] }),
1263
+ cogInChromeRow && /* @__PURE__ */ jsx(
1264
+ IconButton,
1265
+ {
1266
+ size: "sm",
1267
+ ref: settingsButtonRef,
1268
+ className: "crewlet-data-table__settings-btn",
1269
+ onClick: openTableSettings,
1270
+ label: labels.settings,
1271
+ title: labels.settings,
1272
+ icon: /* @__PURE__ */ jsx(SettingsGlyph, { size: "md" })
1273
+ }
1274
+ )
1275
+ ] }) : null;
1276
+ const chromeInOwnBar = topControlsVisible && !headerVisible && !cardHeader.hosted;
1277
+ const toolbarVisible = renderToolbar != null || chromeInOwnBar;
1278
+ return /* @__PURE__ */ jsxs("div", { className: rootClass, children: [
1279
+ cardHeader.hosted && cardHeader.node !== null ? createPortal(renderTopControls, cardHeader.node) : null,
1280
+ headerVisible && /* @__PURE__ */ jsxs("header", { className: "crewlet-data-table__header", children: [
1281
+ icon != null && /* @__PURE__ */ jsx("span", { className: "crewlet-data-table__header-icon", children: icon }),
1282
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-data-table__header-text", children: [
1283
+ title != null && /* @__PURE__ */ jsx("h3", { className: "crewlet-data-table__title", children: title }),
1284
+ description != null && /* @__PURE__ */ jsx("p", { className: "crewlet-data-table__description", children: description })
1285
+ ] }),
1286
+ renderTopControls
1287
+ ] }),
1288
+ toolbarVisible && /* @__PURE__ */ jsxs("div", { className: "crewlet-data-table__toolbar", children: [
1289
+ renderToolbar != null && /* @__PURE__ */ jsx("div", { className: "crewlet-data-table__toolbar-start", children: renderToolbar }),
1290
+ onClearFilters != null && filtersActive && /* @__PURE__ */ jsx(
1291
+ "button",
1292
+ {
1293
+ type: "button",
1294
+ className: "crewlet-data-table__clear-filters",
1295
+ onClick: onClearFilters,
1296
+ children: clearFiltersLabel
1297
+ }
1298
+ ),
1299
+ chromeInOwnBar && renderTopControls
1300
+ ] }),
1301
+ renderFilterBar != null && /* @__PURE__ */ jsx("div", { className: "crewlet-data-table__filter-bar", children: renderFilterBar }),
1302
+ /* @__PURE__ */ jsxs(
1303
+ "div",
1304
+ {
1305
+ className: [
1306
+ "crewlet-data-table__rail",
1307
+ /*
1308
+ * When the table carries a sticky-right action column the
1309
+ * row is treated as a frozen, screen-fitting surface: the
1310
+ * fit pass redistributes regular columns to consume only
1311
+ * the room left after the sticky pane and the gutter, the
1312
+ * resize handles are suppressed, and the scroll container
1313
+ * locks horizontal overflow. The modifier class flips that
1314
+ * behaviour on so the CSS can also drop the scrollbar mask
1315
+ * that would otherwise float over rows when no scrollbar
1316
+ * is present.
1317
+ */
1318
+ isCompact && columnOrder.some(
1319
+ (k) => columns[k]?.sticky === "right" && isColumnVisible(k)
1320
+ ) ? "crewlet-data-table__rail--frozen" : void 0
1321
+ ].filter(Boolean).join(" "),
1322
+ style: isCompact ? {
1323
+ "--crewlet-data-table-sticky-pane-width": `${columnOrder.filter((key) => columns[key]?.sticky === "right" && isColumnVisible(key)).reduce((sum, key) => sum + (columnWidths[key] ?? minColumnWidth), 0)}px`
1324
+ } : void 0,
1325
+ children: [
1326
+ /* @__PURE__ */ jsx("span", { role: "status", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: loading ? labels.loading : emptySaid }) }),
1327
+ /* @__PURE__ */ jsx(
1328
+ "div",
1329
+ {
1330
+ className: "crewlet-data-table__scroll",
1331
+ ref: scrollRef,
1332
+ style: boundedBody ? { maxHeight: maxBodyHeight } : void 0,
1333
+ children: /* @__PURE__ */ jsxs(
1334
+ "table",
1335
+ {
1336
+ className: cx(
1337
+ "crewlet-data-table__table",
1338
+ !bodyHoldsRows && "crewlet-data-table__table--rowless"
1339
+ ),
1340
+ "aria-busy": loading || void 0,
1341
+ children: [
1342
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
1343
+ renderExpandHeader(),
1344
+ columnOrder.filter((key) => columns[key]?.sticky !== "right").map((columnKey) => renderHeaderCell(columnKey)),
1345
+ isCompact && /* @__PURE__ */ jsx(
1346
+ "th",
1347
+ {
1348
+ className: "crewlet-data-table__th--chrome crewlet-data-table__th--spacer",
1349
+ "aria-hidden": true
1350
+ },
1351
+ "__spacer"
1352
+ ),
1353
+ columnOrder.filter((key) => columns[key]?.sticky === "right").map((columnKey) => renderHeaderCell(columnKey)),
1354
+ renderActionsHeader()
1355
+ ] }) }),
1356
+ /* @__PURE__ */ jsx("tbody", { children: loading && displayedData.length === 0 ? (
1357
+ /*
1358
+ * Skeleton rows live inside the real <tbody> and reuse the
1359
+ * live column set + widths, so the shimmer lines up exactly
1360
+ * with the data that replaces it. Bar widths cycle a fixed
1361
+ * pattern (not Math.random) so re-renders never reshuffle
1362
+ * the shimmer.
1363
+ */
1364
+ Array.from({ length: Math.max(1, skeletonRows) }, (_, rowIdx) => {
1365
+ const widths = [72, 46, 84, 58, 64];
1366
+ const visibleKeys = columnOrder.filter(
1367
+ (key) => columns[key]?.sticky !== "right" && isColumnVisible(key)
1368
+ );
1369
+ return /* @__PURE__ */ jsxs("tr", { className: "crewlet-data-table__skeleton-row", "aria-hidden": true, children: [
1370
+ expandable && /* @__PURE__ */ jsx("td", { className: "crewlet-data-table__expand-cell", style: { width: 32 } }, "__expand"),
1371
+ visibleKeys.map((columnKey, colIdx) => /* @__PURE__ */ jsx(
1372
+ "td",
1373
+ {
1374
+ style: columnWidths[columnKey] != null ? { width: `${columnWidths[columnKey]}px` } : void 0,
1375
+ children: /* @__PURE__ */ jsx(
1376
+ "span",
1377
+ {
1378
+ className: "crewlet-data-table__skeleton-bar",
1379
+ style: {
1380
+ width: `${widths[(rowIdx + colIdx) % widths.length]}%`,
1381
+ animationDelay: `${rowIdx * 0.1}s`
1382
+ }
1383
+ }
1384
+ )
1385
+ },
1386
+ columnKey
1387
+ )),
1388
+ isCompact && /* @__PURE__ */ jsx("td", { className: "crewlet-data-table__td--spacer", "aria-hidden": true }, "__spacer"),
1389
+ columnOrder.filter((key) => columns[key]?.sticky === "right" && isColumnVisible(key)).map((columnKey) => /* @__PURE__ */ jsx("td", { className: "crewlet-data-table__td--sticky-right" }, columnKey)),
1390
+ hasChromeColumn && /* @__PURE__ */ jsx("td", { className: "crewlet-data-table__td--actions" }, "__actions")
1391
+ ] }, `__skeleton_${rowIdx}`);
1392
+ })
1393
+ ) : error ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
1394
+ "td",
1395
+ {
1396
+ colSpan: expandColSpan,
1397
+ className: "crewlet-data-table__empty",
1398
+ children: error
1399
+ }
1400
+ ) }) : displayedData.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
1401
+ "td",
1402
+ {
1403
+ ref: emptyCellRef,
1404
+ colSpan: expandColSpan,
1405
+ className: "crewlet-data-table__empty",
1406
+ children: emptyMessage
1407
+ }
1408
+ ) }) : displayedData.map((row) => {
1409
+ const trKey = resolveRowKey(row);
1410
+ const isArchived = archivedPredicate ? archivedPredicate(row) : false;
1411
+ const expanded = expandable ? expandedKeys.has(trKey) : false;
1412
+ const expandedContent = expandable ? renderExpandedRow(row) : null;
1413
+ const canExpand = expandable && expandedContent != null;
1414
+ const href = getRowHref ? getRowHref(row) : null;
1415
+ const tone = rowTone ? rowTone(row) : null;
1416
+ const selected = isSelected ? isSelected(row) : void 0;
1417
+ const isClickable = !!onRowClick || canExpand || !!href;
1418
+ const trClass = cx(
1419
+ isArchived && "crewlet-data-table__row--archived",
1420
+ isClickable && "crewlet-data-table__row--clickable",
1421
+ canExpand && "crewlet-data-table__row--expandable",
1422
+ expanded && "is-expanded",
1423
+ selected && "crewlet-data-table__row--selected",
1424
+ tone && `crewlet-data-table__row--tone-${tone}`
1425
+ );
1426
+ const accessory = renderAccessoryRow ? renderAccessoryRow(row) : null;
1427
+ const onRowSurfaceClick = canExpand ? () => toggleExpanded(trKey) : onRowClick ? () => onRowClick(row) : void 0;
1428
+ const onSurface = onRowSurfaceClick ? (event) => {
1429
+ const from = event.target;
1430
+ if (from?.closest?.('a,button,input,select,textarea,label,[role="button"],[role="link"],[role="menuitem"]')) {
1431
+ return;
1432
+ }
1433
+ onRowSurfaceClick();
1434
+ } : void 0;
1435
+ const rowLead = {
1436
+ tone: tone ? /* @__PURE__ */ jsx(VisuallyHidden, { children: labels.tone[tone] }) : null,
1437
+ href
1438
+ };
1439
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
1440
+ /* @__PURE__ */ jsxs(
1441
+ "tr",
1442
+ {
1443
+ className: trClass || void 0,
1444
+ title: isArchived ? labels.archivedRow(archivedLabel) : void 0,
1445
+ onClick: onSurface,
1446
+ tabIndex: onRowClick && !href && !canExpand ? 0 : void 0,
1447
+ "aria-selected": selected,
1448
+ onKeyDown: onRowClick && !href && !canExpand ? (e) => {
1449
+ if (e.key === "Enter" || e.key === " ") {
1450
+ e.preventDefault();
1451
+ onRowClick(row);
1452
+ }
1453
+ } : void 0,
1454
+ children: [
1455
+ renderExpandCell(expanded, canExpand, () => toggleExpanded(trKey)),
1456
+ columnOrder.filter((columnKey) => columns[columnKey]?.sticky !== "right").map((columnKey) => {
1457
+ if (!isColumnVisible(columnKey)) return null;
1458
+ return renderBodyCell(row, columnKey, columnKey === firstVisibleKey ? rowLead : {});
1459
+ }),
1460
+ isCompact && /* @__PURE__ */ jsx("td", { className: "crewlet-data-table__td--spacer", "aria-hidden": true }, "__spacer"),
1461
+ columnOrder.filter((columnKey) => columns[columnKey]?.sticky === "right").map((columnKey) => {
1462
+ if (!isColumnVisible(columnKey)) return null;
1463
+ return renderBodyCell(row, columnKey);
1464
+ }),
1465
+ renderActionsCell(row)
1466
+ ]
1467
+ }
1468
+ ),
1469
+ expanded && expandedContent != null && /* @__PURE__ */ jsx(
1470
+ "tr",
1471
+ {
1472
+ className: [
1473
+ "crewlet-data-table__expanded-row",
1474
+ isArchived ? "crewlet-data-table__row--archived" : void 0
1475
+ ].filter(Boolean).join(" "),
1476
+ children: /* @__PURE__ */ jsx("td", { colSpan: expandColSpan, className: "crewlet-data-table__expanded-cell", children: expandedContent })
1477
+ }
1478
+ ),
1479
+ accessory != null && /* @__PURE__ */ jsx(
1480
+ "tr",
1481
+ {
1482
+ className: [
1483
+ "crewlet-data-table__accessory-row",
1484
+ isArchived ? "crewlet-data-table__row--archived" : void 0
1485
+ ].filter(Boolean).join(" "),
1486
+ children: /* @__PURE__ */ jsx("td", { colSpan, className: "crewlet-data-table__accessory-cell", children: accessory })
1487
+ }
1488
+ )
1489
+ ] }, trKey ?? JSON.stringify(row));
1490
+ }) })
1491
+ ]
1492
+ }
1493
+ )
1494
+ }
1495
+ )
1496
+ ]
1497
+ }
1498
+ ),
1499
+ hasMore && onLoadMore && /* @__PURE__ */ jsx("div", { className: "crewlet-data-table__load-more", children: /* @__PURE__ */ jsx(
1500
+ Button,
1501
+ {
1502
+ variant: "outline",
1503
+ size: "small",
1504
+ onClick: onLoadMore,
1505
+ loading: loadingMore,
1506
+ children: loadMoreLabel
1507
+ }
1508
+ ) }),
1509
+ !hasMore && endMessage != null && displayedData.length > 0 && !loading && /* @__PURE__ */ jsx("p", { className: "crewlet-data-table__end", children: endMessage }),
1510
+ /* @__PURE__ */ jsxs(
1511
+ Modal,
1512
+ {
1513
+ open: tableSettingsOpen,
1514
+ onClose: cancelTableSettings,
1515
+ title: labels.settingsTitle,
1516
+ size: "lg",
1517
+ footerStart: /* @__PURE__ */ jsxs(Fragment, { children: [
1518
+ /* @__PURE__ */ jsx(
1519
+ Button,
1520
+ {
1521
+ variant: "secondary",
1522
+ onClick: handleResetTableSettings,
1523
+ leadingIcon: resetConfirmed ? /* @__PURE__ */ jsx(CheckGlyph, { className: "crewlet-data-table__reset-confirm-icon", size: "sm" }) : void 0,
1524
+ children: labels.resetColumns
1525
+ }
1526
+ ),
1527
+ /* @__PURE__ */ jsx("span", { role: "status", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: settingsSaid }) })
1528
+ ] }),
1529
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
1530
+ /* @__PURE__ */ jsx(Button, { variant: "tertiary", onClick: cancelTableSettings, children: labels.cancel }),
1531
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: applyTableSettings, children: labels.apply })
1532
+ ] }),
1533
+ children: [
1534
+ pageSizeOffered ? /* @__PURE__ */ jsxs("div", { className: "crewlet-data-table__settings-section", children: [
1535
+ /* @__PURE__ */ jsx("h3", { className: "crewlet-data-table__settings-section-title", children: labels.itemsPerPage }),
1536
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-data-table__items-per-page-options", children: [
1537
+ itemsPerPageOptions.map((value) => /* @__PURE__ */ jsx(
1538
+ "button",
1539
+ {
1540
+ type: "button",
1541
+ className: cx("crewlet-data-table__items-per-page-btn", draftItemsPerPage === value && "is-active"),
1542
+ "aria-pressed": draftItemsPerPage === value,
1543
+ onClick: () => handleItemsPerPageChange(value),
1544
+ children: value
1545
+ },
1546
+ value
1547
+ )),
1548
+ /* @__PURE__ */ jsxs(
1549
+ "button",
1550
+ {
1551
+ type: "button",
1552
+ className: cx("crewlet-data-table__items-per-page-btn", draftItemsPerPage === ALL_ITEMS && "is-active"),
1553
+ "aria-pressed": draftItemsPerPage === ALL_ITEMS,
1554
+ onClick: () => handleItemsPerPageChange(ALL_ITEMS),
1555
+ children: [
1556
+ labels.allItems,
1557
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: ` ${labels.allItemsCount(sortedDataMemo.length)}` })
1558
+ ]
1559
+ }
1560
+ )
1561
+ ] })
1562
+ ] }) : null,
1563
+ /* @__PURE__ */ jsx("div", { className: "crewlet-data-table__settings-section", children: /* @__PURE__ */ jsx(
1564
+ Checkbox,
1565
+ {
1566
+ label: labels.wrapLines,
1567
+ description: labels.wrapLinesHint,
1568
+ checked: draftWrapLines,
1569
+ onChange: (e) => setDraftWrapLines(e.target.checked)
1570
+ }
1571
+ ) }),
1572
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-data-table__settings-section", children: [
1573
+ /* @__PURE__ */ jsx("h3", { className: "crewlet-data-table__settings-section-title", children: labels.columnsSection }),
1574
+ /* @__PURE__ */ jsx("p", { className: "crewlet-data-table__settings-section-hint", children: labels.columnsHint }),
1575
+ /* @__PURE__ */ jsx(VisuallyHidden, { id: reorderHintId, children: labels.reorderHint }),
1576
+ /* @__PURE__ */ jsx("ul", { className: "crewlet-data-table__column-toggles", children: draftColumnOrder.map((key, index) => {
1577
+ const name = columnName(key);
1578
+ const fixed = whyFixed(key, draftVisibleColumns);
1579
+ const shown = draftVisibleColumns[key] !== false;
1580
+ return /* @__PURE__ */ jsxs(
1581
+ "li",
1582
+ {
1583
+ className: cx("crewlet-data-table__column-toggle-item", draggedColumn === key && "is-dragging"),
1584
+ onDragOver: (e) => handleDragOver(e, key),
1585
+ onDrop: (e) => handleDrop(e),
1586
+ children: [
1587
+ /* @__PURE__ */ jsx(
1588
+ IconButton,
1589
+ {
1590
+ size: "sm",
1591
+ className: "crewlet-data-table__column-drag-handle",
1592
+ label: labels.reorder(name),
1593
+ icon: /* @__PURE__ */ jsx(DragIndicatorGlyph, { size: "md" }),
1594
+ "aria-describedby": reorderHintId,
1595
+ draggable: true,
1596
+ onDragStart: (e) => handleDragStart(e, key),
1597
+ onDragEnd: handleDragEnd,
1598
+ onKeyDown: (e) => {
1599
+ if (e.key !== "ArrowUp" && e.key !== "ArrowDown") return;
1600
+ e.preventDefault();
1601
+ moveColumn(key, e.key === "ArrowUp" ? -1 : 1);
1602
+ }
1603
+ }
1604
+ ),
1605
+ /* @__PURE__ */ jsx(
1606
+ Checkbox,
1607
+ {
1608
+ className: cx(
1609
+ "crewlet-data-table__column-toggle",
1610
+ fixed !== null && shown && "is-fixed"
1611
+ ),
1612
+ label: name,
1613
+ ...fixed !== null && shown ? { description: fixed, "aria-disabled": true } : {},
1614
+ checked: shown,
1615
+ onChange: () => handleToggleColumn(key)
1616
+ }
1617
+ ),
1618
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-data-table__column-toggle-actions", children: [
1619
+ /* @__PURE__ */ jsx(
1620
+ IconButton,
1621
+ {
1622
+ size: "sm",
1623
+ label: labels.moveUp(name),
1624
+ icon: /* @__PURE__ */ jsx(KeyboardArrowUpGlyph, { size: "sm" }),
1625
+ ...index === 0 ? { disabledReason: labels.atTop(name) } : {},
1626
+ onClick: () => moveColumn(key, -1)
1627
+ }
1628
+ ),
1629
+ /* @__PURE__ */ jsx(
1630
+ IconButton,
1631
+ {
1632
+ size: "sm",
1633
+ label: labels.moveDown(name),
1634
+ icon: /* @__PURE__ */ jsx(KeyboardArrowDownGlyph, { size: "sm" }),
1635
+ ...index === draftColumnOrder.length - 1 ? { disabledReason: labels.atBottom(name) } : {},
1636
+ onClick: () => moveColumn(key, 1)
1637
+ }
1638
+ )
1639
+ ] })
1640
+ ]
1641
+ },
1642
+ key
1643
+ );
1644
+ }) })
1645
+ ] })
1646
+ ]
1647
+ }
1648
+ )
1649
+ ] });
1650
+ };
1651
+
1652
+ export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu };