@freighttech/ui 0.13.18

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 (1477) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/dist/backend/AppShell.js +1289 -0
  4. package/dist/backend/AppShell.js.map +7 -0
  5. package/dist/backend/BackendChromeProvider.js +83 -0
  6. package/dist/backend/BackendChromeProvider.js.map +7 -0
  7. package/dist/backend/BackendPageSurface.js +19 -0
  8. package/dist/backend/BackendPageSurface.js.map +7 -0
  9. package/dist/backend/CollapsibleNavSection.js +149 -0
  10. package/dist/backend/CollapsibleNavSection.js.map +7 -0
  11. package/dist/backend/ContextHelp.js +33 -0
  12. package/dist/backend/ContextHelp.js.map +7 -0
  13. package/dist/backend/CrudForm.js +3163 -0
  14. package/dist/backend/CrudForm.js.map +7 -0
  15. package/dist/backend/DataTable.js +2091 -0
  16. package/dist/backend/DataTable.js.map +7 -0
  17. package/dist/backend/EmptyState.js +52 -0
  18. package/dist/backend/EmptyState.js.map +7 -0
  19. package/dist/backend/FilterBar.js +147 -0
  20. package/dist/backend/FilterBar.js.map +7 -0
  21. package/dist/backend/FilterOverlay.js +337 -0
  22. package/dist/backend/FilterOverlay.js.map +7 -0
  23. package/dist/backend/FlashMessages.js +158 -0
  24. package/dist/backend/FlashMessages.js.map +7 -0
  25. package/dist/backend/HtmlRichTextEditor.js +129 -0
  26. package/dist/backend/HtmlRichTextEditor.js.map +7 -0
  27. package/dist/backend/IntegrationsButton.js +25 -0
  28. package/dist/backend/IntegrationsButton.js.map +7 -0
  29. package/dist/backend/JsonBuilder.js +323 -0
  30. package/dist/backend/JsonBuilder.js.map +7 -0
  31. package/dist/backend/JsonDisplay.js +207 -0
  32. package/dist/backend/JsonDisplay.js.map +7 -0
  33. package/dist/backend/NextStepCallout.js +79 -0
  34. package/dist/backend/NextStepCallout.js.map +7 -0
  35. package/dist/backend/Page.js +27 -0
  36. package/dist/backend/Page.js.map +7 -0
  37. package/dist/backend/PerspectiveSidebar.js +456 -0
  38. package/dist/backend/PerspectiveSidebar.js.map +7 -0
  39. package/dist/backend/ProfileDropdown.js +341 -0
  40. package/dist/backend/ProfileDropdown.js.map +7 -0
  41. package/dist/backend/RowActions.js +155 -0
  42. package/dist/backend/RowActions.js.map +7 -0
  43. package/dist/backend/SectionHeader.js +74 -0
  44. package/dist/backend/SectionHeader.js.map +7 -0
  45. package/dist/backend/SettingsButton.js +25 -0
  46. package/dist/backend/SettingsButton.js.map +7 -0
  47. package/dist/backend/Sidebar.js +510 -0
  48. package/dist/backend/Sidebar.js.map +7 -0
  49. package/dist/backend/Sidebar.stories.js +166 -0
  50. package/dist/backend/Sidebar.stories.js.map +7 -0
  51. package/dist/backend/TruncatedCell.js +92 -0
  52. package/dist/backend/TruncatedCell.js.map +7 -0
  53. package/dist/backend/UserMenu.js +146 -0
  54. package/dist/backend/UserMenu.js.map +7 -0
  55. package/dist/backend/ValueIcons.js +34 -0
  56. package/dist/backend/ValueIcons.js.map +7 -0
  57. package/dist/backend/WebhookSetupGuide.js +79 -0
  58. package/dist/backend/WebhookSetupGuide.js.map +7 -0
  59. package/dist/backend/charts/BarChart.js +154 -0
  60. package/dist/backend/charts/BarChart.js.map +7 -0
  61. package/dist/backend/charts/ChartUtils.js +141 -0
  62. package/dist/backend/charts/ChartUtils.js.map +7 -0
  63. package/dist/backend/charts/ComboChart.js +261 -0
  64. package/dist/backend/charts/ComboChart.js.map +7 -0
  65. package/dist/backend/charts/ComboChart.stories.js +88 -0
  66. package/dist/backend/charts/ComboChart.stories.js.map +7 -0
  67. package/dist/backend/charts/KpiCard.js +96 -0
  68. package/dist/backend/charts/KpiCard.js.map +7 -0
  69. package/dist/backend/charts/LineChart.js +165 -0
  70. package/dist/backend/charts/LineChart.js.map +7 -0
  71. package/dist/backend/charts/PieChart.js +121 -0
  72. package/dist/backend/charts/PieChart.js.map +7 -0
  73. package/dist/backend/charts/ScatterChart.js +320 -0
  74. package/dist/backend/charts/ScatterChart.js.map +7 -0
  75. package/dist/backend/charts/TopNTable.js +91 -0
  76. package/dist/backend/charts/TopNTable.js.map +7 -0
  77. package/dist/backend/charts/WaterfallChart.js +136 -0
  78. package/dist/backend/charts/WaterfallChart.js.map +7 -0
  79. package/dist/backend/charts/index.js +30 -0
  80. package/dist/backend/charts/index.js.map +7 -0
  81. package/dist/backend/columns/ColumnChooserPanel.js +244 -0
  82. package/dist/backend/columns/ColumnChooserPanel.js.map +7 -0
  83. package/dist/backend/confirm-dialog/ConfirmDialog.js +214 -0
  84. package/dist/backend/confirm-dialog/ConfirmDialog.js.map +7 -0
  85. package/dist/backend/confirm-dialog/index.js +7 -0
  86. package/dist/backend/confirm-dialog/index.js.map +7 -0
  87. package/dist/backend/confirm-dialog/useConfirmDialog.js +113 -0
  88. package/dist/backend/confirm-dialog/useConfirmDialog.js.map +7 -0
  89. package/dist/backend/custom-fields/FieldDefinitionsEditor.js +1352 -0
  90. package/dist/backend/custom-fields/FieldDefinitionsEditor.js.map +7 -0
  91. package/dist/backend/custom-fields/FieldDefinitionsManager.js +332 -0
  92. package/dist/backend/custom-fields/FieldDefinitionsManager.js.map +7 -0
  93. package/dist/backend/dashboard/DashboardScreen.js +598 -0
  94. package/dist/backend/dashboard/DashboardScreen.js.map +7 -0
  95. package/dist/backend/dashboard/index.js +5 -0
  96. package/dist/backend/dashboard/index.js.map +7 -0
  97. package/dist/backend/dashboard/widgetRegistry.js +55 -0
  98. package/dist/backend/dashboard/widgetRegistry.js.map +7 -0
  99. package/dist/backend/date-range/DateRangeSelect.js +39 -0
  100. package/dist/backend/date-range/DateRangeSelect.js.map +7 -0
  101. package/dist/backend/date-range/InlineDateRangeSelect.js +42 -0
  102. package/dist/backend/date-range/InlineDateRangeSelect.js.map +7 -0
  103. package/dist/backend/date-range/InlineGranularitySelect.js +40 -0
  104. package/dist/backend/date-range/InlineGranularitySelect.js.map +7 -0
  105. package/dist/backend/date-range/dateRanges.js +176 -0
  106. package/dist/backend/date-range/dateRanges.js.map +7 -0
  107. package/dist/backend/date-range/index.js +25 -0
  108. package/dist/backend/date-range/index.js.map +7 -0
  109. package/dist/backend/detail/AccessDeniedMessage.js +28 -0
  110. package/dist/backend/detail/AccessDeniedMessage.js.map +7 -0
  111. package/dist/backend/detail/ActivitiesSection.js +947 -0
  112. package/dist/backend/detail/ActivitiesSection.js.map +7 -0
  113. package/dist/backend/detail/AddressEditor.js +417 -0
  114. package/dist/backend/detail/AddressEditor.js.map +7 -0
  115. package/dist/backend/detail/AddressTiles.js +441 -0
  116. package/dist/backend/detail/AddressTiles.js.map +7 -0
  117. package/dist/backend/detail/AddressesSection.js +274 -0
  118. package/dist/backend/detail/AddressesSection.js.map +7 -0
  119. package/dist/backend/detail/AttachmentDeleteDialog.js +41 -0
  120. package/dist/backend/detail/AttachmentDeleteDialog.js.map +7 -0
  121. package/dist/backend/detail/AttachmentMetadataDialog.js +519 -0
  122. package/dist/backend/detail/AttachmentMetadataDialog.js.map +7 -0
  123. package/dist/backend/detail/AttachmentVisualPreview.js +132 -0
  124. package/dist/backend/detail/AttachmentVisualPreview.js.map +7 -0
  125. package/dist/backend/detail/AttachmentsSection.js +281 -0
  126. package/dist/backend/detail/AttachmentsSection.js.map +7 -0
  127. package/dist/backend/detail/CustomDataSection.js +575 -0
  128. package/dist/backend/detail/CustomDataSection.js.map +7 -0
  129. package/dist/backend/detail/DetailFieldsSection.js +85 -0
  130. package/dist/backend/detail/DetailFieldsSection.js.map +7 -0
  131. package/dist/backend/detail/ErrorMessage.js +28 -0
  132. package/dist/backend/detail/ErrorMessage.js.map +7 -0
  133. package/dist/backend/detail/InlineEditors.js +697 -0
  134. package/dist/backend/detail/InlineEditors.js.map +7 -0
  135. package/dist/backend/detail/LoadingMessage.js +14 -0
  136. package/dist/backend/detail/LoadingMessage.js.map +7 -0
  137. package/dist/backend/detail/NotesSection.js +1022 -0
  138. package/dist/backend/detail/NotesSection.js.map +7 -0
  139. package/dist/backend/detail/TabEmptyState.js +25 -0
  140. package/dist/backend/detail/TabEmptyState.js.map +7 -0
  141. package/dist/backend/detail/TagsSection.js +375 -0
  142. package/dist/backend/detail/TagsSection.js.map +7 -0
  143. package/dist/backend/detail/addressFormat.js +77 -0
  144. package/dist/backend/detail/addressFormat.js.map +7 -0
  145. package/dist/backend/detail/index.js +36 -0
  146. package/dist/backend/detail/index.js.map +7 -0
  147. package/dist/backend/devtools/UmesDevToolsPanel.js +109 -0
  148. package/dist/backend/devtools/UmesDevToolsPanel.js.map +7 -0
  149. package/dist/backend/devtools/components/ConflictWarnings.js +32 -0
  150. package/dist/backend/devtools/components/ConflictWarnings.js.map +7 -0
  151. package/dist/backend/devtools/components/EnricherTiming.js +46 -0
  152. package/dist/backend/devtools/components/EnricherTiming.js.map +7 -0
  153. package/dist/backend/devtools/components/EventFlow.js +34 -0
  154. package/dist/backend/devtools/components/EventFlow.js.map +7 -0
  155. package/dist/backend/devtools/components/ExtensionPointList.js +58 -0
  156. package/dist/backend/devtools/components/ExtensionPointList.js.map +7 -0
  157. package/dist/backend/devtools/components/InterceptorActivity.js +36 -0
  158. package/dist/backend/devtools/components/InterceptorActivity.js.map +7 -0
  159. package/dist/backend/devtools/index.js +7 -0
  160. package/dist/backend/devtools/index.js.map +7 -0
  161. package/dist/backend/devtools/useUmesDevTools.js +125 -0
  162. package/dist/backend/devtools/useUmesDevTools.js.map +7 -0
  163. package/dist/backend/document-viewer/RegionOverlay.js +92 -0
  164. package/dist/backend/document-viewer/RegionOverlay.js.map +7 -0
  165. package/dist/backend/document-viewer/index.js +6 -0
  166. package/dist/backend/document-viewer/index.js.map +7 -0
  167. package/dist/backend/dynamic-grid/DynamicGrid.js +130 -0
  168. package/dist/backend/dynamic-grid/DynamicGrid.js.map +7 -0
  169. package/dist/backend/dynamic-grid/adapters.js +34 -0
  170. package/dist/backend/dynamic-grid/adapters.js.map +7 -0
  171. package/dist/backend/dynamic-grid/components/GridCell.js +149 -0
  172. package/dist/backend/dynamic-grid/components/GridCell.js.map +7 -0
  173. package/dist/backend/dynamic-grid/components/GridRow.js +32 -0
  174. package/dist/backend/dynamic-grid/components/GridRow.js.map +7 -0
  175. package/dist/backend/dynamic-grid/hooks/useGridKeyboardNav.js +115 -0
  176. package/dist/backend/dynamic-grid/hooks/useGridKeyboardNav.js.map +7 -0
  177. package/dist/backend/dynamic-grid/index.js +9 -0
  178. package/dist/backend/dynamic-grid/index.js.map +7 -0
  179. package/dist/backend/dynamic-grid/types.js +1 -0
  180. package/dist/backend/dynamic-grid/types.js.map +7 -0
  181. package/dist/backend/dynamic-table/DynamicTable.js +2607 -0
  182. package/dist/backend/dynamic-table/DynamicTable.js.map +7 -0
  183. package/dist/backend/dynamic-table/DynamicTable.stories.js +233 -0
  184. package/dist/backend/dynamic-table/DynamicTable.stories.js.map +7 -0
  185. package/dist/backend/dynamic-table/components/ActiveFilterChips.js +60 -0
  186. package/dist/backend/dynamic-table/components/ActiveFilterChips.js.map +7 -0
  187. package/dist/backend/dynamic-table/components/BulkActionsBar.js +58 -0
  188. package/dist/backend/dynamic-table/components/BulkActionsBar.js.map +7 -0
  189. package/dist/backend/dynamic-table/components/Cell.js +155 -0
  190. package/dist/backend/dynamic-table/components/Cell.js.map +7 -0
  191. package/dist/backend/dynamic-table/components/CellCommentDialog.js +726 -0
  192. package/dist/backend/dynamic-table/components/CellCommentDialog.js.map +7 -0
  193. package/dist/backend/dynamic-table/components/CellCommentHoverPopup.js +77 -0
  194. package/dist/backend/dynamic-table/components/CellCommentHoverPopup.js.map +7 -0
  195. package/dist/backend/dynamic-table/components/ColumnFilterPopover.js +485 -0
  196. package/dist/backend/dynamic-table/components/ColumnFilterPopover.js.map +7 -0
  197. package/dist/backend/dynamic-table/components/ColumnHeaderMenu.js +173 -0
  198. package/dist/backend/dynamic-table/components/ColumnHeaderMenu.js.map +7 -0
  199. package/dist/backend/dynamic-table/components/ColumnHeaders.js +528 -0
  200. package/dist/backend/dynamic-table/components/ColumnHeaders.js.map +7 -0
  201. package/dist/backend/dynamic-table/components/CompactLabelCell.js +64 -0
  202. package/dist/backend/dynamic-table/components/CompactLabelCell.js.map +7 -0
  203. package/dist/backend/dynamic-table/components/ConfigureViewFields.js +139 -0
  204. package/dist/backend/dynamic-table/components/ConfigureViewFields.js.map +7 -0
  205. package/dist/backend/dynamic-table/components/ConfigureViewFilters.js +305 -0
  206. package/dist/backend/dynamic-table/components/ConfigureViewFilters.js.map +7 -0
  207. package/dist/backend/dynamic-table/components/ConfigureViewFormatting.js +169 -0
  208. package/dist/backend/dynamic-table/components/ConfigureViewFormatting.js.map +7 -0
  209. package/dist/backend/dynamic-table/components/ConfigureViewFormulas.js +298 -0
  210. package/dist/backend/dynamic-table/components/ConfigureViewFormulas.js.map +7 -0
  211. package/dist/backend/dynamic-table/components/ConfigureViewGrouping.js +224 -0
  212. package/dist/backend/dynamic-table/components/ConfigureViewGrouping.js.map +7 -0
  213. package/dist/backend/dynamic-table/components/ConfigureViewLinkedColumns.js +167 -0
  214. package/dist/backend/dynamic-table/components/ConfigureViewLinkedColumns.js.map +7 -0
  215. package/dist/backend/dynamic-table/components/ConfigureViewPanel.js +592 -0
  216. package/dist/backend/dynamic-table/components/ConfigureViewPanel.js.map +7 -0
  217. package/dist/backend/dynamic-table/components/ConfigureViewRollups.js +269 -0
  218. package/dist/backend/dynamic-table/components/ConfigureViewRollups.js.map +7 -0
  219. package/dist/backend/dynamic-table/components/ConfigureViewSorting.js +107 -0
  220. package/dist/backend/dynamic-table/components/ConfigureViewSorting.js.map +7 -0
  221. package/dist/backend/dynamic-table/components/ContextMenu.js +91 -0
  222. package/dist/backend/dynamic-table/components/ContextMenu.js.map +7 -0
  223. package/dist/backend/dynamic-table/components/DateCell.js +80 -0
  224. package/dist/backend/dynamic-table/components/DateCell.js.map +7 -0
  225. package/dist/backend/dynamic-table/components/Debugger.js +311 -0
  226. package/dist/backend/dynamic-table/components/Debugger.js.map +7 -0
  227. package/dist/backend/dynamic-table/components/DensityControl.js +289 -0
  228. package/dist/backend/dynamic-table/components/DensityControl.js.map +7 -0
  229. package/dist/backend/dynamic-table/components/EmptyState.js +42 -0
  230. package/dist/backend/dynamic-table/components/EmptyState.js.map +7 -0
  231. package/dist/backend/dynamic-table/components/EntitySearchEditor.js +369 -0
  232. package/dist/backend/dynamic-table/components/EntitySearchEditor.js.map +7 -0
  233. package/dist/backend/dynamic-table/components/ExportMenu.js +63 -0
  234. package/dist/backend/dynamic-table/components/ExportMenu.js.map +7 -0
  235. package/dist/backend/dynamic-table/components/FilterDatePicker.js +165 -0
  236. package/dist/backend/dynamic-table/components/FilterDatePicker.js.map +7 -0
  237. package/dist/backend/dynamic-table/components/FilterValueInput.js +200 -0
  238. package/dist/backend/dynamic-table/components/FilterValueInput.js.map +7 -0
  239. package/dist/backend/dynamic-table/components/FooterTotalsRow.js +165 -0
  240. package/dist/backend/dynamic-table/components/FooterTotalsRow.js.map +7 -0
  241. package/dist/backend/dynamic-table/components/FullscreenOverlay.js +51 -0
  242. package/dist/backend/dynamic-table/components/FullscreenOverlay.js.map +7 -0
  243. package/dist/backend/dynamic-table/components/GroupHeaderRow.js +108 -0
  244. package/dist/backend/dynamic-table/components/GroupHeaderRow.js.map +7 -0
  245. package/dist/backend/dynamic-table/components/GroupSummaryRow.js +134 -0
  246. package/dist/backend/dynamic-table/components/GroupSummaryRow.js.map +7 -0
  247. package/dist/backend/dynamic-table/components/ImportPanel.js +341 -0
  248. package/dist/backend/dynamic-table/components/ImportPanel.js.map +7 -0
  249. package/dist/backend/dynamic-table/components/ImportPreviewGrid.js +114 -0
  250. package/dist/backend/dynamic-table/components/ImportPreviewGrid.js.map +7 -0
  251. package/dist/backend/dynamic-table/components/LoadErrorState.js +23 -0
  252. package/dist/backend/dynamic-table/components/LoadErrorState.js.map +7 -0
  253. package/dist/backend/dynamic-table/components/MentionPopup.js +149 -0
  254. package/dist/backend/dynamic-table/components/MentionPopup.js.map +7 -0
  255. package/dist/backend/dynamic-table/components/PerspectiveDeleteDialog.js +57 -0
  256. package/dist/backend/dynamic-table/components/PerspectiveDeleteDialog.js.map +7 -0
  257. package/dist/backend/dynamic-table/components/PerspectivePublishDialog.js +100 -0
  258. package/dist/backend/dynamic-table/components/PerspectivePublishDialog.js.map +7 -0
  259. package/dist/backend/dynamic-table/components/PerspectiveTabMenu.js +159 -0
  260. package/dist/backend/dynamic-table/components/PerspectiveTabMenu.js.map +7 -0
  261. package/dist/backend/dynamic-table/components/PerspectiveTabs.js +319 -0
  262. package/dist/backend/dynamic-table/components/PerspectiveTabs.js.map +7 -0
  263. package/dist/backend/dynamic-table/components/PerspectiveTemplateMenu.js +90 -0
  264. package/dist/backend/dynamic-table/components/PerspectiveTemplateMenu.js.map +7 -0
  265. package/dist/backend/dynamic-table/components/RowHeaderCell.js +58 -0
  266. package/dist/backend/dynamic-table/components/RowHeaderCell.js.map +7 -0
  267. package/dist/backend/dynamic-table/components/SearchBar.js +221 -0
  268. package/dist/backend/dynamic-table/components/SearchBar.js.map +7 -0
  269. package/dist/backend/dynamic-table/components/SelectMenu.js +186 -0
  270. package/dist/backend/dynamic-table/components/SelectMenu.js.map +7 -0
  271. package/dist/backend/dynamic-table/components/StaleDataBar.js +26 -0
  272. package/dist/backend/dynamic-table/components/StaleDataBar.js.map +7 -0
  273. package/dist/backend/dynamic-table/components/TableDeleteDialog.js +48 -0
  274. package/dist/backend/dynamic-table/components/TableDeleteDialog.js.map +7 -0
  275. package/dist/backend/dynamic-table/components/TablePagination.js +69 -0
  276. package/dist/backend/dynamic-table/components/TablePagination.js.map +7 -0
  277. package/dist/backend/dynamic-table/components/TableSkeleton.js +43 -0
  278. package/dist/backend/dynamic-table/components/TableSkeleton.js.map +7 -0
  279. package/dist/backend/dynamic-table/components/ToolbarOverflow.js +204 -0
  280. package/dist/backend/dynamic-table/components/ToolbarOverflow.js.map +7 -0
  281. package/dist/backend/dynamic-table/components/ViewModeSwitch.js +50 -0
  282. package/dist/backend/dynamic-table/components/ViewModeSwitch.js.map +7 -0
  283. package/dist/backend/dynamic-table/components/VirtualRow.js +214 -0
  284. package/dist/backend/dynamic-table/components/VirtualRow.js.map +7 -0
  285. package/dist/backend/dynamic-table/components/editors.js +1483 -0
  286. package/dist/backend/dynamic-table/components/editors.js.map +7 -0
  287. package/dist/backend/dynamic-table/components/renderers.js +131 -0
  288. package/dist/backend/dynamic-table/components/renderers.js.map +7 -0
  289. package/dist/backend/dynamic-table/events/events.js +73 -0
  290. package/dist/backend/dynamic-table/events/events.js.map +7 -0
  291. package/dist/backend/dynamic-table/formula/check.js +243 -0
  292. package/dist/backend/dynamic-table/formula/check.js.map +7 -0
  293. package/dist/backend/dynamic-table/formula/evaluate.js +302 -0
  294. package/dist/backend/dynamic-table/formula/evaluate.js.map +7 -0
  295. package/dist/backend/dynamic-table/formula/functions.js +602 -0
  296. package/dist/backend/dynamic-table/formula/functions.js.map +7 -0
  297. package/dist/backend/dynamic-table/formula/index.js +47 -0
  298. package/dist/backend/dynamic-table/formula/index.js.map +7 -0
  299. package/dist/backend/dynamic-table/formula/parse.js +293 -0
  300. package/dist/backend/dynamic-table/formula/parse.js.map +7 -0
  301. package/dist/backend/dynamic-table/formula/types.js +24 -0
  302. package/dist/backend/dynamic-table/formula/types.js.map +7 -0
  303. package/dist/backend/dynamic-table/handlers/cellWrites.js +143 -0
  304. package/dist/backend/dynamic-table/handlers/cellWrites.js.map +7 -0
  305. package/dist/backend/dynamic-table/handlers/index.js +504 -0
  306. package/dist/backend/dynamic-table/handlers/index.js.map +7 -0
  307. package/dist/backend/dynamic-table/handlers/perspectiveHandlers.js +377 -0
  308. package/dist/backend/dynamic-table/handlers/perspectiveHandlers.js.map +7 -0
  309. package/dist/backend/dynamic-table/hooks/index.js +524 -0
  310. package/dist/backend/dynamic-table/hooks/index.js.map +7 -0
  311. package/dist/backend/dynamic-table/hooks/useAbbreviations.js +19 -0
  312. package/dist/backend/dynamic-table/hooks/useAbbreviations.js.map +7 -0
  313. package/dist/backend/dynamic-table/hooks/useAnnotations.js +115 -0
  314. package/dist/backend/dynamic-table/hooks/useAnnotations.js.map +7 -0
  315. package/dist/backend/dynamic-table/hooks/useColumnVirtualizer.js +155 -0
  316. package/dist/backend/dynamic-table/hooks/useColumnVirtualizer.js.map +7 -0
  317. package/dist/backend/dynamic-table/hooks/useColumnWidthPersistence.js +135 -0
  318. package/dist/backend/dynamic-table/hooks/useColumnWidthPersistence.js.map +7 -0
  319. package/dist/backend/dynamic-table/hooks/useDensityPreference.js +203 -0
  320. package/dist/backend/dynamic-table/hooks/useDensityPreference.js.map +7 -0
  321. package/dist/backend/dynamic-table/hooks/useDynamicTablePage.js +1005 -0
  322. package/dist/backend/dynamic-table/hooks/useDynamicTablePage.js.map +7 -0
  323. package/dist/backend/dynamic-table/hooks/useEscapeLayer.js +32 -0
  324. package/dist/backend/dynamic-table/hooks/useEscapeLayer.js.map +7 -0
  325. package/dist/backend/dynamic-table/hooks/useGrouping.js +256 -0
  326. package/dist/backend/dynamic-table/hooks/useGrouping.js.map +7 -0
  327. package/dist/backend/dynamic-table/hooks/useSuggestionFetch.js +63 -0
  328. package/dist/backend/dynamic-table/hooks/useSuggestionFetch.js.map +7 -0
  329. package/dist/backend/dynamic-table/hooks/useTableDateFormat.js +11 -0
  330. package/dist/backend/dynamic-table/hooks/useTableDateFormat.js.map +7 -0
  331. package/dist/backend/dynamic-table/index.js +476 -0
  332. package/dist/backend/dynamic-table/index.js.map +7 -0
  333. package/dist/backend/dynamic-table/registry/ContentRegistryContext.js +126 -0
  334. package/dist/backend/dynamic-table/registry/ContentRegistryContext.js.map +7 -0
  335. package/dist/backend/dynamic-table/registry/TableRegistryContext.js +43 -0
  336. package/dist/backend/dynamic-table/registry/TableRegistryContext.js.map +7 -0
  337. package/dist/backend/dynamic-table/registry/filterAccessibleTables.js +13 -0
  338. package/dist/backend/dynamic-table/registry/filterAccessibleTables.js.map +7 -0
  339. package/dist/backend/dynamic-table/registry/index.js +44 -0
  340. package/dist/backend/dynamic-table/registry/index.js.map +7 -0
  341. package/dist/backend/dynamic-table/registry/lazyTable.js +55 -0
  342. package/dist/backend/dynamic-table/registry/lazyTable.js.map +7 -0
  343. package/dist/backend/dynamic-table/registry/types.js +1 -0
  344. package/dist/backend/dynamic-table/registry/types.js.map +7 -0
  345. package/dist/backend/dynamic-table/registry/widgetCatalog.js +96 -0
  346. package/dist/backend/dynamic-table/registry/widgetCatalog.js.map +7 -0
  347. package/dist/backend/dynamic-table/server/aggregate.js +261 -0
  348. package/dist/backend/dynamic-table/server/aggregate.js.map +7 -0
  349. package/dist/backend/dynamic-table/server/dateWindows.js +105 -0
  350. package/dist/backend/dynamic-table/server/dateWindows.js.map +7 -0
  351. package/dist/backend/dynamic-table/server/filterParser.js +97 -0
  352. package/dist/backend/dynamic-table/server/filterParser.js.map +7 -0
  353. package/dist/backend/dynamic-table/server/filterSuggestions.js +70 -0
  354. package/dist/backend/dynamic-table/server/filterSuggestions.js.map +7 -0
  355. package/dist/backend/dynamic-table/server/index.js +47 -0
  356. package/dist/backend/dynamic-table/server/index.js.map +7 -0
  357. package/dist/backend/dynamic-table/server/makeDynamicTableRoute.js +270 -0
  358. package/dist/backend/dynamic-table/server/makeDynamicTableRoute.js.map +7 -0
  359. package/dist/backend/dynamic-table/split-view/ContentPicker.js +171 -0
  360. package/dist/backend/dynamic-table/split-view/ContentPicker.js.map +7 -0
  361. package/dist/backend/dynamic-table/split-view/EmptySlot.js +47 -0
  362. package/dist/backend/dynamic-table/split-view/EmptySlot.js.map +7 -0
  363. package/dist/backend/dynamic-table/split-view/SplitViewHost.js +863 -0
  364. package/dist/backend/dynamic-table/split-view/SplitViewHost.js.map +7 -0
  365. package/dist/backend/dynamic-table/split-view/WidgetPane.js +280 -0
  366. package/dist/backend/dynamic-table/split-view/WidgetPane.js.map +7 -0
  367. package/dist/backend/dynamic-table/split-view/WorkspaceFilterBar.js +524 -0
  368. package/dist/backend/dynamic-table/split-view/WorkspaceFilterBar.js.map +7 -0
  369. package/dist/backend/dynamic-table/split-view/index.js +61 -0
  370. package/dist/backend/dynamic-table/split-view/index.js.map +7 -0
  371. package/dist/backend/dynamic-table/split-view/layoutPersistence.js +91 -0
  372. package/dist/backend/dynamic-table/split-view/layoutPersistence.js.map +7 -0
  373. package/dist/backend/dynamic-table/split-view/sharedCriteria.js +62 -0
  374. package/dist/backend/dynamic-table/split-view/sharedCriteria.js.map +7 -0
  375. package/dist/backend/dynamic-table/split-view/types.js +426 -0
  376. package/dist/backend/dynamic-table/split-view/types.js.map +7 -0
  377. package/dist/backend/dynamic-table/split-view/useSplitViewLayouts.js +79 -0
  378. package/dist/backend/dynamic-table/split-view/useSplitViewLayouts.js.map +7 -0
  379. package/dist/backend/dynamic-table/store/index.js +611 -0
  380. package/dist/backend/dynamic-table/store/index.js.map +7 -0
  381. package/dist/backend/dynamic-table/styles/ContextMenu.css.js +2 -0
  382. package/dist/backend/dynamic-table/styles/DynamicTable.css.js +2 -0
  383. package/dist/backend/dynamic-table/styles/DynamicTable.v2.css.js +2 -0
  384. package/dist/backend/dynamic-table/styles/SearchBar.css.js +2 -0
  385. package/dist/backend/dynamic-table/styles/dateCell.css.js +2 -0
  386. package/dist/backend/dynamic-table/styles/density.css.js +2 -0
  387. package/dist/backend/dynamic-table/types/density.js +29 -0
  388. package/dist/backend/dynamic-table/types/density.js.map +7 -0
  389. package/dist/backend/dynamic-table/types/filters.js +124 -0
  390. package/dist/backend/dynamic-table/types/filters.js.map +7 -0
  391. package/dist/backend/dynamic-table/types/grouping.js +34 -0
  392. package/dist/backend/dynamic-table/types/grouping.js.map +7 -0
  393. package/dist/backend/dynamic-table/types/import.js +7 -0
  394. package/dist/backend/dynamic-table/types/import.js.map +7 -0
  395. package/dist/backend/dynamic-table/types/index.js +46 -0
  396. package/dist/backend/dynamic-table/types/index.js.map +7 -0
  397. package/dist/backend/dynamic-table/types/perspective.js +79 -0
  398. package/dist/backend/dynamic-table/types/perspective.js.map +7 -0
  399. package/dist/backend/dynamic-table/types/rollup.js +13 -0
  400. package/dist/backend/dynamic-table/types/rollup.js.map +7 -0
  401. package/dist/backend/dynamic-table/utils/abbreviations.js +228 -0
  402. package/dist/backend/dynamic-table/utils/abbreviations.js.map +7 -0
  403. package/dist/backend/dynamic-table/utils/anchoredPosition.js +21 -0
  404. package/dist/backend/dynamic-table/utils/anchoredPosition.js.map +7 -0
  405. package/dist/backend/dynamic-table/utils/badgeAutoFit.js +35 -0
  406. package/dist/backend/dynamic-table/utils/badgeAutoFit.js.map +7 -0
  407. package/dist/backend/dynamic-table/utils/clipboard.js +172 -0
  408. package/dist/backend/dynamic-table/utils/clipboard.js.map +7 -0
  409. package/dist/backend/dynamic-table/utils/coerceCellValue.js +52 -0
  410. package/dist/backend/dynamic-table/utils/coerceCellValue.js.map +7 -0
  411. package/dist/backend/dynamic-table/utils/colorAdjacency.js +27 -0
  412. package/dist/backend/dynamic-table/utils/colorAdjacency.js.map +7 -0
  413. package/dist/backend/dynamic-table/utils/columnFill.js +36 -0
  414. package/dist/backend/dynamic-table/utils/columnFill.js.map +7 -0
  415. package/dist/backend/dynamic-table/utils/columnSpacerStyle.js +21 -0
  416. package/dist/backend/dynamic-table/utils/columnSpacerStyle.js.map +7 -0
  417. package/dist/backend/dynamic-table/utils/columnWindow.js +293 -0
  418. package/dist/backend/dynamic-table/utils/columnWindow.js.map +7 -0
  419. package/dist/backend/dynamic-table/utils/conditionalFormat.js +188 -0
  420. package/dist/backend/dynamic-table/utils/conditionalFormat.js.map +7 -0
  421. package/dist/backend/dynamic-table/utils/exportTable.js +82 -0
  422. package/dist/backend/dynamic-table/utils/exportTable.js.map +7 -0
  423. package/dist/backend/dynamic-table/utils/fillGeometry.js +92 -0
  424. package/dist/backend/dynamic-table/utils/fillGeometry.js.map +7 -0
  425. package/dist/backend/dynamic-table/utils/fillPatterns.js +241 -0
  426. package/dist/backend/dynamic-table/utils/fillPatterns.js.map +7 -0
  427. package/dist/backend/dynamic-table/utils/formatAggregate.js +82 -0
  428. package/dist/backend/dynamic-table/utils/formatAggregate.js.map +7 -0
  429. package/dist/backend/dynamic-table/utils/formatDateCompact.js +508 -0
  430. package/dist/backend/dynamic-table/utils/formatDateCompact.js.map +7 -0
  431. package/dist/backend/dynamic-table/utils/formatLabelCompact.js +312 -0
  432. package/dist/backend/dynamic-table/utils/formatLabelCompact.js.map +7 -0
  433. package/dist/backend/dynamic-table/utils/formulaColumns.js +158 -0
  434. package/dist/backend/dynamic-table/utils/formulaColumns.js.map +7 -0
  435. package/dist/backend/dynamic-table/utils/importMapping.js +118 -0
  436. package/dist/backend/dynamic-table/utils/importMapping.js.map +7 -0
  437. package/dist/backend/dynamic-table/utils/importParse.js +121 -0
  438. package/dist/backend/dynamic-table/utils/importParse.js.map +7 -0
  439. package/dist/backend/dynamic-table/utils/lookupColumns.js +28 -0
  440. package/dist/backend/dynamic-table/utils/lookupColumns.js.map +7 -0
  441. package/dist/backend/dynamic-table/utils/perspectiveTransforms.js +191 -0
  442. package/dist/backend/dynamic-table/utils/perspectiveTransforms.js.map +7 -0
  443. package/dist/backend/dynamic-table/utils/rollupColumns.js +81 -0
  444. package/dist/backend/dynamic-table/utils/rollupColumns.js.map +7 -0
  445. package/dist/backend/dynamic-table/validators/index.js +36 -0
  446. package/dist/backend/dynamic-table/validators/index.js.map +7 -0
  447. package/dist/backend/fields/registry.generated.js +8 -0
  448. package/dist/backend/fields/registry.generated.js.map +7 -0
  449. package/dist/backend/fields/registry.js +29 -0
  450. package/dist/backend/fields/registry.js.map +7 -0
  451. package/dist/backend/filters/AdvancedFilterBuilder.js +280 -0
  452. package/dist/backend/filters/AdvancedFilterBuilder.js.map +7 -0
  453. package/dist/backend/forms/ActionsDropdown.js +160 -0
  454. package/dist/backend/forms/ActionsDropdown.js.map +7 -0
  455. package/dist/backend/forms/FormActionButtons.js +59 -0
  456. package/dist/backend/forms/FormActionButtons.js.map +7 -0
  457. package/dist/backend/forms/FormFooter.js +18 -0
  458. package/dist/backend/forms/FormFooter.js.map +7 -0
  459. package/dist/backend/forms/FormHeader.js +125 -0
  460. package/dist/backend/forms/FormHeader.js.map +7 -0
  461. package/dist/backend/forms/index.js +11 -0
  462. package/dist/backend/forms/index.js.map +7 -0
  463. package/dist/backend/hooks/useAdvancedFilter.js +64 -0
  464. package/dist/backend/hooks/useAdvancedFilter.js.map +7 -0
  465. package/dist/backend/indexes/PartialIndexBanner.js +74 -0
  466. package/dist/backend/indexes/PartialIndexBanner.js.map +7 -0
  467. package/dist/backend/indexes/store.js +62 -0
  468. package/dist/backend/indexes/store.js.map +7 -0
  469. package/dist/backend/injection/ComponentOverrideProvider.js +55 -0
  470. package/dist/backend/injection/ComponentOverrideProvider.js.map +7 -0
  471. package/dist/backend/injection/InjectedField.js +166 -0
  472. package/dist/backend/injection/InjectedField.js.map +7 -0
  473. package/dist/backend/injection/InjectionSpot.js +323 -0
  474. package/dist/backend/injection/InjectionSpot.js.map +7 -0
  475. package/dist/backend/injection/InjectionWizard.js +256 -0
  476. package/dist/backend/injection/InjectionWizard.js.map +7 -0
  477. package/dist/backend/injection/PageInjectionBoundary.js +26 -0
  478. package/dist/backend/injection/PageInjectionBoundary.js.map +7 -0
  479. package/dist/backend/injection/SseEventIndicator.js +8 -0
  480. package/dist/backend/injection/SseEventIndicator.js.map +7 -0
  481. package/dist/backend/injection/StatusBadgeInjectionSpot.js +34 -0
  482. package/dist/backend/injection/StatusBadgeInjectionSpot.js.map +7 -0
  483. package/dist/backend/injection/StatusBadgeRenderer.js +58 -0
  484. package/dist/backend/injection/StatusBadgeRenderer.js.map +7 -0
  485. package/dist/backend/injection/WidgetSharedState.js +49 -0
  486. package/dist/backend/injection/WidgetSharedState.js.map +7 -0
  487. package/dist/backend/injection/WizardInjectionSpot.js +30 -0
  488. package/dist/backend/injection/WizardInjectionSpot.js.map +7 -0
  489. package/dist/backend/injection/eventBridge.js +129 -0
  490. package/dist/backend/injection/eventBridge.js.map +7 -0
  491. package/dist/backend/injection/helpers.js +26 -0
  492. package/dist/backend/injection/helpers.js.map +7 -0
  493. package/dist/backend/injection/mergeMenuItems.js +49 -0
  494. package/dist/backend/injection/mergeMenuItems.js.map +7 -0
  495. package/dist/backend/injection/mutationEvents.js +20 -0
  496. package/dist/backend/injection/mutationEvents.js.map +7 -0
  497. package/dist/backend/injection/resolveInjectedIcon.js +23 -0
  498. package/dist/backend/injection/resolveInjectedIcon.js.map +7 -0
  499. package/dist/backend/injection/spotIds.js +72 -0
  500. package/dist/backend/injection/spotIds.js.map +7 -0
  501. package/dist/backend/injection/useAppEvent.js +35 -0
  502. package/dist/backend/injection/useAppEvent.js.map +7 -0
  503. package/dist/backend/injection/useGuardedMutation.js +71 -0
  504. package/dist/backend/injection/useGuardedMutation.js.map +7 -0
  505. package/dist/backend/injection/useInjectedMenuItems.js +49 -0
  506. package/dist/backend/injection/useInjectedMenuItems.js.map +7 -0
  507. package/dist/backend/injection/useInjectionDataWidgets.js +36 -0
  508. package/dist/backend/injection/useInjectionDataWidgets.js.map +7 -0
  509. package/dist/backend/injection/useOperationProgress.js +64 -0
  510. package/dist/backend/injection/useOperationProgress.js.map +7 -0
  511. package/dist/backend/injection/useRegisteredComponent.js +89 -0
  512. package/dist/backend/injection/useRegisteredComponent.js.map +7 -0
  513. package/dist/backend/injection/useWidgetSharedState.js +26 -0
  514. package/dist/backend/injection/useWidgetSharedState.js.map +7 -0
  515. package/dist/backend/injection/visibility-utils.js +29 -0
  516. package/dist/backend/injection/visibility-utils.js.map +7 -0
  517. package/dist/backend/injection/widgetRegistry.js +55 -0
  518. package/dist/backend/injection/widgetRegistry.js.map +7 -0
  519. package/dist/backend/inputs/ComboboxInput.js +228 -0
  520. package/dist/backend/inputs/ComboboxInput.js.map +7 -0
  521. package/dist/backend/inputs/DatePicker.js +148 -0
  522. package/dist/backend/inputs/DatePicker.js.map +7 -0
  523. package/dist/backend/inputs/DateTimePicker.js +188 -0
  524. package/dist/backend/inputs/DateTimePicker.js.map +7 -0
  525. package/dist/backend/inputs/EventPatternInput.js +38 -0
  526. package/dist/backend/inputs/EventPatternInput.js.map +7 -0
  527. package/dist/backend/inputs/EventSelect.js +115 -0
  528. package/dist/backend/inputs/EventSelect.js.map +7 -0
  529. package/dist/backend/inputs/LookupSelect.js +197 -0
  530. package/dist/backend/inputs/LookupSelect.js.map +7 -0
  531. package/dist/backend/inputs/PhoneNumberField.js +133 -0
  532. package/dist/backend/inputs/PhoneNumberField.js.map +7 -0
  533. package/dist/backend/inputs/SwitchableMarkdownInput.js +73 -0
  534. package/dist/backend/inputs/SwitchableMarkdownInput.js.map +7 -0
  535. package/dist/backend/inputs/TagsInput.js +258 -0
  536. package/dist/backend/inputs/TagsInput.js.map +7 -0
  537. package/dist/backend/inputs/TimeInput.js +132 -0
  538. package/dist/backend/inputs/TimeInput.js.map +7 -0
  539. package/dist/backend/inputs/TimePicker.js +105 -0
  540. package/dist/backend/inputs/TimePicker.js.map +7 -0
  541. package/dist/backend/inputs/index.js +12 -0
  542. package/dist/backend/inputs/index.js.map +7 -0
  543. package/dist/backend/markdown/MarkdownContent.js +20 -0
  544. package/dist/backend/markdown/MarkdownContent.js.map +7 -0
  545. package/dist/backend/markdown/index.js +3 -0
  546. package/dist/backend/markdown/index.js.map +7 -0
  547. package/dist/backend/markdown/useMarkdownRemarkPlugins.js +33 -0
  548. package/dist/backend/markdown/useMarkdownRemarkPlugins.js.map +7 -0
  549. package/dist/backend/messages/MessageComposer.js +158 -0
  550. package/dist/backend/messages/MessageComposer.js.map +7 -0
  551. package/dist/backend/messages/MessageObjectDetail.js +81 -0
  552. package/dist/backend/messages/MessageObjectDetail.js.map +7 -0
  553. package/dist/backend/messages/MessageObjectPreview.js +48 -0
  554. package/dist/backend/messages/MessageObjectPreview.js.map +7 -0
  555. package/dist/backend/messages/MessageObjectRecordPicker.js +89 -0
  556. package/dist/backend/messages/MessageObjectRecordPicker.js.map +7 -0
  557. package/dist/backend/messages/MessagePrioritySelector.js +74 -0
  558. package/dist/backend/messages/MessagePrioritySelector.js.map +7 -0
  559. package/dist/backend/messages/MessagesIcon.js +22 -0
  560. package/dist/backend/messages/MessagesIcon.js.map +7 -0
  561. package/dist/backend/messages/SendObjectMessageDialog.js +65 -0
  562. package/dist/backend/messages/SendObjectMessageDialog.js.map +7 -0
  563. package/dist/backend/messages/index.js +17 -0
  564. package/dist/backend/messages/index.js.map +7 -0
  565. package/dist/backend/messages/message-compose-form-groups.js +333 -0
  566. package/dist/backend/messages/message-compose-form-groups.js.map +7 -0
  567. package/dist/backend/messages/message-composer.types.js +1 -0
  568. package/dist/backend/messages/message-composer.types.js.map +7 -0
  569. package/dist/backend/messages/message-priority.js +40 -0
  570. package/dist/backend/messages/message-priority.js.map +7 -0
  571. package/dist/backend/messages/useMessageCompose.js +488 -0
  572. package/dist/backend/messages/useMessageCompose.js.map +7 -0
  573. package/dist/backend/messages/useMessageComposeOperations.js +163 -0
  574. package/dist/backend/messages/useMessageComposeOperations.js.map +7 -0
  575. package/dist/backend/messages/useMessagesPoll.js +79 -0
  576. package/dist/backend/messages/useMessagesPoll.js.map +7 -0
  577. package/dist/backend/notifications/NotificationBell.js +83 -0
  578. package/dist/backend/notifications/NotificationBell.js.map +7 -0
  579. package/dist/backend/notifications/NotificationCountBadge.js +9 -0
  580. package/dist/backend/notifications/NotificationCountBadge.js.map +7 -0
  581. package/dist/backend/notifications/NotificationDispatcher.js +165 -0
  582. package/dist/backend/notifications/NotificationDispatcher.js.map +7 -0
  583. package/dist/backend/notifications/NotificationItem.js +187 -0
  584. package/dist/backend/notifications/NotificationItem.js.map +7 -0
  585. package/dist/backend/notifications/NotificationPanel.js +146 -0
  586. package/dist/backend/notifications/NotificationPanel.js.map +7 -0
  587. package/dist/backend/notifications/index.js +19 -0
  588. package/dist/backend/notifications/index.js.map +7 -0
  589. package/dist/backend/notifications/useNotificationActions.js +124 -0
  590. package/dist/backend/notifications/useNotificationActions.js.map +7 -0
  591. package/dist/backend/notifications/useNotificationEffect.js +13 -0
  592. package/dist/backend/notifications/useNotificationEffect.js.map +7 -0
  593. package/dist/backend/notifications/useNotifications.js +11 -0
  594. package/dist/backend/notifications/useNotifications.js.map +7 -0
  595. package/dist/backend/notifications/useNotificationsPoll.js +135 -0
  596. package/dist/backend/notifications/useNotificationsPoll.js.map +7 -0
  597. package/dist/backend/notifications/useNotificationsSse.js +173 -0
  598. package/dist/backend/notifications/useNotificationsSse.js.map +7 -0
  599. package/dist/backend/operations/LastOperationBanner.js +80 -0
  600. package/dist/backend/operations/LastOperationBanner.js.map +7 -0
  601. package/dist/backend/operations/store.js +183 -0
  602. package/dist/backend/operations/store.js.map +7 -0
  603. package/dist/backend/progress/ProgressTopBar.js +129 -0
  604. package/dist/backend/progress/ProgressTopBar.js.map +7 -0
  605. package/dist/backend/progress/useProgress.js +11 -0
  606. package/dist/backend/progress/useProgress.js.map +7 -0
  607. package/dist/backend/progress/useProgressPoll.js +69 -0
  608. package/dist/backend/progress/useProgressPoll.js.map +7 -0
  609. package/dist/backend/progress/useProgressSse.js +104 -0
  610. package/dist/backend/progress/useProgressSse.js.map +7 -0
  611. package/dist/backend/schedule/ScheduleAgenda.js +107 -0
  612. package/dist/backend/schedule/ScheduleAgenda.js.map +7 -0
  613. package/dist/backend/schedule/ScheduleGrid.js +107 -0
  614. package/dist/backend/schedule/ScheduleGrid.js.map +7 -0
  615. package/dist/backend/schedule/ScheduleToolbar.js +166 -0
  616. package/dist/backend/schedule/ScheduleToolbar.js.map +7 -0
  617. package/dist/backend/schedule/ScheduleView.js +168 -0
  618. package/dist/backend/schedule/ScheduleView.js.map +7 -0
  619. package/dist/backend/schedule/index.js +6 -0
  620. package/dist/backend/schedule/index.js.map +7 -0
  621. package/dist/backend/schedule/recurrence.js +83 -0
  622. package/dist/backend/schedule/recurrence.js.map +7 -0
  623. package/dist/backend/schedule/types.js +1 -0
  624. package/dist/backend/schedule/types.js.map +7 -0
  625. package/dist/backend/section-page/SectionNav.js +104 -0
  626. package/dist/backend/section-page/SectionNav.js.map +7 -0
  627. package/dist/backend/section-page/SectionPage.js +33 -0
  628. package/dist/backend/section-page/SectionPage.js.map +7 -0
  629. package/dist/backend/section-page/index.js +7 -0
  630. package/dist/backend/section-page/index.js.map +7 -0
  631. package/dist/backend/section-page/types.js +1 -0
  632. package/dist/backend/section-page/types.js.map +7 -0
  633. package/dist/backend/settings/SettingsNavigation.js +43 -0
  634. package/dist/backend/settings/SettingsNavigation.js.map +7 -0
  635. package/dist/backend/settings/SettingsPageWrapper.js +66 -0
  636. package/dist/backend/settings/SettingsPageWrapper.js.map +7 -0
  637. package/dist/backend/settings/index.js +6 -0
  638. package/dist/backend/settings/index.js.map +7 -0
  639. package/dist/backend/upgrades/UpgradeActionBanner.js +91 -0
  640. package/dist/backend/upgrades/UpgradeActionBanner.js.map +7 -0
  641. package/dist/backend/utils/api.js +178 -0
  642. package/dist/backend/utils/api.js.map +7 -0
  643. package/dist/backend/utils/apiCall.js +68 -0
  644. package/dist/backend/utils/apiCall.js.map +7 -0
  645. package/dist/backend/utils/crud.js +126 -0
  646. package/dist/backend/utils/crud.js.map +7 -0
  647. package/dist/backend/utils/customFieldColumns.js +100 -0
  648. package/dist/backend/utils/customFieldColumns.js.map +7 -0
  649. package/dist/backend/utils/customFieldDefs.js +143 -0
  650. package/dist/backend/utils/customFieldDefs.js.map +7 -0
  651. package/dist/backend/utils/customFieldFilters.js +151 -0
  652. package/dist/backend/utils/customFieldFilters.js.map +7 -0
  653. package/dist/backend/utils/customFieldForms.js +169 -0
  654. package/dist/backend/utils/customFieldForms.js.map +7 -0
  655. package/dist/backend/utils/customFieldRelationDisplay.js +239 -0
  656. package/dist/backend/utils/customFieldRelationDisplay.js.map +7 -0
  657. package/dist/backend/utils/customFieldValues.js +26 -0
  658. package/dist/backend/utils/customFieldValues.js.map +7 -0
  659. package/dist/backend/utils/flash.js +16 -0
  660. package/dist/backend/utils/flash.js.map +7 -0
  661. package/dist/backend/utils/nav.js +280 -0
  662. package/dist/backend/utils/nav.js.map +7 -0
  663. package/dist/backend/utils/richTextSanitizer.js +11 -0
  664. package/dist/backend/utils/richTextSanitizer.js.map +7 -0
  665. package/dist/backend/utils/scopedHeaderStack.js +44 -0
  666. package/dist/backend/utils/scopedHeaderStack.js.map +7 -0
  667. package/dist/backend/utils/serverErrors.js +237 -0
  668. package/dist/backend/utils/serverErrors.js.map +7 -0
  669. package/dist/backend/utils/useAutoDiscoveredFields.js +96 -0
  670. package/dist/backend/utils/useAutoDiscoveredFields.js.map +7 -0
  671. package/dist/backend/version-history/VersionHistoryAction.js +67 -0
  672. package/dist/backend/version-history/VersionHistoryAction.js.map +7 -0
  673. package/dist/backend/version-history/VersionHistoryDetail.js +57 -0
  674. package/dist/backend/version-history/VersionHistoryDetail.js.map +7 -0
  675. package/dist/backend/version-history/VersionHistoryPanel.js +270 -0
  676. package/dist/backend/version-history/VersionHistoryPanel.js.map +7 -0
  677. package/dist/backend/version-history/index.js +13 -0
  678. package/dist/backend/version-history/index.js.map +7 -0
  679. package/dist/backend/version-history/labels.js +52 -0
  680. package/dist/backend/version-history/labels.js.map +7 -0
  681. package/dist/backend/version-history/types.js +1 -0
  682. package/dist/backend/version-history/types.js.map +7 -0
  683. package/dist/backend/version-history/useAuditPermissions.js +72 -0
  684. package/dist/backend/version-history/useAuditPermissions.js.map +7 -0
  685. package/dist/backend/version-history/useVersionHistory.js +141 -0
  686. package/dist/backend/version-history/useVersionHistory.js.map +7 -0
  687. package/dist/backend/views/NewViewForm.js +56 -0
  688. package/dist/backend/views/NewViewForm.js.map +7 -0
  689. package/dist/backend/views/ShareForm.js +49 -0
  690. package/dist/backend/views/ShareForm.js.map +7 -0
  691. package/dist/backend/views/ViewChip.js +112 -0
  692. package/dist/backend/views/ViewChip.js.map +7 -0
  693. package/dist/backend/views/ViewChipMenu.js +89 -0
  694. package/dist/backend/views/ViewChipMenu.js.map +7 -0
  695. package/dist/backend/views/types.js +1 -0
  696. package/dist/backend/views/types.js.map +7 -0
  697. package/dist/frontend/AuthFooter.js +23 -0
  698. package/dist/frontend/AuthFooter.js.map +7 -0
  699. package/dist/frontend/LanguageSwitcher.js +57 -0
  700. package/dist/frontend/LanguageSwitcher.js.map +7 -0
  701. package/dist/frontend/Layout.js +14 -0
  702. package/dist/frontend/Layout.js.map +7 -0
  703. package/dist/hooks/useIsMobile.js +21 -0
  704. package/dist/hooks/useIsMobile.js.map +7 -0
  705. package/dist/index.js +40 -0
  706. package/dist/index.js.map +7 -0
  707. package/dist/portal/PortalContext.js +113 -0
  708. package/dist/portal/PortalContext.js.map +7 -0
  709. package/dist/portal/PortalLayoutProvider.js +5 -0
  710. package/dist/portal/PortalLayoutProvider.js.map +7 -0
  711. package/dist/portal/PortalLayoutShell.js +44 -0
  712. package/dist/portal/PortalLayoutShell.js.map +7 -0
  713. package/dist/portal/PortalShell.js +229 -0
  714. package/dist/portal/PortalShell.js.map +7 -0
  715. package/dist/portal/components/PortalCard.js +31 -0
  716. package/dist/portal/components/PortalCard.js.map +7 -0
  717. package/dist/portal/components/PortalEmptyState.js +16 -0
  718. package/dist/portal/components/PortalEmptyState.js.map +7 -0
  719. package/dist/portal/components/PortalFeatureCard.js +21 -0
  720. package/dist/portal/components/PortalFeatureCard.js.map +7 -0
  721. package/dist/portal/components/PortalNotificationBell.js +67 -0
  722. package/dist/portal/components/PortalNotificationBell.js.map +7 -0
  723. package/dist/portal/components/PortalNotificationPanel.js +158 -0
  724. package/dist/portal/components/PortalNotificationPanel.js.map +7 -0
  725. package/dist/portal/components/PortalPageHeader.js +16 -0
  726. package/dist/portal/components/PortalPageHeader.js.map +7 -0
  727. package/dist/portal/components/index.js +18 -0
  728. package/dist/portal/components/index.js.map +7 -0
  729. package/dist/portal/hooks/useCustomerAuth.js +69 -0
  730. package/dist/portal/hooks/useCustomerAuth.js.map +7 -0
  731. package/dist/portal/hooks/usePortalAppEvent.js +26 -0
  732. package/dist/portal/hooks/usePortalAppEvent.js.map +7 -0
  733. package/dist/portal/hooks/usePortalDashboardWidgets.js +37 -0
  734. package/dist/portal/hooks/usePortalDashboardWidgets.js.map +7 -0
  735. package/dist/portal/hooks/usePortalEventBridge.js +129 -0
  736. package/dist/portal/hooks/usePortalEventBridge.js.map +7 -0
  737. package/dist/portal/hooks/usePortalInjectedMenuItems.js +88 -0
  738. package/dist/portal/hooks/usePortalInjectedMenuItems.js.map +7 -0
  739. package/dist/portal/hooks/usePortalNotifications.js +85 -0
  740. package/dist/portal/hooks/usePortalNotifications.js.map +7 -0
  741. package/dist/portal/hooks/useTenantContext.js +53 -0
  742. package/dist/portal/hooks/useTenantContext.js.map +7 -0
  743. package/dist/primitives/DataLoader.js +68 -0
  744. package/dist/primitives/DataLoader.js.map +7 -0
  745. package/dist/primitives/ErrorNotice.js +14 -0
  746. package/dist/primitives/ErrorNotice.js.map +7 -0
  747. package/dist/primitives/Notice.js +55 -0
  748. package/dist/primitives/Notice.js.map +7 -0
  749. package/dist/primitives/alert.js +38 -0
  750. package/dist/primitives/alert.js.map +7 -0
  751. package/dist/primitives/badge.js +33 -0
  752. package/dist/primitives/badge.js.map +7 -0
  753. package/dist/primitives/button.js +45 -0
  754. package/dist/primitives/button.js.map +7 -0
  755. package/dist/primitives/calendar.js +62 -0
  756. package/dist/primitives/calendar.js.map +7 -0
  757. package/dist/primitives/card.js +91 -0
  758. package/dist/primitives/card.js.map +7 -0
  759. package/dist/primitives/checkbox.js +28 -0
  760. package/dist/primitives/checkbox.js.map +7 -0
  761. package/dist/primitives/dialog.js +101 -0
  762. package/dist/primitives/dialog.js.map +7 -0
  763. package/dist/primitives/form-field.js +78 -0
  764. package/dist/primitives/form-field.js.map +7 -0
  765. package/dist/primitives/icon-button.js +40 -0
  766. package/dist/primitives/icon-button.js.map +7 -0
  767. package/dist/primitives/input.js +22 -0
  768. package/dist/primitives/input.js.map +7 -0
  769. package/dist/primitives/label.js +21 -0
  770. package/dist/primitives/label.js.map +7 -0
  771. package/dist/primitives/popover.js +36 -0
  772. package/dist/primitives/popover.js.map +7 -0
  773. package/dist/primitives/primitives.stories.js +187 -0
  774. package/dist/primitives/primitives.stories.js.map +7 -0
  775. package/dist/primitives/progress.js +28 -0
  776. package/dist/primitives/progress.js.map +7 -0
  777. package/dist/primitives/separator.js +9 -0
  778. package/dist/primitives/separator.js.map +7 -0
  779. package/dist/primitives/sheet.js +103 -0
  780. package/dist/primitives/sheet.js.map +7 -0
  781. package/dist/primitives/spinner.js +24 -0
  782. package/dist/primitives/spinner.js.map +7 -0
  783. package/dist/primitives/status-badge.js +38 -0
  784. package/dist/primitives/status-badge.js.map +7 -0
  785. package/dist/primitives/switch.js +80 -0
  786. package/dist/primitives/switch.js.map +7 -0
  787. package/dist/primitives/table.js +29 -0
  788. package/dist/primitives/table.js.map +7 -0
  789. package/dist/primitives/tabs.js +90 -0
  790. package/dist/primitives/tabs.js.map +7 -0
  791. package/dist/primitives/textarea.js +21 -0
  792. package/dist/primitives/textarea.js.map +7 -0
  793. package/dist/primitives/tooltip.js +60 -0
  794. package/dist/primitives/tooltip.js.map +7 -0
  795. package/dist/primitives-v2/Alert.js +69 -0
  796. package/dist/primitives-v2/Alert.js.map +7 -0
  797. package/dist/primitives-v2/Alert.stories.js +42 -0
  798. package/dist/primitives-v2/Alert.stories.js.map +7 -0
  799. package/dist/primitives-v2/Avatar.js +93 -0
  800. package/dist/primitives-v2/Avatar.js.map +7 -0
  801. package/dist/primitives-v2/Avatar.stories.js +57 -0
  802. package/dist/primitives-v2/Avatar.stories.js.map +7 -0
  803. package/dist/primitives-v2/Badge.js +50 -0
  804. package/dist/primitives-v2/Badge.js.map +7 -0
  805. package/dist/primitives-v2/Badge.stories.js +66 -0
  806. package/dist/primitives-v2/Badge.stories.js.map +7 -0
  807. package/dist/primitives-v2/Breadcrumb.js +53 -0
  808. package/dist/primitives-v2/Breadcrumb.js.map +7 -0
  809. package/dist/primitives-v2/Breadcrumb.stories.js +70 -0
  810. package/dist/primitives-v2/Breadcrumb.stories.js.map +7 -0
  811. package/dist/primitives-v2/Button.js +85 -0
  812. package/dist/primitives-v2/Button.js.map +7 -0
  813. package/dist/primitives-v2/Button.stories.js +48 -0
  814. package/dist/primitives-v2/Button.stories.js.map +7 -0
  815. package/dist/primitives-v2/Checkbox.js +65 -0
  816. package/dist/primitives-v2/Checkbox.js.map +7 -0
  817. package/dist/primitives-v2/Checkbox.stories.js +31 -0
  818. package/dist/primitives-v2/Checkbox.stories.js.map +7 -0
  819. package/dist/primitives-v2/IconButton.js +13 -0
  820. package/dist/primitives-v2/IconButton.js.map +7 -0
  821. package/dist/primitives-v2/IconButton.stories.js +37 -0
  822. package/dist/primitives-v2/IconButton.stories.js.map +7 -0
  823. package/dist/primitives-v2/Input.js +74 -0
  824. package/dist/primitives-v2/Input.js.map +7 -0
  825. package/dist/primitives-v2/Input.stories.js +56 -0
  826. package/dist/primitives-v2/Input.stories.js.map +7 -0
  827. package/dist/primitives-v2/NavGroup.js +54 -0
  828. package/dist/primitives-v2/NavGroup.js.map +7 -0
  829. package/dist/primitives-v2/NavGroup.stories.js +39 -0
  830. package/dist/primitives-v2/NavGroup.stories.js.map +7 -0
  831. package/dist/primitives-v2/NavItem.js +61 -0
  832. package/dist/primitives-v2/NavItem.js.map +7 -0
  833. package/dist/primitives-v2/NavItem.stories.js +56 -0
  834. package/dist/primitives-v2/NavItem.stories.js.map +7 -0
  835. package/dist/primitives-v2/SearchInput.js +93 -0
  836. package/dist/primitives-v2/SearchInput.js.map +7 -0
  837. package/dist/primitives-v2/SearchInput.stories.js +41 -0
  838. package/dist/primitives-v2/SearchInput.stories.js.map +7 -0
  839. package/dist/primitives-v2/Sidebar.js +48 -0
  840. package/dist/primitives-v2/Sidebar.js.map +7 -0
  841. package/dist/primitives-v2/Sidebar.stories.js +76 -0
  842. package/dist/primitives-v2/Sidebar.stories.js.map +7 -0
  843. package/dist/primitives-v2/Tab.js +78 -0
  844. package/dist/primitives-v2/Tab.js.map +7 -0
  845. package/dist/primitives-v2/Tab.stories.js +51 -0
  846. package/dist/primitives-v2/Tab.stories.js.map +7 -0
  847. package/dist/primitives-v2/Tag.js +61 -0
  848. package/dist/primitives-v2/Tag.js.map +7 -0
  849. package/dist/primitives-v2/Tag.stories.js +121 -0
  850. package/dist/primitives-v2/Tag.stories.js.map +7 -0
  851. package/dist/primitives-v2/Toggle.js +72 -0
  852. package/dist/primitives-v2/Toggle.js.map +7 -0
  853. package/dist/primitives-v2/Toggle.stories.js +34 -0
  854. package/dist/primitives-v2/Toggle.stories.js.map +7 -0
  855. package/dist/primitives-v2/Topbar.js +24 -0
  856. package/dist/primitives-v2/Topbar.js.map +7 -0
  857. package/dist/primitives-v2/Topbar.stories.js +58 -0
  858. package/dist/primitives-v2/Topbar.stories.js.map +7 -0
  859. package/dist/primitives-v2/index.js +41 -0
  860. package/dist/primitives-v2/index.js.map +7 -0
  861. package/dist/primitives-v2/utils.js +7 -0
  862. package/dist/primitives-v2/utils.js.map +7 -0
  863. package/dist/theme/BrandThemeProvider.js +49 -0
  864. package/dist/theme/BrandThemeProvider.js.map +7 -0
  865. package/dist/theme/QueryProvider.js +44 -0
  866. package/dist/theme/QueryProvider.js.map +7 -0
  867. package/dist/theme/ThemeProvider.js +96 -0
  868. package/dist/theme/ThemeProvider.js.map +7 -0
  869. package/dist/theme/ThemeToggle.js +88 -0
  870. package/dist/theme/ThemeToggle.js.map +7 -0
  871. package/dist/theme/index.js +12 -0
  872. package/dist/theme/index.js.map +7 -0
  873. package/dist/theme/m3.css.js +2 -0
  874. package/dist/theme/tokens.v2.css.js +2 -0
  875. package/dist/theme/typography.css.js +2 -0
  876. package/dist/theme/typography.stories.js +123 -0
  877. package/dist/theme/typography.stories.js.map +7 -0
  878. package/dist/theme/typography.tokens.js +281 -0
  879. package/dist/theme/typography.tokens.js.map +7 -0
  880. package/dist/types/react-big-calendar.d.js +1 -0
  881. package/dist/types/react-big-calendar.d.js.map +7 -0
  882. package/package.json +411 -0
  883. package/src/backend/AppShell.tsx +1606 -0
  884. package/src/backend/BackendChromeProvider.tsx +99 -0
  885. package/src/backend/BackendPageSurface.tsx +57 -0
  886. package/src/backend/CollapsibleNavSection.tsx +201 -0
  887. package/src/backend/ContextHelp.tsx +40 -0
  888. package/src/backend/CrudForm.tsx +3796 -0
  889. package/src/backend/DataTable.tsx +2584 -0
  890. package/src/backend/EmptyState.tsx +65 -0
  891. package/src/backend/FilterBar.tsx +171 -0
  892. package/src/backend/FilterOverlay.tsx +388 -0
  893. package/src/backend/FlashMessages.tsx +189 -0
  894. package/src/backend/HtmlRichTextEditor.tsx +124 -0
  895. package/src/backend/IntegrationsButton.tsx +29 -0
  896. package/src/backend/JsonBuilder.tsx +359 -0
  897. package/src/backend/JsonDisplay.tsx +258 -0
  898. package/src/backend/NextStepCallout.tsx +134 -0
  899. package/src/backend/Page.tsx +30 -0
  900. package/src/backend/PerspectiveSidebar.tsx +506 -0
  901. package/src/backend/ProfileDropdown.tsx +369 -0
  902. package/src/backend/RowActions.tsx +158 -0
  903. package/src/backend/SectionHeader.tsx +119 -0
  904. package/src/backend/SettingsButton.tsx +28 -0
  905. package/src/backend/Sidebar.stories.tsx +183 -0
  906. package/src/backend/Sidebar.tsx +737 -0
  907. package/src/backend/TruncatedCell.tsx +133 -0
  908. package/src/backend/UserMenu.tsx +153 -0
  909. package/src/backend/ValueIcons.tsx +48 -0
  910. package/src/backend/WebhookSetupGuide.tsx +127 -0
  911. package/src/backend/__tests__/AppShell.test.tsx +392 -0
  912. package/src/backend/__tests__/CrudForm.custom-fields.test.tsx +180 -0
  913. package/src/backend/__tests__/CrudForm.datetime.test.tsx +95 -0
  914. package/src/backend/__tests__/CrudForm.defaults.test.tsx +195 -0
  915. package/src/backend/__tests__/CrudForm.navigation.test.tsx +156 -0
  916. package/src/backend/__tests__/CrudForm.render.test.tsx +146 -0
  917. package/src/backend/__tests__/CrudForm.transformData.test.tsx +231 -0
  918. package/src/backend/__tests__/CrudForm.unsavedNavigation.test.tsx +145 -0
  919. package/src/backend/__tests__/CrudForm.validation.test.tsx +178 -0
  920. package/src/backend/__tests__/CustomDataSection.test.tsx +465 -0
  921. package/src/backend/__tests__/DataTable.extensions.test.tsx +339 -0
  922. package/src/backend/__tests__/DataTable.namespaces.test.ts +32 -0
  923. package/src/backend/__tests__/DataTable.render.test.tsx +48 -0
  924. package/src/backend/__tests__/FieldDefinitionsEditor.test.tsx +64 -0
  925. package/src/backend/__tests__/FlashMessages.test.tsx +105 -0
  926. package/src/backend/__tests__/FormHeader.test.tsx +81 -0
  927. package/src/backend/__tests__/NotificationDispatcher.test.ts +172 -0
  928. package/src/backend/__tests__/VersionHistoryPanel.test.tsx +109 -0
  929. package/src/backend/__tests__/component-replacement.test.tsx +270 -0
  930. package/src/backend/__tests__/custom-field-filters.test.ts +72 -0
  931. package/src/backend/__tests__/custom-field-forms.test.ts +54 -0
  932. package/src/backend/__tests__/nav-utils.test.ts +175 -0
  933. package/src/backend/__tests__/serverErrors.test.ts +83 -0
  934. package/src/backend/__tests__/useAuditPermissions.test.tsx +51 -0
  935. package/src/backend/__tests__/useNotifications.strategy.test.ts +58 -0
  936. package/src/backend/__tests__/useProgress.strategy.test.ts +62 -0
  937. package/src/backend/charts/BarChart.tsx +208 -0
  938. package/src/backend/charts/ChartUtils.tsx +196 -0
  939. package/src/backend/charts/ComboChart.stories.tsx +103 -0
  940. package/src/backend/charts/ComboChart.tsx +350 -0
  941. package/src/backend/charts/KpiCard.tsx +155 -0
  942. package/src/backend/charts/LineChart.tsx +207 -0
  943. package/src/backend/charts/PieChart.tsx +157 -0
  944. package/src/backend/charts/ScatterChart.tsx +498 -0
  945. package/src/backend/charts/TopNTable.tsx +141 -0
  946. package/src/backend/charts/WaterfallChart.tsx +213 -0
  947. package/src/backend/charts/index.ts +21 -0
  948. package/src/backend/columns/ColumnChooserPanel.tsx +293 -0
  949. package/src/backend/confirm-dialog/ConfirmDialog.tsx +275 -0
  950. package/src/backend/confirm-dialog/index.ts +7 -0
  951. package/src/backend/confirm-dialog/useConfirmDialog.tsx +146 -0
  952. package/src/backend/custom-fields/FieldDefinitionsEditor.tsx +1413 -0
  953. package/src/backend/custom-fields/FieldDefinitionsManager.tsx +381 -0
  954. package/src/backend/dashboard/DashboardScreen.tsx +706 -0
  955. package/src/backend/dashboard/__tests__/DashboardScreen.test.tsx +114 -0
  956. package/src/backend/dashboard/index.ts +1 -0
  957. package/src/backend/dashboard/widgetRegistry.ts +68 -0
  958. package/src/backend/date-range/DateRangeSelect.tsx +50 -0
  959. package/src/backend/date-range/InlineDateRangeSelect.tsx +52 -0
  960. package/src/backend/date-range/InlineGranularitySelect.tsx +63 -0
  961. package/src/backend/date-range/__tests__/dateRanges.test.ts +224 -0
  962. package/src/backend/date-range/dateRanges.ts +218 -0
  963. package/src/backend/date-range/index.ts +15 -0
  964. package/src/backend/detail/AccessDeniedMessage.tsx +32 -0
  965. package/src/backend/detail/ActivitiesSection.tsx +1261 -0
  966. package/src/backend/detail/AddressEditor.tsx +479 -0
  967. package/src/backend/detail/AddressTiles.tsx +591 -0
  968. package/src/backend/detail/AddressesSection.tsx +362 -0
  969. package/src/backend/detail/AttachmentDeleteDialog.tsx +56 -0
  970. package/src/backend/detail/AttachmentMetadataDialog.tsx +674 -0
  971. package/src/backend/detail/AttachmentVisualPreview.tsx +155 -0
  972. package/src/backend/detail/AttachmentsSection.tsx +327 -0
  973. package/src/backend/detail/CustomDataSection.tsx +700 -0
  974. package/src/backend/detail/DetailFieldsSection.tsx +163 -0
  975. package/src/backend/detail/ErrorMessage.tsx +32 -0
  976. package/src/backend/detail/InlineEditors.tsx +894 -0
  977. package/src/backend/detail/LoadingMessage.tsx +14 -0
  978. package/src/backend/detail/NotesSection.tsx +1266 -0
  979. package/src/backend/detail/TabEmptyState.tsx +48 -0
  980. package/src/backend/detail/TagsSection.tsx +470 -0
  981. package/src/backend/detail/__tests__/InlineEditors.test.tsx +59 -0
  982. package/src/backend/detail/addressFormat.tsx +121 -0
  983. package/src/backend/detail/index.ts +46 -0
  984. package/src/backend/devtools/UmesDevToolsPanel.tsx +122 -0
  985. package/src/backend/devtools/components/ConflictWarnings.tsx +36 -0
  986. package/src/backend/devtools/components/EnricherTiming.tsx +50 -0
  987. package/src/backend/devtools/components/EventFlow.tsx +45 -0
  988. package/src/backend/devtools/components/ExtensionPointList.tsx +59 -0
  989. package/src/backend/devtools/components/InterceptorActivity.tsx +48 -0
  990. package/src/backend/devtools/index.ts +2 -0
  991. package/src/backend/devtools/useUmesDevTools.ts +188 -0
  992. package/src/backend/document-viewer/RegionOverlay.tsx +150 -0
  993. package/src/backend/document-viewer/index.ts +2 -0
  994. package/src/backend/dynamic-grid/DynamicGrid.tsx +161 -0
  995. package/src/backend/dynamic-grid/adapters.ts +57 -0
  996. package/src/backend/dynamic-grid/components/GridCell.tsx +194 -0
  997. package/src/backend/dynamic-grid/components/GridRow.tsx +40 -0
  998. package/src/backend/dynamic-grid/hooks/useGridKeyboardNav.ts +134 -0
  999. package/src/backend/dynamic-grid/index.ts +4 -0
  1000. package/src/backend/dynamic-grid/types.ts +55 -0
  1001. package/src/backend/dynamic-table/DynamicTable.stories.tsx +274 -0
  1002. package/src/backend/dynamic-table/DynamicTable.tsx +4419 -0
  1003. package/src/backend/dynamic-table/README.md +1199 -0
  1004. package/src/backend/dynamic-table/URL_FILTERING.md +217 -0
  1005. package/src/backend/dynamic-table/__e2e__/GridHarness.ts +1155 -0
  1006. package/src/backend/dynamic-table/__e2e__/SplitViewHarness.ts +366 -0
  1007. package/src/backend/dynamic-table/__tests__/BulkActionsBar.test.tsx +143 -0
  1008. package/src/backend/dynamic-table/__tests__/ColumnQuickFilter.test.tsx +607 -0
  1009. package/src/backend/dynamic-table/__tests__/ConfigureViewFilters.suggestions.test.tsx +177 -0
  1010. package/src/backend/dynamic-table/__tests__/ConfigureViewFormatting.test.tsx +125 -0
  1011. package/src/backend/dynamic-table/__tests__/ConfigureViewFormulas.test.tsx +228 -0
  1012. package/src/backend/dynamic-table/__tests__/ConfigureViewGrouping.aggregations.test.tsx +131 -0
  1013. package/src/backend/dynamic-table/__tests__/ConfigureViewPanel.baseView.test.tsx +162 -0
  1014. package/src/backend/dynamic-table/__tests__/ConfigureViewPanel.focus.test.tsx +54 -0
  1015. package/src/backend/dynamic-table/__tests__/ConfigureViewPanel.sections.test.tsx +142 -0
  1016. package/src/backend/dynamic-table/__tests__/ConfigureViewRollups.test.tsx +228 -0
  1017. package/src/backend/dynamic-table/__tests__/ContextMenu.test.tsx +89 -0
  1018. package/src/backend/dynamic-table/__tests__/DynamicTable.density.test.tsx +299 -0
  1019. package/src/backend/dynamic-table/__tests__/DynamicTable.exportTruncation.test.tsx +145 -0
  1020. package/src/backend/dynamic-table/__tests__/DynamicTable.loadError.test.tsx +173 -0
  1021. package/src/backend/dynamic-table/__tests__/DynamicTable.wiring.test.tsx +357 -0
  1022. package/src/backend/dynamic-table/__tests__/EmptyState.test.tsx +70 -0
  1023. package/src/backend/dynamic-table/__tests__/ExportMenu.test.tsx +82 -0
  1024. package/src/backend/dynamic-table/__tests__/FooterTotalsRow.test.tsx +154 -0
  1025. package/src/backend/dynamic-table/__tests__/GroupSummaryRow.render.test.tsx +131 -0
  1026. package/src/backend/dynamic-table/__tests__/LoadErrorState.test.tsx +74 -0
  1027. package/src/backend/dynamic-table/__tests__/MentionPopup.search.test.tsx +127 -0
  1028. package/src/backend/dynamic-table/__tests__/PerspectiveTabs.test.tsx +170 -0
  1029. package/src/backend/dynamic-table/__tests__/RowHeaderCell.selection.test.tsx +80 -0
  1030. package/src/backend/dynamic-table/__tests__/abbreviationsSubscription.test.ts +171 -0
  1031. package/src/backend/dynamic-table/__tests__/aggregate.spec.test.ts +224 -0
  1032. package/src/backend/dynamic-table/__tests__/aggregateDimension.test.tsx +191 -0
  1033. package/src/backend/dynamic-table/__tests__/anchoredPosition.test.ts +88 -0
  1034. package/src/backend/dynamic-table/__tests__/badgeAutoFit.test.ts +121 -0
  1035. package/src/backend/dynamic-table/__tests__/cellHandlers.save.test.ts +282 -0
  1036. package/src/backend/dynamic-table/__tests__/cellWrites.test.ts +274 -0
  1037. package/src/backend/dynamic-table/__tests__/clipboard.test.ts +230 -0
  1038. package/src/backend/dynamic-table/__tests__/coerceCellValue.test.ts +117 -0
  1039. package/src/backend/dynamic-table/__tests__/colorAdjacency.test.ts +151 -0
  1040. package/src/backend/dynamic-table/__tests__/columnFill.test.ts +66 -0
  1041. package/src/backend/dynamic-table/__tests__/columnHeaderHandlers.sort.test.ts +100 -0
  1042. package/src/backend/dynamic-table/__tests__/columnHeaderReorder.test.tsx +209 -0
  1043. package/src/backend/dynamic-table/__tests__/columnReorderPersistence.test.tsx +127 -0
  1044. package/src/backend/dynamic-table/__tests__/columnVirtualization.render.test.tsx +420 -0
  1045. package/src/backend/dynamic-table/__tests__/columnVisibilityPersistence.test.tsx +136 -0
  1046. package/src/backend/dynamic-table/__tests__/columnWindow.test.ts +643 -0
  1047. package/src/backend/dynamic-table/__tests__/commentAudience.test.tsx +137 -0
  1048. package/src/backend/dynamic-table/__tests__/commentScope.test.tsx +214 -0
  1049. package/src/backend/dynamic-table/__tests__/conditionalFormat.test.ts +175 -0
  1050. package/src/backend/dynamic-table/__tests__/contentRegistry.test.ts +267 -0
  1051. package/src/backend/dynamic-table/__tests__/dateWindows.test.ts +149 -0
  1052. package/src/backend/dynamic-table/__tests__/density.test.ts +204 -0
  1053. package/src/backend/dynamic-table/__tests__/exportTable.test.ts +146 -0
  1054. package/src/backend/dynamic-table/__tests__/fillGeometry.test.ts +201 -0
  1055. package/src/backend/dynamic-table/__tests__/fillPatterns.test.ts +272 -0
  1056. package/src/backend/dynamic-table/__tests__/filterParser.presets.test.ts +64 -0
  1057. package/src/backend/dynamic-table/__tests__/filterParser.relative.test.ts +109 -0
  1058. package/src/backend/dynamic-table/__tests__/filterSuggestions.test.ts +152 -0
  1059. package/src/backend/dynamic-table/__tests__/formatAggregate.test.ts +99 -0
  1060. package/src/backend/dynamic-table/__tests__/formatDateCompact.test.ts +489 -0
  1061. package/src/backend/dynamic-table/__tests__/formatLabelCompact.test.ts +717 -0
  1062. package/src/backend/dynamic-table/__tests__/formula.check.test.ts +257 -0
  1063. package/src/backend/dynamic-table/__tests__/formula.evaluate.test.ts +274 -0
  1064. package/src/backend/dynamic-table/__tests__/formula.functions.test.ts +226 -0
  1065. package/src/backend/dynamic-table/__tests__/formula.noEval.test.ts +92 -0
  1066. package/src/backend/dynamic-table/__tests__/formula.parse.test.ts +233 -0
  1067. package/src/backend/dynamic-table/__tests__/formulaColumns.test.tsx +213 -0
  1068. package/src/backend/dynamic-table/__tests__/handlerIdentity.test.ts +77 -0
  1069. package/src/backend/dynamic-table/__tests__/importMapping.test.ts +174 -0
  1070. package/src/backend/dynamic-table/__tests__/importParse.test.ts +130 -0
  1071. package/src/backend/dynamic-table/__tests__/importServerOnly.test.ts +37 -0
  1072. package/src/backend/dynamic-table/__tests__/layoutPersistence.test.ts +372 -0
  1073. package/src/backend/dynamic-table/__tests__/mouseHandlers.doubleClick.test.ts +155 -0
  1074. package/src/backend/dynamic-table/__tests__/perspectivePersonalization.test.ts +188 -0
  1075. package/src/backend/dynamic-table/__tests__/perspectiveResolver.test.ts +133 -0
  1076. package/src/backend/dynamic-table/__tests__/perspectiveState.defaultGrouping.test.ts +306 -0
  1077. package/src/backend/dynamic-table/__tests__/perspectiveState.defaults.test.ts +107 -0
  1078. package/src/backend/dynamic-table/__tests__/perspectiveTemplates.test.tsx +269 -0
  1079. package/src/backend/dynamic-table/__tests__/perspectiveTransforms.aggregations.test.ts +105 -0
  1080. package/src/backend/dynamic-table/__tests__/perspectiveTransforms.conditionalFormats.test.ts +107 -0
  1081. package/src/backend/dynamic-table/__tests__/perspectiveTransforms.dateFormat.test.ts +61 -0
  1082. package/src/backend/dynamic-table/__tests__/perspectiveTransforms.formulas.test.ts +85 -0
  1083. package/src/backend/dynamic-table/__tests__/perspectiveTransforms.frozenColumns.test.ts +124 -0
  1084. package/src/backend/dynamic-table/__tests__/rollupColumns.test.ts +149 -0
  1085. package/src/backend/dynamic-table/__tests__/sharedCriteria.test.ts +255 -0
  1086. package/src/backend/dynamic-table/__tests__/splitViewTree.test.ts +324 -0
  1087. package/src/backend/dynamic-table/__tests__/store.clipboardMarker.test.ts +143 -0
  1088. package/src/backend/dynamic-table/__tests__/store.fillPreview.test.ts +168 -0
  1089. package/src/backend/dynamic-table/__tests__/store.mutations.test.ts +345 -0
  1090. package/src/backend/dynamic-table/__tests__/store.selection.test.ts +157 -0
  1091. package/src/backend/dynamic-table/__tests__/store.undo.test.ts +225 -0
  1092. package/src/backend/dynamic-table/__tests__/store.valueSource.test.tsx +204 -0
  1093. package/src/backend/dynamic-table/__tests__/useAnnotations.legacyOptions.test.tsx +58 -0
  1094. package/src/backend/dynamic-table/__tests__/useColumnVirtualizer.test.ts +290 -0
  1095. package/src/backend/dynamic-table/__tests__/useDensityPreference.test.ts +435 -0
  1096. package/src/backend/dynamic-table/__tests__/useDynamicTablePage.duplicate.test.tsx +99 -0
  1097. package/src/backend/dynamic-table/__tests__/useDynamicTablePage.export.test.tsx +281 -0
  1098. package/src/backend/dynamic-table/__tests__/useDynamicTablePage.personalization.test.tsx +313 -0
  1099. package/src/backend/dynamic-table/__tests__/useDynamicTablePage.perspectiveRestore.test.tsx +126 -0
  1100. package/src/backend/dynamic-table/__tests__/useGrouping.aggregations.test.ts +158 -0
  1101. package/src/backend/dynamic-table/__tests__/useGrouping.groupKey.test.ts +58 -0
  1102. package/src/backend/dynamic-table/__tests__/useKeyboardNavigation.test.ts +594 -0
  1103. package/src/backend/dynamic-table/__tests__/useStickyOffsets.memo.test.tsx +75 -0
  1104. package/src/backend/dynamic-table/__tests__/useStickyOffsets.test.ts +106 -0
  1105. package/src/backend/dynamic-table/__tests__/widgetPane.test.tsx +338 -0
  1106. package/src/backend/dynamic-table/components/ActiveFilterChips.tsx +109 -0
  1107. package/src/backend/dynamic-table/components/BulkActionsBar.tsx +89 -0
  1108. package/src/backend/dynamic-table/components/Cell.tsx +292 -0
  1109. package/src/backend/dynamic-table/components/CellCommentDialog.tsx +887 -0
  1110. package/src/backend/dynamic-table/components/CellCommentHoverPopup.tsx +94 -0
  1111. package/src/backend/dynamic-table/components/ColumnFilterPopover.tsx +775 -0
  1112. package/src/backend/dynamic-table/components/ColumnHeaderMenu.tsx +189 -0
  1113. package/src/backend/dynamic-table/components/ColumnHeaders.tsx +867 -0
  1114. package/src/backend/dynamic-table/components/CompactLabelCell.tsx +293 -0
  1115. package/src/backend/dynamic-table/components/ConfigureViewFields.tsx +173 -0
  1116. package/src/backend/dynamic-table/components/ConfigureViewFilters.tsx +346 -0
  1117. package/src/backend/dynamic-table/components/ConfigureViewFormatting.tsx +205 -0
  1118. package/src/backend/dynamic-table/components/ConfigureViewFormulas.tsx +423 -0
  1119. package/src/backend/dynamic-table/components/ConfigureViewGrouping.tsx +264 -0
  1120. package/src/backend/dynamic-table/components/ConfigureViewLinkedColumns.tsx +249 -0
  1121. package/src/backend/dynamic-table/components/ConfigureViewPanel.tsx +857 -0
  1122. package/src/backend/dynamic-table/components/ConfigureViewRollups.tsx +364 -0
  1123. package/src/backend/dynamic-table/components/ConfigureViewSorting.tsx +121 -0
  1124. package/src/backend/dynamic-table/components/ContextMenu.tsx +140 -0
  1125. package/src/backend/dynamic-table/components/DateCell.tsx +205 -0
  1126. package/src/backend/dynamic-table/components/Debugger.tsx +340 -0
  1127. package/src/backend/dynamic-table/components/DensityControl.tsx +441 -0
  1128. package/src/backend/dynamic-table/components/EmptyState.tsx +103 -0
  1129. package/src/backend/dynamic-table/components/EntitySearchEditor.tsx +528 -0
  1130. package/src/backend/dynamic-table/components/ExportMenu.tsx +90 -0
  1131. package/src/backend/dynamic-table/components/FilterDatePicker.tsx +194 -0
  1132. package/src/backend/dynamic-table/components/FilterValueInput.tsx +294 -0
  1133. package/src/backend/dynamic-table/components/FooterTotalsRow.tsx +291 -0
  1134. package/src/backend/dynamic-table/components/FullscreenOverlay.tsx +66 -0
  1135. package/src/backend/dynamic-table/components/GroupHeaderRow.tsx +136 -0
  1136. package/src/backend/dynamic-table/components/GroupSummaryRow.tsx +184 -0
  1137. package/src/backend/dynamic-table/components/ImportPanel.tsx +445 -0
  1138. package/src/backend/dynamic-table/components/ImportPreviewGrid.tsx +155 -0
  1139. package/src/backend/dynamic-table/components/LoadErrorState.tsx +70 -0
  1140. package/src/backend/dynamic-table/components/MentionPopup.tsx +224 -0
  1141. package/src/backend/dynamic-table/components/PerspectiveDeleteDialog.tsx +96 -0
  1142. package/src/backend/dynamic-table/components/PerspectivePublishDialog.tsx +152 -0
  1143. package/src/backend/dynamic-table/components/PerspectiveTabMenu.tsx +215 -0
  1144. package/src/backend/dynamic-table/components/PerspectiveTabs.tsx +426 -0
  1145. package/src/backend/dynamic-table/components/PerspectiveTemplateMenu.tsx +135 -0
  1146. package/src/backend/dynamic-table/components/RowHeaderCell.tsx +73 -0
  1147. package/src/backend/dynamic-table/components/SearchBar.tsx +309 -0
  1148. package/src/backend/dynamic-table/components/SelectMenu.tsx +237 -0
  1149. package/src/backend/dynamic-table/components/StaleDataBar.tsx +74 -0
  1150. package/src/backend/dynamic-table/components/TableDeleteDialog.tsx +74 -0
  1151. package/src/backend/dynamic-table/components/TablePagination.tsx +96 -0
  1152. package/src/backend/dynamic-table/components/TableSkeleton.tsx +123 -0
  1153. package/src/backend/dynamic-table/components/ToolbarOverflow.tsx +284 -0
  1154. package/src/backend/dynamic-table/components/ViewModeSwitch.tsx +92 -0
  1155. package/src/backend/dynamic-table/components/VirtualRow.tsx +346 -0
  1156. package/src/backend/dynamic-table/components/editors.tsx +1727 -0
  1157. package/src/backend/dynamic-table/components/renderers.tsx +162 -0
  1158. package/src/backend/dynamic-table/events/events.ts +107 -0
  1159. package/src/backend/dynamic-table/formula/check.ts +359 -0
  1160. package/src/backend/dynamic-table/formula/evaluate.ts +473 -0
  1161. package/src/backend/dynamic-table/formula/functions.ts +737 -0
  1162. package/src/backend/dynamic-table/formula/index.ts +57 -0
  1163. package/src/backend/dynamic-table/formula/parse.ts +414 -0
  1164. package/src/backend/dynamic-table/formula/types.ts +151 -0
  1165. package/src/backend/dynamic-table/handlers/cellWrites.ts +362 -0
  1166. package/src/backend/dynamic-table/handlers/index.ts +789 -0
  1167. package/src/backend/dynamic-table/handlers/perspectiveHandlers.ts +684 -0
  1168. package/src/backend/dynamic-table/hooks/index.ts +888 -0
  1169. package/src/backend/dynamic-table/hooks/useAbbreviations.ts +67 -0
  1170. package/src/backend/dynamic-table/hooks/useAnnotations.ts +215 -0
  1171. package/src/backend/dynamic-table/hooks/useColumnVirtualizer.ts +303 -0
  1172. package/src/backend/dynamic-table/hooks/useColumnWidthPersistence.ts +214 -0
  1173. package/src/backend/dynamic-table/hooks/useDensityPreference.ts +451 -0
  1174. package/src/backend/dynamic-table/hooks/useDynamicTablePage.tsx +1681 -0
  1175. package/src/backend/dynamic-table/hooks/useEscapeLayer.ts +72 -0
  1176. package/src/backend/dynamic-table/hooks/useGrouping.ts +428 -0
  1177. package/src/backend/dynamic-table/hooks/useSuggestionFetch.ts +109 -0
  1178. package/src/backend/dynamic-table/hooks/useTableDateFormat.tsx +19 -0
  1179. package/src/backend/dynamic-table/index.ts +497 -0
  1180. package/src/backend/dynamic-table/registry/ContentRegistryContext.tsx +244 -0
  1181. package/src/backend/dynamic-table/registry/TableRegistryContext.tsx +84 -0
  1182. package/src/backend/dynamic-table/registry/filterAccessibleTables.ts +36 -0
  1183. package/src/backend/dynamic-table/registry/index.ts +38 -0
  1184. package/src/backend/dynamic-table/registry/lazyTable.tsx +80 -0
  1185. package/src/backend/dynamic-table/registry/types.ts +181 -0
  1186. package/src/backend/dynamic-table/registry/widgetCatalog.ts +226 -0
  1187. package/src/backend/dynamic-table/server/aggregate.ts +474 -0
  1188. package/src/backend/dynamic-table/server/dateWindows.ts +201 -0
  1189. package/src/backend/dynamic-table/server/filterParser.ts +132 -0
  1190. package/src/backend/dynamic-table/server/filterSuggestions.ts +150 -0
  1191. package/src/backend/dynamic-table/server/index.ts +47 -0
  1192. package/src/backend/dynamic-table/server/makeDynamicTableRoute.ts +426 -0
  1193. package/src/backend/dynamic-table/split-view/ContentPicker.tsx +251 -0
  1194. package/src/backend/dynamic-table/split-view/EmptySlot.tsx +69 -0
  1195. package/src/backend/dynamic-table/split-view/SplitViewHost.tsx +1336 -0
  1196. package/src/backend/dynamic-table/split-view/WidgetPane.tsx +390 -0
  1197. package/src/backend/dynamic-table/split-view/WorkspaceFilterBar.tsx +728 -0
  1198. package/src/backend/dynamic-table/split-view/index.ts +48 -0
  1199. package/src/backend/dynamic-table/split-view/layoutPersistence.ts +185 -0
  1200. package/src/backend/dynamic-table/split-view/sharedCriteria.ts +196 -0
  1201. package/src/backend/dynamic-table/split-view/types.ts +778 -0
  1202. package/src/backend/dynamic-table/split-view/useSplitViewLayouts.ts +97 -0
  1203. package/src/backend/dynamic-table/store/index.ts +1011 -0
  1204. package/src/backend/dynamic-table/styles/ContextMenu.css +387 -0
  1205. package/src/backend/dynamic-table/styles/DynamicTable.css +3659 -0
  1206. package/src/backend/dynamic-table/styles/DynamicTable.v2.css +2651 -0
  1207. package/src/backend/dynamic-table/styles/SearchBar.css +426 -0
  1208. package/src/backend/dynamic-table/styles/dateCell.css +146 -0
  1209. package/src/backend/dynamic-table/styles/density.css +690 -0
  1210. package/src/backend/dynamic-table/types/density.ts +179 -0
  1211. package/src/backend/dynamic-table/types/filters.ts +156 -0
  1212. package/src/backend/dynamic-table/types/grouping.ts +189 -0
  1213. package/src/backend/dynamic-table/types/import.ts +132 -0
  1214. package/src/backend/dynamic-table/types/index.ts +1198 -0
  1215. package/src/backend/dynamic-table/types/perspective.ts +436 -0
  1216. package/src/backend/dynamic-table/types/rollup.ts +111 -0
  1217. package/src/backend/dynamic-table/utils/abbreviations.ts +556 -0
  1218. package/src/backend/dynamic-table/utils/anchoredPosition.ts +106 -0
  1219. package/src/backend/dynamic-table/utils/badgeAutoFit.ts +108 -0
  1220. package/src/backend/dynamic-table/utils/clipboard.ts +294 -0
  1221. package/src/backend/dynamic-table/utils/coerceCellValue.ts +96 -0
  1222. package/src/backend/dynamic-table/utils/colorAdjacency.ts +87 -0
  1223. package/src/backend/dynamic-table/utils/columnFill.ts +93 -0
  1224. package/src/backend/dynamic-table/utils/columnSpacerStyle.ts +53 -0
  1225. package/src/backend/dynamic-table/utils/columnWindow.ts +668 -0
  1226. package/src/backend/dynamic-table/utils/conditionalFormat.ts +300 -0
  1227. package/src/backend/dynamic-table/utils/exportTable.ts +140 -0
  1228. package/src/backend/dynamic-table/utils/fillGeometry.ts +187 -0
  1229. package/src/backend/dynamic-table/utils/fillPatterns.ts +422 -0
  1230. package/src/backend/dynamic-table/utils/formatAggregate.ts +145 -0
  1231. package/src/backend/dynamic-table/utils/formatDateCompact.ts +879 -0
  1232. package/src/backend/dynamic-table/utils/formatLabelCompact.ts +640 -0
  1233. package/src/backend/dynamic-table/utils/formulaColumns.tsx +237 -0
  1234. package/src/backend/dynamic-table/utils/importMapping.ts +202 -0
  1235. package/src/backend/dynamic-table/utils/importParse.ts +220 -0
  1236. package/src/backend/dynamic-table/utils/lookupColumns.tsx +47 -0
  1237. package/src/backend/dynamic-table/utils/perspectiveTransforms.ts +368 -0
  1238. package/src/backend/dynamic-table/utils/rollupColumns.ts +162 -0
  1239. package/src/backend/dynamic-table/validators/index.ts +40 -0
  1240. package/src/backend/fields/registry.generated.ts +8 -0
  1241. package/src/backend/fields/registry.ts +38 -0
  1242. package/src/backend/filters/AdvancedFilterBuilder.tsx +339 -0
  1243. package/src/backend/forms/ActionsDropdown.tsx +198 -0
  1244. package/src/backend/forms/FormActionButtons.tsx +98 -0
  1245. package/src/backend/forms/FormFooter.tsx +27 -0
  1246. package/src/backend/forms/FormHeader.tsx +204 -0
  1247. package/src/backend/forms/index.ts +4 -0
  1248. package/src/backend/hooks/useAdvancedFilter.ts +77 -0
  1249. package/src/backend/indexes/PartialIndexBanner.tsx +86 -0
  1250. package/src/backend/indexes/store.ts +88 -0
  1251. package/src/backend/injection/ComponentOverrideProvider.tsx +66 -0
  1252. package/src/backend/injection/InjectedField.tsx +196 -0
  1253. package/src/backend/injection/InjectionSpot.tsx +457 -0
  1254. package/src/backend/injection/InjectionWizard.tsx +335 -0
  1255. package/src/backend/injection/PageInjectionBoundary.tsx +31 -0
  1256. package/src/backend/injection/SseEventIndicator.tsx +11 -0
  1257. package/src/backend/injection/StatusBadgeInjectionSpot.tsx +50 -0
  1258. package/src/backend/injection/StatusBadgeRenderer.tsx +100 -0
  1259. package/src/backend/injection/WidgetSharedState.ts +58 -0
  1260. package/src/backend/injection/WizardInjectionSpot.tsx +46 -0
  1261. package/src/backend/injection/eventBridge.ts +158 -0
  1262. package/src/backend/injection/helpers.ts +35 -0
  1263. package/src/backend/injection/mergeMenuItems.ts +80 -0
  1264. package/src/backend/injection/mutationEvents.ts +22 -0
  1265. package/src/backend/injection/resolveInjectedIcon.tsx +30 -0
  1266. package/src/backend/injection/spotIds.ts +64 -0
  1267. package/src/backend/injection/useAppEvent.ts +76 -0
  1268. package/src/backend/injection/useGuardedMutation.ts +101 -0
  1269. package/src/backend/injection/useInjectedMenuItems.ts +67 -0
  1270. package/src/backend/injection/useInjectionDataWidgets.ts +41 -0
  1271. package/src/backend/injection/useOperationProgress.ts +105 -0
  1272. package/src/backend/injection/useRegisteredComponent.tsx +106 -0
  1273. package/src/backend/injection/useWidgetSharedState.ts +28 -0
  1274. package/src/backend/injection/visibility-utils.ts +31 -0
  1275. package/src/backend/injection/widgetRegistry.ts +68 -0
  1276. package/src/backend/inputs/ComboboxInput.tsx +272 -0
  1277. package/src/backend/inputs/DatePicker.tsx +162 -0
  1278. package/src/backend/inputs/DateTimePicker.tsx +199 -0
  1279. package/src/backend/inputs/EventPatternInput.tsx +46 -0
  1280. package/src/backend/inputs/EventSelect.tsx +183 -0
  1281. package/src/backend/inputs/LookupSelect.tsx +253 -0
  1282. package/src/backend/inputs/PhoneNumberField.tsx +166 -0
  1283. package/src/backend/inputs/SwitchableMarkdownInput.tsx +106 -0
  1284. package/src/backend/inputs/TagsInput.tsx +297 -0
  1285. package/src/backend/inputs/TimeInput.tsx +146 -0
  1286. package/src/backend/inputs/TimePicker.tsx +120 -0
  1287. package/src/backend/inputs/__tests__/DatePicker.test.tsx +76 -0
  1288. package/src/backend/inputs/__tests__/DateTimePicker.logic.test.ts +126 -0
  1289. package/src/backend/inputs/__tests__/PhoneNumberField.test.tsx +73 -0
  1290. package/src/backend/inputs/__tests__/TagsInput.test.tsx +78 -0
  1291. package/src/backend/inputs/__tests__/TimeInput.test.tsx +134 -0
  1292. package/src/backend/inputs/__tests__/TimePicker.test.tsx +50 -0
  1293. package/src/backend/inputs/index.ts +11 -0
  1294. package/src/backend/markdown/MarkdownContent.tsx +33 -0
  1295. package/src/backend/markdown/index.ts +2 -0
  1296. package/src/backend/markdown/useMarkdownRemarkPlugins.ts +39 -0
  1297. package/src/backend/messages/MessageComposer.tsx +197 -0
  1298. package/src/backend/messages/MessageObjectDetail.tsx +95 -0
  1299. package/src/backend/messages/MessageObjectPreview.tsx +64 -0
  1300. package/src/backend/messages/MessageObjectRecordPicker.tsx +149 -0
  1301. package/src/backend/messages/MessagePrioritySelector.tsx +78 -0
  1302. package/src/backend/messages/MessagesIcon.tsx +32 -0
  1303. package/src/backend/messages/SendObjectMessageDialog.tsx +74 -0
  1304. package/src/backend/messages/__tests__/MessageComposer.test.tsx +350 -0
  1305. package/src/backend/messages/__tests__/SendObjectMessageDialog.test.tsx +77 -0
  1306. package/src/backend/messages/index.ts +22 -0
  1307. package/src/backend/messages/message-compose-form-groups.tsx +383 -0
  1308. package/src/backend/messages/message-composer.types.ts +82 -0
  1309. package/src/backend/messages/message-priority.ts +53 -0
  1310. package/src/backend/messages/useMessageCompose.ts +666 -0
  1311. package/src/backend/messages/useMessageComposeOperations.ts +259 -0
  1312. package/src/backend/messages/useMessagesPoll.ts +118 -0
  1313. package/src/backend/notifications/NotificationBell.tsx +91 -0
  1314. package/src/backend/notifications/NotificationCountBadge.tsx +14 -0
  1315. package/src/backend/notifications/NotificationDispatcher.ts +213 -0
  1316. package/src/backend/notifications/NotificationItem.tsx +262 -0
  1317. package/src/backend/notifications/NotificationPanel.tsx +225 -0
  1318. package/src/backend/notifications/__tests__/NotificationCountBadge.test.tsx +34 -0
  1319. package/src/backend/notifications/index.ts +20 -0
  1320. package/src/backend/notifications/useNotificationActions.ts +161 -0
  1321. package/src/backend/notifications/useNotificationEffect.ts +17 -0
  1322. package/src/backend/notifications/useNotifications.ts +12 -0
  1323. package/src/backend/notifications/useNotificationsPoll.ts +167 -0
  1324. package/src/backend/notifications/useNotificationsSse.ts +220 -0
  1325. package/src/backend/operations/LastOperationBanner.tsx +85 -0
  1326. package/src/backend/operations/__tests__/LastOperationBanner.test.tsx +101 -0
  1327. package/src/backend/operations/store.ts +230 -0
  1328. package/src/backend/progress/ProgressTopBar.tsx +189 -0
  1329. package/src/backend/progress/useProgress.ts +12 -0
  1330. package/src/backend/progress/useProgressPoll.ts +100 -0
  1331. package/src/backend/progress/useProgressSse.ts +118 -0
  1332. package/src/backend/schedule/ScheduleAgenda.tsx +136 -0
  1333. package/src/backend/schedule/ScheduleGrid.tsx +136 -0
  1334. package/src/backend/schedule/ScheduleToolbar.tsx +178 -0
  1335. package/src/backend/schedule/ScheduleView.tsx +201 -0
  1336. package/src/backend/schedule/index.ts +5 -0
  1337. package/src/backend/schedule/recurrence.ts +99 -0
  1338. package/src/backend/schedule/types.ts +26 -0
  1339. package/src/backend/section-page/SectionNav.tsx +140 -0
  1340. package/src/backend/section-page/SectionPage.tsx +34 -0
  1341. package/src/backend/section-page/index.ts +3 -0
  1342. package/src/backend/section-page/types.ts +30 -0
  1343. package/src/backend/settings/SettingsNavigation.tsx +74 -0
  1344. package/src/backend/settings/SettingsPageWrapper.tsx +78 -0
  1345. package/src/backend/settings/index.ts +3 -0
  1346. package/src/backend/upgrades/UpgradeActionBanner.tsx +128 -0
  1347. package/src/backend/utils/__tests__/api.scoped-headers.test.ts +58 -0
  1348. package/src/backend/utils/__tests__/api.test.ts +148 -0
  1349. package/src/backend/utils/__tests__/apiCall.scoped-request-headers.test.ts +58 -0
  1350. package/src/backend/utils/__tests__/apiCall.test.ts +109 -0
  1351. package/src/backend/utils/__tests__/crud.test.ts +87 -0
  1352. package/src/backend/utils/__tests__/customFieldDefs.test.ts +25 -0
  1353. package/src/backend/utils/__tests__/customFieldValues.test.ts +35 -0
  1354. package/src/backend/utils/__tests__/richTextSanitizer.test.ts +57 -0
  1355. package/src/backend/utils/api.ts +214 -0
  1356. package/src/backend/utils/apiCall.ts +123 -0
  1357. package/src/backend/utils/crud.ts +174 -0
  1358. package/src/backend/utils/customFieldColumns.ts +118 -0
  1359. package/src/backend/utils/customFieldDefs.ts +247 -0
  1360. package/src/backend/utils/customFieldFilters.ts +174 -0
  1361. package/src/backend/utils/customFieldForms.ts +203 -0
  1362. package/src/backend/utils/customFieldRelationDisplay.ts +302 -0
  1363. package/src/backend/utils/customFieldValues.ts +41 -0
  1364. package/src/backend/utils/flash.ts +17 -0
  1365. package/src/backend/utils/nav.ts +402 -0
  1366. package/src/backend/utils/richTextSanitizer.ts +7 -0
  1367. package/src/backend/utils/scopedHeaderStack.ts +49 -0
  1368. package/src/backend/utils/serverErrors.ts +313 -0
  1369. package/src/backend/utils/useAutoDiscoveredFields.ts +138 -0
  1370. package/src/backend/version-history/VersionHistoryAction.tsx +76 -0
  1371. package/src/backend/version-history/VersionHistoryDetail.tsx +87 -0
  1372. package/src/backend/version-history/VersionHistoryPanel.tsx +331 -0
  1373. package/src/backend/version-history/index.ts +9 -0
  1374. package/src/backend/version-history/labels.ts +56 -0
  1375. package/src/backend/version-history/types.ts +27 -0
  1376. package/src/backend/version-history/useAuditPermissions.ts +94 -0
  1377. package/src/backend/version-history/useVersionHistory.ts +173 -0
  1378. package/src/backend/views/NewViewForm.tsx +54 -0
  1379. package/src/backend/views/ShareForm.tsx +62 -0
  1380. package/src/backend/views/ViewChip.tsx +123 -0
  1381. package/src/backend/views/ViewChipMenu.tsx +94 -0
  1382. package/src/backend/views/types.ts +4 -0
  1383. package/src/frontend/AuthFooter.tsx +29 -0
  1384. package/src/frontend/LanguageSwitcher.tsx +66 -0
  1385. package/src/frontend/Layout.tsx +13 -0
  1386. package/src/hooks/useIsMobile.ts +27 -0
  1387. package/src/index.ts +40 -0
  1388. package/src/portal/PortalContext.tsx +180 -0
  1389. package/src/portal/PortalLayoutProvider.tsx +5 -0
  1390. package/src/portal/PortalLayoutShell.tsx +64 -0
  1391. package/src/portal/PortalShell.tsx +370 -0
  1392. package/src/portal/components/PortalCard.tsx +77 -0
  1393. package/src/portal/components/PortalEmptyState.tsx +32 -0
  1394. package/src/portal/components/PortalFeatureCard.tsx +41 -0
  1395. package/src/portal/components/PortalNotificationBell.tsx +81 -0
  1396. package/src/portal/components/PortalNotificationPanel.tsx +230 -0
  1397. package/src/portal/components/PortalPageHeader.tsx +33 -0
  1398. package/src/portal/components/index.ts +6 -0
  1399. package/src/portal/hooks/useCustomerAuth.ts +97 -0
  1400. package/src/portal/hooks/usePortalAppEvent.ts +56 -0
  1401. package/src/portal/hooks/usePortalDashboardWidgets.ts +50 -0
  1402. package/src/portal/hooks/usePortalEventBridge.ts +162 -0
  1403. package/src/portal/hooks/usePortalInjectedMenuItems.ts +130 -0
  1404. package/src/portal/hooks/usePortalNotifications.ts +116 -0
  1405. package/src/portal/hooks/useTenantContext.ts +83 -0
  1406. package/src/primitives/DataLoader.tsx +93 -0
  1407. package/src/primitives/ErrorNotice.tsx +17 -0
  1408. package/src/primitives/Notice.tsx +83 -0
  1409. package/src/primitives/alert.tsx +59 -0
  1410. package/src/primitives/badge.tsx +43 -0
  1411. package/src/primitives/button.tsx +60 -0
  1412. package/src/primitives/calendar.tsx +69 -0
  1413. package/src/primitives/card.tsx +92 -0
  1414. package/src/primitives/checkbox.tsx +34 -0
  1415. package/src/primitives/dialog.tsx +122 -0
  1416. package/src/primitives/form-field.tsx +106 -0
  1417. package/src/primitives/icon-button.tsx +48 -0
  1418. package/src/primitives/input.tsx +26 -0
  1419. package/src/primitives/label.tsx +18 -0
  1420. package/src/primitives/popover.tsx +37 -0
  1421. package/src/primitives/primitives.stories.tsx +223 -0
  1422. package/src/primitives/progress.tsx +28 -0
  1423. package/src/primitives/separator.tsx +7 -0
  1424. package/src/primitives/sheet.tsx +137 -0
  1425. package/src/primitives/spinner.tsx +27 -0
  1426. package/src/primitives/status-badge.tsx +62 -0
  1427. package/src/primitives/switch.tsx +92 -0
  1428. package/src/primitives/table.tsx +27 -0
  1429. package/src/primitives/tabs.tsx +131 -0
  1430. package/src/primitives/textarea.tsx +20 -0
  1431. package/src/primitives/tooltip.tsx +85 -0
  1432. package/src/primitives-v2/AGENTS.md +66 -0
  1433. package/src/primitives-v2/Alert.stories.tsx +56 -0
  1434. package/src/primitives-v2/Alert.tsx +108 -0
  1435. package/src/primitives-v2/Avatar.stories.tsx +60 -0
  1436. package/src/primitives-v2/Avatar.tsx +139 -0
  1437. package/src/primitives-v2/Badge.stories.tsx +80 -0
  1438. package/src/primitives-v2/Badge.tsx +99 -0
  1439. package/src/primitives-v2/Breadcrumb.stories.tsx +61 -0
  1440. package/src/primitives-v2/Breadcrumb.tsx +96 -0
  1441. package/src/primitives-v2/Button.stories.tsx +72 -0
  1442. package/src/primitives-v2/Button.tsx +178 -0
  1443. package/src/primitives-v2/Checkbox.stories.tsx +34 -0
  1444. package/src/primitives-v2/Checkbox.tsx +103 -0
  1445. package/src/primitives-v2/IconButton.stories.tsx +40 -0
  1446. package/src/primitives-v2/IconButton.tsx +40 -0
  1447. package/src/primitives-v2/Input.stories.tsx +60 -0
  1448. package/src/primitives-v2/Input.tsx +113 -0
  1449. package/src/primitives-v2/NavGroup.stories.tsx +50 -0
  1450. package/src/primitives-v2/NavGroup.tsx +76 -0
  1451. package/src/primitives-v2/NavItem.stories.tsx +68 -0
  1452. package/src/primitives-v2/NavItem.tsx +105 -0
  1453. package/src/primitives-v2/SearchInput.stories.tsx +44 -0
  1454. package/src/primitives-v2/SearchInput.tsx +123 -0
  1455. package/src/primitives-v2/Sidebar.stories.tsx +91 -0
  1456. package/src/primitives-v2/Sidebar.tsx +92 -0
  1457. package/src/primitives-v2/Tab.stories.tsx +62 -0
  1458. package/src/primitives-v2/Tab.tsx +148 -0
  1459. package/src/primitives-v2/Tag.stories.tsx +123 -0
  1460. package/src/primitives-v2/Tag.tsx +115 -0
  1461. package/src/primitives-v2/Toggle.stories.tsx +37 -0
  1462. package/src/primitives-v2/Toggle.tsx +93 -0
  1463. package/src/primitives-v2/Topbar.stories.tsx +65 -0
  1464. package/src/primitives-v2/Topbar.tsx +37 -0
  1465. package/src/primitives-v2/index.ts +31 -0
  1466. package/src/primitives-v2/utils.ts +9 -0
  1467. package/src/theme/BrandThemeProvider.tsx +122 -0
  1468. package/src/theme/QueryProvider.tsx +46 -0
  1469. package/src/theme/ThemeProvider.tsx +120 -0
  1470. package/src/theme/ThemeToggle.tsx +88 -0
  1471. package/src/theme/index.ts +4 -0
  1472. package/src/theme/m3.css +622 -0
  1473. package/src/theme/tokens.v2.css +559 -0
  1474. package/src/theme/typography.css +163 -0
  1475. package/src/theme/typography.stories.tsx +157 -0
  1476. package/src/theme/typography.tokens.ts +326 -0
  1477. package/src/types/react-big-calendar.d.ts +16 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/backend/dynamic-table/DynamicTable.tsx"],
4
+ "sourcesContent": ["// DynamicTable.tsx\n\n\n'use client';\n\nimport React, {\n useState,\n useEffect,\n useLayoutEffect,\n useRef,\n useMemo,\n useCallback,\n} from 'react';\nimport { useVirtualizer } from '@tanstack/react-virtual';\n\nimport { createCellStore, CellStore } from './store/index';\nimport {\n CellStoreContext,\n useStickyOffsets,\n ROW_HEADER_WIDTH,\n useKeyboardNavigation,\n useCopyHandler,\n useRowActionShortcuts,\n columnMountsEditor,\n} from './hooks/index';\nimport {\n createCellHandlers,\n createRowHandlers,\n createDragHandlers,\n createMouseHandlers,\n createColumnHeaderHandlers,\n createRowHeaderHandlers,\n createContextMenuHandlers,\n createResizeHandlers,\n DragState,\n} from './handlers/index';\nimport { createPerspectiveHandlers, resolvePerspectiveState } from './handlers/perspectiveHandlers';\nimport { TableDateFormatContext } from './hooks/useTableDateFormat';\nimport { useColumnWidthPersistence } from './hooks/useColumnWidthPersistence';\nimport { useColumnVirtualizer } from './hooks/useColumnVirtualizer';\nimport { getPinnedColumnIndices } from './utils/columnWindow';\nimport { computeColumnFill } from './utils/columnFill';\nimport { useDensityPreference } from './hooks/useDensityPreference';\nimport { DENSITY_ATTRIBUTE, resolveDensityRowHeight } from './types/density';\nimport { DensityControl } from './components/DensityControl';\nimport { ToolbarOverflow } from './components/ToolbarOverflow';\nimport { dispatch, useEventHandlers } from './events/events';\nimport {\n ColumnDef,\n ContextMenuState,\n SortState,\n FilterRow,\n TableEvents,\n FilterChangeEvent,\n PaginationProps,\n ContextMenuAction,\n SavedFilter,\n TableUIConfig,\n LoadFilterSuggestions,\n LoadLookupSources,\n KeyboardShortcutsConfig,\n OnRowAction,\n SelectionBounds,\n} from './types/index';\nimport {\n PerspectiveConfig,\n PerspectiveTemplate,\n SortRule,\n PerspectiveChangeEvent,\n LookupColumnRef,\n} from './types/perspective';\nimport type { TableViewMode } from './types/perspective';\nimport type { TableBodyRenderContext, ExportAllResult } from './types/index';\nimport { ViewModeSwitch } from './components/ViewModeSwitch';\nimport { buildLookupColumnDefs } from './utils/lookupColumns';\nimport type { LoadRollupSources, RollupColumnRef } from './types/rollup';\nimport { buildRollupColumnDefs } from './utils/rollupColumns';\nimport { applyCellWrites } from './handlers/cellWrites';\nimport type { CellWrite, CellWriteOrigin, CellWriteReport } from './handlers/cellWrites';\nimport { coerceCellValue } from './utils/coerceCellValue';\nimport { parseClipboardGrid, selectionToTsv } from './utils/clipboard';\nimport { detectFillPattern, generateFill, invertFillMode } from './utils/fillPatterns';\nimport type { FillMode, FillSeed } from './utils/fillPatterns';\nimport { buildFillLines, cellsInRect, computeFillPreview } from './utils/fillGeometry';\nimport { compileConditionalFormats } from './utils/conditionalFormat';\nimport type { ConditionalFormatRule } from './utils/conditionalFormat';\nimport { buildFormulaColumnDefs, isFormulaColumnKey } from './utils/formulaColumns';\nimport { fieldMetaFromColumns } from './formula/check';\nimport type { FormulaColumnRef } from './formula/types';\nimport { badgeFitWidth, recordBadgeFit, planBadgeWidths } from './utils/badgeAutoFit';\nimport type { GroupRule, AggregationRule, AggregateResult, VisualRow as VisualRowType } from './types/grouping';\n\nimport { useGrouping, computeAggregates } from './hooks/useGrouping';\n\n// Import components\nimport PerspectiveTabs from './components/PerspectiveTabs';\nimport ConfigureViewPanel from './components/ConfigureViewPanel';\nimport SearchBar from './components/SearchBar';\nimport ActiveFilterChips from './components/ActiveFilterChips';\nimport EmptyState from './components/EmptyState';\nimport LoadErrorState from './components/LoadErrorState';\nimport StaleDataBar from './components/StaleDataBar';\nimport ContextMenu from './components/ContextMenu';\nimport VirtualRow from './components/VirtualRow';\nimport GroupHeaderRow from './components/GroupHeaderRow';\nimport GroupSummaryRow from './components/GroupSummaryRow';\nimport FooterTotalsRow from './components/FooterTotalsRow';\nimport ColumnHeaders from './components/ColumnHeaders';\nimport BulkActionsBar from './components/BulkActionsBar';\nimport ExportMenu from './components/ExportMenu';\nimport {\n extractExportRows,\n extractExportRowsFromData,\n toCsv,\n toXlsxBlob,\n slugifyFileName,\n downloadBlob,\n type ExtractedTable,\n type ExportFormat,\n} from './utils/exportTable';\nimport Debugger from './components/Debugger';\nimport FullscreenOverlay from './components/FullscreenOverlay';\nimport { Maximize2, FunnelX, Replace } from 'lucide-react';\nimport { generateSortRuleId, generatePerspectiveId, BASE_VIEW_PERSPECTIVE_NAME } from './types/perspective';\nimport { useAnnotations, annotationKey } from './hooks/useAnnotations';\nimport type { AnnotationComment } from './hooks/useAnnotations';\nimport CellCommentDialog from './components/CellCommentDialog';\nimport CellCommentHoverPopup from './components/CellCommentHoverPopup';\nimport { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '../../primitives/dialog';\nimport { Button } from '../../primitives/button';\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context';\nimport { flash } from '../FlashMessages';\nimport TablePagination from './components/TablePagination';\n\n/**\n * Stable empty default for `defaultGrouping`. A fresh `[]` per render would give\n * every effect that depends on it a new identity each commit \u2014 and one of those\n * effects RESETS the table's group rules, so an inline default would silently\n * undo the user's own grouping on the next render.\n */\nconst EMPTY_GROUP_RULES: GroupRule[] = [];\n\n// Built-in action ids for the drag-selection context menu (handled internally\n// in DynamicTable, not dispatched to consumer cellActions handlers).\nconst SELECTION_COPY_ID = '__cellsel_copy';\nconst SELECTION_ANNOTATE_ID = '__cellsel_annotate';\n\n/** Input types that are buttons/toggles, not places a caret can sit. */\nconst NON_TEXT_INPUT_TYPES = ['checkbox', 'radio', 'button', 'submit', 'range', 'color', 'file'];\n\n/**\n * Is this element a place the user is typing into?\n *\n * Every grid-level keyboard shortcut that shadows a native text-editing key\n * (`Ctrl+Z`, `Ctrl+D`, `Delete`, `Backspace`) has to defer to the search box,\n * a filter input or an open cell editor. One predicate so a new shortcut\n * cannot get the exemption list subtly wrong.\n */\nfunction isTextEntryTarget(el: HTMLElement | null | undefined): boolean {\n if (!el) return false;\n const tag = el.tagName;\n if (tag === 'TEXTAREA' || el.isContentEditable) return true;\n return tag === 'INPUT' && !NON_TEXT_INPUT_TYPES.includes((el as HTMLInputElement).type);\n}\n\nif (typeof window !== 'undefined') {\n // @ts-ignore - CSS import handled by bundler\n import('./styles/DynamicTable.css');\n // @ts-ignore - v2 appearance theme layer (scoped under .hot-appearance-v2)\n import('./styles/DynamicTable.v2.css');\n}\n\n// ============================================\n// PROPS INTERFACE\n// ============================================\n\nexport interface DynamicTableProps {\n data?: any[];\n columns?: ColumnDef[];\n colHeaders?: boolean;\n rowHeaders?: boolean;\n height?: string | number;\n width?: string | number;\n idColumnName?: string;\n /**\n * Column holding a value that is **unique per visual row**, used as the\n * identity key for checkbox selection. Defaults to `idColumnName`. Set this\n * when `idColumnName` is an entity key that repeats across rows (e.g. a\n * transport grid with one row per leg but `idColumnName='unitId'`), otherwise\n * selecting one row also selects its siblings sharing the same id.\n */\n rowKeyColumn?: string;\n tableName?: string;\n /**\n * The LIST request failed (HEDGE-119) \u2014 as opposed to \"the list is empty\".\n * Both reach this component as `data: []`, so without this flag the zero-row\n * region cannot tell them apart and renders `EmptyState` for a 500. Defaults\n * false; every pre-existing host keeps its current behaviour.\n */\n /**\n * REQUIRED, not optional \u2014 HEDGE-123.\n *\n * It was `loadError?: boolean` and defaulted to `false`, which quietly meant\n * \"every caller that has not thought about this asserts the fetch succeeded\".\n * The hook-driven tables were fixed; six components that fetch their own data\n * and render this component directly were simply never visited, and went on\n * reporting a 500 as \"no rows\" \u2014 a contractor with a failed address request\n * looked like a contractor with no addresses.\n *\n * Optionality is what let that happen silently. Required, the compiler names\n * every site that renders a table, so a new one cannot be added without\n * someone deciding what a failed load looks like. Pass `false` for a table\n * whose rows are local and cannot fail.\n */\n loadError: boolean;\n /** Re-runs the failed list request, from the error state's retry button. */\n onRetryLoad?: () => void;\n /**\n * Stable identifier for this table, used to persist per-user column widths in\n * localStorage across reloads. Scoped to the signed-in user (falling back to\n * the active organization). When omitted, manual column resizes are not\n * remembered. Pass the same id you use for `perspectives` so widths track the\n * table, not the page instance.\n */\n tableId?: string;\n /**\n * Row density. `'sm'` = 36px rows, `'md'` = 44px rows. Omitted uses the\n * 32px default (Figma 220:2935 \u2014 the tight v2 baseline).\n */\n density?: 'sm' | 'md';\n /** Zebra-stripe alternate rows with the secondary surface (v2 design). */\n striped?: boolean;\n /** Called with the selected row IDs whenever the v2 checkbox-column selection changes. */\n onSelectionChange?: (selectedIds: string[]) => void;\n /**\n * Batch-delete the given row IDs. When provided, selecting more than one row\n * via the checkbox column reveals a grouped-actions bar with a Delete action.\n */\n onBulkDelete?: (ids: string[]) => void | Promise<void>;\n /**\n * Fetch the entire dataset (all pages, ignoring the active perspective's\n * filters) for a whole-table export. Supplied by `useDynamicTablePage`. When\n * present, the toolbar Export button exports every row across all columns;\n * when absent it falls back to the currently-loaded page.\n */\n /**\n * Fetch the whole dataset for the toolbar export. MAY REJECT \u2014 a page that\n * fails mid-pagination must abort the export, never shorten it (HEDGE-123).\n *\n * The union with {@link ExportAllResult} must stay in step with the identical\n * prop in `types/index.ts`. It did not, briefly: `types/index.ts` was widened\n * for HEDGE-123 and this declaration was not, which broke every host that\n * spreads `{...table.props}` into this component. `packages/ui`'s own tsc\n * cannot catch that \u2014 the hosts live in other packages \u2014 so the workspace\n * typecheck is the gate that matters for this prop.\n */\n onExportAll?: () => Promise<any[] | ExportAllResult>;\n tableRef: React.RefObject<HTMLDivElement | null>;\n /** Message to display when data is empty (e.g., \"No addresses\") */\n emptyMessage?: string;\n columnActions?: (column: ColumnDef, colIndex: number) => ContextMenuAction[];\n rowActions?: (rowData: any, rowIndex: number) => ContextMenuAction[];\n cellActions?: (rowData: any, col: ColumnDef, rowIndex: number, colIndex: number) => ContextMenuAction[];\n actionsRenderer?: (rowData: any, rowIndex: number) => React.ReactNode;\n pagination?: PaginationProps;\n /**\n * The dataset-wide search term currently narrowing `data` (the `SearchBar`'s\n * query). Read-only, used for ONE thing: find-and-replace's scope label says\n * \"\u2026in 100 loaded rows (filtered by \"abc\")\", so a loaded-page match count can\n * never be mistaken for a dataset count. Omitted \u2192 the clause is omitted.\n */\n searchQuery?: string;\n\n // NEW - Perspective management\n /**\n * Array of perspective configurations to display in the perspective tabs/dropdown.\n * Perspectives define saved views with filters, sorting, column visibility, etc.\n * \n * VIRTUAL PERSPECTIVES:\n * Perspectives with IDs starting with '__' (double underscore) are considered\n * \"virtual\" or \"system\" perspectives. They are hidden from the UI tabs (via\n * PerspectiveTabs.tsx filter) but can still be active to provide functionality\n * like URL-based filtering.\n * \n * Example virtual perspective: `{ id: '__url_filters__', name: 'Filters from URL', ... }`\n */\n savedPerspectives?: PerspectiveConfig[];\n \n /**\n * The ID of the currently active perspective. When controlled by parent component,\n * the table will sync its internal state (filters, sorting, columns) to match\n * the active perspective.\n * \n * CONTROLLED MODE:\n * When both `savedPerspectives` and `activePerspectiveId` are provided, the table\n * operates in controlled mode. The parent component manages perspective state and\n * the table syncs to match.\n * \n * CLEARING PERSPECTIVES:\n * Set to `null` to clear the active perspective. The table will update its internal\n * state but will NOT re-apply the perspective if the parent tries to set it again\n * to the same value (prevents infinite loops when user manually clears filters).\n * \n * VIRTUAL PERSPECTIVES:\n * Virtual perspective IDs (starting with '__') can be used as `activePerspectiveId`\n * to provide hidden functionality without cluttering the UI.\n */\n activePerspectiveId?: string | null;\n\n /**\n * The view that opens by default FOR THIS USER (workshop A4). Rendered as a\n * star on the tab and used to disable \"Set as my default\" on the view that\n * already is one. Per-user by contract: `isDefault` is scoped to `userId`\n * upstream, so this never reflects \u2014 or changes \u2014 anyone else's choice.\n */\n defaultPerspectiveId?: string | null;\n\n /**\n * Views colleagues have published as SHARED TEMPLATES. Offered for copying \u2014\n * never applied to anyone automatically. A copy lands in the user's own space\n * and records which template and which version it came from.\n */\n sharedTemplates?: PerspectiveTemplate[];\n\n /**\n * Whether this user may publish a view as a shared template. Comes from the\n * server's own RBAC answer (`perspectives.role_defaults`), so the affordance\n * is absent exactly when the endpoint would refuse it.\n */\n canPublishTemplates?: boolean;\n\n /** Roles a template can be published to. Empty unless `canPublishTemplates`. */\n publishableRoles?: Array<{ id: string; name: string }>;\n\n /** Default columns to hide when no perspective is active */\n defaultHiddenColumns?: string[];\n\n /**\n * How rows are grouped when no perspective is active \u2014 the table's DEFAULT\n * VIEW, and the only way a host can open on a grouping without first writing\n * a saved view into the database.\n *\n * It seeds state exactly as `defaultHiddenColumns` does: on mount and on every\n * reset to the base view. A saved perspective replaces it wholesale, so a view\n * saved with no grouping opens with no grouping \u2014 the alternative (merging)\n * would make \"ungrouped\" a thing a user cannot save.\n *\n * Rules naming a column the table does not declare are dropped rather than\n * applied; see `resolvePerspectiveState`.\n */\n defaultGrouping?: GroupRule[];\n\n /**\n * \u26A0 `DynamicTableProps` IS DECLARED TWICE \u2014 here and in `types/index.ts`.\n *\n * They have drifted in BOTH directions, which is how FMS's production build\n * broke: this copy carried `defaultGrouping` and not `renderBody`, the other\n * carried `renderBody` and not `defaultGrouping`, and the component and its\n * consumers each resolved a different one. `tsc` reported a prop that is\n * plainly used as not existing.\n *\n * Reconciled rather than merged: collapsing two ~150-member interfaces is a\n * change worth doing on its own, not while unblocking a deploy. Anything\n * added to one MUST be added to the other until then.\n */\n /** An alternative body renderer \u2014 the tile grid. Called only while\n * `viewMode` is not `'table'`. */\n renderBody?: (ctx: TableBodyRenderContext) => React.ReactNode;\n\n // DEPRECATED - Keep for backward compatibility (converts to perspectives internally)\n savedFilters?: SavedFilter[];\n activeFilterId?: string | null;\n hiddenColumns?: string[];\n\n // Debug mode - shows floating event log panel\n debug?: boolean;\n\n // UI visibility configuration\n uiConfig?: TableUIConfig;\n\n /** When true, automatically selects the first cell when table receives focus with no existing selection */\n autoSelectOnFocus?: boolean;\n\n /**\n * When true, Tab navigation enters edit mode on the target cell (Excel-like behavior).\n * When false, Tab only selects the cell without entering edit mode.\n * @default true\n */\n autoEditOnTab?: boolean;\n\n /**\n * Function to load filter suggestions from the server.\n * When provided, the filter popover will fetch suggestions via this function\n * instead of extracting values from currently loaded data.\n * Recommended for large datasets (1000+ rows) to avoid client-side performance issues.\n */\n loadFilterSuggestions?: LoadFilterSuggestions;\n\n /**\n * Loads the table's FK lookup sources. When provided, the Configure View\n * drawer shows a \"Linked columns\" section so the user can attach read-only\n * columns pulled from FK-related records to the active perspective.\n */\n loadLookupSources?: LoadLookupSources;\n\n /**\n * Loads the table's one-to-many rollup sources. When provided, the Configure\n * View drawer shows a \"Summarised columns\" section so the user can attach\n * read-only aggregates over child records (\"sum of this folder's cost lines\")\n * to the active perspective.\n */\n loadRollupSources?: LoadRollupSources;\n\n /**\n * Date/time format presets this table offers. When provided (non-empty), the\n * Configure View drawer shows a \"Date format\" selector so each perspective can\n * carry its own display format, and the active choice is published to cell\n * renderers via `useTableDateFormat()`. The `value` strings are opaque host\n * tokens the table stores and round-trips but never interprets. Omit to leave\n * date formatting entirely to the host's renderers.\n */\n dateFormatOptions?: { value: string; label: string }[];\n\n /**\n * Keyboard shortcuts configuration for row-level actions.\n * Shortcuts only fire when a single cell is selected (not editing, not multi-select).\n */\n keyboardShortcuts?: KeyboardShortcutsConfig;\n\n /**\n * Callback fired when a keyboard shortcut triggers a row action.\n * Receives the shortcut id, the row data, and the row index.\n */\n onRowAction?: OnRowAction;\n\n /**\n * Refs to adjacent DynamicTable containers for cross-table navigation.\n * ArrowDown at the last row / ArrowUp at the first row moves focus to\n * `next` / `prev`. Tab past the last editable cell also moves to `next`,\n * and Shift+Tab before the first editable cell moves to `prev`.\n */\n siblingTableRefs?: {\n prev?: React.RefObject<HTMLDivElement | null>;\n next?: React.RefObject<HTMLDivElement | null>;\n };\n /**\n * Callback when a row is clicked. Enables clickable row mode with hover highlighting.\n * The callback receives the row index, row data, and the mouse event.\n * Clicks on interactive elements (buttons, inputs, etc.) are excluded.\n */\n onRowClick?: (rowIndex: number, rowData: any, event: React.MouseEvent) => void;\n\n /**\n * ID of the row to highlight (same style as hover).\n * When set, the row with matching ID will be visually highlighted and scrolled into view\n * if not already visible. Useful for syncing selection state with external components.\n */\n highlightedRowId?: string | null;\n\n /**\n * Width in pixels for the actions column.\n * Increase this when you have more action buttons (e.g., 3+ icons).\n * @default 80\n */\n actionsColumnWidth?: number;\n\n /** Enable cell comments and color annotations */\n enableComments?: boolean;\n /** Entity type for annotations. String or function that resolves per-row (e.g., for mixed transport types). */\n commentsEntityType?: string | ((row: any) => string);\n /**\n * B8a \u2014 resolve the annotation target for ONE CELL.\n *\n * Defaults to today's behaviour: `{ entityType: commentsEntityType,\n * rowId: String(row[idColumnName]) }`, so no existing consumer changes.\n *\n * Declare it when a row is not one record. On the transport list a row is a\n * unit-leg: `truckPlate` belongs to the leg, `containerNumber` belongs to the\n * container that rides on both legs, `bookingNumber` to the sea leg. Without\n * this, one comment on the container appeared on every leg of that container\n * \u2014 \"on si\u0119 teraz powiela w innych miejscach\".\n *\n * MUST be a pure function of `(row, col)`; it is called once per rendered\n * cell and once per row \u00D7 column when the annotation request is built.\n */\n commentsCellTarget?: (row: Record<string, any>, col: ColumnDef) => { entityType: string; rowId: string };\n /** Optional view context label stored as metadata (e.g., \"project_sea_containers\"). */\n commentsViewContext?: string;\n /** Called after any annotation or comment change (create, update, delete). */\n onAnnotationChange?: () => void;\n /**\n * Server-computed aggregate over the WHOLE filtered dataset (`?aggregate=`).\n * Supplied by `useDynamicTablePage`. When absent, the pinned totals row still\n * renders \u2014 folded from the loaded page and labelled as page-scoped, which is\n * the honest answer rather than a silent lie.\n */\n aggregateResult?: AggregateResult | null;\n /** The dataset aggregate request is in flight. */\n aggregateLoading?: boolean;\n /** The dataset aggregate request failed \u2014 the footer says so instead of showing 0. */\n aggregateError?: boolean;\n}\n\n// ============================================\n// MAIN DYNAMIC TABLE COMPONENT\n// ============================================\nconst DynamicTable: React.FC<DynamicTableProps> = ({\n data = [],\n columns = [],\n colHeaders = true,\n rowHeaders = false,\n height = 'auto',\n width = 'auto',\n idColumnName = 'id',\n rowKeyColumn,\n tableName = 'Table Name',\n loadError,\n onRetryLoad,\n tableId,\n density,\n striped = false,\n onSelectionChange,\n onBulkDelete,\n onExportAll,\n tableRef,\n emptyMessage,\n columnActions,\n rowActions,\n cellActions,\n actionsRenderer,\n pagination,\n searchQuery,\n // New perspective props\n savedPerspectives: propSavedPerspectives,\n activePerspectiveId: controlledActivePerspectiveId,\n defaultPerspectiveId,\n sharedTemplates,\n canPublishTemplates = false,\n publishableRoles,\n defaultHiddenColumns = [],\n defaultGrouping = EMPTY_GROUP_RULES,\n // Deprecated props (backward compatibility)\n savedFilters: deprecatedSavedFilters,\n activeFilterId: deprecatedActiveFilterId,\n hiddenColumns: deprecatedHiddenColumns = [],\n debug = false,\n uiConfig = {},\n autoSelectOnFocus = false,\n autoEditOnTab = true,\n loadFilterSuggestions,\n loadLookupSources,\n loadRollupSources,\n dateFormatOptions,\n keyboardShortcuts,\n onRowAction,\n siblingTableRefs,\n onRowClick,\n highlightedRowId,\n actionsColumnWidth: actionsColumnWidthProp = 80,\n enableComments = false,\n commentsEntityType,\n commentsCellTarget,\n commentsViewContext,\n onAnnotationChange,\n aggregateResult = null,\n aggregateLoading = false,\n aggregateError = false,\n renderBody,\n}) => {\n // NOTE: the `appearance` prop is a deprecated no-op \u2014 every table renders the\n // v2 design system. The prop is retained in the type only for Tier-3 BC.\n\n // -------------------- BACKWARD COMPATIBILITY --------------------\n // Convert deprecated savedFilters to savedPerspectives format\n const savedPerspectives = useMemo<PerspectiveConfig[]>(() => {\n if (propSavedPerspectives) {\n return propSavedPerspectives;\n }\n // Convert old savedFilters to perspectives\n if (deprecatedSavedFilters && deprecatedSavedFilters.length > 0) {\n return deprecatedSavedFilters.map(filter => ({\n id: filter.id,\n name: filter.name,\n color: filter.color,\n columns: {\n visible: columns.map(c => c.data),\n hidden: [] as string[],\n },\n filters: filter.rows,\n sorting: [] as SortRule[],\n grouping: [] as GroupRule[],\n aggregations: [] as AggregationRule[],\n lookupColumns: [] as LookupColumnRef[],\n }));\n }\n return [];\n }, [propSavedPerspectives, deprecatedSavedFilters, columns]);\n\n // Use new prop or deprecated prop\n const controlledActiveId = controlledActivePerspectiveId !== undefined\n ? controlledActivePerspectiveId\n : deprecatedActiveFilterId;\n\n // Merge hidden columns from deprecated prop and new prop\n const initialHiddenColumns = useMemo(() => {\n return [...new Set([...defaultHiddenColumns, ...deprecatedHiddenColumns])];\n }, [defaultHiddenColumns, deprecatedHiddenColumns]);\n\n // -------------------- UI CONFIG --------------------\n const {\n hideToolbar = false,\n hideTitle = false,\n searchSuggestions,\n searchDebounceMs,\n searchPlaceholder,\n formatGroupValue,\n hideSearch = false,\n hideAddRowButton = false,\n hidePerspectiveTabs: hidePerspectiveTabsExplicit,\n hidePagination = false,\n hideActionsColumn = false,\n topBarStart,\n topBarEnd,\n searchBarEnd,\n searchBarStart,\n beforeBody,\n enableFullscreen = false,\n onFullscreenChange,\n enableFillHandle = false,\n fillConfirmThreshold = 100,\n readOnlyStyle = 'muted',\n rowHoverStyle = 'default',\n disableBuiltinColumnMenu = false,\n borderless = false,\n bulkActions,\n hideExportButton = false,\n exportFileName,\n enableColumnVirtualization = false,\n columnOverscan,\n hideDensityControl = false,\n expandToolbarActions = false,\n toolbarOverflowExtras,\n densityLevel: densityLevelOverride,\n viewModes,\n onViewModeChange,\n } = uiConfig;\n\n // -------------------- DENSITY (PER-USER) --------------------\n // One attribute on the container flips a block of CSS custom properties\n // (styles/density.css) and restyles every mounted cell with ZERO React work.\n // `comfortable` is the default and matches today's rendering exactly, so a\n // user who never opens the picker sees no change at all.\n const { density: densityLevel } = useDensityPreference(densityLevelOverride, tableId);\n // NOTE the distinct attribute name. `data-density` is the LEGACY developer\n // prop ('sm' | 'md'), and `DynamicTable.v2.css` carries rules keyed on\n // `:not([data-density])` that define part of today's DEFAULT rendering \u2014\n // reusing that attribute would switch those rules off the moment a user\n // picked `comfortable`, which is the \"opting out is a no-op\" guarantee,\n // broken. Spread rather than written literally because the attribute name is\n // owned by types/density.ts, not by this file.\n const densityAttribute = useMemo(\n () => ({ [DENSITY_ATTRIBUTE]: densityLevel }) as Record<string, string>,\n [densityLevel],\n );\n\n // Auto-hide perspective tabs when no perspectives are configured\n const hasPerspectives = !!(propSavedPerspectives || deprecatedSavedFilters);\n const hidePerspectiveTabs = hidePerspectiveTabsExplicit ?? !hasPerspectives;\n\n // Translator + locale are read HERE, above the column build, because the\n // formula column defs need `t` for their per-cell error tooltips and the\n // footer/summary rows need `locale` for number formatting.\n const t = useT();\n const locale = useLocale();\n\n // -------------------- REFS --------------------\n const storeRef = useRef<CellStore | null>(null);\n const dragStateRef = useRef<DragState>({\n isDragging: false,\n type: null,\n start: null,\n });\n\n // -------------------- CONSTANTS --------------------\n const actionsColumnWidth = actionsColumnWidthProp;\n\n // -------------------- BASE COLUMNS --------------------\n // -------------------- LINKED (LOOKUP) COLUMNS --------------------\n // Read-only columns surfaced from FK-related records, carried by the active\n // perspective. Initialised from the active perspective on mount; updated via\n // the Configure View \"Linked columns\" section and perspective select.\n const [lookupColumns, setLookupColumns] = useState<LookupColumnRef[]>(() => {\n const activePerspective = controlledActiveId\n ? savedPerspectives.find(p => p.id === controlledActiveId)\n : null;\n return activePerspective?.lookupColumns ?? [];\n });\n const lookupColumnDefs = useMemo(() => buildLookupColumnDefs(lookupColumns), [lookupColumns]);\n\n // -------------------- ROLLUP (SUMMARISED) COLUMNS --------------------\n // The one-to-many direction: aggregates over the records that point AT this\n // row. Same lifecycle as linked columns \u2014 carried by the active perspective,\n // updated by the Configure View \"Summarised columns\" section. The VALUE is\n // attached to the row by the host's list route (which sees the `rollups`\n // query param the host derives from these refs); the grid only renders it.\n const [rollupColumns, setRollupColumns] = useState<RollupColumnRef[]>(() => {\n const activePerspective = controlledActiveId\n ? savedPerspectives.find(p => p.id === controlledActiveId)\n : null;\n return activePerspective?.rollupColumns ?? [];\n });\n const rollupColumnDefs = useMemo(\n () => buildRollupColumnDefs(rollupColumns, { locale }),\n [rollupColumns, locale],\n );\n\n // -------------------- CALCULATED (FORMULA) COLUMNS --------------------\n // Same lifecycle as linked columns: carried by the active perspective,\n // initialised on mount, updated by the Configure View \"Calculated columns\"\n // section and by a perspective switch.\n const [formulas, setFormulas] = useState<FormulaColumnRef[]>(() => {\n const activePerspective = controlledActiveId\n ? savedPerspectives.find(p => p.id === controlledActiveId)\n : null;\n return activePerspective?.formulas ?? [];\n });\n\n const nativeColumns = useMemo(() => {\n let raw: ColumnDef[];\n if (columns.length > 0) {\n raw = columns;\n } else if (data.length > 0 && typeof data[0] === 'object' && !Array.isArray(data[0])) {\n raw = Object.keys(data[0])\n .filter((k) => k !== '_isNew')\n .map((k) => ({ data: k }));\n } else {\n raw = [];\n }\n // Virtual columns go LAST and in a fixed order (linked, then summarised) so\n // adding one never shifts the index of a native column.\n if (lookupColumnDefs.length === 0 && rollupColumnDefs.length === 0) return raw;\n return [...raw, ...lookupColumnDefs, ...rollupColumnDefs];\n }, [columns, data, lookupColumnDefs, rollupColumnDefs]);\n\n // A formula may reference native and linked columns, never another formula \u2014\n // `fields` is therefore derived from the NON-formula set. Memoised per\n // (formulas, fields): the returned defs own the per-row evaluation cache, so\n // rebuilding them on every render would throw that cache away every frame.\n const formulaColumnDefs = useMemo(\n () => buildFormulaColumnDefs(formulas, { fields: fieldMetaFromColumns(nativeColumns), translate: t }),\n [formulas, nativeColumns, t],\n );\n\n const baseColumns = useMemo(\n () => (formulaColumnDefs.length > 0 ? [...nativeColumns, ...formulaColumnDefs] : nativeColumns),\n [nativeColumns, formulaColumnDefs],\n );\n\n // -------------------- PERSPECTIVE STATE --------------------\n const initialState = useMemo(() => {\n // Find active perspective\n const activePerspective = controlledActiveId\n ? savedPerspectives.find(p => p.id === controlledActiveId)\n : null;\n return resolvePerspectiveState({\n baseColumns,\n perspective: activePerspective,\n defaultHiddenColumns: initialHiddenColumns,\n defaultGrouping,\n });\n }, []); // Only compute on mount\n\n const [visibleColumns, setVisibleColumns] = useState<string[]>(initialState.visibleColumns);\n const [hiddenColumns, setHiddenColumns] = useState<string[]>(initialState.hiddenColumns);\n const [filters, setFilters] = useState<FilterRow[]>(initialState.filters);\n const [sortRules, setSortRules] = useState<SortRule[]>(initialState.sortRules);\n const [groupRules, setGroupRules] = useState<GroupRule[]>(initialState.groupRules);\n /**\n * How this table draws its rows. Held EXACTLY like `groupRules` \u2014 seeded from\n * the active perspective, dispatched upward in PERSPECTIVE_CHANGE, persisted\n * by the host's perspective save. It is a property of the view, so it is\n * state of the same kind, in the same place, saved by the same path. Anything\n * else (a `useState` + `localStorage`, as `RfqBoardPage` does for its Kanban\n * toggle) cannot belong to a saved view.\n */\n const [viewMode, setViewMode] = useState<TableViewMode>(initialState.viewMode ?? 'table');\n const [aggregations, setAggregations] = useState<AggregationRule[]>(initialState.aggregations);\n const [conditionalFormats, setConditionalFormats] = useState<ConditionalFormatRule[]>(\n initialState.conditionalFormats,\n );\n const [dateFormat, setDateFormat] = useState<string | undefined>(initialState.dateFormat);\n /**\n * Columns pinned sticky-left, seeded from the view rather than from nothing.\n *\n * HEDGE-102: this was `useState(new Set())` with no reader and no writer, so\n * a pin lived until the next render of the page and was gone on reload. It is\n * a property of the view \u2014 the same kind of state as `viewMode` and\n * `conditionalFormats` above \u2014 so it is seeded, applied and saved by the same\n * paths those use.\n */\n const [frozenColumns, setFrozenColumns] = useState<Set<string>>(\n () => new Set(initialState.frozenColumns),\n );\n const [internalActivePerspectiveId, setInternalActivePerspectiveId] = useState<string | null>(\n controlledActiveId ?? null\n );\n\n // Active perspective ID (controlled or internal)\n const activePerspectiveId = controlledActiveId !== undefined\n ? controlledActiveId\n : internalActivePerspectiveId;\n\n // `initialState` above is computed on mount only, but `savedPerspectives` and\n // `controlledActiveId` arrive asynchronously \u2014 the host fetches them from\n // /api/perspectives/:tableId. So on mount they are empty/null and the grid\n // always initialises to the DEFAULT column set, while the toolbar goes on to\n // render the saved view's tab as active. Without the sync below, that desync\n // persists until the user manually clicks the tab: saved columns, filters and\n // sorting silently never apply, and returning from a detail page looks like\n // the view \"reset to Default\".\n //\n // Keyed on the perspective ID, never on the `savedPerspectives` array\n // identity \u2014 the host rebuilds that array on every refetch, and re-applying\n // on identity change would stomp on the user's in-session edits.\n //\n // THIS IS THE ONLY EFFECT THAT APPLIES A PERSPECTIVE. A second \"sync controlled\n // props\" effect used to live further down the file, copying the perspective's\n // raw fields without `defaultHiddenColumns`. Both ran on the same commit, so\n // which one won was an effect-ordering accident. Do not add another.\n const appliedPerspectiveRef = useRef<string | null | undefined>(undefined);\n useEffect(() => {\n if (appliedPerspectiveRef.current === activePerspectiveId) return;\n // Nothing to apply yet: an id is set but its config hasn't loaded. Stay put\n // rather than resetting to defaults, and retry once the fetch lands.\n const perspective = activePerspectiveId\n ? savedPerspectives.find(p => p.id === activePerspectiveId)\n : null;\n if (activePerspectiveId && !perspective) return;\n\n appliedPerspectiveRef.current = activePerspectiveId;\n const next = resolvePerspectiveState({\n baseColumns,\n perspective,\n defaultHiddenColumns: initialHiddenColumns,\n defaultGrouping,\n });\n setVisibleColumns(next.visibleColumns);\n setHiddenColumns(next.hiddenColumns);\n setFilters(next.filters);\n setSortRules(next.sortRules);\n setGroupRules(next.groupRules);\n setViewMode(next.viewMode ?? 'table');\n setAggregations(next.aggregations);\n setLookupColumns(next.lookupColumns);\n setRollupColumns(next.rollupColumns);\n setFormulas(next.formulas);\n setConditionalFormats(next.conditionalFormats);\n setFrozenColumns(new Set(next.frozenColumns));\n setDateFormat(next.dateFormat);\n // Keep the internal mirror in step while the parent controls the id, so a\n // later switch to uncontrolled mode does not resurrect a stale view.\n if (controlledActiveId !== undefined) {\n setInternalActivePerspectiveId(activePerspectiveId ?? null);\n }\n }, [activePerspectiveId, controlledActiveId, savedPerspectives, baseColumns, initialHiddenColumns, defaultGrouping]);\n\n // Display name: use perspective name if selected (except for built-in perspectives starting with '_'), otherwise default tableName\n const displayTableName = useMemo(() => {\n if (activePerspectiveId && !activePerspectiveId.startsWith('_')) {\n const activePerspective = savedPerspectives.find(p => p.id === activePerspectiveId);\n // The base-view row is a personalization of the \"Default view\" TAB, not a\n // named view \u2014 its reserved internal name must never reach the heading.\n if (activePerspective && !activePerspective.isBaseView) {\n return activePerspective.name;\n }\n }\n return tableName;\n }, [activePerspectiveId, savedPerspectives, tableName]);\n\n // -------------------- MODERN LAYOUT STATE --------------------\n const [configPanelOpen, setConfigPanelOpen] = useState(false);\n const [configPanelInitialSection, setConfigPanelInitialSection] = useState<string | null>(null);\n // Perspective currently open for editing in the Configure View panel. Null when\n // the panel was opened to create a brand-new view (\"Add view\").\n const [editingPerspectiveId, setEditingPerspectiveId] = useState<string | null>(null);\n /**\n * Whether the Configure View drawer is currently configuring the BASE\n * (\"Default view\") tab. Explicit state rather than \"no view is active\",\n * because \"Add view\" is also reached from that state and must keep demanding\n * a name for the new view.\n */\n const [configureBaseView, setConfigureBaseView] = useState(false);\n /** This user's saved personalization of the base tab, if any. */\n const baseViewPerspective = useMemo(\n () => savedPerspectives.find((p) => p.isBaseView) ?? null,\n [savedPerspectives],\n );\n\n // -------------------- COMMENTS STATE --------------------\n const [commentDialog, setCommentDialog] = useState<{\n /**\n * B8a \u2014 the target this dialog writes to, resolved from the CELL, not from\n * the row. On a leg-scoped column it is the leg; on a container-scoped\n * column, the container. Carried explicitly so the dialog never has to\n * re-derive it from the row and land on a different record.\n */\n entityType: string;\n rowId: string;\n columnKey: string;\n columnTitle: string;\n rowLabel?: string;\n annotationId?: string | null;\n currentColor?: string | null;\n anchorRect?: DOMRect | null;\n /** Bulk cells carry their own scope \u2014 one range can span two entity types. */\n bulkCells?: { entityType: string; rowId: string; columnKey: string }[];\n } | null>(null);\n\n // Read-only hover preview of a commented cell's thread (shown on hovering the\n // comment indicator; click opens the full dialog above).\n const [commentHover, setCommentHover] = useState<{\n comments: AnnotationComment[];\n columnTitle?: string;\n anchorRect: DOMRect;\n } | null>(null);\n\n\n // -------------------- FULLSCREEN STATE --------------------\n const [isFullscreen, setIsFullscreen] = useState(false);\n\n // -------------------- COMPUTED COLUMNS (ordered by perspective) --------------------\n const cols = useMemo(() => {\n // Get columns in the order specified by visibleColumns\n const orderedCols: ColumnDef[] = [];\n for (const key of visibleColumns) {\n const col = baseColumns.find(c => c.data === key);\n if (col) {\n orderedCols.push(col);\n }\n }\n return orderedCols;\n }, [baseColumns, visibleColumns]);\n\n /**\n * B8a \u2014 the annotation target of one cell. Everything that reads or writes an\n * annotation goes through this ONE resolver, so the fetch, the render, the\n * dialog and the bulk write can never disagree about which record a comment\n * belongs to.\n */\n const resolveCommentTarget = useCallback(\n (rowData: Record<string, any> | undefined, col: ColumnDef): { entityType: string; rowId: string } => {\n if (!rowData) return { entityType: '', rowId: '' };\n if (commentsCellTarget) return commentsCellTarget(rowData, col);\n const entityType =\n typeof commentsEntityType === 'function' ? commentsEntityType(rowData) : commentsEntityType || '';\n return { entityType, rowId: String(rowData[idColumnName] ?? '') };\n },\n [commentsCellTarget, commentsEntityType, idColumnName],\n );\n\n /**\n * Every distinct (entityType, rowId) on screen. Computed over rows \u00D7 VISIBLE\n * columns because a cell's target may depend on its column: a page showing\n * only leg columns must not request container annotations, and one showing\n * both must request both.\n */\n const annotationTargets = useMemo(() => {\n if (!enableComments) return [] as Array<{ entityType: string; rowId: string }>;\n const seen = new Set<string>();\n const out: Array<{ entityType: string; rowId: string }> = [];\n for (const row of data) {\n for (const col of cols) {\n const target = resolveCommentTarget(row, col);\n if (!target.entityType || !target.rowId) continue;\n const key = `${target.entityType}:${target.rowId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(target);\n }\n }\n return out;\n }, [enableComments, data, cols, resolveCommentTarget]);\n\n const { annotations, refresh: refreshAnnotations } = useAnnotations({\n enabled: enableComments && annotationTargets.length > 0,\n targets: annotationTargets,\n });\n\n /**\n * The annotation map key for one cell, handed to every row. Stable identity\n * (it only changes when the resolver does) so `VirtualRow`'s `React.memo`\n * survives \u2014 a fresh function per render would repaint every mounted row on\n * every keystroke.\n */\n const cellAnnotationKeyAt = useCallback(\n (rowData: Record<string, any>, column: ColumnDef): string | null => {\n const target = resolveCommentTarget(rowData, column);\n if (!target.entityType || !target.rowId) return null;\n return annotationKey(target, column.data);\n },\n [resolveCommentTarget],\n );\n\n // Compile the highlighting rule set ONCE per change. `Cell` must never\n // compile: it runs per cell per render, and a 57-column page mounts thousands.\n const compiledFormats = useMemo(\n () => compileConditionalFormats(conditionalFormats),\n [conditionalFormats],\n );\n\n // -------------------- STORE INITIALIZATION --------------------\n if (!storeRef.current) {\n storeRef.current = createCellStore(data, cols);\n }\n const store = storeRef.current;\n\n // -------------------- GROUPING --------------------\n // `totalRows` is not optional in practice: without it EVERY subtotal is\n // labelled \"this page only\", because the hook cannot prove the loaded page is\n // the whole filtered dataset.\n const groupingResult = useGrouping(data, groupRules, cols, aggregations, {\n totalRows: pagination?.total,\n });\n const isGrouped = groupingResult.visualRows !== null;\n\n /**\n * Is an alternative body renderer drawing the rows right now?\n *\n * When it is, the SPREADSHEET affordances are turned off \u2014 the cell-range\n * drag, the fill handle, the clipboard grid, the `role=\"grid\"` semantics.\n * Not because they would crash (every one of them bails when it cannot find a\n * `td[data-row]`), but because leaving them armed would announce a grid with\n * rows and columns to a screen reader that is looking at a wall of tiles.\n *\n * Everything ABOVE and BELOW the body stays: the toolbar, the search box, the\n * filters, the perspective tabs, the selection bar, the pagination. That is\n * what makes the two renderers structurally unable to diverge \u2014 they are not\n * two views of the data, they are one view with two bodies.\n */\n // Report the mode the table actually settled on \u2014 the initial one, and any\n // restored from a perspective, neither of which goes through the switcher.\n const reportedViewMode = useRef<TableViewMode | null>(null);\n useEffect(() => {\n if (reportedViewMode.current === viewMode) return;\n reportedViewMode.current = viewMode;\n onViewModeChange?.(viewMode);\n }, [viewMode, onViewModeChange]);\n\n const usingCustomBody = viewMode !== 'table' && !!renderBody;\n\n // -------------------- OTHER STATE --------------------\n const [rowCount, setRowCount] = useState(store.getRowCount());\n const [storeRevision, setStoreRevision] = useState(0);\n // SINGLE SOURCE OF TRUTH FOR SORT.\n // `sortRules` is the only sort state: it is what the perspective carries, what\n // the Configure View drawer edits, what the column menu writes and what the\n // server query is built from. `sortState` is a pure projection of its primary\n // rule onto the header's column index \u2014 never stored, so a header click and a\n // menu sort can no longer disagree (which is what made a sorted column render\n // no indicator at all).\n const sortState = useMemo<SortState>(() => {\n const primary = sortRules[0];\n if (!primary) return { columnIndex: null, direction: null };\n const columnIndex = cols.findIndex((c) => c.data === primary.field);\n if (columnIndex < 0) return { columnIndex: null, direction: null };\n return { columnIndex, direction: primary.direction };\n }, [sortRules, cols]);\n const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);\n\n // -------------------- COMPUTED VALUES --------------------\n const { leftOffsets, rightOffsets } = useStickyOffsets(cols, store, rowHeaders);\n\n // Only reserve the Actions column when it actually has something to render:\n // row actions (the kebab), a custom actions renderer, or an in-progress new\n // row (whose save button lives in this column). Read-only/display tables with\n // none of these drop the empty column entirely. Recomputed on every render;\n // adding/removing a new row bumps `storeRevision` (see setStoreRevision),\n // which re-renders and re-reads `store.hasNewRows()` so the column toggles.\n const showActionsColumn = !hideActionsColumn && (!!rowActions || !!actionsRenderer || store.hasNewRows());\n\n // Sticky-column scroll shadows (v2 affordance \u2014 CSS scopes them):\n // \u2022 Actions column gets a LEFT-edge shadow while there's content still to\n // reveal to the right (not scrolled all the way right).\n // \u2022 First (sticky) column gets a RIGHT-edge shadow while there's content\n // hidden to the left (i.e. scrolled right at all \u2192 can scroll back left).\n const [actionsScrollShadow, setActionsScrollShadow] = useState(false);\n const [firstColScrollShadow, setFirstColScrollShadow] = useState(false);\n // Frozen-column float shadow: ON only once the pinned block has actually\n // reached its sticky point (content scrolling UNDER its right edge) \u2014 not\n // while a not-yet-pinned frozen column is still drifting left with the scroll.\n const [frozenColShadow, setFrozenColShadow] = useState(false);\n useEffect(() => {\n const el = tableRef.current;\n if (!el) return;\n // The `querySelector` + `getComputedStyle` + two `getBoundingClientRect`\n // calls below each force a synchronous style/layout flush, and this fires on\n // EVERY scroll event \u2014 vertical included, since it is one scroller. That is\n // the same scroll-path DOM work this file documents removing at Defect 7.\n //\n // Two changes keep it off the scroll path: the frozen edge and its sticky\n // target are measured ONCE per effect run (both only change with\n // `frozenColumns` / `cols.length`, which are already dependencies), and the\n // handler itself is coalesced onto an animation frame so a burst of scroll\n // events costs one measurement per painted frame instead of one per event.\n let frozenEdge: HTMLElement | null = null;\n let frozenTarget = 0;\n const measureFrozenEdge = () => {\n frozenEdge = el.querySelector('.hot-headers-sticky [data-frozen-edge=\"true\"]');\n frozenTarget = frozenEdge ? parseFloat(getComputedStyle(frozenEdge).left) || 0 : 0;\n };\n\n const update = () => {\n const maxScroll = el.scrollWidth - el.clientWidth;\n setActionsScrollShadow(maxScroll > 1 && Math.ceil(el.scrollLeft) < maxScroll - 1);\n setFirstColScrollShadow(el.scrollLeft > 1);\n // The rightmost pinned column is \"stuck\" when its rendered left equals its\n // sticky target (inline `left`); while drifting it sits further right.\n if (frozenEdge && el.scrollLeft > 1) {\n const rel = frozenEdge.getBoundingClientRect().left - el.getBoundingClientRect().left;\n setFrozenColShadow(rel <= frozenTarget + 1);\n } else {\n setFrozenColShadow(false);\n }\n };\n\n let frame: number | null = null;\n const onScroll = () => {\n if (frame !== null) return;\n frame = requestAnimationFrame(() => {\n frame = null;\n update();\n });\n };\n\n measureFrozenEdge();\n update();\n el.addEventListener('scroll', onScroll, { passive: true });\n // A resize can add or remove the frozen edge, so re-measure before updating.\n const ro = new ResizeObserver(() => {\n measureFrozenEdge();\n onScroll();\n });\n ro.observe(el);\n return () => {\n el.removeEventListener('scroll', onScroll);\n if (frame !== null) cancelAnimationFrame(frame);\n ro.disconnect();\n };\n // isFullscreen: entering/leaving fullscreen re-parents tableContent (the\n // scroller remounts), so re-attach the listener to the new node.\n // frozenColumns: re-measure engagement when the pinned set changes.\n }, [tableRef, cols.length, showActionsColumn, isFullscreen, frozenColumns]);\n\n const totalWidth = useMemo(() => {\n return (\n cols.reduce((sum, _, idx) => sum + store.getColumnWidth(idx), 0) +\n (rowHeaders ? 50 : 0) +\n (showActionsColumn ? actionsColumnWidth : 0)\n );\n }, [cols, store, rowHeaders, actionsColumnWidth, showActionsColumn, storeRevision]);\n\n /** Row furniture that sits outside the column widths. */\n const furnitureWidth = (rowHeaders ? 50 : 0) + (showActionsColumn ? actionsColumnWidth : 0);\n\n // Stable width getter for the pinned totals row, so its `memo` survives a\n // render that changed nothing it cares about. Widths only move when the store\n // revision does, which is exactly what invalidates this.\n const getColumnWidth = useCallback(\n (colIndex: number) => store.getColumnWidth(colIndex),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [store, storeRevision],\n );\n\n // Page-scoped fallback for the pinned totals: folded with the SAME function\n // the group subtotals use, so the two can never disagree. It is shown\n // immediately (so the footer is never blank) and `FooterTotalsRow` labels it\n // honestly as page-scoped until the server's dataset figure lands.\n const pageAggregates = useMemo(() => {\n if (aggregations.length === 0) return undefined;\n const columnsByField = new Map(cols.map((c) => [c.data, c] as const));\n const indices = data.map((_, i) => i);\n return computeAggregates(data, indices, aggregations, columnsByField);\n }, [data, aggregations, cols]);\n const pageAggregateValues = pageAggregates?.values;\n const pageAggregateBreakdowns = pageAggregates?.breakdowns;\n\n // When grouped, virtualizer count is visual rows length; otherwise original row count\n const virtualizerCount = isGrouped ? groupingResult.visualRows!.length : rowCount;\n\n // Row height by density: sm=36, md=44; default 32 (Figma 220:2935 \u2014 tighter\n // baseline for all v2 tables). Includes the 4px inter-row gap (2px transparent\n // border top + bottom) so the visible row pill is ~28px, matching Figma.\n // The user's density preference wins when they have actually expressed one.\n // At `comfortable` (the default) this is the ORIGINAL expression, unchanged \u2014\n // that is what makes shipping density a pixel-level no-op for everyone who\n // never opens the picker. Row height is the single number CSS cannot own:\n // rows are absolutely positioned by the virtualizer, so JS has to know it.\n const dataRowHeight =\n densityLevel !== 'comfortable'\n ? resolveDensityRowHeight(densityLevel)\n : density === 'md' ? 44 : density === 'sm' ? 36 : 32;\n\n // Row selection (v2 checkbox column for bulk / grouped actions).\n // Selection identity must be unique per visual row \u2014 fall back to\n // `idColumnName`, but allow consumers to point at a distinct unique column\n // when `idColumnName` is a repeating entity key (see `rowKeyColumn`).\n const selectionColumnName = rowKeyColumn ?? idColumnName;\n const selectable = rowHeaders;\n const [selectedRowIds, setSelectedRowIds] = useState<Set<string>>(new Set());\n\n // v2 Actions column shows a kebab (\u2022\u2022\u2022) menu built from `rowActions`, unless\n // the consumer supplies a custom `actionsRenderer`.\n const showRowActionsMenu = !!rowActions && !actionsRenderer;\n const pageRowIds = useMemo(\n () => data\n .map((r) => (r == null ? undefined : r[selectionColumnName]))\n .filter((id) => id != null)\n .map((id) => String(id)),\n [data, selectionColumnName]\n );\n const allSelected = pageRowIds.length > 0 && pageRowIds.every((id) => selectedRowIds.has(id));\n const someSelected = !allSelected && pageRowIds.some((id) => selectedRowIds.has(id));\n const handleToggleRowSelect = useCallback((rowId: string) => {\n setSelectedRowIds((prev) => {\n const next = new Set(prev);\n if (next.has(rowId)) next.delete(rowId); else next.add(rowId);\n onSelectionChange?.(Array.from(next));\n return next;\n });\n }, [onSelectionChange]);\n const handleToggleSelectAll = useCallback(() => {\n setSelectedRowIds((prev) => {\n const next = new Set(prev);\n const everySelected = pageRowIds.length > 0 && pageRowIds.every((id) => next.has(id));\n if (everySelected) pageRowIds.forEach((id) => next.delete(id));\n else pageRowIds.forEach((id) => next.add(id));\n onSelectionChange?.(Array.from(next));\n return next;\n });\n }, [pageRowIds, onSelectionChange]);\n // Toggle every row in a group: select all unless they're already all selected.\n const handleToggleGroupSelect = useCallback((groupRowIds: string[]) => {\n setSelectedRowIds((prev) => {\n const next = new Set(prev);\n const everySelected = groupRowIds.length > 0 && groupRowIds.every((id) => next.has(id));\n if (everySelected) groupRowIds.forEach((id) => next.delete(id));\n else groupRowIds.forEach((id) => next.add(id));\n onSelectionChange?.(Array.from(next));\n return next;\n });\n }, [onSelectionChange]);\n\n // Grouped (bulk) actions \u2014 surfaced when >1 row is selected.\n const [isBulkDeleting, setIsBulkDeleting] = useState(false);\n // Holds the last visible selection count so the bar can finish its close\n // animation showing the real number instead of flashing \"1 selected\".\n const bulkBarCountRef = useRef(0);\n const clearSelection = useCallback(() => {\n setSelectedRowIds(new Set());\n onSelectionChange?.([]);\n }, [onSelectionChange]);\n const handleBulkDelete = useCallback(async () => {\n if (!onBulkDelete) return;\n const ids = Array.from(selectedRowIds);\n if (ids.length === 0) return;\n setIsBulkDeleting(true);\n try {\n await onBulkDelete(ids);\n // Resolved \u2192 rows deleted; drop the now-stale selection.\n clearSelection();\n } catch {\n // Rejected \u2192 cancelled from the confirm modal; keep the selection.\n } finally {\n setIsBulkDeleting(false);\n }\n }, [onBulkDelete, selectedRowIds, clearSelection]);\n\n const rowVirtualizer = useVirtualizer({\n count: virtualizerCount,\n getScrollElement: () => tableRef?.current,\n // Group headers share the data-row height so the grouped band lines up\n // with the rest of the rows (same pill height + inter-row gap).\n estimateSize: () => dataRowHeight,\n overscan: 10,\n });\n\n // Row height is the one density value CSS cannot own (rows are absolutely\n // positioned by the virtualiser, which caches item sizes), so a density\n // switch must invalidate that cache SYNCHRONOUSLY \u2014 before paint. The 50ms\n // timer below is for the fullscreen re-parent, which genuinely needs the DOM\n // to settle; using it here would paint one frame of overlapping rows.\n useLayoutEffect(() => {\n rowVirtualizer.measure();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [dataRowHeight]);\n\n // Re-measure when fullscreen state or row density changes\n useEffect(() => {\n // Small delay to ensure DOM is ready after fullscreen transition\n const timer = setTimeout(() => {\n rowVirtualizer.measure();\n }, 50);\n return () => clearTimeout(timer);\n }, [isFullscreen, dataRowHeight, rowVirtualizer]);\n\n const virtualRows = rowVirtualizer.getVirtualItems();\n\n // -------------------- HANDLERS --------------------\n // Anchor Defect 5: these factories return the callbacks that are passed into\n // every mounted `VirtualRow` (`onCellSave`, `onSaveNewRow`, `onCancelNewRow`,\n // `onRowHeaderDoubleClick`). Constructing them in the render body gave each a\n // fresh identity on EVERY render, which defeated `VirtualRow`'s `React.memo`\n // outright \u2014 a keystroke in the filter box re-rendered every mounted row and\n // therefore every mounted cell.\n //\n // They are memoised over exactly what they close over. `store`, `tableRef`\n // and `dragStateRef` are stable for the table's lifetime; `cols` changes only\n // on a perspective reorder/show-hide, which genuinely must rebuild them (the\n // handlers index into `cols`). No mutable state is captured, so there is no\n // stale-closure hazard here \u2014 a factory that captured React state instead of\n // reading it from the store would need a ref, not a wider dep list.\n const { handleCellSave: handleCellSaveBase } = useMemo(\n () => createCellHandlers(store, cols, tableRef, idColumnName),\n [store, cols, tableRef, idColumnName],\n );\n const hasFormulaColumns = useMemo(() => cols.some((c) => isFormulaColumnKey(c.data)), [cols]);\n // A formula cell reads OTHER columns of its row, but `setCellValue` bumps only\n // the edited cell's revision \u2014 so editing an input left the calculated column\n // showing a stale number until something else forced a repaint. Repainting the\n // row is the fix; widening `setCellValue` would make every write pay for a\n // feature almost no view uses. The evaluator's cache is already correct under\n // in-place mutation, so this is purely a repaint trigger.\n const handleCellSave = useCallback(\n (row: number, col: number, newValue: any, clearEditing: boolean = true) => {\n handleCellSaveBase(row, col, newValue, clearEditing);\n if (hasFormulaColumns) store.bumpRowRevisions(row, cols.length);\n },\n [handleCellSaveBase, hasFormulaColumns, store, cols.length],\n );\n const { handleAddRow, handleSaveNewRow, handleCancelNewRow } = useMemo(\n () => createRowHandlers(store, cols, tableRef),\n [store, cols, tableRef],\n );\n const dragHandlers = useMemo(\n () => createDragHandlers(store, cols, dragStateRef),\n [store, cols],\n );\n const { handleMouseDown, handleMouseMove, handleMouseUp, handleDoubleClick } = useMemo(\n () => createMouseHandlers(store, cols, dragStateRef, dragHandlers),\n [store, cols, dragHandlers],\n );\n\n // Perspective handlers. Created BEFORE the column-header handlers because the\n // header's sort click writes through `handleSortRulesChange` \u2014 sort has exactly\n // one owner (see the `sortState` projection above).\n const {\n handleColumnVisibilityChange,\n handleColumnOrderChange,\n handleFiltersChange,\n handleSortRulesChange,\n handleGroupRulesChange,\n handleAggregationsChange,\n handleLookupColumnsChange,\n handleRollupColumnsChange,\n handleFormulasChange,\n handleConditionalFormatsChange,\n handleDateFormatChange,\n handleSavePerspective,\n handlePerspectiveSelect,\n handlePerspectiveRename,\n handlePerspectiveDelete,\n handlePerspectiveDuplicate,\n handlePerspectiveSetDefault,\n handlePerspectivePublish,\n handlePerspectiveTemplateCopy,\n } = useMemo(\n () =>\n createPerspectiveHandlers({\n tableRef,\n columns: baseColumns,\n savedPerspectives,\n activePerspectiveId,\n setVisibleColumns,\n setHiddenColumns,\n setFilters,\n setSortRules,\n setGroupRules,\n setAggregations,\n setLookupColumns,\n setRollupColumns,\n setFormulas,\n setConditionalFormats,\n setFrozenColumns,\n setDateFormat,\n setInternalActivePerspectiveId,\n defaultHiddenColumns: initialHiddenColumns,\n defaultGrouping,\n }),\n // The `set*` functions are React state setters (stable by contract) plus\n // `setInternalActivePerspectiveId`; only the three data inputs can change.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tableRef, baseColumns, savedPerspectives, activePerspectiveId, initialHiddenColumns, defaultGrouping],\n );\n\n /**\n * \"Reset to defaults\" on the base tab.\n *\n * EMPTIES this user's base-view row rather than deleting it. The upstream\n * `perspectives` table soft-deletes (sets `deleted_at`) while its unique index\n * on `(user_id, tenant_id, organization_id, table_id, name)` ignores that\n * column \u2014 so a deleted row keeps owning the reserved `__base__` name and the\n * NEXT save would fail with a duplicate-key 500, permanently. Verified live\n * before this was written, not assumed.\n *\n * An empty `columnOrder` is exactly \"no column personalization\": both\n * `apiToDynamicTable` and `resolvePerspectiveState` already fall back to the\n * table's own defaults for it, so the row also does not freeze the user at\n * today's column set the way an explicit list would.\n */\n const handleBaseViewReset = useCallback(() => {\n if (!baseViewPerspective) return;\n handleSavePerspective({\n id: baseViewPerspective.id,\n name: BASE_VIEW_PERSPECTIVE_NAME,\n isBaseView: true,\n columns: { visible: [], hidden: [] },\n filters: [],\n sorting: [],\n grouping: [],\n aggregations: [],\n lookupColumns: [],\n rollupColumns: [],\n formulas: [],\n conditionalFormats: [],\n dateFormat: undefined,\n });\n // Repaint the coded defaults immediately; the row we just wrote resolves to\n // the same thing once the host refetches.\n const next = resolvePerspectiveState({\n baseColumns,\n perspective: null,\n defaultHiddenColumns: initialHiddenColumns,\n defaultGrouping,\n });\n setVisibleColumns(next.visibleColumns);\n setHiddenColumns(next.hiddenColumns);\n setFilters(next.filters);\n setSortRules(next.sortRules);\n setGroupRules(next.groupRules);\n setAggregations(next.aggregations);\n setLookupColumns(next.lookupColumns);\n setRollupColumns(next.rollupColumns);\n setFormulas(next.formulas);\n setConditionalFormats(next.conditionalFormats);\n setFrozenColumns(new Set(next.frozenColumns));\n setDateFormat(next.dateFormat);\n }, [baseViewPerspective, handleSavePerspective, baseColumns, initialHiddenColumns, defaultGrouping]);\n\n // Header click / column menu / Configure View drawer all land here.\n const handleSortDirectionChange = useCallback(\n (colIndex: number, direction: 'asc' | 'desc' | null) => {\n const col = cols[colIndex];\n if (!col) return;\n handleSortRulesChange(\n direction === null\n ? []\n : [{ id: generateSortRuleId(), field: col.data, direction }],\n );\n },\n [cols, handleSortRulesChange],\n );\n\n const { handleColumnSort, handleColumnHeaderDoubleClick, handleColumnHeaderMouseDown } = useMemo(\n () =>\n createColumnHeaderHandlers(\n store,\n cols,\n tableRef,\n sortState,\n handleSortDirectionChange,\n setContextMenu,\n columnActions,\n ),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [store, cols, tableRef, sortState, handleSortDirectionChange, columnActions],\n );\n // `handleRowHeaderDoubleClick` is a `VirtualRow` prop \u2014 memoised for the same\n // reason as the cell handlers. NOTE: `rowActions` is consumer-supplied; a\n // consumer that passes an inline arrow re-creates this every render, and also\n // hands `VirtualRow` a fresh `rowActions` prop directly, so the memo is\n // defeated from the outside. That is a consumer-side fix, not a grid one.\n const { handleRowHeaderDoubleClick } = useMemo(\n () => createRowHeaderHandlers(store, tableRef, setContextMenu, rowActions),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [store, tableRef, rowActions],\n );\n const { handleContextMenuAction, handleContextMenuClose } = useMemo(\n () =>\n createContextMenuHandlers(store, cols, tableRef, contextMenu, setContextMenu, onRowAction),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [store, cols, tableRef, contextMenu, onRowAction],\n );\n\n // v2 Actions column: the kebab (\u2022\u2022\u2022) button opens the same row menu the\n // right-click context menu uses, anchored below the button.\n const handleRowActionsMenu = useCallback((e: React.MouseEvent, rowIndex: number) => {\n if (!rowActions) return;\n const rowData = store.getRowData(rowIndex);\n const actions = rowActions(rowData, rowIndex);\n if (!actions.length) return;\n e.preventDefault();\n e.stopPropagation();\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n setContextMenu({ isOpen: true, position: { x: rect.right, y: rect.bottom + 4 }, actions, type: 'row', index: rowIndex });\n }, [rowActions, store]);\n // Latest-callback ref so the resize handlers (created here) can persist widths\n // via the persistence hook, which is set up later in the body (it needs the\n // ordered `cols` and must register its apply-effect after store.setColumns).\n const persistColumnWidthRef = useRef<(colIndex: number) => void>(() => {});\n const { handleResizeStart } = useMemo(\n () => createResizeHandlers(store, (colIndex) => persistColumnWidthRef.current(colIndex)),\n [store],\n );\n // Columns the user has manually resized \u2014 excluded from badge auto-fit so we\n // never fight a deliberate width.\n const userResizedColsRef = useRef<Set<number>>(new Set());\n // Badge auto-fit cache: stable `col.data` key \u2192 fitted width. Model-held, so\n // it answers for unmounted columns and survives a perspective reorder.\n const badgeFitRef = useRef<Map<string, number>>(new Map());\n\n // -------------------- FILL THE CONTAINER --------------------\n // The sum of the DECLARED widths \u2014 what the fill measures against. Re-running\n // the fill when it moves is what makes a hand resize, a badge auto-fit or a\n // restored saved width redistribute whatever is left over.\n const declaredTotalWidth = useMemo(\n () => cols.reduce((sum, _, idx) => sum + store.getBaseColumnWidth(idx), 0) + furnitureWidth,\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [cols, store, furnitureWidth, storeRevision],\n );\n\n /**\n * Fill the container when the declared widths do not (see\n * `utils/columnFill.ts` for the arithmetic and, more importantly, for why it\n * IS arithmetic rather than `width: 100%`).\n *\n * The surplus is written into the store as resolved PIXELS, so every column\n * keeps an honest declared width \u2014 which is precisely what lets column\n * virtualization stay ON while the grid fills the width. Those two used to be\n * mutually exclusive.\n *\n * No feedback loop, by construction: the target is the scroller's own\n * `clientWidth`, so a filled row can never widen the scroller, and\n * `setColumnStretch` notifies nobody when the distribution did not move.\n */\n const applyColumnFill = useCallback(() => {\n const el = tableRef.current;\n if (!el) return;\n const rigid = new Set<number>();\n cols.forEach((col, idx) => {\n // Pinned / frozen columns keep their exact width (sticky offsets depend\n // on it), and so does any column the user sized by hand.\n if (col.sticky || frozenColumns.has(col.data) || userResizedColsRef.current.has(idx)) {\n rigid.add(idx);\n }\n });\n store.setColumnStretch(\n computeColumnFill({\n widths: cols.map((_, idx) => store.getBaseColumnWidth(idx)),\n rigid,\n furnitureWidth,\n containerWidth: el.clientWidth,\n }),\n );\n }, [cols, store, frozenColumns, furnitureWidth, tableRef]);\n\n useLayoutEffect(() => {\n applyColumnFill();\n const el = tableRef.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n // Re-run on container resize: a browser-window resize, the split view\n // opening, a sidebar collapsing \u2014 all of them change what \"full width\" is.\n const ro = new ResizeObserver(() => applyColumnFill());\n ro.observe(el);\n return () => ro.disconnect();\n // `isFullscreen` re-parents the scroller, so the observer must move with it.\n }, [applyColumnFill, declaredTotalWidth, isFullscreen, tableRef]);\n\n // -------------------- MODERN LAYOUT COLUMN MENU HANDLERS --------------------\n const handleModernSortAsc = useCallback(\n (colIndex: number) => handleSortDirectionChange(colIndex, 'asc'),\n [handleSortDirectionChange],\n );\n\n const handleModernSortDesc = useCallback(\n (colIndex: number) => handleSortDirectionChange(colIndex, 'desc'),\n [handleSortDirectionChange],\n );\n\n const handleModernFilterByField = useCallback((colIndex: number) => {\n const col = cols[colIndex];\n if (!col) return;\n // Add a new empty filter row for this field\n const newFilter: FilterRow = {\n id: `filter-${Date.now()}`,\n field: col.data,\n operator: 'contains',\n values: [],\n };\n handleFiltersChange([...filters, newFilter]);\n // Open the configure view panel with filters section expanded. It inherits\n // the CURRENT context: opened from the base tab, saving keeps the user's\n // Default view rather than insisting on a name for it.\n setEditingPerspectiveId(null);\n setConfigureBaseView(!activePerspectiveId || activePerspectiveId === baseViewPerspective?.id);\n setConfigPanelInitialSection('filters');\n setConfigPanelOpen(true);\n }, [cols, filters, handleFiltersChange, activePerspectiveId, baseViewPerspective]);\n\n /**\n * A16 / ledger 7.11 / HEDGE-7 \u2014 write a COLUMN LAYOUT change THROUGH to this\n * user's view.\n *\n * Two entry points land here, and they are the two that change the layout\n * from OUTSIDE the Configure View drawer: a header drag (or its \"Move\n * left/right\" menu twin) and the column menu's \"Hide field\". Both used to\n * move `visibleColumns`/`hiddenColumns` only, which is in-memory state, so the\n * change was gone on the next reload and the only way to keep it was to\n * reopen the drawer and press Save. Column layout is per-user personalization\n * (decision of 2026-08-03) and each of these IS the user's explicit act \u2014\n * nothing else should be needed to keep it.\n *\n * The drawer deliberately does NOT come through here: it owns a Save/Cancel\n * pair whose Cancel reverts the live preview, so writing on every toggle\n * would break the contract the panel documents at its snapshot ref.\n *\n * The payload is built from the SAVED row, not from live table state, with\n * only `columns` replaced. That is the whole point: ad-hoc quick filters stay\n * ephemeral (A2/D6), so persisting the grid's current `filters`/`sortRules`\n * here would quietly promote a throwaway funnel tick into the saved view just\n * because the user nudged a column afterwards.\n *\n * With no saved row yet we are necessarily on the base (\"Default view\") tab \u2014\n * every named view has a row by construction \u2014 so we mint the base row the\n * same way `handleBaseViewReset` and the drawer's base-view Save do, carrying\n * ONLY the column layout.\n *\n * WHOSE VIEW THIS TOUCHES (the HEDGE-5 worry, answered): a `perspectives` row\n * is keyed by `(user_id, tenant_id, organization_id, table_id, name)` and the\n * base row is no exception \u2014 the reserved `__base__` name is per user. So the\n * shared-looking \"Default view\" tab is in fact this user's own personalization\n * of it, and an autosave here cannot change what anyone else sees. The only\n * role-scoped rows are `role_perspectives`, written solely by the explicit\n * Publish action.\n */\n const persistColumnLayout = useCallback((visible: string[], hidden: string[]) => {\n // Only when a host actually owns perspectives. `controlledActiveId` is\n // `undefined` exactly when nobody passed `activePerspectiveId` \u2014 an\n // uncontrolled grid (a drawer sub-table, a Storybook story) has nowhere to\n // save to, and should not mint a base-view row on the first drag.\n if (controlledActiveId === undefined) return;\n const target = activePerspectiveId\n ? savedPerspectives.find(p => p.id === activePerspectiveId) ?? null\n : baseViewPerspective;\n if (target) {\n handleSavePerspective({ ...target, columns: { visible, hidden } }, true);\n return;\n }\n if (activePerspectiveId) return; // a named view whose row hasn't loaded \u2014 don't invent one\n handleSavePerspective(\n {\n id: generatePerspectiveId(),\n name: BASE_VIEW_PERSPECTIVE_NAME,\n isBaseView: true,\n columns: { visible, hidden },\n // FROM THE LIVE STATE \u2014 same rule as the view-mode switch below. A\n // column drag records a column order and a \"Hide field\" records a\n // column set; neither is a statement that the user wanted their\n // filters, sorting and grouping thrown away, and writing empty literals\n // here made it exactly that.\n filters,\n sorting: sortRules,\n grouping: groupRules,\n aggregations,\n lookupColumns,\n rollupColumns,\n formulas,\n conditionalFormats,\n dateFormat,\n viewMode,\n },\n true,\n );\n }, [activePerspectiveId, controlledActiveId, savedPerspectives, baseViewPerspective, handleSavePerspective,\n filters, sortRules, groupRules, aggregations, lookupColumns, rollupColumns, formulas,\n conditionalFormats, dateFormat, viewMode]);\n\n /**\n * HEDGE-102 \u2014 write a FREEZE change through to this user's view.\n *\n * Deliberately a sibling of `persistColumnLayout` above rather than a shared\n * generic: the two agree on how to find the target row, and differ on the one\n * thing that matters \u2014 which key the freshly minted base row carries. Folding\n * them together would mean a `Partial<PerspectiveConfig>` threaded through a\n * mint block whose whole point is being explicit about what it writes, and\n * that block already carries a comment about what writing empty literals here\n * cost last time.\n *\n * Whose view this touches is the same answer as above and it was checked\n * against the schema, not assumed: `perspectives` is unique on\n * `(user_id, tenant_id, organization_id, table_id, name)` with `user_id NOT\n * NULL`, so the shared-looking \"Default view\" is this user's own row.\n * `role_perspectives` is the only role-scoped surface and only Publish writes\n * it \u2014 one user pinning a column cannot move anyone else's grid.\n */\n const persistFrozenColumns = useCallback((next: Set<string>) => {\n if (controlledActiveId === undefined) return;\n const frozen = [...next];\n const target = activePerspectiveId\n ? savedPerspectives.find(p => p.id === activePerspectiveId) ?? null\n : baseViewPerspective;\n if (target) {\n handleSavePerspective({ ...target, frozenColumns: frozen }, true);\n return;\n }\n if (activePerspectiveId) return; // a named view whose row hasn't loaded \u2014 don't invent one\n handleSavePerspective(\n {\n id: generatePerspectiveId(),\n name: BASE_VIEW_PERSPECTIVE_NAME,\n isBaseView: true,\n columns: { visible: visibleColumns, hidden: hiddenColumns },\n frozenColumns: frozen,\n // Same rule as the column-layout mint: pinning a column is not a\n // statement that the user wanted their filters and sorting discarded.\n filters,\n sorting: sortRules,\n grouping: groupRules,\n aggregations,\n lookupColumns,\n rollupColumns,\n formulas,\n conditionalFormats,\n dateFormat,\n viewMode,\n },\n true,\n );\n }, [activePerspectiveId, controlledActiveId, savedPerspectives, baseViewPerspective,\n handleSavePerspective, visibleColumns, hiddenColumns, filters, sortRules, groupRules,\n aggregations, lookupColumns, rollupColumns, formulas, conditionalFormats, dateFormat,\n viewMode]);\n\n /**\n * Pin or unpin a column. The user's explicit act, so it saves itself \u2014 the\n * same contract the header drag and \"Hide field\" got in HEDGE-7.\n */\n const handleModernFreezeToggle = useCallback((colIndex: number) => {\n const col = cols[colIndex];\n if (!col) return;\n // `next` is computed OUTSIDE the state updater and the handler depends on\n // `frozenColumns`, so the closure is always the committed value. Persisting\n // from inside the updater would have been tidier to read and wrong: React\n // may invoke an updater twice (StrictMode does in development), and a save\n // is not a pure function of the previous state.\n const next = new Set(frozenColumns);\n if (next.has(col.data)) {\n next.delete(col.data);\n } else {\n next.add(col.data);\n }\n setFrozenColumns(next);\n persistFrozenColumns(next);\n }, [cols, frozenColumns, persistFrozenColumns]);\n\n /**\n * A16 \u2014 commit a header drag (or a \"Move left/right\" menu click).\n *\n * Both indices address `cols` \u2014 the VIEW order. The write happens on\n * `visibleColumns`, the persisted key array, and is done by KEY, not by\n * position: `visibleColumns` may legitimately carry keys that `baseColumns`\n * has not produced a column for yet (a linked or calculated column added by\n * the perspective), and those must survive a reorder untouched.\n *\n * Column order is PER-USER: it lands in the active view's `columns.visible`,\n * which the perspectives API stores against this user's row.\n */\n const handleColumnReorder = useCallback((fromIndex: number, toIndex: number) => {\n const fromCol = cols[fromIndex];\n const toCol = cols[toIndex];\n if (!fromCol || !toCol || fromIndex === toIndex) return;\n const fromKey = fromCol.data;\n const toKey = toCol.data;\n const fi = visibleColumns.indexOf(fromKey);\n const ti = visibleColumns.indexOf(toKey);\n if (fi < 0 || ti < 0 || fi === ti) return;\n const next = visibleColumns.slice();\n next.splice(fi, 1);\n next.splice(ti, 0, fromKey);\n // Goes through the same writer the Configure View drawer uses, so the host\n // gets its PERSPECTIVE_CHANGE and the two entry points cannot drift.\n handleColumnVisibilityChange(next, hiddenColumns);\n persistColumnLayout(next, hiddenColumns);\n }, [cols, visibleColumns, hiddenColumns, handleColumnVisibilityChange, persistColumnLayout]);\n\n /**\n * HEDGE-7 \u2014 \"Hide field\" in the column menu, written THROUGH to this user's\n * view.\n *\n * This is the reported defect, and it is a MISSING CALL, not a missing\n * mechanism: hiding a column moved `visibleColumns`/`hiddenColumns` and\n * stopped there, so nothing ever reached the server and a reload brought the\n * column straight back. The user got no undo prompt, no dirty marker and no\n * Save button, so the change looked done \u2014 which is exactly how the reporter\n * described it (\"it went back to the earlier settings\", not \"I didn't save\").\n *\n * It now takes the same route a \"Move left\" already takes: `persistColumnLayout`,\n * silent, into this user's own perspective row. One writer, three callers.\n *\n * The mirror action \u2014 putting the column back \u2014 lives in the Configure View\n * drawer's \"Hide fields\" section and persists on that drawer's Save. It is not\n * routed through here on purpose; see the note on `persistColumnLayout`.\n */\n const handleModernHideField = useCallback((colIndex: number) => {\n const col = cols[colIndex];\n if (!col) return;\n // Idempotent: a double-fire must not push the same key into `hiddenColumns`\n // twice, which would survive the round trip and show up as a duplicate row\n // in the drawer's field list.\n if (!visibleColumns.includes(col.data)) return;\n const newVisible = visibleColumns.filter(k => k !== col.data);\n const newHidden = hiddenColumns.includes(col.data) ? hiddenColumns : [...hiddenColumns, col.data];\n handleColumnVisibilityChange(newVisible, newHidden);\n persistColumnLayout(newVisible, newHidden);\n }, [cols, visibleColumns, hiddenColumns, handleColumnVisibilityChange, persistColumnLayout]);\n\n /**\n * The view switcher \u2014 write the chosen mode THROUGH to this user's view.\n *\n * Deliberately the same mechanism as `persistColumnLayout`, and for the same\n * reason: clicking the switcher IS the user's explicit act, and a mode that\n * is gone on the next reload is not a property of the view, it is a mood.\n *\n * The payload is built from the SAVED row with only `viewMode` replaced \u2014\n * never from live table state \u2014 so switching to the grid cannot quietly\n * promote an ad-hoc quick filter into the saved view. Same trap the column\n * drag documents above; same answer.\n *\n * `silent` because one toast per switch is noise, not feedback. A FAILED\n * write is still reported.\n *\n * With no saved row we are on the base (\"Default view\") tab by construction,\n * so the base row is minted carrying only the mode. With no perspectives at\n * all (an uncontrolled grid \u2014 a drawer sub-table, a story) the mode is still\n * applied, just not persisted: there is nowhere to persist it to, and\n * refusing to switch would be worse than forgetting.\n */\n const handleViewModeChange = useCallback((mode: TableViewMode) => {\n setViewMode(mode);\n onViewModeChange?.(mode);\n if (controlledActiveId === undefined) return;\n const target = activePerspectiveId\n ? savedPerspectives.find(p => p.id === activePerspectiveId) ?? null\n : baseViewPerspective;\n if (target) {\n handleSavePerspective({ ...target, viewMode: mode }, true);\n return;\n }\n if (activePerspectiveId) return; // a named view whose row hasn't loaded \u2014 don't invent one\n /**\n * Mint the base row FROM THE LIVE STATE, not from empty literals.\n *\n * This used to write `filters: []`, `sorting: []`, `grouping: []` and a bare\n * `dateFormat: undefined` alongside the real column lists \u2014 so flipping\n * list\u2194grid persisted an \"everything cleared\" view over whatever the user\n * had on screen, and the next perspective read applied it back. Filters and\n * sorting survived the round trip only because the host owns those; the\n * GROUPING did not, and a table that opens grouped lost its sections the\n * first time anyone touched the view switcher.\n *\n * Measured on the documents list: grouped by case in the table, one click\n * to Grid, and `groupRules` came back `[]`.\n *\n * The switcher's job is to record the MODE. Everything else about the view\n * belongs to the view and travels unchanged.\n */\n handleSavePerspective(\n {\n id: generatePerspectiveId(),\n name: BASE_VIEW_PERSPECTIVE_NAME,\n isBaseView: true,\n columns: { visible: visibleColumns, hidden: hiddenColumns },\n filters,\n sorting: sortRules,\n grouping: groupRules,\n aggregations,\n lookupColumns,\n rollupColumns,\n formulas,\n conditionalFormats,\n dateFormat,\n viewMode: mode,\n },\n true,\n );\n }, [\n controlledActiveId,\n activePerspectiveId,\n savedPerspectives,\n baseViewPerspective,\n handleSavePerspective,\n visibleColumns,\n hiddenColumns,\n filters,\n sortRules,\n groupRules,\n aggregations,\n lookupColumns,\n rollupColumns,\n formulas,\n conditionalFormats,\n dateFormat,\n ]);\n\n /** Keyboard/menu equivalent of the drag: one step left or right. */\n const handleColumnMove = useCallback((colIndex: number, direction: -1 | 1) => {\n const target = colIndex + direction;\n if (target < 0 || target >= cols.length) return;\n handleColumnReorder(colIndex, target);\n }, [cols.length, handleColumnReorder]);\n\n const handleModernColumnAction = useCallback((actionId: string, colIndex: number) => {\n if (!tableRef?.current) return;\n dispatch(tableRef.current, TableEvents.COLUMN_CONTEXT_MENU_ACTION, {\n columnIndex: colIndex,\n columnName: cols[colIndex]?.data,\n actionId,\n });\n }, [cols, tableRef]);\n\n // Apply frozen columns as sticky-left by computing adjusted offsets\n const effectiveLeftOffsets = useMemo(() => {\n if (frozenColumns.size === 0) return leftOffsets;\n const offsets = [...leftOffsets];\n let cumulativeOffset = rowHeaders ? ROW_HEADER_WIDTH : 0;\n // Check existing sticky-left columns first\n for (let i = 0; i < cols.length; i++) {\n if (cols[i].sticky === 'left') {\n cumulativeOffset = (offsets[i] ?? 0) + store.getColumnWidth(i);\n }\n }\n // Apply frozen columns\n for (let i = 0; i < cols.length; i++) {\n if (frozenColumns.has(cols[i].data) && cols[i].sticky !== 'left') {\n offsets[i] = cumulativeOffset;\n cumulativeOffset += store.getColumnWidth(i);\n }\n }\n return offsets;\n }, [frozenColumns, leftOffsets, cols, store, rowHeaders, storeRevision]);\n\n // Data key of the RIGHTMOST pinned (sticky-left or frozen) column \u2014 its right\n // edge is the boundary the scrolling body slides under, so it carries the\n // float shadow. Derived from the resolved offsets so it covers both natively\n // sticky-left columns and menu-frozen ones.\n const lastFrozenColumnKey = useMemo(() => {\n let key: string | null = null;\n for (let i = 0; i < cols.length; i++) {\n if (effectiveLeftOffsets[i] !== undefined) key = cols[i].data;\n }\n return key;\n }, [effectiveLeftOffsets, cols]);\n\n // -------------------- COLUMN VIRTUALIZATION --------------------\n // Opt-in (`uiConfig.enableColumnVirtualization`), default OFF. When off, the\n // hook returns a FULL window \u2014 every column mounted, no spacers \u2014 which is\n // byte-identical to the render this grid has always produced.\n //\n // Pinned columns derive from the SAME two sources as `effectiveLeftOffsets`\n // (`ColumnDef.sticky` + the runtime `frozenColumns` key set), because\n // `position: sticky` needs an element that exists: anything pinned is mounted\n // unconditionally.\n const pinnedColumnIndices = useMemo(\n () => getPinnedColumnIndices(cols, frozenColumns),\n [cols, frozenColumns],\n );\n\n // The caret and the editor must never land on an unmounted column. Held in\n // STATE rather than read during render so that an arrow key which stays\n // inside the same column costs no DynamicTable render at all \u2014 this component\n // deliberately does not subscribe to the selection.\n const [forcedColumnIndices, setForcedColumnIndices] = useState<number[]>([]);\n\n const getColumnKeyByIndex = useCallback(\n (colIndex: number) => cols[colIndex]?.data ?? colIndex,\n [cols],\n );\n\n const columnVirtualizer = useColumnVirtualizer({\n enabled: enableColumnVirtualization,\n columnCount: cols.length,\n getColumnWidth,\n getScrollElement: () => tableRef.current,\n pinnedLeftIndices: pinnedColumnIndices.left,\n pinnedRightIndices: pinnedColumnIndices.right,\n forcedIndices: forcedColumnIndices,\n overscan: columnOverscan,\n // ROW_HEADER_WIDTH (32), NOT the 50 that `totalWidth` uses for the same\n // gutter \u2014 the two disagree today (a pre-existing bug). The 18px difference\n // moves only the scroll-range arithmetic, well inside one overscan column,\n // and never touches a spacer width. Do NOT \"fix\" it by swapping `totalWidth`\n // for the virtualizer's: that visibly narrows every table by 18px.\n leadingWidth: rowHeaders ? ROW_HEADER_WIDTH : 0,\n trailingWidth: showActionsColumn ? actionsColumnWidth : 0,\n widthRevision: storeRevision,\n getColumnKey: getColumnKeyByIndex,\n hasRowHeader: rowHeaders,\n hasActionsColumn: showActionsColumn,\n });\n\n const columnVirtualizerRef = useRef(columnVirtualizer);\n columnVirtualizerRef.current = columnVirtualizer;\n\n // Range-operation contract rule 9: MOVING THE SELECTION TO A COLUMN IMPLIES\n // SCROLLING IT INTO VIEW \u2014 in the same commit, before any focus attempt.\n //\n // Subscribing to the store rather than patching each `setSelection` /\n // `setEditingCell` call site covers every path there is (keyboard, Tab,\n // double-click, add-row, context menu, a consumer calling the store directly)\n // and cannot be missed by a future one. The callback runs SYNCHRONOUSLY inside\n // the store notification, so `scrollLeft` is written before React re-renders\n // and long before `Cell`'s `setTimeout(0)` focus effect runs.\n //\n // `setEditingCell` has its own channel: it bumps only the two affected cells'\n // revisions, so a selection subscriber cannot see the editor move.\n useEffect(() => {\n if (!enableColumnVirtualization) return;\n let lastKey = '';\n const sync = () => {\n const sel = store.getSelection();\n const editing = store.getEditingCell();\n const next: number[] = [];\n if (sel.anchor) next.push(sel.anchor.col);\n if (sel.focus) next.push(sel.focus.col);\n if (editing) next.push(editing.col);\n const unique = Array.from(new Set(next)).sort((a, b) => a - b);\n const key = unique.join(',');\n if (key !== lastKey) {\n lastKey = key;\n setForcedColumnIndices(unique);\n }\n // No-op when the target is pinned or already visible.\n const target = editing?.col ?? sel.focus?.col ?? sel.anchor?.col;\n if (target != null) columnVirtualizerRef.current.scrollToColumn(target);\n };\n sync();\n const offSelection = store.subscribeToSelection(sync);\n const offEditing = store.subscribeToEditing(sync);\n return () => {\n offSelection();\n offEditing();\n };\n }, [store, enableColumnVirtualization]);\n\n /**\n * The VERTICAL companion to the column scroll above: moving the selection to\n * a row implies scrolling that row into view.\n *\n * `Ctrl/Cmd+Shift+ArrowDown` extends to the far edge of the data block, which\n * on a 50-row page is always outside the ~29 mounted rows. Without this the\n * extension is correct in the model and invisible on screen \u2014 and a keyboard\n * gesture whose result you cannot see is worse than one that does nothing.\n *\n * Bails out for a row that is already MOUNTED rather than relying on\n * `align: 'auto'`: the virtualizer issues a `scrollTo` either way, and an\n * unconditional scroll on every click would fight the column scroll-into-view\n * above and make a drag-select jitter.\n */\n useEffect(() => {\n let lastRow = -1;\n const sync = () => {\n const editing = store.getEditingCell();\n const sel = store.getSelection();\n const target = editing?.row ?? sel.focus?.row ?? sel.anchor?.row;\n if (target == null || target < 0 || target >= store.getRowCount()) return;\n if (target === lastRow) return;\n lastRow = target;\n // Already painted \u2192 nothing to do. A drag-select's focus can only ever be\n // a mounted cell, so this is also what keeps a drag from auto-scrolling.\n const mounted = rowVirtualizer.getVirtualItems();\n if (mounted.length === 0) return;\n if (target >= mounted[0].index && target <= mounted[mounted.length - 1].index) return;\n rowVirtualizer.scrollToIndex(target, { align: 'auto' });\n };\n const offSelection = store.subscribeToSelection(sync);\n const offEditing = store.subscribeToEditing(sync);\n return () => {\n offSelection();\n offEditing();\n };\n }, [store, rowVirtualizer]);\n\n const keyboardHandler = useKeyboardNavigation(store, cols.length, cols, autoEditOnTab, handleCellSave, siblingTableRefs);\n const shortcutHandler = useRowActionShortcuts(store, keyboardShortcuts, onRowAction);\n\n // Row click handler using event delegation\n const handleTableClick = useCallback((e: React.MouseEvent) => {\n if (!onRowClick) return;\n\n const target = e.target as HTMLElement;\n\n // Skip group header rows\n if (target.closest('tr[data-group-header]')) return;\n\n // Don't trigger row click if clicking on action buttons, inputs, etc.\n if (target.closest('button, input, select, textarea, a, [data-no-row-click]')) return;\n\n // Find the row element\n const row = target.closest('tr[data-row]');\n if (!row) return;\n\n const rowIndex = parseInt(row.getAttribute('data-row') || '', 10);\n if (isNaN(rowIndex)) return;\n\n const rowData = store.getRowData(rowIndex);\n if (rowData) {\n onRowClick(rowIndex, rowData, e);\n }\n }, [store, onRowClick]);\n\n /**\n * Every cell of a selection, as annotation TARGETS.\n *\n * Iterates the bounds arithmetically \u2014 a cell whose column is outside the\n * virtualization window is still part of the range. De-duplicated on\n * `entityType:rowId:columnKey`, which is also the annotations table's unique\n * key: a range covering both legs of one container resolves the container's\n * columns to the SAME target twice, and the batch endpoint rejects the\n * duplicate. That de-duplication is now correct rather than accidental \u2014\n * before B8a it collapsed two genuinely different legs into one cell.\n */\n const collectBulkCells = useCallback(\n (bounds: { startRow: number; endRow: number; startCol: number; endCol: number }) => {\n const cells: { entityType: string; rowId: string; columnKey: string }[] = [];\n const seen = new Set<string>();\n for (let r = bounds.startRow; r <= bounds.endRow; r++) {\n const rData = store.getRowData(r);\n if (!rData) continue;\n for (let c = bounds.startCol; c <= bounds.endCol; c++) {\n const cConfig = cols[c];\n if (!cConfig) continue;\n const target = resolveCommentTarget(rData, cConfig);\n if (!target.entityType || !target.rowId) continue;\n const key = annotationKey(target, cConfig.data);\n if (seen.has(key)) continue;\n seen.add(key);\n cells.push({ entityType: target.entityType, rowId: target.rowId, columnKey: cConfig.data });\n }\n }\n return cells;\n },\n [store, cols, resolveCommentTarget],\n );\n\n // Resolve a comment-indicator (or any element inside a cell) to its cell\n // coordinates + the annotation backing it. Used by the hover preview and the\n // click-to-open-dialog paths.\n const resolveCommentCell = useCallback((el: Element) => {\n const cell = el.closest('td[data-row][data-col]') as HTMLElement | null;\n if (!cell) return null;\n const rowIndex = parseInt(cell.getAttribute('data-row') || '', 10);\n const colIndex = parseInt(cell.getAttribute('data-col') || '', 10);\n if (Number.isNaN(rowIndex) || Number.isNaN(colIndex)) return null;\n const rowData = store.getRowData(rowIndex);\n const col = cols[colIndex];\n if (!rowData || !col) return null;\n // B8a \u2014 the target comes from the CELL. `rowId` is the target's id, which\n // on a leg-scoped column is the leg and on a container-scoped column the\n // container, NOT the row's id column.\n const target = resolveCommentTarget(rowData, col);\n if (!target.rowId || !target.entityType) return null;\n return {\n rowIndex,\n colIndex,\n rowData,\n col,\n entityType: target.entityType,\n rowId: target.rowId,\n annotation: annotations.get(annotationKey(target, col.data)),\n cell,\n };\n }, [store, cols, resolveCommentTarget, annotations]);\n\n // Track the cell under the pointer so it can offer the comment affordance\n // (ledger 8.1 \u2014 hover used to paint a selection box and nothing else).\n //\n // Written to the STORE, never to React state: `setHoveredCell` repaints the\n // cell left and the cell entered and nothing else, while a `useState` here\n // would re-render every mounted row on every pointer move. Piggy-backs on the\n // container's existing delegated mouseover, so no new listener is added.\n const handleCellHoverOver = useCallback((e: React.MouseEvent) => {\n if (!enableComments || !commentsEntityType) return;\n const td = (e.target as HTMLElement).closest?.('td.hot-cell[data-row][data-col]') as HTMLElement | null;\n if (!td || td.hasAttribute('data-actions-cell')) { store.setHoveredCell(null); return; }\n const row = Number(td.getAttribute('data-row'));\n const col = Number(td.getAttribute('data-col'));\n if (Number.isNaN(row) || Number.isNaN(col)) { store.setHoveredCell(null); return; }\n store.setHoveredCell({ row, col });\n }, [enableComments, commentsEntityType, store]);\n\n // Hover the comment indicator \u2192 show a read-only preview of its thread.\n const handleCommentHoverOver = useCallback((e: React.MouseEvent) => {\n if (!enableComments || !commentsEntityType) return;\n const indicator = (e.target as HTMLElement).closest?.('.cell-comment-indicator');\n if (!indicator) return;\n const info = resolveCommentCell(indicator);\n if (!info?.annotation || info.annotation.comments.length === 0) return;\n setCommentHover({\n comments: info.annotation.comments,\n columnTitle: info.col.title || info.col.data,\n anchorRect: indicator.getBoundingClientRect(),\n });\n }, [enableComments, commentsEntityType, resolveCommentCell]);\n\n const handleCommentHoverOut = useCallback((e: React.MouseEvent) => {\n const indicator = (e.target as HTMLElement).closest?.('.cell-comment-indicator');\n if (!indicator) return;\n // mouseout bubbles from the icon's children \u2014 only close when truly leaving.\n const related = e.relatedTarget as Node | null;\n if (related && indicator.contains(related)) return;\n setCommentHover(null);\n }, []);\n\n // Open comment dialog on Shift+Click (or a direct click on the comment icon)\n // when comments are enabled.\n // Called from onMouseDown so it runs BEFORE handleMouseDown resets the selection.\n // Returns true if it handled the event (caller should skip normal mousedown).\n const handleCommentMouseDown = useCallback((e: React.MouseEvent): boolean => {\n if (!enableComments || !commentsEntityType) return false;\n // Direct click on the comment indicator opens the full thread dialog \u2014 no\n // modifier required (the icon is the affordance).\n const indicator = (e.target as HTMLElement).closest?.('.cell-comment-indicator');\n if (indicator) {\n const info = resolveCommentCell(indicator);\n if (info) {\n e.preventDefault();\n e.stopPropagation();\n setCommentHover(null);\n setCommentDialog({\n entityType: info.entityType,\n rowId: info.rowId,\n columnKey: info.col.data,\n columnTitle: info.col.title || info.col.data,\n rowLabel: info.rowData.name || info.rowData.title || undefined,\n annotationId: info.annotation?.id || null,\n currentColor: info.annotation?.color || null,\n anchorRect: (info.cell as HTMLElement).getBoundingClientRect(),\n });\n return true;\n }\n }\n if (!e.shiftKey) return false;\n\n const target = e.target as HTMLElement;\n const cell = target.closest('td[data-row][data-col]');\n if (!cell) return false;\n\n const rowIndex = parseInt(cell.getAttribute('data-row') || '', 10);\n const colIndex = parseInt(cell.getAttribute('data-col') || '', 10);\n if (isNaN(rowIndex) || isNaN(colIndex)) return false;\n\n const rowData = store.getRowData(rowIndex);\n const colConfig = cols[colIndex];\n if (!rowData || !colConfig) return false;\n\n const cellTarget = resolveCommentTarget(rowData, colConfig);\n if (!cellTarget.entityType || !cellTarget.rowId) return false;\n\n // Check if there's a multi-cell selection \u2014 must read BEFORE handleMouseDown resets it\n const bounds = store.getSelectionBounds();\n const isMultiCell = bounds && (bounds.startRow !== bounds.endRow || bounds.startCol !== bounds.endCol);\n\n if (isMultiCell && bounds) {\n const bulkCells = collectBulkCells(bounds);\n if (bulkCells.length > 1) {\n e.preventDefault();\n e.stopPropagation();\n setCommentDialog({\n entityType: cellTarget.entityType,\n rowId: cellTarget.rowId,\n columnKey: colConfig.data,\n columnTitle: colConfig.title || colConfig.data,\n anchorRect: (cell as HTMLElement).getBoundingClientRect(),\n bulkCells,\n });\n return true;\n }\n }\n\n // Single cell \u2014 open comment dialog (also prevent mousedown from resetting)\n e.preventDefault();\n e.stopPropagation();\n\n const annotation = annotations.get(annotationKey(cellTarget, colConfig.data));\n\n setCommentDialog({\n entityType: cellTarget.entityType,\n rowId: cellTarget.rowId,\n columnKey: colConfig.data,\n columnTitle: colConfig.title || colConfig.data,\n rowLabel: rowData.name || rowData.title || undefined,\n annotationId: annotation?.id || null,\n currentColor: annotation?.color || null,\n anchorRect: (cell as HTMLElement).getBoundingClientRect(),\n });\n return true;\n }, [enableComments, commentsEntityType, store, cols, resolveCommentTarget, collectBulkCells, annotations]);\n\n // \u2500\u2500 Cell-range selection: committed dotted outline + drag-end context menu \u2500\u2500\n // The dotted outline and the Copy/Comment menu appear ONLY when a drag finishes\n // on a multi-cell range. `rangePhase` drives the `data-range-phase` attribute\n // the CSS keys off of: 'committed' (fade in) \u2192 'exiting' (fade out) \u2192 cleared.\n const [rangePhase, setRangePhase] = useState<'idle' | 'committed' | 'exiting'>('idle');\n const rangePhaseRef = useRef<'idle' | 'committed' | 'exiting'>('idle');\n const rangeExitTimerRef = useRef<number | null>(null);\n const applyRangePhase = useCallback((p: 'idle' | 'committed' | 'exiting') => {\n rangePhaseRef.current = p;\n setRangePhase(p);\n }, []);\n\n // Clear the selection, fading a committed outline out first (opacity 1\u21920).\n const clearSelectionAnimated = useCallback(() => {\n if (rangePhaseRef.current === 'committed') {\n applyRangePhase('exiting');\n if (rangeExitTimerRef.current) window.clearTimeout(rangeExitTimerRef.current);\n rangeExitTimerRef.current = window.setTimeout(() => {\n store.setSelection({ type: null, anchor: null, focus: null });\n applyRangePhase('idle');\n rangeExitTimerRef.current = null;\n }, 170);\n } else {\n store.setSelection({ type: null, anchor: null, focus: null });\n applyRangePhase('idle');\n }\n }, [store, applyRangePhase]);\n\n const copySelectionToClipboard = useCallback(() => {\n const cells = store.getCellsInSelection();\n const bounds = store.getSelectionBounds();\n if (!cells.length || !bounds) return;\n const text = selectionToTsv(cells, bounds);\n // Marching ants go up IMMEDIATELY \u2014 Excel's marquee appears with the\n // gesture, not a round-trip later, and `navigator.clipboard.writeText` is\n // async. They are taken back down in the failure branch, so an outline\n // claiming the clipboard holds this block never outlives a rejected write.\n store.setClipboardMarker({ mode: 'copy', bounds });\n void navigator.clipboard?.writeText(text)\n .then(() => flash(t('dynamicTable.cellMenu.copied', 'Copied to clipboard'), 'success'))\n .catch(() => {\n store.setClipboardMarker(null);\n flash(t('dynamicTable.cellMenu.copyFailed', 'Could not copy to clipboard'), 'error');\n });\n }, [store, t]);\n\n // Ctrl/Cmd+C copy. The base handler copies a cell-range selection; when there's\n // no range but rows are checkbox-selected, fall back to copying those rows\n // (visible columns, in page order) as TSV. Either way, flash success.\n const copyRowSelectionText = useCallback((): string | null => {\n if (selectedRowIds.size === 0) return null;\n const rowCount = store.getRowCount();\n const lines: string[] = [];\n for (let r = 0; r < rowCount; r++) {\n const rowData = store.getRowData(r);\n if (!rowData) continue;\n const id = String(rowData[selectionColumnName] ?? '');\n if (!id || !selectedRowIds.has(id)) continue;\n lines.push(cols.map((_, c) => String(store.getCellValue(r, c) ?? '')).join('\\t'));\n }\n return lines.length ? lines.join('\\n') : null;\n }, [store, selectedRowIds, selectionColumnName, cols]);\n\n const handleCopied = useCallback((bounds: SelectionBounds | null) => {\n // Excel's marquee. `bounds` is null for the checkbox-row fallback, which\n // has no rectangle to draw around \u2014 that path copies rows, not a range.\n if (bounds) store.setClipboardMarker({ mode: 'copy', bounds });\n flash(t('dynamicTable.cellMenu.copied', 'Copied to clipboard'), 'success');\n }, [store, t]);\n\n const handleCopy = useCopyHandler(store, tableRef, {\n getFallbackText: copyRowSelectionText,\n onCopy: handleCopied,\n });\n\n // Grouped-actions-bar Copy button: actively write the selected rows to the\n // clipboard (the Ctrl+C path relies on the browser copy event; a button click\n // can't, so it uses the async clipboard API directly). Flashes on success.\n const handleBulkCopy = useCallback(() => {\n const text = copyRowSelectionText();\n if (!text) return;\n void navigator.clipboard?.writeText(text)\n .then(() => flash(t('dynamicTable.cellMenu.copied', 'Copied to clipboard'), 'success'))\n .catch(() => flash(t('dynamicTable.cellMenu.copyFailed', 'Could not copy to clipboard'), 'error'));\n }, [copyRowSelectionText, t]);\n\n // Shared serializer: turn an extracted table into a downloaded CSV/Excel file.\n // The xlsx serializer is imported lazily so the CSV path never loads SheetJS.\n const serializeAndDownload = useCallback(async (table: ExtractedTable, format: ExportFormat) => {\n if (table.rows.length === 0) {\n flash(t('dynamicTable.export.empty', 'No rows to export'), 'info');\n return;\n }\n const stem = exportFileName?.trim() || slugifyFileName(displayTableName);\n try {\n if (format === 'csv') {\n const blob = new Blob([toCsv(table)], { type: 'text/csv;charset=utf-8' });\n downloadBlob(blob, `${stem}.csv`);\n } else {\n const XLSX = await import('xlsx');\n downloadBlob(toXlsxBlob(table, XLSX), `${stem}.xlsx`);\n }\n flash(t('dynamicTable.export.success', 'Export ready'), 'success');\n } catch {\n flash(t('dynamicTable.export.failed', 'Could not export'), 'error');\n }\n }, [exportFileName, displayTableName, t]);\n\n // Grouped-actions-bar export: the checkbox-selected rows, visible columns in\n // view order. Mirrors the Copy extraction (`store.getCellValue`).\n const handleExportSelection = useCallback((format: ExportFormat) => {\n void serializeAndDownload(\n extractExportRows(store, cols, selectedRowIds, selectionColumnName),\n format,\n );\n }, [serializeAndDownload, store, cols, selectedRowIds, selectionColumnName]);\n\n // Toolbar export: the WHOLE table \u2014 every column (ignoring the active\n // perspective's column visibility) and every row. When the page supplies\n // `onExportAll`, re-fetch all pages from the server (ignoring filters);\n // otherwise fall back to the currently-loaded rows.\n const [isExportingAll, setIsExportingAll] = useState(false);\n const handleExportAll = useCallback(async (format: ExportFormat) => {\n if (isExportingAll) return;\n setIsExportingAll(true);\n try {\n const outcome = onExportAll ? await onExportAll() : data;\n\n // HEDGE-123 \u2014 a file is only written for a result proven complete.\n //\n // `onExportAll` may reject (a page failed, or came back unreadable) \u2014 the\n // catch below turns that into a visible error and NO download, which is\n // the point: a failure the user can see and retry, instead of a short\n // file they cannot. It may also resolve carrying its own counts, for the\n // case where rows were fetched but completeness could not be proven.\n // A bare array still means complete, so hosts predating this are unchanged.\n const counted: ExportAllResult | null =\n outcome != null && !Array.isArray(outcome) ? (outcome as ExportAllResult) : null;\n const rows = counted ? counted.rows : (outcome as any[]);\n\n if (counted && !counted.complete) {\n // Deliberately NOT a download. Handing over a file here would restore\n // exactly the defect this replaces \u2014 the numbers exist precisely so the\n // user is told what is missing rather than shown a plausible file.\n flash(\n t(\n 'dynamicTable.export.incomplete',\n 'Export stopped early and was NOT saved \u2014 {reason}. Try again.',\n { reason: counted.reason ?? 'the full table could not be read' },\n ),\n 'error',\n );\n return;\n }\n\n await serializeAndDownload(extractExportRowsFromData(rows ?? [], baseColumns), format);\n } catch (err) {\n // Name the failure. \"Could not export\" alone left a user unable to say\n // whether it was their filter, the network, or the server.\n const detail = err instanceof Error && err.message ? err.message : null;\n flash(\n detail\n ? t('dynamicTable.export.failedDetail', 'Could not export \u2014 {detail}', { detail })\n : t('dynamicTable.export.failed', 'Could not export'),\n 'error',\n );\n } finally {\n setIsExportingAll(false);\n }\n }, [isExportingAll, onExportAll, data, serializeAndDownload, baseColumns, t]);\n\n const openAnnotateForSelection = useCallback(() => {\n if (!enableComments || !commentsEntityType) return;\n const bounds = store.getSelectionBounds();\n if (!bounds) return;\n const anchorCell = tableRef.current?.querySelector(\n `td[data-row=\"${bounds.endRow}\"][data-col=\"${bounds.endCol}\"]`\n ) as HTMLElement | null;\n // MODEL FALLBACK. Under column virtualization the range's bottom-right cell\n // may not be mounted, and an `undefined` rect drops the dialog into the\n // middle of the viewport instead of next to the selection. Column x comes\n // from the prefix-sum geometry (which answers for unmounted columns), row y\n // from the row height \u2014 the two facts the DOM was being asked for.\n const anchorRect = anchorCell?.getBoundingClientRect() ?? (() => {\n const el = tableRef.current;\n if (!el) return undefined;\n const box = el.getBoundingClientRect();\n const geo = columnVirtualizer.geometry;\n const x = box.left + (geo.starts[bounds.endCol] ?? 0) - el.scrollLeft;\n const y = box.top + bounds.endRow * dataRowHeight - el.scrollTop;\n const width = store.getColumnWidth(bounds.endCol);\n return new DOMRect(x, y, width, dataRowHeight);\n })();\n const firstRowData = store.getRowData(bounds.startRow);\n const firstCol = cols[bounds.startCol];\n if (!firstRowData || !firstCol) return;\n const firstTarget = resolveCommentTarget(firstRowData, firstCol);\n if (!firstTarget.entityType || !firstTarget.rowId) return;\n\n const isMultiCell = bounds.startRow !== bounds.endRow || bounds.startCol !== bounds.endCol;\n if (isMultiCell) {\n const bulkCells = collectBulkCells(bounds);\n if (bulkCells.length > 1) {\n setCommentDialog({\n entityType: firstTarget.entityType,\n rowId: firstTarget.rowId,\n columnKey: firstCol.data,\n columnTitle: firstCol.title || firstCol.data,\n anchorRect,\n bulkCells,\n });\n return;\n }\n }\n const annotation = annotations.get(annotationKey(firstTarget, firstCol.data));\n setCommentDialog({\n entityType: firstTarget.entityType,\n rowId: firstTarget.rowId,\n columnKey: firstCol.data,\n columnTitle: firstCol.title || firstCol.data,\n rowLabel: firstRowData.name || firstRowData.title || undefined,\n annotationId: annotation?.id || null,\n currentColor: annotation?.color || null,\n anchorRect,\n });\n }, [enableComments, commentsEntityType, store, cols, resolveCommentTarget, collectBulkCells, annotations, columnVirtualizer, dataRowHeight]);\n\n // After a drag finishes on a multi-cell range, commit the outline.\n //\n // This used to ALSO pop the cell context menu at the cursor, unprompted, on\n // every range drag \u2014 so selecting cells to read them threw a menu over the\n // data you had just selected. Copy is `Ctrl/\u2318+C` (and the bulk bar, and\n // right-click), so the popup was interrupting to offer something the\n // keyboard already does. Right-click still opens the same menu, which is\n // where Comment / colour remains discoverable.\n const handleMouseUpWithMenu = useCallback(() => {\n handleMouseUp();\n const bounds = store.getSelectionBounds();\n const isRange = !!bounds && (bounds.startRow !== bounds.endRow || bounds.startCol !== bounds.endCol);\n if (isRange) applyRangePhase('committed');\n }, [handleMouseUp, store, applyRangePhase]);\n\n // ---- Fill handle (drag-to-fill) ----\n // A fill drag starts on the bottom-right nub of the SELECTION \u2014 any size\n // (`[data-fill-handle]`). Excel fills a RECTANGLE in four directions and each\n // source line continues its own series; so does this. Distinct from\n // range-select, which starts on the cell body. Opt-in via\n // `uiConfig.enableFillHandle`.\n //\n // The geometry (axis lock, back-drag, direction) is NOT computed here \u2014 it\n // lives in `utils/fillGeometry.ts` as a pure function, because rules a user\n // notices must be provable without a browser.\n const fillStateRef = useRef<{\n source: SelectionBounds;\n pointer: { row: number; col: number };\n modifier: boolean;\n } | null>(null);\n // A large write held back for confirmation. Deliberately a WRITE BATCH, not a\n // fill-shaped triple: the same dialog now guards a big paste, and a second\n // confirmation flow is how the two would drift apart.\n const [pendingWrite, setPendingWrite] = useState<{\n writes: CellWrite[];\n origin: CellWriteOrigin;\n /**\n * Carried through the dialog rather than re-derived from `origin`: a\n * back-drag clear IS the fill handle and must honour `disableFill`, while a\n * Delete-key clear is an ordinary edit and must not. Same origin, different\n * answer \u2014 so the answer travels with the batch.\n */\n respectDisableFill?: boolean;\n } | null>(null);\n\n /**\n * Seed values for one fill line, read by INDEX into the full column array.\n * Never by DOM query: a column may be unmounted by column virtualization and\n * still be part of the source block.\n */\n const readFillSeed = useCallback(\n (cells: Array<{ row: number; col: number }>, seedColIndex: number): FillSeed => {\n const column = cols[seedColIndex];\n const values = cells.map(({ row, col }) => {\n const raw = store.getCellValue(row, col);\n // A boolean column may be backed by a non-boolean value (a timestamp\n // rendered as a checkbox). Seed the boolean STATE so the per-cell save\n // coerces and persists exactly like a manual toggle would.\n return cols[col]?.type === 'boolean' ? Boolean(raw) : raw;\n });\n return { values, column };\n },\n [cols, store],\n );\n\n /** Re-derive the preview rectangle for the current pointer and modifier. */\n const paintFillPreview = useCallback(() => {\n const fs = fillStateRef.current;\n if (!fs) return;\n // Two passes, deliberately: the axis decides which line is the seed, and the\n // seed decides the default mode. Pass 1 is geometry only, so the mode it is\n // handed is discarded; pass 2 re-labels it with the truth.\n const geometry = computeFillPreview(fs.source, fs.pointer, {\n modifier: false,\n defaultMode: 'series',\n });\n const [firstLine] = buildFillLines(geometry);\n let defaultMode: FillMode = 'copy';\n if (firstLine && firstLine.seedCells.length > 0) {\n defaultMode = detectFillPattern(readFillSeed(firstLine.seedCells, firstLine.seedCol)).defaultMode;\n }\n const mode = fs.modifier ? invertFillMode(defaultMode) : defaultMode;\n store.setFillPreview({ ...geometry, mode });\n }, [store, readFillSeed]);\n\n const handleFillMouseDown = useCallback((e: React.MouseEvent): boolean => {\n if (!enableFillHandle) return false;\n if (!(e.target as HTMLElement).closest('[data-fill-handle]')) return false;\n const bounds = store.getSelectionBounds();\n if (!bounds) return false;\n // Selection SIZE is unconstrained \u2014 an N\u00D7M block is a legitimate source.\n // Fillability is a property of the block, not of one corner cell: a source\n // containing a read-only column still fills, that column's writes are just\n // rejected and reported. This mirrors the store's `isFillOrigin`, which is\n // what put the nub on screen in the first place.\n const anyFillable = (() => {\n for (let c = bounds.startCol; c <= bounds.endCol; c++) {\n const col = cols[c];\n if (col && !col.readOnly && !col.disableFill) return true;\n }\n return false;\n })();\n if (!anyFillable) return false;\n fillStateRef.current = {\n source: bounds,\n pointer: { row: bounds.endRow, col: bounds.endCol },\n modifier: e.altKey || e.ctrlKey,\n };\n paintFillPreview();\n e.preventDefault();\n return true;\n }, [enableFillHandle, store, cols, paintFillPreview]);\n\n const handleFillMouseMove = useCallback((e: React.MouseEvent) => {\n const fs = fillStateRef.current;\n if (!fs) return;\n const cell = document.elementFromPoint(e.clientX, e.clientY)?.closest('td');\n if (!cell) return;\n // A 2D drag crosses the row-header gutter and the actions column, neither of\n // which is a data cell. Reading `data-col` off them yields NaN or an index\n // outside the column array, so they are rejected outright \u2014 the preview\n // simply stops updating rather than jumping to column 0.\n if (cell.hasAttribute('data-row-header') || cell.hasAttribute('data-actions-cell')) return;\n const row = parseInt(cell.getAttribute('data-row') || '', 10);\n const col = parseInt(cell.getAttribute('data-col') || '', 10);\n if (Number.isNaN(row) || Number.isNaN(col)) return;\n if (col < 0 || col >= cols.length) return;\n fs.pointer = { row, col };\n // Excel lets the modifier be pressed or released MID-drag, so it is tracked\n // continuously and the preview badge follows.\n fs.modifier = e.altKey || e.ctrlKey;\n paintFillPreview();\n }, [cols, paintFillPreview]);\n\n /**\n * THE multi-cell write. Fill, paste, cut, clear, find-&-replace and import all\n * come through here \u2014 a second write path is how the grid ends up with two\n * undo behaviours and two rejection tables.\n *\n * No `beginUndoGroup()` here: `applyCellWrites` already opens exactly one\n * group around the whole batch, and a second group NESTS and destroys the\n * outer one, which would turn a 30x4 paste back into 120 separate Ctrl+Z's.\n *\n * No caller-side `disableFill` filtering either: `applyCellWrites` rejects it\n * when (and only when) `origin === 'fill'`. A paste or a replace MUST still\n * write those columns \u2014 `disableFill` excludes identity fields from the DRAG\n * HANDLE, it does not make them read-only.\n *\n * `tableRef.current` is read INSIDE the callback so the batch events reach the\n * live container even if it remounted (fullscreen re-parents it).\n */\n /**\n * Bumped after every multi-cell write. `CellStore` bumps revisions PER CELL,\n * so nothing at this level can observe a batch landing \u2014 and find-and-replace\n * has to re-scan after its own Replace All, or it goes on reporting\n * counts for text it just changed. One counter covers every write path\n * (paste, cut, clear, fill, replace, and the large-write dialog).\n */\n const [writeRevision, setWriteRevision] = useState(0);\n\n const writeCells = useCallback(\n (\n writes: readonly CellWrite[],\n origin: CellWriteOrigin,\n respectDisableFill?: boolean,\n ): CellWriteReport => {\n const report = applyCellWrites(\n {\n store,\n columns: cols,\n handleCellSave,\n coerce: coerceCellValue,\n element: tableRef.current,\n idColumnName,\n },\n writes,\n { origin, respectDisableFill },\n );\n if (report.written > 0) setWriteRevision((n) => n + 1);\n return report;\n },\n [store, cols, handleCellSave, idColumnName, tableRef],\n );\n\n /**\n * Say what happened. A batch that silently drops 12 of 40 cells is the single\n * worst failure mode of a paste, so rejections are always surfaced \u2014 counted\n * by reason, never as a generic \"some cells failed\".\n */\n const reportWrite = useCallback((report: CellWriteReport) => {\n if (report.rejected.length === 0) {\n if (report.written > 0) {\n // Name the gesture back to the user: \"Cleared 12 cells\" after Delete\n // reads as confirmation, \"Updated 12 cells\" reads as a surprise.\n const applied = report.origin === 'cut'\n ? t('dynamicTable.cut.done', 'Cut {count} cells', { count: report.written })\n : report.origin === 'clear'\n ? t('dynamicTable.clear.done', 'Cleared {count} cells', { count: report.written })\n : t('dynamicTable.write.applied', 'Updated {count} cells', { count: report.written });\n flash(applied, 'success');\n }\n return;\n }\n const parts: string[] = [];\n const r = report.rejectedByReason;\n if (r.readOnly) parts.push(t('dynamicTable.write.rejectedReadOnly', '{count} read-only', { count: r.readOnly }));\n if (r.notCoercible) parts.push(t('dynamicTable.write.rejectedNotCoercible', '{count} wrong type', { count: r.notCoercible }));\n if (r.notInSource) parts.push(t('dynamicTable.write.rejectedNotInSource', '{count} not an allowed value', { count: r.notInSource }));\n if (r.required) parts.push(t('dynamicTable.write.rejectedRequired', '{count} required', { count: r.required }));\n if (r.outOfRange) parts.push(t('dynamicTable.write.rejectedOutOfRange', '{count} outside the table', { count: r.outOfRange }));\n flash(\n t('dynamicTable.write.partial', 'Updated {written} cells; skipped {skipped} ({reasons})', {\n written: report.written,\n skipped: report.rejected.length,\n reasons: parts.join(', '),\n }),\n report.written > 0 ? 'info' : 'error',\n );\n }, [t]);\n\n /** Run a batch now, or hold it for confirmation when it is large. */\n const submitWrites = useCallback((writes: CellWrite[], origin: CellWriteOrigin) => {\n if (writes.length === 0) return;\n // The threshold counts CELLS (rows x columns), not rows \u2014 a 40-row paste\n // across 6 columns is 240 persist requests, and that is what the user is\n // being asked about.\n if (writes.length > fillConfirmThreshold) {\n setPendingWrite({ writes, origin });\n return;\n }\n reportWrite(writeCells(writes, origin));\n }, [fillConfirmThreshold, reportWrite, writeCells]);\n\n /**\n * Turn the preview rectangle into writes and hand them to the ONE write\n * primitive.\n *\n * The undo rule this must not break: `applyCellWrites` opens exactly ONE\n * group around the whole batch. The per-line loop below GENERATES VALUES, it\n * does not write \u2014 iterating lines and calling the writer once per line would\n * produce one undo entry per column, so an n-column fill would need n Ctrl+Z's.\n */\n const commitFill = useCallback(() => {\n const fs = fillStateRef.current;\n if (!fs) return;\n fillStateRef.current = null;\n\n const preview = store.getFillPreview();\n if (!preview) { store.setFillPreview(null); return; }\n\n // Back-drag: the cells the user dragged back over are EMPTIED. Not a special\n // path \u2014 same primitive, same single undo entry, same persistence.\n if (preview.clearing && preview.cleared) {\n const writes: CellWrite[] = cellsInRect(preview.cleared).map(({ row, col }) => ({\n row,\n col,\n value: null,\n }));\n if (writes.length === 0) { store.setFillPreview(null); return; }\n if (writes.length > fillConfirmThreshold) {\n setPendingWrite({ writes, origin: 'clear', respectDisableFill: true });\n return;\n }\n reportWrite(writeCells(writes, 'clear', true));\n store.setFillPreview(null);\n return;\n }\n\n // Each source LINE continues its own series: one line per source column on a\n // vertical fill, one per source row on a horizontal one. That is Excel's\n // rule and it is what stops a multi-column drag smearing one column's\n // sequence sideways.\n const writes: CellWrite[] = [];\n for (const line of buildFillLines(preview)) {\n if (line.targets.length === 0) continue;\n const seed = readFillSeed(line.seedCells, line.seedCol);\n const pattern = detectFillPattern(seed);\n const mode = fs.modifier ? invertFillMode(pattern.defaultMode) : pattern.defaultMode;\n const values = generateFill(seed, line.targets.length, preview.backwards ? -1 : 1, mode);\n line.targets.forEach((cell, i) => {\n writes.push({ row: cell.row, col: cell.col, value: values[i] });\n });\n }\n\n if (writes.length === 0) { store.setFillPreview(null); return; }\n if (writes.length > fillConfirmThreshold) {\n // Keep the dashed preview up while the user confirms the large write.\n setPendingWrite({ writes, origin: 'fill' });\n return;\n }\n reportWrite(writeCells(writes, 'fill'));\n store.setFillPreview(null);\n }, [store, fillConfirmThreshold, writeCells, reportWrite, readFillSeed]);\n\n const confirmPendingWrite = useCallback(() => {\n if (pendingWrite) {\n reportWrite(\n writeCells(pendingWrite.writes, pendingWrite.origin, pendingWrite.respectDisableFill),\n );\n }\n setPendingWrite(null);\n store.setFillPreview(null);\n }, [pendingWrite, writeCells, reportWrite, store]);\n\n const cancelPendingWrite = useCallback(() => {\n setPendingWrite(null);\n store.setFillPreview(null);\n }, [store]);\n\n // ---- In-grid Find & Replace ----\n /**\n * Bring a match into view under virtualization.\n *\n * Three things have to happen in order, and skipping any one of them lands the\n * user on the wrong cell:\n * 1. a match inside a COLLAPSED GROUP expands that group first \u2014\n * `dataIndexToVisualIndex` silently returns the raw data index for a row\n * that is not visible, which would scroll to an unrelated row;\n * 2. the ROW is scrolled by the virtualizer, which is the only thing that\n * knows where an unmounted row lives;\n * 3. the COLUMN is scrolled through the column virtualizer's `scrollToColumn`,\n * which answers from the PREFIX-SUM GEOMETRY \u2014 not from a `<td>`.\n *\n * (3) used to be `querySelector('td[data-row][data-col]')?.scrollIntoView()`\n * in a `requestAnimationFrame`. That is an indices\u2192element read, which the\n * range-operation contract forbids for exactly the reason it failed here: a\n * match in a column outside the mounted window has no `<td>`, so the lookup\n * returned null and the bar made a cell active at x=1179 in a 966px\n * viewport with `scrollLeft` still 0 (ledger row 1.24). `scrollToColumn` is\n * model-driven and therefore answers for unmounted columns, and it runs\n * SYNCHRONOUSLY \u2014 mounting the column is a consequence of the scroll, not a\n * precondition for it.\n */\n const scrollToCell = useCallback((row: number, col: number) => {\n const groupKey = groupingResult.groupKeyOfDataIndex(row);\n if (groupKey && groupingResult.collapsedGroups.has(groupKey)) {\n groupingResult.toggleGroup(groupKey);\n }\n const visualIndex = groupingResult.visualRows\n ? groupingResult.dataIndexToVisualIndex(row)\n : row;\n rowVirtualizer.scrollToIndex(visualIndex, { align: 'center' });\n columnVirtualizerRef.current.scrollToColumn(col, { align: 'auto' });\n }, [groupingResult, rowVirtualizer]);\n\n /**\n * Drive the dataset-wide `SearchBar` from inside the grid, through the\n * machinery that already exists \u2014 the dataset filters and the page reloads.\n * Its one caller today is the zero-result state's \"clear the search\" link.\n */\n const handleSearchWholeDataset = useCallback((query: string) => {\n if (!tableRef.current) return;\n dispatch(tableRef.current, TableEvents.SEARCH, { query, timestamp: Date.now() });\n }, [tableRef]);\n\n /**\n * Clear the dataset-wide search from the zero-result state (ledger 2.20).\n *\n * Goes through the SAME `TableEvents.SEARCH` dispatch the SearchBar uses, so\n * the input box empties too \u2014 `SearchBar` mirrors a search dispatched by\n * anyone else. Anything that reached in and reset host state directly would\n * leave the box still showing the dead term.\n */\n const handleClearSearch = useCallback(() => {\n handleSearchWholeDataset('');\n }, [handleSearchWholeDataset]);\n\n\n /**\n * Ctrl/Cmd+V. Reads the RICH flavour first (`text/html`) and only falls back\n * to TSV \u2014 Excel's `text/plain` mangles any cell containing a tab or a\n * newline, and its HTML flavour does not.\n *\n * Geometry follows Excel: the grid lands at the selection's top-left corner;\n * when the selection is an exact multiple of the copied block in both\n * directions the block is TILED to fill it (that is how \"copy one row, select\n * ten, paste\" is expected to behave). Cells that would land past the last row\n * or column are still submitted \u2014 `applyCellWrites` reports them as\n * `outOfRange` and the user is told, rather than the paste silently shrinking.\n */\n const handlePaste = useCallback((e: ClipboardEvent) => {\n const container = tableRef.current;\n if (!container || !(e.target instanceof Node) || !container.contains(e.target)) return;\n // An open editor owns its own input \u2014 never hijack a paste into a text box.\n if (store.getEditingCell()) return;\n const bounds = store.getSelectionBounds();\n if (!bounds) return;\n\n const grid = parseClipboardGrid({\n html: e.clipboardData?.getData('text/html'),\n text: e.clipboardData?.getData('text/plain'),\n });\n // Never fail silently: \"I pressed Ctrl+V and nothing happened\" is\n // indistinguishable from a broken grid.\n if (grid.source === 'empty') {\n flash(t('dynamicTable.paste.empty', 'The clipboard has nothing to paste'), 'info');\n return;\n }\n e.preventDefault();\n\n const selRows = bounds.endRow - bounds.startRow + 1;\n const selCols = bounds.endCol - bounds.startCol + 1;\n const tile =\n selRows >= grid.rowCount &&\n selCols >= grid.colCount &&\n selRows % grid.rowCount === 0 &&\n selCols % grid.colCount === 0;\n const spanRows = tile ? selRows : grid.rowCount;\n const spanCols = tile ? selCols : grid.colCount;\n\n const writes: CellWrite[] = [];\n for (let dr = 0; dr < spanRows; dr++) {\n for (let dc = 0; dc < spanCols; dc++) {\n writes.push({\n row: bounds.startRow + dr,\n col: bounds.startCol + dc,\n value: grid.rows[dr % grid.rowCount]?.[dc % grid.colCount] ?? '',\n });\n }\n }\n submitWrites(writes, 'paste');\n // Excel ends the marquee on paste. Ours must too \u2014 and here it is also a\n // correctness matter: the paste refetches, which can re-order rows under\n // an index-addressed rectangle.\n store.setClipboardMarker(null);\n }, [store, tableRef, submitWrites, t]);\n\n /**\n * Every cell of a rectangle, as writes of one value.\n *\n * Range-operation contract: the bounds are walked ARITHMETICALLY, so a\n * selection that spans columns scrolled out of the mounted window (column\n * virtualization is live on `/backend/invoicing`) clears exactly the same\n * cells as one that does not. Nothing here asks the DOM what exists.\n *\n * Out-of-range cells are deliberately still submitted \u2014 `applyCellWrites`\n * reports them rather than the operation silently shrinking.\n */\n const rectWrites = useCallback((\n bounds: { startRow: number; endRow: number; startCol: number; endCol: number },\n value: unknown,\n ): CellWrite[] => {\n const writes: CellWrite[] = [];\n for (let r = bounds.startRow; r <= bounds.endRow; r++) {\n for (let c = bounds.startCol; c <= bounds.endCol; c++) {\n writes.push({ row: r, col: c, value });\n }\n }\n return writes;\n }, []);\n\n /**\n * Delete / Backspace on a selection: CLEAR CONTENTS, never delete rows.\n *\n * `null` (not `''`) is the cleared value \u2014 `coerceCellValue` maps both to\n * `null` for typed columns, but `null` is also right for the untyped ones,\n * where `''` would persist an empty string into a nullable field.\n *\n * Read-only columns and `required` fields are rejected BY the write\n * primitive and reported by `reportWrite` \u2014 a clear that quietly skips half\n * its cells is the failure mode this replaces.\n */\n const clearSelectionContents = useCallback(() => {\n const bounds = store.getSelectionBounds();\n if (!bounds) return false;\n submitWrites(rectWrites(bounds, null), 'clear');\n return true;\n }, [store, rectWrites, submitWrites]);\n\n /**\n * Ctrl/Cmd+X. Copy, then clear the source \u2014 ONE undo entry, because the clear\n * is a single `applyCellWrites` batch and the copy writes nothing.\n *\n * The clipboard is written FIRST and synchronously, inside the native `cut`\n * event: `navigator.clipboard.writeText` would resolve after the clear and a\n * failure there would leave the data gone with nothing to paste back.\n */\n const handleCut = useCallback((e: ClipboardEvent) => {\n const container = tableRef.current;\n if (!container || !(e.target instanceof Node) || !container.contains(e.target)) return;\n // An open editor owns its own cut \u2014 never hijack one out of a text box.\n if (store.getEditingCell()) return;\n const bounds = store.getSelectionBounds();\n const cells = store.getCellsInSelection();\n if (!bounds || cells.length === 0 || !e.clipboardData) return;\n\n e.clipboardData.setData('text/plain', selectionToTsv(cells, bounds));\n e.preventDefault();\n submitWrites(rectWrites(bounds, null), 'cut');\n // The ants mark WHAT IS ON THE CLIPBOARD and where it came from. The source\n // is already empty by this line \u2014 see the note above `handleCut` for why\n // this grid clears on cut rather than on paste.\n store.setClipboardMarker({ mode: 'cut', bounds });\n }, [store, tableRef, rectWrites, submitWrites]);\n\n // ---- Undo / redo ----\n // Replays the inverse edit through the normal save path, so the reverse also\n // persists (PATCH/POST) and is itself redoable. `suppressed` stops the replay\n // from being re-recorded. Rows are resolved by stable id (they survive the\n // post-edit refetch); rows no longer present are skipped.\n const applyUndoEntry = useCallback((entry: { changes: { rowId: any; colKey: string; oldValue: any; newValue: any }[] }, useOldValue: boolean) => {\n store.setUndoSuppressed(true);\n try {\n for (const ch of entry.changes) {\n const rowIdx = store.findRowIndexById(idColumnName, ch.rowId);\n const colIdx = cols.findIndex((c) => c.data === ch.colKey);\n if (rowIdx >= 0 && colIdx >= 0) {\n handleCellSave(rowIdx, colIdx, useOldValue ? ch.oldValue : ch.newValue, false);\n }\n }\n } finally {\n store.setUndoSuppressed(false);\n }\n }, [store, cols, idColumnName, handleCellSave]);\n\n const undo = useCallback(() => {\n const entry = store.popUndo();\n if (!entry) return;\n applyUndoEntry(entry, true);\n store.pushRedo(entry);\n flash(t('dynamicTable.undo.undone', 'Undone'), 'info');\n }, [store, applyUndoEntry, t]);\n\n const redo = useCallback(() => {\n const entry = store.popRedo();\n if (!entry) return;\n applyUndoEntry(entry, false);\n store.pushUndo(entry);\n flash(t('dynamicTable.undo.redone', 'Redone'), 'info');\n }, [store, applyUndoEntry, t]);\n\n // Intercept the built-in selection actions; defer everything else to the\n // normal cell/row/column dispatch.\n const handleMenuActionClick = useCallback((actionId: string) => {\n // Copy \u2192 drop the selection (the user is done with it). Comment/colour keeps\n // it (the dialog needs the visible context); it's cleared on dialog close.\n if (actionId === SELECTION_COPY_ID) { copySelectionToClipboard(); setContextMenu(null); clearSelectionAnimated(); return; }\n if (actionId === SELECTION_ANNOTATE_ID) { openAnnotateForSelection(); setContextMenu(null); return; }\n handleContextMenuAction(actionId);\n }, [copySelectionToClipboard, openAnnotateForSelection, handleContextMenuAction, clearSelectionAnimated]);\n\n // Right-click on a cell ALWAYS opens the context menu \u2014 even on a single cell\n // (the drag-end menu in handleMouseUpWithMenu only fires for multi-cell ranges).\n // The clicked cell is selected first so the built-in Copy / Comment actions\n // operate on it; built-in actions are merged with any consumer `cellActions`.\n const handleCellContextMenu = useCallback((e: React.MouseEvent, rowIndex: number, colIndex: number) => {\n const rowData = store.getRowData(rowIndex);\n const col = cols[colIndex];\n if (!col) return;\n // Select the right-clicked cell only when it isn't already inside the current\n // selection \u2014 otherwise a right-click on a multi-cell range would collapse it\n // to the single cell and Copy/Comment would lose the range.\n const bounds = store.getSelectionBounds();\n const insideSelection = !!bounds\n && rowIndex >= bounds.startRow && rowIndex <= bounds.endRow\n && colIndex >= bounds.startCol && colIndex <= bounds.endCol;\n if (!insideSelection) {\n store.setSelection({ type: 'range', anchor: { row: rowIndex, col: colIndex }, focus: { row: rowIndex, col: colIndex } });\n }\n const actions: ContextMenuAction[] = [\n { id: SELECTION_COPY_ID, label: t('dynamicTable.cellMenu.copy', 'Copy') },\n ];\n if (enableComments && commentsEntityType) {\n actions.push({ id: SELECTION_ANNOTATE_ID, label: t('dynamicTable.cellMenu.annotate', 'Comment / colour') });\n }\n if (cellActions) actions.push(...cellActions(rowData, col, rowIndex, colIndex));\n e.preventDefault();\n setContextMenu({ isOpen: true, position: { x: e.clientX, y: e.clientY }, actions, type: 'cell', index: rowIndex, colIndex });\n }, [cellActions, store, cols, enableComments, commentsEntityType, t]);\n\n // Stable identity so CellCommentDialog's outside-click listener isn't churned\n // (re-added with a delay) on every parent render \u2014 otherwise the first click\n // outside clears the selection but the dialog needs a second click to close.\n // Closing it both drops the selection AND closes the dialog in one click.\n const handleCommentDialogClose = useCallback(() => {\n setCommentDialog(null);\n clearSelectionAnimated();\n }, [clearSelectionAnimated]);\n\n // Wrap keyboard handler for React event system\n // Shortcuts are checked first; if one matches, skip normal navigation\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n // Undo / redo. Cmd/Ctrl+Z (undo), Cmd/Ctrl+Shift+Z or Ctrl+Y (redo). Never\n // hijacked while a cell editor / search box / textarea has focus \u2014 there the\n // input's own native undo must win.\n const key = e.key.toLowerCase();\n const metaOrCtrl = e.ctrlKey || e.metaKey;\n // B9 \u2014 Shift+F2 opens the comment dialog for the current selection. Excel's\n // own \"Insert/Edit Comment\" chord, adopted verbatim: the workshop finding\n // was that the feature existed but nobody (including its author) could find\n // the way in, so it gets the shortcut users already have in their fingers.\n if (e.key === 'F2' && e.shiftKey && enableComments && commentsEntityType) {\n if (!isTextEntryTarget(e.target as HTMLElement) && !store.getEditingCell()) {\n e.preventDefault();\n openAnnotateForSelection();\n return;\n }\n }\n if (metaOrCtrl && (key === 'z' || key === 'y')) {\n const isTextEntry = isTextEntryTarget(e.target as HTMLElement);\n if (!isTextEntry && !store.getEditingCell()) {\n e.preventDefault();\n if (key === 'y' || (key === 'z' && e.shiftKey)) redo();\n else undo();\n return;\n }\n }\n // Cmd/Ctrl + D with checkbox-selected rows \u2192 bulk delete, identical to the\n // grouped-actions bar's Delete button (so the consumer's confirm modal still\n // applies). preventDefault also suppresses the browser's bookmark-page\n // default. Plain Delete/Backspace is deliberately NOT used \u2014 in spreadsheets\n // those clear cell contents, not the row. Guarded so it never fires from a\n // text entry (search box, cell editor).\n const isDeleteCombo = e.key.toLowerCase() === 'd' && (e.ctrlKey || e.metaKey);\n if (isDeleteCombo && selectable && onBulkDelete && selectedRowIds.size > 0) {\n if (!isTextEntryTarget(e.target as HTMLElement) && !store.getEditingCell()) {\n e.preventDefault();\n void handleBulkDelete();\n return;\n }\n }\n // Plain Delete / Backspace on a selection CLEARS CONTENTS \u2014 the spreadsheet\n // meaning. The ROW is never touched: bulk row deletion stays on Cmd/Ctrl+D\n // and the grouped-actions bar, both of which route through the consumer's\n // confirm modal.\n if ((e.key === 'Delete' || e.key === 'Backspace') && !metaOrCtrl && !e.altKey) {\n if (!isTextEntryTarget(e.target as HTMLElement) && !store.getEditingCell()) {\n // preventDefault only when there IS something to clear, so Backspace\n // outside a selection still bubbles (it is \"back\" on some browsers).\n if (clearSelectionContents()) {\n e.preventDefault();\n return;\n }\n }\n }\n // Ctrl+H (control key only \u2014 Cmd+H hides the application on macOS) opens\n // FIND AND REPLACE, which is Excel's binding on both platforms. It is an\n // accelerator, never the only path: the same tool is one click away in the\n // toolbar, because a shortcut nobody can discover may as well not exist.\n //\n // Ctrl+F belongs to the BROWSER. Every list carries a Search box in the\n // toolbar that filters the whole dataset server-side; an in-grid finder\n // searching only the loaded page was a second, weaker search stacked under\n // the real one, so it was removed rather than kept behind a flag.\n // The rung below the bar and above \"exit editing\": Escape dismisses the\n // MARCHING ANTS first, exactly as Excel cancels its marquee before it does\n // anything else. Skipped while an editor is open \u2014 there the first Escape\n // still belongs to the edit session.\n if (e.key === 'Escape' && !store.getEditingCell() && store.getClipboardMarker()) {\n e.preventDefault();\n store.setClipboardMarker(null);\n return;\n }\n // Enter on a cell whose column mounts NO editor. `useKeyboardNavigation`\n // already refuses to open the edit session (without that guard the cell\n // blanks and every arrow key afterwards is swallowed \u2014 ledger 1.27); this\n // rung exists only to say WHY nothing happened, because a key that silently\n // does nothing is indistinguishable from a broken grid. Raised here rather\n // than in the hook because `flash` and the translations live at this level.\n if (e.key === 'Enter' && !e.shiftKey && !metaOrCtrl && !store.getEditingCell()) {\n const b = store.getSelectionBounds();\n if (b && b.startRow === b.endRow && b.startCol === b.endCol && !columnMountsEditor(cols[b.startCol])) {\n e.preventDefault();\n flash(\n t('dynamicTable.cell.readOnlyColumn', '\"{column}\" is read-only', {\n column: String(cols[b.startCol]?.title ?? cols[b.startCol]?.data ?? ''),\n }),\n 'info',\n );\n return;\n }\n }\n if (shortcutHandler(e.nativeEvent)) return;\n keyboardHandler(e.nativeEvent);\n }, [keyboardHandler, shortcutHandler, selectable, onBulkDelete, selectedRowIds, store, handleBulkDelete, undo, redo, clearSelectionContents, enableComments, commentsEntityType, openAnnotateForSelection, cols, t]);\n\n // Auto-select cell on focus (when enabled and no existing selection).\n // Reads optional data-focus-direction / data-focus-trigger attributes set\n // by the cross-table arrow and Tab handlers.\n const handleFocus = useCallback(() => {\n const direction = tableRef.current?.getAttribute('data-focus-direction');\n const trigger = tableRef.current?.getAttribute('data-focus-trigger');\n if (direction) tableRef.current?.removeAttribute('data-focus-direction');\n if (trigger) tableRef.current?.removeAttribute('data-focus-trigger');\n\n if (store.getRowCount() === 0) {\n // Empty table: if Tab-triggered, forward to the next sibling in the\n // same direction so empty tables are transparently skipped.\n if (trigger === 'tab') {\n const nextSibling = direction === 'up'\n ? siblingTableRefs?.prev?.current\n : siblingTableRefs?.next?.current;\n if (nextSibling) {\n nextSibling.setAttribute('data-focus-direction', direction || 'down');\n nextSibling.setAttribute('data-focus-trigger', 'tab');\n nextSibling.focus();\n }\n }\n return;\n }\n\n if (!autoSelectOnFocus || store.getSelection().anchor) return;\n\n const rowCount = store.getRowCount();\n const targetRow = direction === 'up' ? rowCount - 1 : 0;\n store.setSelection({\n type: 'range',\n anchor: { row: targetRow, col: 0 },\n focus: { row: targetRow, col: 0 },\n });\n }, [autoSelectOnFocus, store, tableRef, siblingTableRefs]);\n\n // Returns true when the target element sits inside a modal dialog that\n // does NOT contain this table. Modal dialogs (delete confirmations,\n // forms) are rendered as sibling portals \u2014 keeping selection while\n // they're open is correct because they return focus to the table on\n // close via onCloseAutoFocus. Drawers/Sheets also carry\n // `role=\"dialog\"` but they *contain* the table, so they must NOT be\n // exempted (sibling tables inside the same drawer need independent\n // selection clearing).\n const isInsideExternalDialog = useCallback((el: HTMLElement): boolean => {\n const dialog = el.closest('[role=\"dialog\"]');\n if (!dialog) return false;\n return !dialog.contains(tableRef?.current);\n }, [tableRef]);\n\n // Clear selection when DOM focus leaves the table container.\n // This ensures that when a user clicks on another table (or any element\n // outside this table), the stale selection is removed so only the newly\n // focused table shows a highlight. We skip clearing when focus moves to\n // portal-rendered popups (date pickers, dropdowns, entity search) that\n // logically belong to this table even though they live outside its DOM.\n const handleBlur = useCallback((e: React.FocusEvent) => {\n const relatedTarget = e.relatedTarget as HTMLElement | null;\n // Focus left the window entirely (e.g. alt-tab) \u2014 keep selection.\n if (!relatedTarget) return;\n // Focus stayed inside our table container \u2014 nothing to clear.\n if (tableRef?.current?.contains(relatedTarget)) return;\n // Focus moved to a portal popup (Radix dropdown/popover, editor popup\n // like calendar or dropdown, context menu) that belongs to this table \u2014\n // keep selection.\n if (relatedTarget.closest('[data-radix-popper-content-wrapper]') ||\n relatedTarget.closest('.hot-editor-popup') ||\n relatedTarget.closest('.hot-context-menu') ||\n relatedTarget.closest('.context-menu') ||\n // The find-and-replace bar renders OUTSIDE the grid container (it has\n // grid. Without this exemption, clicking into it would clear the very\n // selection the active match just established.\n relatedTarget.closest('.hot-comment-popover')) return;\n // Focus moved to a modal dialog (delete confirmation, form, etc.)\n // that does NOT contain this table \u2014 keep selection; the dialog will\n // return focus on close via onCloseAutoFocus.\n if (isInsideExternalDialog(relatedTarget)) return;\n\n store.clearEditing();\n clearSelectionAnimated();\n }, [store, tableRef, isInsideExternalDialog, clearSelectionAnimated]);\n\n // -------------------- FULLSCREEN HANDLERS --------------------\n // No width bookkeeping here any more. Entering fullscreen used to scale every\n // column by `windowWidth / currentTotal` and exiting used to restore the\n // saved map \u2014 which overwrote the user's own widths on the way in and could\n // resurrect stale ones on the way out. The fill effect above already does the\n // job properly: the scroller resizes, its `ResizeObserver` fires, and the\n // surplus is redistributed across the columns that are allowed to take it.\n const handleEnterFullscreen = () => {\n setIsFullscreen(true);\n onFullscreenChange?.(true);\n };\n\n const handleExitFullscreen = () => {\n setIsFullscreen(false);\n onFullscreenChange?.(false);\n };\n\n // -------------------- EFFECTS --------------------\n // Register table container ref with store for focus management\n useEffect(() => {\n store.setTableRef(tableRef);\n }, [store, tableRef]);\n\n // Sync data to store.\n // Skip when the store contains unsaved new rows to prevent wiping\n // in-progress edits (e.g., dropdown selections in insert mode).\n useEffect(() => {\n if (store.hasNewRows()) return;\n store.setData(data);\n }, [data, store]);\n\n // Sync columns to store when they change (e.g., perspective reorder/hide/show).\n // This ensures setCellValue uses the correct field mapping.\n useEffect(() => {\n store.setColumns(cols);\n }, [cols, store]);\n\n // Persist manual column-width changes per user (localStorage). Saved widths are\n // applied in a pre-paint layout effect (no layout shift on reload), and the\n // store preserves widths across setColumns() so perspective reorder/show-hide\n // keeps them.\n const { persistResize } = useColumnWidthPersistence({ tableId, store, cols, userResizedColsRef });\n persistColumnWidthRef.current = persistResize;\n\n // Subscribe to store-level changes (row add/remove, column resize)\n useEffect(() => {\n return store.subscribeToStore(() => {\n setRowCount(store.getRowCount());\n setStoreRevision(prev => prev + 1);\n });\n }, [store]);\n\n // Auto-fit badge columns to their widest badge. Unlike text (which ellipses),\n // status/type pills must never be clipped \u2014 so the column grows to fit the\n // longest badge instead.\n //\n // The measurement has to touch the DOM (a consumer's custom renderer can emit\n // any label, so there is no string in the model to measure), but everything\n // else is model-driven \u2014 see `utils/badgeAutoFit.ts` for the full rationale.\n // Two properties matter and are deliberate:\n //\n // - What we read is INTRINSIC: `badge.scrollWidth` is the pill's own content\n // width. It does not depend on the cell's current width, the scroll\n // position, or which columns happen to be mounted. The old code compared it\n // against `td.clientWidth`, which made the answer geometry-coupled \u2014 under\n // column virtualization that is a scroll-coupled layout feedback loop\n // (column widens on mount \u2192 offsets shift \u2192 another column mounts \u2192 \u2026).\n // - The result is cached by the stable `col.data` key and re-applied to\n // whatever index that key currently occupies, INCLUDING columns that are\n // not mounted. So `store.getColumnWidth(i)` answers for every `i`, and a\n // fitted width follows its column through a perspective reorder.\n //\n // Grow-only and idempotent: once a column is wide enough it produces no write,\n // so no write can trigger another pass. Skips columns the user resized by\n // hand. This effect is NOT subscribed to scroll and must never become so.\n useEffect(() => {\n const root = tableRef.current;\n if (!root) return;\n const raf = requestAnimationFrame(() => {\n const cache = badgeFitRef.current;\n root.querySelectorAll<HTMLElement>('td.hot-cell .cell-badge').forEach((badge) => {\n const td = badge.closest('td[data-col]') as HTMLElement | null;\n if (!td) return;\n const colIndex = parseInt(td.getAttribute('data-col') || '', 10);\n // Cache by the stable data key, never the index \u2014 a reorder must not\n // move one column's fitted width onto another.\n const key = cols[colIndex]?.data;\n if (!key) return;\n const hasComment = td.getAttribute('data-has-comment') === 'true';\n recordBadgeFit(cache, key, badgeFitWidth(badge.scrollWidth, hasComment));\n });\n // In stretch mode this raises the column's flex-basis + min-width\n // (Cell.tsx), so the badge column no longer shrinks below the badge;\n // in fixed mode it simply widens the column.\n planBadgeWidths(\n cache,\n cols,\n // The DECLARED width, never the painted one: the fill surplus is not\n // the column's own width, and comparing against it would let a badge\n // stay clipped the moment the container narrows and the surplus goes.\n (col) => store.getBaseColumnWidth(col),\n (col) => userResizedColsRef.current.has(col),\n ).forEach(({ col, width }) => store.setColumnWidth(col, width));\n });\n return () => cancelAnimationFrame(raf);\n }, [data, cols, store, tableRef, annotations]);\n\n // Colour-block adjacency (the `data-cb-{above,below,left,right}` attributes)\n // used to be discovered here by running `querySelectorAll` over the rendered\n // cells on every scroll event. That effect is GONE \u2014 anchor Defect 7. It read\n // facts about the data out of the DOM, so it was wrong for any neighbour\n // outside the virtualization window (a painted gap and a rounded corner in\n // the middle of a colour run, moving as you scroll) and it put a full-grid\n // DOM query on the scroll path. Adjacency is now computed in the model by\n // `utils/colorAdjacency.ts` and passed to `Cell` as props. Do not reinstate a\n // DOM scan; throttling one would not make it correct.\n\n // Scroll highlighted row into view when highlightedRowId changes.\n // Only scrolls if the row is not already visible.\n useEffect(() => {\n if (!highlightedRowId || !tableRef?.current) return;\n\n // Find the row index by ID\n const rowIndex = data.findIndex(row => row[idColumnName] === highlightedRowId);\n if (rowIndex === -1) return;\n\n // Use the virtualizer to scroll to this row\n // scrollToIndex brings the row into view with 'auto' behavior (minimal scroll)\n rowVirtualizer.scrollToIndex(rowIndex, { align: 'center', behavior: 'smooth' });\n }, [highlightedRowId, data, idColumnName, rowVirtualizer]);\n\n // Keyboard navigation is now handled via onKeyDown prop on the table container\n // This ensures React synthetic events fire before the handler, allowing editors to save first\n\n // Copy handler\n useEffect(() => {\n document.addEventListener('copy', handleCopy);\n return () => document.removeEventListener('copy', handleCopy);\n }, [handleCopy]);\n\n // Cut handler \u2014 the native `cut` event, not a Ctrl+X keybinding, so the\n // clipboard write is a user-gesture write the browser actually permits and\n // the OS-level Edit > Cut menu item works too.\n useEffect(() => {\n document.addEventListener('cut', handleCut);\n return () => document.removeEventListener('cut', handleCut);\n }, [handleCut]);\n\n // Paste handler \u2014 same document-level attachment as copy, and the handler\n // itself checks the event target is inside THIS table, so several grids on\n // one page never fight over a paste.\n useEffect(() => {\n document.addEventListener('paste', handlePaste);\n return () => document.removeEventListener('paste', handlePaste);\n }, [handlePaste]);\n\n // Global mouse up for drag end\n useEffect(() => {\n const handleGlobalMouseUp = () => {\n // Commit a fill that was released outside the table container. The\n // container's own onMouseUp commits first when released inside it, after\n // which fillStateRef is null and this is a no-op (no double-commit).\n if (fillStateRef.current) {\n commitFill();\n }\n if (dragStateRef.current.isDragging) {\n dragHandlers.handleDragEnd();\n }\n };\n\n document.addEventListener('mouseup', handleGlobalMouseUp);\n return () => document.removeEventListener('mouseup', handleGlobalMouseUp);\n }, [dragHandlers, commitFill]);\n\n // Click outside handler to clear selection.\n // When multiple DynamicTables coexist inside a dialog/drawer, clicking on\n // another table must clear THIS table's selection. Portal-rendered popups\n // (date pickers, dropdowns, context menus) are excluded so interacting with\n // them doesn't accidentally clear the selection.\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n\n // Click is inside our own table container \u2014 keep selection.\n if (tableRef?.current?.contains(target)) {\n return;\n }\n\n // Click is inside a Radix portal popup, context menu, or there's an active\n // editor popup anywhere in the DOM. For editor popups, we check existence\n // (not containment) because clicking OUTSIDE the popup to close it should\n // let the editor's own click-outside handler save the value first.\n if (target.closest('[data-radix-popper-content-wrapper]') ||\n target.closest('.hot-context-menu') ||\n target.closest('.context-menu') ||\n target.closest('.hot-comment-popover') ||\n document.querySelector('.hot-editor-popup')) {\n return;\n }\n\n // Click landed inside a modal dialog that does NOT contain this\n // table (e.g., delete confirmation overlay) \u2014 keep selection.\n // Drawers/Sheets also have `role=\"dialog\"` but they *contain* the\n // table, so clicks inside the same drawer still clear selection.\n if (isInsideExternalDialog(target)) {\n return;\n }\n\n // If there's an active editing cell, defer clearing so the editor's blur\n // handler has a chance to save the value first. mousedown fires before blur,\n // so without this delay the editor unmounts before onBlur can call onSave.\n const editingCell = store.getEditingCell();\n if (editingCell) {\n setTimeout(() => {\n store.clearEditing();\n clearSelectionAnimated();\n }, 0);\n } else {\n store.clearEditing();\n clearSelectionAnimated();\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [store, tableRef, isInsideExternalDialog, clearSelectionAnimated]);\n\n // Dispatch FILTER_CHANGE when filters change (backward compatibility)\n useEffect(() => {\n if (!tableRef?.current) return;\n dispatch<FilterChangeEvent>(\n tableRef.current,\n TableEvents.FILTER_CHANGE,\n { filters, savedFilterId: activePerspectiveId },\n );\n }, [filters, activePerspectiveId, tableRef]);\n\n /**\n * Dispatch PERSPECTIVE_CHANGE event whenever table configuration changes.\n * \n * PURPOSE:\n * Notifies parent components and event listeners when the table's perspective\n * settings change (filters, sorting, column visibility). This enables:\n * - Parent components to sync URL parameters with active filters\n * - External state management to track table configuration\n * - Analytics/logging of user interactions with the table\n * \n * IMPORTANT:\n * Parent components handling this event should be careful not to create infinite\n * loops. Common patterns:\n * - Extract only sorting changes: `if (payload.config.sorting) { ... }`\n * - Use refs to track initialization state before updating controlled props\n * - Avoid re-setting `activePerspectiveId` in response to this event unless\n * implementing specific logic like URL sync\n * \n * This event fires for ALL config changes, not just user interactions. It will\n * fire when:\n * - User adds/removes filters via UI\n * - User clicks column headers to sort\n * - User shows/hides columns\n * - Parent component applies a perspective via `activePerspectiveId` prop\n * (via the perspective sync effect above)\n * \n * See the `useDynamicTablePage` hook's PERSPECTIVE_CHANGE handling for an example of safe usage.\n */\n useEffect(() => {\n if (!tableRef?.current) return;\n dispatch<PerspectiveChangeEvent>(\n tableRef.current,\n TableEvents.PERSPECTIVE_CHANGE,\n {\n config: {\n columns: { visible: visibleColumns, hidden: hiddenColumns },\n filters,\n sorting: sortRules,\n grouping: groupRules,\n aggregations,\n lookupColumns,\n rollupColumns,\n formulas,\n conditionalFormats,\n dateFormat,\n viewMode,\n },\n },\n );\n }, [visibleColumns, hiddenColumns, filters, sortRules, groupRules, aggregations, lookupColumns, rollupColumns, formulas, conditionalFormats, dateFormat, viewMode, tableRef]);\n\n // -------------------- EVENT HANDLERS --------------------\n useEventHandlers({\n [TableEvents.CELL_SAVE_START]: (payload) => {\n store.setSaveState(payload.rowIndex, payload.colIndex, 'saving');\n },\n [TableEvents.CELL_SAVE_SUCCESS]: (payload) => {\n store.setSaveState(payload.rowIndex, payload.colIndex, 'success');\n setTimeout(() => store.setSaveState(payload.rowIndex, payload.colIndex, null), 2000);\n },\n [TableEvents.CELL_SAVE_ERROR]: (payload) => {\n store.setSaveState(payload.rowIndex, payload.colIndex, 'error');\n setTimeout(() => store.setSaveState(payload.rowIndex, payload.colIndex, null), 3000);\n },\n [TableEvents.NEW_ROW_SAVE_SUCCESS]: (payload) => {\n store.markRowAsSaved(payload.rowIndex, payload.savedRowData);\n },\n [TableEvents.NEW_ROW_SAVE_ERROR]: (payload) => {\n console.error('Failed to save new row:', payload.error);\n // Ledger 4.10 \u2014 \"Save silently does nothing\". The host flashes the reason,\n // but the GRID said nothing at all: the draft row sat there looking\n // identical to one that had never been submitted, so the only way to tell\n // a rejected create from a slow one was to reload. Paint the failure on\n // the row and put the caret back in the first cell, which is the field\n // every rejection so far has been about (an empty required name).\n if (store.isNewRow(payload.rowIndex)) {\n store.setSaveState(payload.rowIndex, 0, 'error');\n setTimeout(() => store.setSaveState(payload.rowIndex, 0, null), 3000);\n store.setEditingCell(payload.rowIndex, 0);\n }\n },\n }, tableRef);\n\n // -------------------- RENDER --------------------\n\n // Determine if we should fill available height\n const shouldFillHeight = height === '100%' || height === 'fill'\n const isViewportFill = height === 'fill'\n const outerContainerRef = useRef<HTMLDivElement>(null)\n const [fillHeight, setFillHeight] = useState<number | null>(null)\n\n // When height='fill', measure available viewport space and set explicit height.\n // This avoids relying on CSS flex chain from parent containers.\n useLayoutEffect(() => {\n if (!isViewportFill || isFullscreen) return\n const el = outerContainerRef.current\n if (!el) return\n // Find the nearest SCROLL-PANE ancestor (e.g. the app shell's scroll\n // container). Fill to ITS visible bottom, not the raw viewport \u2014 otherwise\n // the table runs under page chrome (app-shell footer) that lives below the\n // pane and the table's own footer ends up below the fold.\n let scrollPane: HTMLElement | null = el.parentElement\n while (scrollPane && scrollPane !== document.body) {\n const oy = getComputedStyle(scrollPane).overflowY\n if (oy === 'auto' || oy === 'scroll') break\n scrollPane = scrollPane.parentElement\n }\n const measure = () => {\n const rect = el.getBoundingClientRect()\n // Use the pane's CLIENT-area bottom (`top + clientHeight`), not\n // getBoundingClientRect().bottom: clientHeight is the stable laid-out\n // inner height and excludes transient content overflow, so the measure\n // doesn't overshoot while the flex layout is still settling.\n const paneBottom = scrollPane && scrollPane !== document.body\n ? Math.min(window.innerHeight, Math.round(scrollPane.getBoundingClientRect().top) + scrollPane.clientHeight)\n : window.innerHeight\n setFillHeight(Math.max(Math.floor(paneBottom - rect.top), 200))\n }\n measure()\n window.addEventListener('resize', measure)\n // Re-measure when the pane (or container) resizes \u2014 the app-shell panes\n // settle a few px after the first layout pass, which the one-shot measure\n // above would otherwise miss (leaving the footer a few px below the fold).\n const ro = new ResizeObserver(measure)\n if (scrollPane && scrollPane !== document.body) ro.observe(scrollPane)\n return () => {\n window.removeEventListener('resize', measure)\n ro.disconnect()\n }\n }, [isViewportFill, isFullscreen])\n\n // Table content shared between normal and fullscreen modes\n const tableContent = (\n <div\n ref={outerContainerRef}\n className={`hot-container ${shouldFillHeight ? 'flex flex-col flex-1' : ''}${borderless ? ' hot-borderless' : ''} hot-appearance-v2`}\n data-range-phase={rangePhase === 'idle' ? undefined : rangePhase}\n data-readonly-style={readOnlyStyle}\n data-density={density || undefined}\n {...densityAttribute}\n data-striped={striped ? 'true' : undefined}\n data-actions-scroll-shadow={actionsScrollShadow ? 'true' : undefined}\n data-firstcol-scroll-shadow={firstColScrollShadow ? 'true' : undefined}\n data-frozen-shadow={frozenColShadow ? 'true' : undefined}\n data-clickable-rows={onRowClick ? 'true' : undefined}\n data-row-hover-style={onRowClick ? rowHoverStyle : undefined}\n style={{\n height: isFullscreen ? '100%' : (isViewportFill && fillHeight ? fillHeight : (shouldFillHeight ? '100%' : height)),\n width: isFullscreen ? '100%' : width,\n position: 'relative',\n ...(shouldFillHeight && { minHeight: 0 }),\n }}\n >\n {/* Toolbar row 1 (Figma 220:2935): [title search] \u2026 [add actions expand].\n Title + search sit on the left; the add-row \"+\", the consumer slot\n (searchBarEnd, e.g. the page's primary button) and the fullscreen\n toggle are right-aligned on the SAME line. */}\n {/* Lead row: a custom `topBarStart` (e.g. category tabs) gets its own line\n ABOVE the title on full list pages (those with perspective tabs), so\n the title + search + buttons row stays uncluttered. Embedded sub-tables\n (no perspective tabs) keep topBarStart inline in the toolbar below. */}\n {!hideToolbar && topBarStart && !hidePerspectiveTabs && (\n <div className=\"hot-toolbar-lead-row\">{topBarStart}</div>\n )}\n\n {/* Card wrapper (v2): on full list pages the toolbar + perspective tabs +\n grid sit on a single white, rounded card floating on the page canvas;\n the lead row (category tabs) above stays OUTSIDE this card. Embedded\n sub-tables (no perspective tabs) use `display:contents` so the wrapper\n is inert and they keep rendering flush. */}\n <div className={hidePerspectiveTabs ? 'contents' : `hot-card${shouldFillHeight ? ' flex flex-col flex-1 min-h-0' : ''}`}>\n\n {!hideToolbar && (\n <div className=\"hot-toolbar\">\n {/* Custom slot: top bar start (inline only for embedded tables) */}\n {hidePerspectiveTabs && topBarStart}\n\n {!hideTitle && (\n <h3 className=\"hot-toolbar-title\">{displayTableName}</h3>\n )}\n\n {!hideSearch && (\n <SearchBar\n tableRef={tableRef}\n placeholder={searchPlaceholder ?? 'Search...'}\n debounceMs={searchDebounceMs}\n renderSuggestions={searchSuggestions}\n />\n )}\n\n {/* Spacer */}\n <div className=\"hot-toolbar-spacer\" />\n\n <div className=\"hot-toolbar-actions\">\n {/* A13 \u2014 WHICH filters are running, and the one-click way out of\n any single one of them. Rendered here, immediately before the\n clear-all, so the chips and their clear-all read as one group;\n it adds no toolbar row \u2014 the strip scrolls inside this one. */}\n <ActiveFilterChips\n filters={filters}\n columns={baseColumns}\n onRemove={(filterId) => handleFiltersChange(filters.filter((f) => f.id !== filterId))}\n />\n {/* The one place that answers \"am I actually seeing everything?\"\n for the whole grid, and the one-click way back to everything.\n These rules are TEMPORARY and are never written to the saved\n view (A2/D6). */}\n {filters.length > 0 && (\n <button\n type=\"button\"\n className=\"hot-clear-filters-btn\"\n onClick={() => handleFiltersChange([])}\n title={t(\n 'dynamicTable.quickFilter.clearAllHint',\n 'These filters are temporary and are not saved with the view',\n )}\n data-clear-all-filters=\"\"\n >\n <FunnelX className=\"w-3.5 h-3.5\" aria-hidden=\"true\" />\n <span className=\"text-body-regular-xs\">\n {t('dynamicTable.quickFilter.clearAll', 'Clear all filters ({count})', {\n count: filters.length,\n })}\n </span>\n </button>\n )}\n {/* A function gets the filter pair, so a header can narrow the\n table in BOTH view modes \u2014 see `SearchBarRenderContext`. */}\n {typeof searchBarStart === 'function'\n ? searchBarStart({ data, filters, setFilters: handleFiltersChange })\n : searchBarStart}\n {!hideAddRowButton && (\n <button\n onClick={handleAddRow}\n className=\"hot-add-row-btn\"\n title=\"Add new row\"\n >\n +\n </button>\n )}\n {searchBarEnd}\n {/* Export, row height and fullscreen are SECONDARY controls. Each\n one used to spend toolbar width on every table in the app,\n crowding the primary action a page actually cares about. They\n now sit behind one overflow button by default; a table that\n wants them one click away sets `expandToolbarActions`. */}\n {/* View switcher \u2014 list / grid. Sits with density, export and\n fullscreen because it is the same KIND of control: it changes\n how you are looking at the rows, not which rows you are looking\n at. Rendered ahead of the overflow menu so it is never buried:\n a mode you cannot see you are in is worse than no mode. */}\n {viewModes && viewModes.length > 1 && (\n <ViewModeSwitch\n options={viewModes}\n value={viewMode}\n onChange={handleViewModeChange}\n />\n )}\n {expandToolbarActions ? (\n <>\n {!hideExportButton && (\n <ExportMenu variant=\"toolbar\" onExport={handleExportAll} disabled={isExportingAll} />\n )}\n {!hideDensityControl && <DensityControl variant=\"toolbar\" tableKey={tableId} />}\n {enableFullscreen && !isFullscreen && (\n <button onClick={handleEnterFullscreen} className=\"fullscreen-toggle-btn\" title=\"Enter fullscreen\">\n <Maximize2 className=\"w-4 h-4\" />\n </button>\n )}\n </>\n ) : (\n <ToolbarOverflow\n onExport={hideExportButton ? undefined : handleExportAll}\n exportDisabled={isExportingAll}\n showDensity={!hideDensityControl}\n densityTableKey={tableId}\n onFullscreen={enableFullscreen && !isFullscreen ? handleEnterFullscreen : undefined}\n extras={toolbarOverflowExtras}\n />\n )}\n </div>\n\n {/* Custom slot: top bar end */}\n {topBarEnd}\n </div>\n )}\n\n {/* Toolbar row 2 (Figma 220:2935): [perspective tabs] \u2026 [pagination].\n Pagination is right-aligned on the tabs line (no bottom footer). */}\n {(!hidePerspectiveTabs || (pagination && !hidePagination)) && (\n <div className=\"hot-tabs-row\">\n {!hidePerspectiveTabs && (\n <PerspectiveTabs\n savedPerspectives={savedPerspectives}\n activePerspectiveId={activePerspectiveId}\n onPerspectiveSelect={handlePerspectiveSelect}\n onPerspectiveRename={handlePerspectiveRename}\n onPerspectiveDelete={handlePerspectiveDelete}\n onPerspectiveDuplicate={handlePerspectiveDuplicate}\n onPerspectiveSetDefault={handlePerspectiveSetDefault}\n defaultPerspectiveId={defaultPerspectiveId}\n sharedTemplates={sharedTemplates}\n publishableRoles={canPublishTemplates ? publishableRoles : undefined}\n onPerspectivePublish={canPublishTemplates ? handlePerspectivePublish : undefined}\n onPerspectiveTemplateCopy={handlePerspectiveTemplateCopy}\n onPerspectiveEdit={(id) => {\n // Load the perspective's config into the working state, then open\n // the panel pre-populated for editing. Saving with the same name\n // updates it in place (save upserts by name).\n handlePerspectiveSelect(id);\n setEditingPerspectiveId(id);\n setConfigureBaseView(false);\n setConfigPanelInitialSection(null);\n setConfigPanelOpen(true);\n }}\n onConfigureBaseView={() => {\n // Configure the BASE tab, not a new view: the drawer's Save\n // then personalizes \"Default view\" for this user instead of\n // demanding a name for something they already have.\n setEditingPerspectiveId(null);\n setConfigureBaseView(true);\n setConfigPanelInitialSection(null);\n setConfigPanelOpen(true);\n }}\n onBaseViewReset={handleBaseViewReset}\n onAddPerspective={() => { setEditingPerspectiveId(null); setConfigureBaseView(false); setConfigPanelInitialSection(null); setConfigPanelOpen(true); }}\n />\n )}\n <div className=\"hot-tabs-row-spacer\" />\n {pagination && !hidePagination && (\n <TablePagination pagination={pagination} />\n )}\n </div>\n )}\n\n {/* HEDGE-165 \u2014 the failed load that still has rows to show.\n `LoadErrorState` below is gated on `rowCount === 0`, so until this bar\n existed `loadError === true && rowCount > 0` rendered NOTHING: the\n rows `placeholderData` is holding stayed on screen with no indication\n that they answer the previous request rather than the current one.\n Sits above the column headers so it is visible wherever the body is\n scrolled to. Mounted only in that state \u2014 nothing on the healthy path\n moves, and no table pays for a permanently-mounted live region. */}\n {loadError && rowCount > 0 && (\n <StaleDataBar tableName={tableName} onRetry={onRetryLoad} />\n )}\n\n {/* Grouped-actions bar \u2014 shown whenever \u22651 row is selected (Figma 546:12289).\n Sits between the perspective tabs and the column headers. Kept mounted\n (not conditionally rendered) so it can animate open/closed via the\n grid-rows collapse on the wrapper \u2014 avoids the hard layout shift.\n `bulkBarCountRef` freezes the last visible count so the text doesn't\n flash \"0 selected\" mid-collapse. */}\n {selectable && (() => {\n const bulkBarOpen = selectedRowIds.size >= 1;\n if (bulkBarOpen) bulkBarCountRef.current = selectedRowIds.size;\n return (\n <div\n className={`hot-bulk-bar-wrap${bulkBarOpen ? ' is-open' : ''}`}\n aria-hidden={!bulkBarOpen}\n >\n <div className=\"hot-bulk-bar-inner\">\n <BulkActionsBar\n count={bulkBarOpen ? selectedRowIds.size : bulkBarCountRef.current}\n busy={isBulkDeleting}\n onCopy={handleBulkCopy}\n onDelete={onBulkDelete ? handleBulkDelete : undefined}\n onExport={hideExportButton ? undefined : handleExportSelection}\n onClear={clearSelection}\n actions={bulkActions}\n selectedIds={Array.from(selectedRowIds)}\n />\n </div>\n </div>\n );\n })()}\n\n {/* A full-width band between the toolbar and the body \u2014 the folder row\n in the documents module. Rendered for BOTH view modes. */}\n {beforeBody ? (\n <div className=\"hot-before-body\">\n {typeof beforeBody === 'function'\n ? beforeBody({ data, filters, setFilters: handleFiltersChange })\n : beforeBody}\n </div>\n ) : null}\n\n {/* Table Container */}\n <div\n ref={tableRef}\n /* The spreadsheet container is focusable so it can receive Escape and\n the arrow keys. A tile grid's tiles are the focusable things. */\n tabIndex={usingCustomBody ? undefined : 0}\n data-fill-enabled={!usingCustomBody && enableFillHandle ? 'true' : undefined}\n /* P5 \u2014 the density guardrail. The perf harness reads these when\n present and falls back to counting mounted <th>s when they are\n absent, so WITHOUT them a successful column virtualization reports\n as a \"57 \u2192 21 column loss\", i.e. exactly the regression the product\n owner forbade. They must never be derived from the mounted window. */\n data-dt-columns={cols.length}\n data-dt-rows={data.length}\n data-column-window={`${columnVirtualizer.startIndex}:${columnVirtualizer.endIndex}`}\n data-column-virtualized={columnVirtualizer.virtualized ? 'true' : undefined}\n /* aria-colcount counts ALL columns, never the mounted subset \u2014 a grid\n whose rendered cells are a subset is required to declare it, which is\n what makes the per-cell aria-colindex meaningful. */\n /* An alternative body is not a grid of cells. Announcing one \u2014 with a\n column count and a row count that address nothing on screen \u2014 is\n worse than announcing nothing. */\n role={usingCustomBody ? 'presentation' : 'grid'}\n aria-colcount={usingCustomBody ? undefined : columnVirtualizer.ariaColCount}\n aria-rowcount={usingCustomBody ? undefined : virtualizerCount}\n className={`hot-virtual-container ${shouldFillHeight ? 'flex-1' : ''}${usingCustomBody ? ' hot-custom-body' : ''}`}\n onFocus={usingCustomBody ? undefined : handleFocus}\n onBlur={usingCustomBody ? undefined : handleBlur}\n onClick={usingCustomBody ? undefined : (e) => {\n handleTableClick(e);\n }}\n onMouseDown={usingCustomBody ? undefined : (e) => {\n // Skip normal mouse handlers on group header rows\n if ((e.target as HTMLElement).closest('tr[data-group-header]')) return;\n // Comment handler runs first \u2014 if it opens the dialog, skip normal mousedown\n if (handleCommentMouseDown(e)) return;\n // Fill handle: a drag starting on the corner nub fills instead of\n // selecting. Leaves the source selection intact; skips normal mousedown.\n if (handleFillMouseDown(e)) return;\n // A new drag starts here: drop any committed outline + selection menu so\n // the dotted border only re-appears once THIS drag finishes.\n if (rangePhaseRef.current !== 'idle') applyRangePhase('idle');\n setContextMenu(null);\n handleMouseDown(e);\n // Focus the table container so it can receive keyboard events (e.g., Escape)\n // But not when clicking inside the currently editing cell \u2014 that would steal\n // focus from the editor input, killing the edit session.\n const editingCell = store.getEditingCell();\n if (editingCell) {\n const cell = (e.target as HTMLElement).closest('td');\n const clickRow = parseInt(cell?.getAttribute('data-row') || '', 10);\n const clickCol = parseInt(cell?.getAttribute('data-col') || '', 10);\n if (clickRow === editingCell.row && clickCol === editingCell.col) {\n return;\n }\n }\n // preventScroll: focusing this tabIndex=0 scroll container would\n // otherwise make the browser scroll it fully into view. When the\n // table sits partly below the fold (e.g. a banner above it pushing\n // it down), that scroll fires on the first mousedown and shifts the\n // page out from under the cursor \u2014 so the click misses its target\n // and the user has to click a second time. See cross-table focus\n // forwarding which already relies on explicit scroll control.\n tableRef.current?.focus({ preventScroll: true });\n }}\n onMouseMove={usingCustomBody ? undefined : (e) => {\n if (fillStateRef.current) { handleFillMouseMove(e); return; }\n handleMouseMove(e);\n }}\n onMouseUp={usingCustomBody ? undefined : () => {\n if (fillStateRef.current) { commitFill(); return; }\n handleMouseUpWithMenu();\n }}\n onMouseOver={usingCustomBody ? undefined : (e) => { handleCellHoverOver(e); handleCommentHoverOver(e); }}\n onMouseOut={usingCustomBody ? undefined : handleCommentHoverOut}\n onMouseLeave={usingCustomBody ? undefined : () => store.setHoveredCell(null)}\n onDoubleClick={usingCustomBody ? undefined : handleDoubleClick}\n onKeyDown={usingCustomBody ? undefined : handleKeyDown}\n style={{\n height: isFullscreen ? 'calc(100% - 90px)' : (shouldFillHeight ? undefined : (typeof height === 'string' && height !== 'auto' ? height : '600px')),\n overflow: 'auto',\n position: 'relative',\n outline: 'none',\n ...(shouldFillHeight && { minHeight: 0 }),\n }}\n >\n {usingCustomBody ? (\n renderBody!({\n data,\n columns: cols,\n visualRows: groupingResult.visualRows,\n groupRules,\n collapsedGroups: groupingResult.collapsedGroups,\n toggleGroup: groupingResult.toggleGroup,\n selectedRowIds,\n rowKeyColumn: selectionColumnName,\n selectable,\n toggleRowSelect: handleToggleRowSelect,\n toggleGroupSelect: handleToggleGroupSelect,\n clearSelection,\n searchQuery,\n filters,\n setFilters: handleFiltersChange,\n filterCount: filters.length,\n clearSearch: handleClearSearch,\n clearFilters: handleFiltersChange ? () => handleFiltersChange([]) : undefined,\n })\n ) : (\n <>\n {/* Column Headers */}\n {colHeaders && (\n <ColumnHeaders\n columns={cols}\n rowHeaders={rowHeaders}\n leftOffsets={effectiveLeftOffsets}\n rightOffsets={rightOffsets}\n totalWidth={totalWidth}\n sortState={sortState}\n actionsColumnWidth={actionsColumnWidth}\n showActionsColumn={showActionsColumn}\n onSort={handleColumnSort}\n onResizeStart={(e, colIndex) => { userResizedColsRef.current.add(colIndex); handleResizeStart(e, colIndex); }}\n onDoubleClick={handleColumnHeaderDoubleClick}\n onMouseDown={(e) => handleColumnHeaderMouseDown(e, dragHandlers.handleDragStart)}\n onMouseMove={handleMouseMove}\n modernLayout={!disableBuiltinColumnMenu}\n onSortAsc={handleModernSortAsc}\n onSortDesc={handleModernSortDesc}\n onFilterByField={handleModernFilterByField}\n /* A1 \u2014 the header quick filter writes straight into the same\n ephemeral `filters` state the Configure View drawer edits.\n Nothing extra persists it, which is the A2/D6 guarantee. */\n filters={filters}\n onFiltersChange={handleFiltersChange}\n loadFilterSuggestions={loadFilterSuggestions}\n onFreezeToggle={handleModernFreezeToggle}\n onHideField={handleModernHideField}\n /* A16 \u2014 reorder from the header itself, not only from the\n Configure View drawer. Per-user, like every other view\n preference. */\n onColumnReorder={handleColumnReorder}\n onColumnMove={handleColumnMove}\n frozenColumns={frozenColumns}\n lastFrozenColumnKey={lastFrozenColumnKey}\n columnActions={columnActions}\n onColumnAction={handleModernColumnAction}\n selectable={selectable}\n allSelected={allSelected}\n someSelected={someSelected}\n onToggleSelectAll={handleToggleSelectAll}\n columnWindow={columnVirtualizer}\n />\n )}\n\n {/* Virtual Body */}\n <table className=\"hot-table\" style={{ width: `${totalWidth}px` }}>\n <tbody\n style={{\n display: 'block',\n height: `${rowVirtualizer.getTotalSize()}px`,\n position: 'relative',\n }}\n >\n {virtualRows.map((virtualItem) => {\n // When grouped, dispatch between GroupHeaderRow and VirtualRow\n if (isGrouped) {\n const vr = groupingResult.visualRows![virtualItem.index];\n if (vr.type === 'groupHeader') {\n const groupRowIds = vr.memberDataIndices\n .map((idx) => {\n const r = data[idx];\n return r == null ? undefined : r[selectionColumnName];\n })\n .filter((id) => id != null)\n .map((id) => String(id));\n const groupSelected = groupRowIds.length > 0 && groupRowIds.every((id) => selectedRowIds.has(id));\n const groupSomeSelected = !groupSelected && groupRowIds.some((id) => selectedRowIds.has(id));\n return (\n <GroupHeaderRow\n key={`gh-${vr.groupKey}`}\n visualRow={vr}\n virtualItem={virtualItem}\n totalWidth={totalWidth}\n columns={cols}\n onToggle={groupingResult.toggleGroup}\n selectable={selectable}\n selected={groupSelected}\n someSelected={groupSomeSelected}\n onToggleSelect={() => handleToggleGroupSelect(groupRowIds)}\n formatGroupValue={formatGroupValue}\n />\n );\n }\n if (vr.type === 'groupSummary') {\n return (\n <GroupSummaryRow\n key={`gs-${vr.groupKey}`}\n visualRow={vr}\n virtualItem={virtualItem}\n columns={cols}\n rowHeaders={rowHeaders}\n leftOffsets={effectiveLeftOffsets}\n rightOffsets={rightOffsets}\n actionsColumnWidth={actionsColumnWidth}\n showActionsColumn={showActionsColumn}\n totalWidth={totalWidth}\n aggregations={aggregations}\n label={t('dynamicTable.aggregation.summaryRowLabel', 'Sum')}\n locale={locale}\n storeRevision={storeRevision}\n columnWindow={columnVirtualizer}\n />\n );\n }\n // dataRow \u2014 use dataIndex for the store\n return (\n <VirtualRow\n key={`dr-${vr.dataIndex}`}\n rowIndex={vr.dataIndex}\n columns={cols}\n virtualRow={virtualItem}\n rowHeaders={rowHeaders}\n leftOffsets={effectiveLeftOffsets}\n lastFrozenColumnKey={lastFrozenColumnKey}\n rightOffsets={rightOffsets}\n actionsColumnWidth={actionsColumnWidth}\n showActionsColumn={showActionsColumn}\n totalWidth={totalWidth}\n storeRevision={storeRevision}\n onSaveNewRow={handleSaveNewRow}\n onCancelNewRow={handleCancelNewRow}\n onRowHeaderDoubleClick={handleRowHeaderDoubleClick}\n onCellSave={handleCellSave}\n onCellContextMenu={handleCellContextMenu}\n actionsRenderer={actionsRenderer}\n showRowActionsMenu={showRowActionsMenu}\n rowActions={rowActions}\n onRowActionsMenu={handleRowActionsMenu}\n highlightedRowId={highlightedRowId}\n idColumnName={idColumnName}\n rowKeyColumn={selectionColumnName}\n annotations={enableComments ? annotations : undefined}\n commentsEnabled={enableComments && !!commentsEntityType}\n annotationKeyAt={enableComments ? cellAnnotationKeyAt : undefined}\n selectable={selectable}\n selectedRowIds={selectedRowIds}\n onToggleRowSelect={handleToggleRowSelect}\n compiledFormats={compiledFormats}\n columnWindow={columnVirtualizer}\n />\n );\n }\n\n // Not grouped \u2014 standard rendering\n return (\n <VirtualRow\n key={virtualItem.index}\n rowIndex={virtualItem.index}\n columns={cols}\n virtualRow={virtualItem}\n rowHeaders={rowHeaders}\n leftOffsets={effectiveLeftOffsets}\n lastFrozenColumnKey={lastFrozenColumnKey}\n rightOffsets={rightOffsets}\n actionsColumnWidth={actionsColumnWidth}\n showActionsColumn={showActionsColumn}\n totalWidth={totalWidth}\n storeRevision={storeRevision}\n onSaveNewRow={handleSaveNewRow}\n onCancelNewRow={handleCancelNewRow}\n onRowHeaderDoubleClick={handleRowHeaderDoubleClick}\n onCellSave={handleCellSave}\n onCellContextMenu={handleCellContextMenu}\n actionsRenderer={actionsRenderer}\n showRowActionsMenu={showRowActionsMenu}\n rowActions={rowActions}\n onRowActionsMenu={handleRowActionsMenu}\n highlightedRowId={highlightedRowId}\n idColumnName={idColumnName}\n rowKeyColumn={selectionColumnName}\n annotations={enableComments ? annotations : undefined}\n commentsEnabled={enableComments && !!commentsEntityType}\n annotationKeyAt={enableComments ? cellAnnotationKeyAt : undefined}\n selectable={selectable}\n selectedRowIds={selectedRowIds}\n onToggleRowSelect={handleToggleRowSelect}\n compiledFormats={compiledFormats}\n columnWindow={columnVirtualizer}\n />\n );\n })}\n </tbody>\n </table>\n\n {/* Ledger 2.20 \u2014 the zero-result state.\n A search that matches nothing used to leave the header row and\n several hundred pixels of nothing: no message, no icon, and no\n way back other than finding the search box again and emptying it\n by hand. The headers STAY (they are the context that tells you\n which table you emptied); the panel sits under them, says which\n of the three reasons applies, and offers the undo for that\n reason. */}\n {/* HEDGE-119 \u2014 a FAILED load is not an empty table.\n `loadError` wins over `EmptyState` because both arrive here as\n `rowCount === 0`: a rejected query leaves `data` undefined and\n the grid holds zero rows either way. Deciding by row count\n alone is what made a 500 read as \"Nothing here yet\". */}\n {rowCount === 0 && (loadError\n ? <LoadErrorState tableName={tableName} onRetry={onRetryLoad} />\n : <EmptyState\n emptyMessage={emptyMessage}\n searchQuery={searchQuery}\n filterCount={filters.length}\n onClearSearch={handleClearSearch}\n onClearFilters={handleFiltersChange ? () => handleFiltersChange([]) : undefined}\n />)}\n\n {/* Pinned totals. Rendered OUTSIDE the virtualiser deliberately: a\n row inside the rows container scrolls away with them, and a\n footer that scrolls away is not a footer. It is sticky to the\n bottom of this scroller exactly as the header is to the top. */}\n {aggregations.length > 0 && (\n <FooterTotalsRow\n columns={cols}\n aggregations={aggregations}\n result={aggregateResult}\n pageValues={pageAggregateValues}\n pageBreakdowns={pageAggregateBreakdowns}\n pageRowCount={data.length}\n loading={aggregateLoading}\n error={aggregateError}\n getColumnWidth={getColumnWidth}\n rowHeaders={rowHeaders}\n leftOffsets={effectiveLeftOffsets}\n rightOffsets={rightOffsets}\n actionsColumnWidth={actionsColumnWidth}\n showActionsColumn={showActionsColumn}\n totalWidth={totalWidth}\n locale={locale}\n columnWindow={columnVirtualizer}\n />\n )}\n </>\n )}\n </div>\n\n </div>{/* /hot-card */}\n\n {/* Configure View Side Panel */}\n {(\n <ConfigureViewPanel\n isOpen={configPanelOpen}\n onOpenChange={setConfigPanelOpen}\n columns={baseColumns}\n visibleColumns={visibleColumns}\n hiddenColumns={hiddenColumns}\n filters={filters}\n sortRules={sortRules}\n groupRules={groupRules}\n aggregations={aggregations}\n lookupColumns={lookupColumns}\n rollupColumns={rollupColumns}\n formulas={formulas}\n conditionalFormats={conditionalFormats}\n sampleRow={data[0]}\n dateFormat={dateFormat}\n viewMode={viewMode}\n dateFormatOptions={dateFormatOptions}\n onColumnVisibilityChange={handleColumnVisibilityChange}\n onFiltersChange={handleFiltersChange}\n onSortRulesChange={handleSortRulesChange}\n onGroupRulesChange={handleGroupRulesChange}\n onAggregationsChange={handleAggregationsChange}\n onLookupColumnsChange={handleLookupColumnsChange}\n onRollupColumnsChange={handleRollupColumnsChange}\n onFormulasChange={handleFormulasChange}\n onConditionalFormatsChange={handleConditionalFormatsChange}\n onDateFormatChange={handleDateFormatChange}\n onSavePerspective={handleSavePerspective}\n activePerspectiveId={activePerspectiveId}\n editingPerspective={savedPerspectives.find((p) => p.id === editingPerspectiveId) ?? null}\n baseViewPerspective={baseViewPerspective}\n isBaseViewMode={configureBaseView}\n loadFilterSuggestions={loadFilterSuggestions}\n loadLookupSources={loadLookupSources}\n loadRollupSources={loadRollupSources}\n initialExpandedSection={configPanelInitialSection}\n />\n )}\n\n {/* Large-write confirmation \u2014 every written cell triggers a persist\n request, so the same dialog guards a big fill, paste, cut and clear.\n The title names the gesture: \"Fill cells?\" on a Delete would read as\n the wrong operation about to run. */}\n <Dialog open={!!pendingWrite} onOpenChange={(open) => { if (!open) cancelPendingWrite(); }}>\n <DialogContent className=\"hot-dialog\">\n <DialogHeader>\n <DialogTitle>\n {pendingWrite?.origin === 'paste'\n ? t('dynamicTable.paste.confirmTitle', 'Paste into these cells?')\n : pendingWrite?.origin === 'cut'\n ? t('dynamicTable.cut.confirmTitle', 'Cut these cells?')\n : pendingWrite?.origin === 'clear'\n ? t('dynamicTable.clear.confirmTitle', 'Clear these cells?')\n : t('dynamicTable.fill.confirmTitle', 'Fill cells?')}\n </DialogTitle>\n <DialogDescription>\n {t('dynamicTable.write.confirmBody', 'This will overwrite {count} cells.', {\n count: pendingWrite?.writes.length ?? 0,\n })}\n </DialogDescription>\n </DialogHeader>\n <DialogFooter>\n <Button variant=\"outline\" onClick={cancelPendingWrite}>{t('dynamicTable.fill.cancel', 'Cancel')}</Button>\n <Button onClick={confirmPendingWrite}>\n {pendingWrite?.origin === 'paste'\n ? t('dynamicTable.paste.confirm', 'Paste')\n : pendingWrite?.origin === 'cut'\n ? t('dynamicTable.cut.confirm', 'Cut')\n : pendingWrite?.origin === 'clear'\n ? t('dynamicTable.clear.confirm', 'Clear')\n : t('dynamicTable.fill.confirm', 'Fill')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {/* Cell Comment Dialog */}\n {enableComments && commentsEntityType && commentDialog && (\n <CellCommentDialog\n isOpen={true}\n onClose={handleCommentDialogClose}\n /* Resolved when the dialog was opened, from the cell that opened it. */\n entityType={commentDialog.entityType}\n viewContext={commentsViewContext}\n rowId={commentDialog.rowId}\n columnKey={commentDialog.columnKey}\n columnTitle={commentDialog.columnTitle}\n rowLabel={commentDialog.rowLabel}\n annotationId={commentDialog.annotationId}\n currentColor={commentDialog.currentColor}\n onAnnotationChange={() => { refreshAnnotations(); onAnnotationChange?.(); }}\n anchorRect={commentDialog.anchorRect}\n bulkCells={commentDialog.bulkCells}\n />\n )}\n\n {/* Cell Comment hover preview (read-only) \u2014 suppressed while the editable\n dialog is open. */}\n {enableComments && commentsEntityType && commentHover && !commentDialog && (\n <CellCommentHoverPopup\n comments={commentHover.comments}\n columnTitle={commentHover.columnTitle}\n anchorRect={commentHover.anchorRect}\n />\n )}\n\n {/* Context Menu */}\n {contextMenu && (\n <ContextMenu\n isOpen={contextMenu.isOpen}\n position={contextMenu.position}\n actions={contextMenu.actions}\n onClose={handleContextMenuClose}\n onActionClick={handleMenuActionClick}\n />\n )}\n\n {/* Debugger */}\n {debug && <Debugger tableRef={tableRef} />}\n </div>\n );\n\n return (\n <TableDateFormatContext.Provider value={dateFormat}>\n <CellStoreContext.Provider value={store}>\n {isFullscreen ? (\n <FullscreenOverlay\n isOpen={isFullscreen}\n onClose={handleExitFullscreen}\n tableName={displayTableName}\n >\n {tableContent}\n </FullscreenOverlay>\n ) : (\n tableContent\n )}\n </CellStoreContext.Provider>\n </TableDateFormatContext.Provider>\n );\n};\n\nexport default DynamicTable;\n"],
5
+ "mappings": "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",
6
+ "names": ["rowCount", "width", "writes"]
7
+ }