@burdenoff/microfe-bigconsole 2026.805.3 → 2026.812.2

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 (247) hide show
  1. package/dist/bigconsole/components/DrilldownDashboardRenderer.js +118 -106
  2. package/dist/bigconsole/components/DrilldownDashboardRenderer.js.map +1 -1
  3. package/dist/bigconsole/components/DrilldownModal.js +54 -50
  4. package/dist/bigconsole/components/DrilldownModal.js.map +1 -1
  5. package/dist/bigconsole/components/builder/BuilderCanvas.js +2 -2
  6. package/dist/bigconsole/components/builder/BuilderCanvas.js.map +1 -1
  7. package/dist/bigconsole/components/builder/BuilderTopbar.js +3 -3
  8. package/dist/bigconsole/components/builder/BuilderTopbar.js.map +1 -1
  9. package/dist/bigconsole/components/builder/inspector/AdvancedSection.js +24 -25
  10. package/dist/bigconsole/components/builder/inspector/AdvancedSection.js.map +1 -1
  11. package/dist/bigconsole/components/builder/inspector/AppearanceSection.js +40 -29
  12. package/dist/bigconsole/components/builder/inspector/AppearanceSection.js.map +1 -1
  13. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +135 -97
  14. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js.map +1 -1
  15. package/dist/bigconsole/components/builder/inspector/GeneralSection.js +58 -44
  16. package/dist/bigconsole/components/builder/inspector/GeneralSection.js.map +1 -1
  17. package/dist/bigconsole/components/common/Section.js +70 -0
  18. package/dist/bigconsole/components/common/Section.js.map +1 -0
  19. package/dist/bigconsole/components/common/index.js +2 -0
  20. package/dist/bigconsole/components/common/sectionStyles.js +42 -0
  21. package/dist/bigconsole/components/common/sectionStyles.js.map +1 -0
  22. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +209 -193
  23. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
  24. package/dist/bigconsole/components/dashboard/DashboardCanvas.js +213 -231
  25. package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
  26. package/dist/bigconsole/components/dashboard/DashboardGrid.js +12 -18
  27. package/dist/bigconsole/components/dashboard/DashboardGrid.js.map +1 -1
  28. package/dist/bigconsole/components/dashboard/DashboardToolbar.js +109 -102
  29. package/dist/bigconsole/components/dashboard/DashboardToolbar.js.map +1 -1
  30. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +81 -70
  31. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js.map +1 -1
  32. package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js +125 -159
  33. package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js.map +1 -1
  34. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +25 -23
  35. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js.map +1 -1
  36. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +3 -3
  37. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js.map +1 -1
  38. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +5 -3
  39. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js.map +1 -1
  40. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +170 -284
  41. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js.map +1 -1
  42. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +147 -151
  43. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
  44. package/dist/bigconsole/components/dashboard/LiveBoardBanner.js +45 -53
  45. package/dist/bigconsole/components/dashboard/LiveBoardBanner.js.map +1 -1
  46. package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js +157 -148
  47. package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js.map +1 -1
  48. package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +17 -8
  49. package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js.map +1 -1
  50. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js +101 -95
  51. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js.map +1 -1
  52. package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js +20 -18
  53. package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js.map +1 -1
  54. package/dist/bigconsole/components/dashboard/TemplateSetupBanner.js +26 -58
  55. package/dist/bigconsole/components/dashboard/TemplateSetupBanner.js.map +1 -1
  56. package/dist/bigconsole/components/dashboard/WidgetPalette.js +307 -231
  57. package/dist/bigconsole/components/dashboard/WidgetPalette.js.map +1 -1
  58. package/dist/bigconsole/components/datasink/CacheTTLSelector.js +29 -29
  59. package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
  60. package/dist/bigconsole/components/datasink/DataSinkCard.js +78 -79
  61. package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
  62. package/dist/bigconsole/components/datasink/DataSinkDataViewer.js +33 -34
  63. package/dist/bigconsole/components/datasink/DataSinkDataViewer.js.map +1 -1
  64. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +79 -56
  65. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js.map +1 -1
  66. package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +75 -65
  67. package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js.map +1 -1
  68. package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js +1 -1
  69. package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js.map +1 -1
  70. package/dist/bigconsole/components/datasink/DataSinkTableViewer.js +20 -19
  71. package/dist/bigconsole/components/datasink/DataSinkTableViewer.js.map +1 -1
  72. package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js +127 -171
  73. package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js.map +1 -1
  74. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +263 -243
  75. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
  76. package/dist/bigconsole/components/datasink/LinkedParsersPanel.js +65 -66
  77. package/dist/bigconsole/components/datasink/LinkedParsersPanel.js.map +1 -1
  78. package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js +121 -127
  79. package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js.map +1 -1
  80. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +33 -26
  81. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js.map +1 -1
  82. package/dist/bigconsole/components/datasink/SetupStateBadge.js +3 -3
  83. package/dist/bigconsole/components/datasink/SetupStateBadge.js.map +1 -1
  84. package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js +95 -95
  85. package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js.map +1 -1
  86. package/dist/bigconsole/components/parser/DataSinkSelector.js +154 -123
  87. package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
  88. package/dist/bigconsole/components/parser/ExpressionEditor.js +3 -3
  89. package/dist/bigconsole/components/parser/ExpressionEditor.js.map +1 -1
  90. package/dist/bigconsole/components/parser/ImportParserDialog.js +235 -275
  91. package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
  92. package/dist/bigconsole/components/parser/ParserCard.js +133 -114
  93. package/dist/bigconsole/components/parser/ParserCard.js.map +1 -1
  94. package/dist/bigconsole/components/parser/ParserSelector.js +191 -174
  95. package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
  96. package/dist/bigconsole/components/parser/ParserStatusBadge.js +2 -2
  97. package/dist/bigconsole/components/parser/ParserStatusBadge.js.map +1 -1
  98. package/dist/bigconsole/components/parser/ParserTypeBadge.js +4 -4
  99. package/dist/bigconsole/components/parser/ParserTypeBadge.js.map +1 -1
  100. package/dist/bigconsole/components/pipeline/PipelineCard.js +134 -89
  101. package/dist/bigconsole/components/pipeline/PipelineCard.js.map +1 -1
  102. package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js +77 -64
  103. package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js.map +1 -1
  104. package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js +7 -10
  105. package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js.map +1 -1
  106. package/dist/bigconsole/components/preview/AiPreviewContent.js +31 -32
  107. package/dist/bigconsole/components/preview/AiPreviewContent.js.map +1 -1
  108. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +152 -106
  109. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js.map +1 -1
  110. package/dist/bigconsole/components/preview/AiPreviewPanel.js +193 -152
  111. package/dist/bigconsole/components/preview/AiPreviewPanel.js.map +1 -1
  112. package/dist/bigconsole/components/preview/previewShared.js +41 -23
  113. package/dist/bigconsole/components/preview/previewShared.js.map +1 -1
  114. package/dist/bigconsole/components/widgets/ActionConfigDialog.js +342 -308
  115. package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
  116. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +262 -238
  117. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
  118. package/dist/bigconsole/components/widgets/PropertiesPanel.js +783 -867
  119. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  120. package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js +7 -5
  121. package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js.map +1 -1
  122. package/dist/bigconsole/components/widgets/WidgetHeader.js +7 -8
  123. package/dist/bigconsole/components/widgets/WidgetHeader.js.map +1 -1
  124. package/dist/bigconsole/components/widgets/WidgetRegistry.js +4 -4
  125. package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
  126. package/dist/bigconsole/components/widgets/WidgetWrapper.js +8 -7
  127. package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
  128. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js +1 -1
  129. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js.map +1 -1
  130. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +2 -2
  131. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
  132. package/dist/bigconsole/components/widgets/chart/ChartConfig.js +11 -5
  133. package/dist/bigconsole/components/widgets/chart/ChartConfig.js.map +1 -1
  134. package/dist/bigconsole/components/widgets/comments/WidgetComments.js +19 -15
  135. package/dist/bigconsole/components/widgets/comments/WidgetComments.js.map +1 -1
  136. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +154 -102
  137. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
  138. package/dist/bigconsole/components/widgets/gauge/CircularGauge.js +36 -32
  139. package/dist/bigconsole/components/widgets/gauge/CircularGauge.js.map +1 -1
  140. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +85 -60
  141. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
  142. package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js +64 -35
  143. package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js.map +1 -1
  144. package/dist/bigconsole/components/widgets/gauge/LinearGauge.js +46 -45
  145. package/dist/bigconsole/components/widgets/gauge/LinearGauge.js.map +1 -1
  146. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +35 -24
  147. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js.map +1 -1
  148. package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js +2 -2
  149. package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js.map +1 -1
  150. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +4 -4
  151. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
  152. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +153 -90
  153. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
  154. package/dist/bigconsole/components/widgets/list/ListConfig.js +8 -2
  155. package/dist/bigconsole/components/widgets/list/ListConfig.js.map +1 -1
  156. package/dist/bigconsole/components/widgets/list/ListItem.js +1 -1
  157. package/dist/bigconsole/components/widgets/list/ListItem.js.map +1 -1
  158. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +1 -1
  159. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js.map +1 -1
  160. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +14 -4
  161. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js.map +1 -1
  162. package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +112 -89
  163. package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
  164. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +21 -13
  165. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
  166. package/dist/bigconsole/components/widgets/metric-card/index.js +4 -4
  167. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +3 -3
  168. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js.map +1 -1
  169. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +34 -25
  170. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
  171. package/dist/bigconsole/components/widgets/progress/ProgressWidget.js +129 -114
  172. package/dist/bigconsole/components/widgets/progress/ProgressWidget.js.map +1 -1
  173. package/dist/bigconsole/components/widgets/retention/RetentionWidget.js +3 -3
  174. package/dist/bigconsole/components/widgets/retention/RetentionWidget.js.map +1 -1
  175. package/dist/bigconsole/components/widgets/states/EmptyState.js +6 -4
  176. package/dist/bigconsole/components/widgets/states/EmptyState.js.map +1 -1
  177. package/dist/bigconsole/components/widgets/states/ErrorState.js +7 -5
  178. package/dist/bigconsole/components/widgets/states/ErrorState.js.map +1 -1
  179. package/dist/bigconsole/components/widgets/states/LoadingState.js +5 -4
  180. package/dist/bigconsole/components/widgets/states/LoadingState.js.map +1 -1
  181. package/dist/bigconsole/components/widgets/table/TableConfig.js +10 -4
  182. package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
  183. package/dist/bigconsole/components/widgets/table/TableHeader.js +1 -1
  184. package/dist/bigconsole/components/widgets/table/TableHeader.js.map +1 -1
  185. package/dist/bigconsole/components/widgets/table/TableWidget.js +1 -1
  186. package/dist/bigconsole/components/widgets/table/TableWidget.js.map +1 -1
  187. package/dist/bigconsole/components/widgets/text-widget/TextWidget.js +1 -1
  188. package/dist/bigconsole/components/widgets/text-widget/TextWidget.js.map +1 -1
  189. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +3 -3
  190. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
  191. package/dist/bigconsole/components/widgets/utils/conditionalFormat.js +2 -2
  192. package/dist/bigconsole/components/widgets/utils/conditionalFormat.js.map +1 -1
  193. package/dist/bigconsole/components/widgets/utils/targetProgress.js +13 -0
  194. package/dist/bigconsole/components/widgets/utils/targetProgress.js.map +1 -0
  195. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +112 -85
  196. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
  197. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js +28 -20
  198. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js.map +1 -1
  199. package/dist/bigconsole/components/workflow/WorkflowCard.js +92 -77
  200. package/dist/bigconsole/components/workflow/WorkflowCard.js.map +1 -1
  201. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js +70 -51
  202. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js.map +1 -1
  203. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js +16 -17
  204. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js.map +1 -1
  205. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +6 -4
  206. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js.map +1 -1
  207. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +360 -338
  208. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
  209. package/dist/bigconsole/hooks/useModalFocusTrap.js +53 -0
  210. package/dist/bigconsole/hooks/useModalFocusTrap.js.map +1 -0
  211. package/dist/bigconsole/pages/DashboardBuilderPage.js +209 -203
  212. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  213. package/dist/bigconsole/pages/DashboardViewPage.js +126 -120
  214. package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
  215. package/dist/bigconsole/pages/DashboardsPage.js +838 -800
  216. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  217. package/dist/bigconsole/pages/DataParsersPage.js +263 -315
  218. package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
  219. package/dist/bigconsole/pages/DataSinkBuilderPage.js +301 -341
  220. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  221. package/dist/bigconsole/pages/DataSinkViewPage.js +346 -339
  222. package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
  223. package/dist/bigconsole/pages/DataSinksPage.js +356 -458
  224. package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
  225. package/dist/bigconsole/pages/DataSourcesPage.js +7 -2
  226. package/dist/bigconsole/pages/DataSourcesPage.js.map +1 -1
  227. package/dist/bigconsole/pages/HomePage.js +186 -193
  228. package/dist/bigconsole/pages/HomePage.js.map +1 -1
  229. package/dist/bigconsole/pages/InsightsPage.js +887 -740
  230. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  231. package/dist/bigconsole/pages/ParserBuilderPage.js +679 -637
  232. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  233. package/dist/bigconsole/pages/ParserViewPage.js +368 -342
  234. package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
  235. package/dist/bigconsole/pages/PipelineBuilderPage.js +537 -444
  236. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  237. package/dist/bigconsole/pages/PipelineViewPage.js +412 -377
  238. package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
  239. package/dist/bigconsole/pages/PipelinesPage.js +248 -298
  240. package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
  241. package/dist/bigconsole/pages/WidgetDemoPage.js +251 -153
  242. package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
  243. package/dist/bigconsole/pages/WorkflowViewPage.js +381 -371
  244. package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
  245. package/dist/bigconsole/pages/WorkflowsPage.js +171 -286
  246. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  247. package/package.json +1 -1
@@ -3,14 +3,15 @@ import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
3
  //#region src/bigconsole/components/widgets/states/LoadingState.tsx
4
4
  var r = e(function({ message: e = "Loading..." }) {
5
5
  return /* @__PURE__ */ n("div", {
6
- className: "\n flex flex-col items-center justify-center\n h-full w-full min-h-[120px]\n text-text-secondary\n ",
6
+ className: "\n flex flex-col items-center justify-center\n h-full w-full min-w-0 min-h-[120px]\n px-3 text-center text-text-secondary\n ",
7
7
  role: "status",
8
8
  "aria-live": "polite",
9
9
  children: [/* @__PURE__ */ n("div", {
10
- className: "relative w-10 h-10 mb-3",
11
- children: [/* @__PURE__ */ t("div", { className: "\n absolute inset-0\n border-4 border-border-default\n rounded-full\n " }), /* @__PURE__ */ t("div", { className: "\n absolute inset-0\n border-4 border-action-primary-bg\n border-t-transparent\n rounded-full\n animate-spin\n " })]
10
+ "aria-hidden": "true",
11
+ className: "relative mb-3 h-12 w-12 shrink-0 p-1",
12
+ children: [/* @__PURE__ */ t("div", { className: "\n absolute inset-1\n border-4 border-[var(--color-border-subtle)]\n rounded-full\n " }), /* @__PURE__ */ t("div", { className: "\n absolute inset-1\n border-4 border-action-primary-bg\n border-t-transparent\n rounded-full\n motion-safe:animate-spin\n " })]
12
13
  }), /* @__PURE__ */ t("p", {
13
- className: "text-sm",
14
+ className: "max-w-[32ch] text-sm",
14
15
  children: e
15
16
  })]
16
17
  });
@@ -1 +1 @@
1
- {"version":3,"file":"LoadingState.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/states/LoadingState.tsx"],"sourcesContent":["/**\n * WidgetLoadingState Component\n *\n * Loading state displayed while widget data is being fetched.\n */\n\nimport { type FC, memo } from 'react';\n\nexport interface WidgetLoadingStateProps {\n /** Optional message to display */\n message?: string;\n}\n\nexport const WidgetLoadingState: FC<WidgetLoadingStateProps> = memo(function WidgetLoadingState({\n message = 'Loading...',\n}) {\n return (\n <div\n className=\"\n flex flex-col items-center justify-center\n h-full w-full min-h-[120px]\n text-text-secondary\n \"\n role=\"status\"\n aria-live=\"polite\"\n >\n {/* Spinner */}\n <div className=\"relative w-10 h-10 mb-3\">\n <div\n className=\"\n absolute inset-0\n border-4 border-border-default\n rounded-full\n \"\n />\n <div\n className=\"\n absolute inset-0\n border-4 border-action-primary-bg\n border-t-transparent\n rounded-full\n animate-spin\n \"\n />\n </div>\n\n {/* Message */}\n <p className=\"text-sm\">{message}</p>\n </div>\n );\n});\n\nexport default WidgetLoadingState;\n"],"mappings":";;;AAaA,IAAa,IAAkD,EAAK,SAA4B,EAC9F,aAAU,gBACT;AACD,QACE,kBAAC,OAAD;EACE,WAAU;EAKV,MAAK;EACL,aAAU;YAPZ,CAUE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD,EACE,WAAU,4HAKV,CAAA,EACF,kBAAC,OAAD,EACE,WAAU,+LAOV,CAAA,CACE;MAGN,kBAAC,KAAD;GAAG,WAAU;aAAW;GAAY,CAAA,CAChC;;EAER"}
1
+ {"version":3,"file":"LoadingState.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/states/LoadingState.tsx"],"sourcesContent":["/**\n * WidgetLoadingState Component\n *\n * Loading state displayed while widget data is being fetched.\n */\n\nimport { type FC, memo } from 'react';\n\nexport interface WidgetLoadingStateProps {\n /** Optional message to display */\n message?: string;\n}\n\nexport const WidgetLoadingState: FC<WidgetLoadingStateProps> = memo(function WidgetLoadingState({\n message = 'Loading...',\n}) {\n return (\n /* Shares the empty/error-state recipe so all four states read as one family. */\n <div\n className=\"\n flex flex-col items-center justify-center\n h-full w-full min-w-0 min-h-[120px]\n px-3 text-center text-text-secondary\n \"\n role=\"status\"\n aria-live=\"polite\"\n >\n {/* Spinner */}\n <div aria-hidden=\"true\" className=\"relative mb-3 h-12 w-12 shrink-0 p-1\">\n <div\n className=\"\n absolute inset-1\n border-4 border-[var(--color-border-subtle)]\n rounded-full\n \"\n />\n <div\n className=\"\n absolute inset-1\n border-4 border-action-primary-bg\n border-t-transparent\n rounded-full\n motion-safe:animate-spin\n \"\n />\n </div>\n\n {/* Message */}\n <p className=\"max-w-[32ch] text-sm\">{message}</p>\n </div>\n );\n});\n\nexport default WidgetLoadingState;\n"],"mappings":";;;AAaA,IAAa,IAAkD,EAAK,SAA4B,EAC9F,aAAU,gBACT;AACD,QAEE,kBAAC,OAAD;EACE,WAAU;EAKV,MAAK;EACL,aAAU;YAPZ,CAUE,kBAAC,OAAD;GAAK,eAAY;GAAO,WAAU;aAAlC,CACE,kBAAC,OAAD,EACE,WAAU,0IAKV,CAAA,EACF,kBAAC,OAAD,EACE,WAAU,2MAOV,CAAA,CACE;MAGN,kBAAC,KAAD;GAAG,WAAU;aAAwB;GAAY,CAAA,CAC7C;;EAER"}
@@ -147,7 +147,7 @@ var c = [
147
147
  m((t) => t.filter((t, n) => n !== e));
148
148
  }, []);
149
149
  return /* @__PURE__ */ s("div", {
150
- className: "space-y-4",
150
+ className: "min-w-0 space-y-form-gap",
151
151
  children: [
152
152
  /* @__PURE__ */ s("div", { children: [/* @__PURE__ */ o("label", {
153
153
  className: "block text-sm font-medium text-text-primary mb-1",
@@ -215,7 +215,7 @@ var c = [
215
215
  })]
216
216
  }),
217
217
  /* @__PURE__ */ s("div", {
218
- className: "grid grid-cols-2 gap-2",
218
+ className: "grid grid-cols-1 gap-2 sm:grid-cols-2",
219
219
  children: [/* @__PURE__ */ o("input", {
220
220
  type: "text",
221
221
  value: e.field || "",
@@ -231,7 +231,7 @@ var c = [
231
231
  })]
232
232
  }),
233
233
  /* @__PURE__ */ s("div", {
234
- className: "grid grid-cols-2 gap-2",
234
+ className: "grid grid-cols-1 gap-2 sm:grid-cols-2",
235
235
  children: [/* @__PURE__ */ s("select", {
236
236
  value: e.format || "text",
237
237
  onChange: (e) => g(t, "format", e.target.value),
@@ -387,8 +387,14 @@ var c = [
387
387
  })]
388
388
  })] }),
389
389
  /* @__PURE__ */ s("div", {
390
- className: "space-y-3",
390
+ role: "group",
391
+ "aria-label": "Display options",
392
+ className: "space-y-3 border-t border-[var(--color-border-subtle)] pt-form-gap",
391
393
  children: [
394
+ /* @__PURE__ */ o("p", {
395
+ className: "text-xs font-bold uppercase tracking-wider text-text-secondary",
396
+ children: "Display options"
397
+ }),
392
398
  /* @__PURE__ */ s("label", {
393
399
  className: "flex items-center gap-3",
394
400
  children: [/* @__PURE__ */ o("input", {
@@ -1 +1 @@
1
- {"version":3,"file":"TableConfig.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableConfig.tsx"],"sourcesContent":["/**\n * TableConfig Component\n *\n * Configuration panel for Table widgets.\n */\n\nimport { type FC, memo, useCallback, useMemo, useEffect, useState } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { TableConfig as ConfigType, TableColumnConfig } from '../../../types';\nimport type { ConditionalRule, ConditionalOperator, SemanticIntent } from '../utils/conditionalFormat';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TableConfigProps {\n /** Current configuration */\n config: ConfigType;\n /** Callback when config changes */\n onChange: (config: ConfigType) => void;\n}\n\n// Operators offered in the conditional-formatting editor. Kept to the common,\n// self-explanatory set; the engine supports more (see conditionalFormat.ts).\nconst CF_OPERATORS: { value: ConditionalOperator; labelKey: string; labelDefault: string }[] = [\n { value: 'gt', labelKey: 'bigconsole.widget.config.table.operator.gt', labelDefault: '> greater than' },\n { value: 'gte', labelKey: 'bigconsole.widget.config.table.operator.gte', labelDefault: '≥ at least' },\n { value: 'lt', labelKey: 'bigconsole.widget.config.table.operator.lt', labelDefault: '< less than' },\n { value: 'lte', labelKey: 'bigconsole.widget.config.table.operator.lte', labelDefault: '≤ at most' },\n { value: 'eq', labelKey: 'bigconsole.widget.config.table.operator.eq', labelDefault: '= equals' },\n { value: 'neq', labelKey: 'bigconsole.widget.config.table.operator.neq', labelDefault: '≠ not equal' },\n { value: 'between', labelKey: 'bigconsole.widget.config.table.operator.between', labelDefault: 'between' },\n { value: 'outside', labelKey: 'bigconsole.widget.config.table.operator.outside', labelDefault: 'outside' },\n { value: 'contains', labelKey: 'bigconsole.widget.config.table.operator.contains', labelDefault: 'contains' },\n];\n\n// Semantic color intents — theme-safe (never raw hex). Resolved to status tokens.\nconst CF_INTENTS: { value: SemanticIntent; labelKey: string; labelDefault: string }[] = [\n { value: 'danger', labelKey: 'bigconsole.widget.config.table.intent.danger', labelDefault: 'Red — danger' },\n { value: 'warning', labelKey: 'bigconsole.widget.config.table.intent.warning', labelDefault: 'Amber — warning' },\n { value: 'success', labelKey: 'bigconsole.widget.config.table.intent.success', labelDefault: 'Green — good' },\n { value: 'info', labelKey: 'bigconsole.widget.config.table.intent.info', labelDefault: 'Blue — info' },\n { value: 'neutral', labelKey: 'bigconsole.widget.config.table.intent.neutral', labelDefault: 'Neutral' },\n];\n\nconst CF_FIELD_CLASS =\n 'px-2 py-1 text-xs text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg';\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableConfig: FC<TableConfigProps> = memo(function TableConfig({ config, onChange }) {\n const { t } = useI18n();\n\n // Normalize columns - convert string[] to TableColumnConfig[]\n const initialColumns = useMemo(() => {\n return ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n }, []); // Only run once on mount\n\n // Local state for columns to make them editable\n const [columns, setColumns] = useState<TableColumnConfig[]>(initialColumns);\n\n // Sync with parent when columns change\n useEffect(() => {\n // Only update if columns actually changed (deep compare)\n const currentStr = JSON.stringify(config.columns);\n const newStr = JSON.stringify(columns);\n if (currentStr !== newStr && columns.length > 0) {\n onChange({ ...config, columns });\n }\n }, [columns]);\n\n // Reset columns when config changes from outside\n useEffect(() => {\n const normalized = ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n setColumns(normalized);\n }, [config.columns]);\n\n const handleChange = useCallback(\n <K extends keyof ConfigType>(key: K, value: ConfigType[K]) => {\n onChange({ ...config, [key]: value });\n },\n [config, onChange]\n );\n\n const handleColumnChange = useCallback((index: number, field: keyof TableColumnConfig, value: string) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], [field]: value };\n return newColumns;\n });\n }, []);\n\n // Conditional-formatting rule edits for a column. The rules array is stored on\n // `column.conditionalRules` and consumed at render time by TableCell.\n const handleColumnRules = useCallback((index: number, rules: ConditionalRule[]) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], conditionalRules: rules };\n return newColumns;\n });\n }, []);\n\n const addRule = useCallback(\n (index: number) => {\n const existing = columns[index]?.conditionalRules ?? [];\n const next: ConditionalRule = {\n operator: 'gt',\n value: 0,\n style: { bgColor: 'danger', textColor: 'danger', bold: true },\n };\n handleColumnRules(index, [...existing, next]);\n },\n [columns, handleColumnRules]\n );\n\n const updateRule = useCallback(\n (colIndex: number, ruleIndex: number, patch: Partial<ConditionalRule>) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) => (i === ruleIndex ? { ...r, ...patch } : r));\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const updateRuleStyle = useCallback(\n (colIndex: number, ruleIndex: number, intent: SemanticIntent) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) =>\n i === ruleIndex ? { ...r, style: { ...r.style, bgColor: intent, textColor: intent } } : r\n );\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const removeRule = useCallback(\n (colIndex: number, ruleIndex: number) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n handleColumnRules(\n colIndex,\n existing.filter((_, i) => i !== ruleIndex)\n );\n },\n [columns, handleColumnRules]\n );\n\n const addColumn = useCallback(() => {\n setColumns((prev) => [...prev, { field: '', header: '' }]);\n }, []);\n\n const removeColumn = useCallback((index: number) => {\n setColumns((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n return (\n <div className=\"space-y-4\">\n {/* Page Size */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.table.pageSize.label', 'Page Size')}\n </label>\n <select\n value={config.pageSize || 10}\n onChange={(e) => handleChange('pageSize', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value={10}>\n {t('bigconsole.widget.config.table.pageSize.rows', '{{count}} rows', { count: 10 })}\n </option>\n <option value={25}>\n {t('bigconsole.widget.config.table.pageSize.rows', '{{count}} rows', { count: 25 })}\n </option>\n <option value={50}>\n {t('bigconsole.widget.config.table.pageSize.rows', '{{count}} rows', { count: 50 })}\n </option>\n <option value={100}>\n {t('bigconsole.widget.config.table.pageSize.rows', '{{count}} rows', { count: 100 })}\n </option>\n </select>\n </div>\n\n {/* Columns Configuration */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm font-medium text-text-primary\">\n {t('bigconsole.widget.config.table.columns.label', 'Columns')}\n </label>\n <button\n type=\"button\"\n onClick={addColumn}\n className=\"\n text-sm text-action-primary-bg\n hover:text-action-primary-bgHover\n \"\n >\n {t('bigconsole.widget.config.table.columns.add', '+ Add Column')}\n </button>\n </div>\n\n <div className=\"space-y-3\">\n {columns.map((col, index) => (\n <div\n key={index}\n className=\"\n p-3\n bg-bg-sunken\n rounded-md\n space-y-2\n \"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-text-secondary\">\n {t('bigconsole.widget.config.table.columns.columnN', 'Column {{index}}', { index: index + 1 })}\n </span>\n <button\n type=\"button\"\n onClick={() => removeColumn(index)}\n className=\"text-status-error-text hover:text-status-error-text/80\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <input\n type=\"text\"\n value={col.field || ''}\n onChange={(e) => handleColumnChange(index, 'field', e.target.value)}\n placeholder={t('bigconsole.widget.config.table.column.fieldPlaceholder', 'Field name')}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n <input\n type=\"text\"\n value={col.header || ''}\n onChange={(e) => handleColumnChange(index, 'header', e.target.value)}\n placeholder={t('bigconsole.widget.config.table.column.headerPlaceholder', 'Header label')}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <select\n value={col.format || 'text'}\n onChange={(e) => handleColumnChange(index, 'format', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"text\">{t('bigconsole.widget.config.table.format.text', 'Text')}</option>\n <option value=\"number\">{t('bigconsole.widget.config.table.format.number', 'Number')}</option>\n <option value=\"currency\">{t('bigconsole.widget.config.table.format.currency', 'Currency')}</option>\n <option value=\"percentage\">\n {t('bigconsole.widget.config.table.format.percentage', 'Percentage')}\n </option>\n <option value=\"date\">{t('bigconsole.widget.config.table.format.date', 'Date')}</option>\n <option value=\"badge\">{t('bigconsole.widget.config.table.format.badge', 'Badge')}</option>\n </select>\n <select\n value={col.align || 'left'}\n onChange={(e) => handleColumnChange(index, 'align', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"left\">{t('bigconsole.widget.config.table.align.left', 'Left')}</option>\n <option value=\"center\">{t('bigconsole.widget.config.table.align.center', 'Center')}</option>\n <option value=\"right\">{t('bigconsole.widget.config.table.align.right', 'Right')}</option>\n </select>\n </div>\n\n {/* Conditional formatting rules */}\n <div className=\"pt-2 border-t border-border-default/60\">\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-xs font-medium text-text-secondary\">\n {t('bigconsole.widget.config.table.conditionalFormatting.title', 'Conditional formatting')}\n </span>\n <button\n type=\"button\"\n onClick={() => addRule(index)}\n className=\"text-xs text-action-primary-bg hover:text-action-primary-bgHover\"\n >\n {t('bigconsole.widget.config.table.conditionalFormatting.addRule', '+ Add rule')}\n </button>\n </div>\n\n {(col.conditionalRules?.length ?? 0) === 0 && (\n <p className=\"text-xs text-text-secondary\">\n {t(\n 'bigconsole.widget.config.table.conditionalFormatting.noRules',\n 'No rules — cell shows its plain value.'\n )}\n </p>\n )}\n\n <div className=\"space-y-2\">\n {(col.conditionalRules ?? []).map((rule, ruleIndex) => {\n const needsSecond = rule.operator === 'between' || rule.operator === 'outside';\n const currentIntent: SemanticIntent = rule.style?.bgColor ?? rule.style?.textColor ?? 'danger';\n return (\n <div\n key={ruleIndex}\n className=\"p-2 bg-bg-surface rounded-md border border-border-default space-y-2\"\n >\n <div className=\"flex items-center gap-2\">\n <select\n value={rule.operator}\n onChange={(e) =>\n updateRule(index, ruleIndex, { operator: e.target.value as ConditionalOperator })\n }\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_OPERATORS.map((op) => (\n <option key={op.value} value={op.value}>\n {t(op.labelKey, op.labelDefault)}\n </option>\n ))}\n </select>\n <input\n type=\"text\"\n value={rule.value ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value: e.target.value })}\n placeholder={t('bigconsole.widget.config.table.rule.valuePlaceholder', 'value')}\n className={`${CF_FIELD_CLASS} w-20`}\n />\n {needsSecond && (\n <input\n type=\"text\"\n value={rule.value2 ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value2: e.target.value })}\n placeholder={t('bigconsole.widget.config.table.rule.value2Placeholder', 'and')}\n className={`${CF_FIELD_CLASS} w-20`}\n />\n )}\n <button\n type=\"button\"\n onClick={() => removeRule(index, ruleIndex)}\n className=\"text-status-error-text hover:text-status-error-text/80\"\n aria-label={t('bigconsole.widget.config.table.rule.remove', 'Remove rule')}\n >\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"flex items-center gap-2\">\n <select\n value={currentIntent}\n onChange={(e) => updateRuleStyle(index, ruleIndex, e.target.value as SemanticIntent)}\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_INTENTS.map((it) => (\n <option key={it.value} value={it.value}>\n {t(it.labelKey, it.labelDefault)}\n </option>\n ))}\n </select>\n <label className=\"flex items-center gap-1 text-xs text-text-primary\">\n <input\n type=\"checkbox\"\n checked={rule.style?.bold === true}\n onChange={(e) =>\n updateRule(index, ruleIndex, { style: { ...rule.style, bold: e.target.checked } })\n }\n className=\"w-3.5 h-3.5 text-action-primary-bg bg-bg-surface border-border-default rounded focus:ring-action-primary-bg\"\n />\n {t('bigconsole.widget.config.table.rule.bold', 'Bold')}\n </label>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n </div>\n ))}\n\n {columns.length === 0 && (\n <p className=\"text-sm text-text-secondary text-center py-4\">\n {t(\n 'bigconsole.widget.config.table.columns.empty',\n 'No columns configured. Columns will be auto-generated from data.'\n )}\n </p>\n )}\n </div>\n </div>\n\n {/* Toggle Options */}\n <div className=\"space-y-3\">\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showSearch !== false}\n onChange={(e) => handleChange('showSearch', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.table.showSearch', 'Show search box')}\n </span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showPagination !== false}\n onChange={(e) => handleChange('showPagination', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.table.showPagination', 'Show pagination')}\n </span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showExport !== false}\n onChange={(e) => handleChange('showExport', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.table.showExport', 'Show export button')}\n </span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stickyHeader === true}\n onChange={(e) => handleChange('stickyHeader', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.table.stickyHeader', 'Sticky header')}\n </span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stripedRows === true}\n onChange={(e) => handleChange('stripedRows', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.table.stripedRows', 'Striped rows')}\n </span>\n </label>\n </div>\n </div>\n );\n});\n\nexport default TableConfig;\n"],"mappings":"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"}
1
+ {"version":3,"file":"TableConfig.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableConfig.tsx"],"sourcesContent":["/**\n * TableConfig Component\n *\n * Configuration panel for Table widgets.\n */\n\nimport { type FC, memo, useCallback, useMemo, useEffect, useState } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { TableConfig as ConfigType, TableColumnConfig } from '../../../types';\nimport type { ConditionalRule, ConditionalOperator, SemanticIntent } from '../utils/conditionalFormat';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TableConfigProps {\n /** Current configuration */\n config: ConfigType;\n /** Callback when config changes */\n onChange: (config: ConfigType) => void;\n}\n\n// Operators offered in the conditional-formatting editor. Kept to the common,\n// self-explanatory set; the engine supports more (see conditionalFormat.ts).\nconst CF_OPERATORS: { value: ConditionalOperator; labelKey: string; labelDefault: string }[] = [\n { value: 'gt', labelKey: 'bigconsole.widget.config.table.operator.gt', labelDefault: '> greater than' },\n { value: 'gte', labelKey: 'bigconsole.widget.config.table.operator.gte', labelDefault: '≥ at least' },\n { value: 'lt', labelKey: 'bigconsole.widget.config.table.operator.lt', labelDefault: '< less than' },\n { value: 'lte', labelKey: 'bigconsole.widget.config.table.operator.lte', labelDefault: '≤ at most' },\n { value: 'eq', labelKey: 'bigconsole.widget.config.table.operator.eq', labelDefault: '= equals' },\n { value: 'neq', labelKey: 'bigconsole.widget.config.table.operator.neq', labelDefault: '≠ not equal' },\n { value: 'between', labelKey: 'bigconsole.widget.config.table.operator.between', labelDefault: 'between' },\n { value: 'outside', labelKey: 'bigconsole.widget.config.table.operator.outside', labelDefault: 'outside' },\n { value: 'contains', labelKey: 'bigconsole.widget.config.table.operator.contains', labelDefault: 'contains' },\n];\n\n// Semantic color intents — theme-safe (never raw hex). Resolved to status tokens.\nconst CF_INTENTS: { value: SemanticIntent; labelKey: string; labelDefault: string }[] = [\n { value: 'danger', labelKey: 'bigconsole.widget.config.table.intent.danger', labelDefault: 'Red — danger' },\n { value: 'warning', labelKey: 'bigconsole.widget.config.table.intent.warning', labelDefault: 'Amber — warning' },\n { value: 'success', labelKey: 'bigconsole.widget.config.table.intent.success', labelDefault: 'Green — good' },\n { value: 'info', labelKey: 'bigconsole.widget.config.table.intent.info', labelDefault: 'Blue — info' },\n { value: 'neutral', labelKey: 'bigconsole.widget.config.table.intent.neutral', labelDefault: 'Neutral' },\n];\n\nconst CF_FIELD_CLASS =\n 'px-2 py-1 text-xs text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg';\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableConfig: FC<TableConfigProps> = memo(function TableConfig({ config, onChange }) {\n const { t } = useI18n();\n\n // Normalize columns - convert string[] to TableColumnConfig[]\n const initialColumns = useMemo(() => {\n return ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n }, []); // Only run once on mount\n\n // Local state for columns to make them editable\n const [columns, setColumns] = useState<TableColumnConfig[]>(initialColumns);\n\n // Sync with parent when columns change\n useEffect(() => {\n // Only update if columns actually changed (deep compare)\n const currentStr = JSON.stringify(config.columns);\n const newStr = JSON.stringify(columns);\n if (currentStr !== newStr && columns.length > 0) {\n onChange({ ...config, columns });\n }\n }, [columns]);\n\n // Reset columns when config changes from outside\n useEffect(() => {\n const normalized = ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n setColumns(normalized);\n }, [config.columns]);\n\n const handleChange = useCallback(\n <K extends keyof ConfigType>(key: K, value: ConfigType[K]) => {\n onChange({ ...config, [key]: value });\n },\n [config, onChange]\n );\n\n const handleColumnChange = useCallback((index: number, field: keyof TableColumnConfig, value: string) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], [field]: value };\n return newColumns;\n });\n }, []);\n\n // Conditional-formatting rule edits for a column. The rules array is stored on\n // `column.conditionalRules` and consumed at render time by TableCell.\n const handleColumnRules = useCallback((index: number, rules: ConditionalRule[]) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], conditionalRules: rules };\n return newColumns;\n });\n }, []);\n\n const addRule = useCallback(\n (index: number) => {\n const existing = columns[index]?.conditionalRules ?? [];\n const next: ConditionalRule = {\n operator: 'gt',\n value: 0,\n style: { bgColor: 'danger', textColor: 'danger', bold: true },\n };\n handleColumnRules(index, [...existing, next]);\n },\n [columns, handleColumnRules]\n );\n\n const updateRule = useCallback(\n (colIndex: number, ruleIndex: number, patch: Partial<ConditionalRule>) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) => (i === ruleIndex ? { ...r, ...patch } : r));\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const updateRuleStyle = useCallback(\n (colIndex: number, ruleIndex: number, intent: SemanticIntent) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) =>\n i === ruleIndex ? { ...r, style: { ...r.style, bgColor: intent, textColor: intent } } : r\n );\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const removeRule = useCallback(\n (colIndex: number, ruleIndex: number) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n handleColumnRules(\n colIndex,\n existing.filter((_, i) => i !== ruleIndex)\n );\n },\n [columns, handleColumnRules]\n );\n\n const addColumn = useCallback(() => {\n setColumns((prev) => [...prev, { field: '', header: '' }]);\n }, []);\n\n const removeColumn = useCallback((index: number) => {\n setColumns((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n return (\n <div className=\"min-w-0 space-y-form-gap\">\n {/* Page Size */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.table.pageSize.label', 'Page Size')}\n </label>\n <select\n value={config.pageSize || 10}\n onChange={(e) => handleChange('pageSize', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value={10}>\n {t('bigconsole.widget.config.table.pageSize.rows', '{{count}} rows', { count: 10 })}\n </option>\n <option value={25}>\n {t('bigconsole.widget.config.table.pageSize.rows', '{{count}} rows', { count: 25 })}\n </option>\n <option value={50}>\n {t('bigconsole.widget.config.table.pageSize.rows', '{{count}} rows', { count: 50 })}\n </option>\n <option value={100}>\n {t('bigconsole.widget.config.table.pageSize.rows', '{{count}} rows', { count: 100 })}\n </option>\n </select>\n </div>\n\n {/* Columns Configuration */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm font-medium text-text-primary\">\n {t('bigconsole.widget.config.table.columns.label', 'Columns')}\n </label>\n <button\n type=\"button\"\n onClick={addColumn}\n className=\"\n text-sm text-action-primary-bg\n hover:text-action-primary-bgHover\n \"\n >\n {t('bigconsole.widget.config.table.columns.add', '+ Add Column')}\n </button>\n </div>\n\n <div className=\"space-y-3\">\n {columns.map((col, index) => (\n <div\n key={index}\n className=\"\n p-3\n bg-bg-sunken\n rounded-md\n space-y-2\n \"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-text-secondary\">\n {t('bigconsole.widget.config.table.columns.columnN', 'Column {{index}}', { index: index + 1 })}\n </span>\n <button\n type=\"button\"\n onClick={() => removeColumn(index)}\n className=\"text-status-error-text hover:text-status-error-text/80\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n <input\n type=\"text\"\n value={col.field || ''}\n onChange={(e) => handleColumnChange(index, 'field', e.target.value)}\n placeholder={t('bigconsole.widget.config.table.column.fieldPlaceholder', 'Field name')}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n <input\n type=\"text\"\n value={col.header || ''}\n onChange={(e) => handleColumnChange(index, 'header', e.target.value)}\n placeholder={t('bigconsole.widget.config.table.column.headerPlaceholder', 'Header label')}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n <select\n value={col.format || 'text'}\n onChange={(e) => handleColumnChange(index, 'format', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"text\">{t('bigconsole.widget.config.table.format.text', 'Text')}</option>\n <option value=\"number\">{t('bigconsole.widget.config.table.format.number', 'Number')}</option>\n <option value=\"currency\">{t('bigconsole.widget.config.table.format.currency', 'Currency')}</option>\n <option value=\"percentage\">\n {t('bigconsole.widget.config.table.format.percentage', 'Percentage')}\n </option>\n <option value=\"date\">{t('bigconsole.widget.config.table.format.date', 'Date')}</option>\n <option value=\"badge\">{t('bigconsole.widget.config.table.format.badge', 'Badge')}</option>\n </select>\n <select\n value={col.align || 'left'}\n onChange={(e) => handleColumnChange(index, 'align', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"left\">{t('bigconsole.widget.config.table.align.left', 'Left')}</option>\n <option value=\"center\">{t('bigconsole.widget.config.table.align.center', 'Center')}</option>\n <option value=\"right\">{t('bigconsole.widget.config.table.align.right', 'Right')}</option>\n </select>\n </div>\n\n {/* Conditional formatting rules */}\n <div className=\"pt-2 border-t border-border-default/60\">\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-xs font-medium text-text-secondary\">\n {t('bigconsole.widget.config.table.conditionalFormatting.title', 'Conditional formatting')}\n </span>\n <button\n type=\"button\"\n onClick={() => addRule(index)}\n className=\"text-xs text-action-primary-bg hover:text-action-primary-bgHover\"\n >\n {t('bigconsole.widget.config.table.conditionalFormatting.addRule', '+ Add rule')}\n </button>\n </div>\n\n {(col.conditionalRules?.length ?? 0) === 0 && (\n <p className=\"text-xs text-text-secondary\">\n {t(\n 'bigconsole.widget.config.table.conditionalFormatting.noRules',\n 'No rules — cell shows its plain value.'\n )}\n </p>\n )}\n\n <div className=\"space-y-2\">\n {(col.conditionalRules ?? []).map((rule, ruleIndex) => {\n const needsSecond = rule.operator === 'between' || rule.operator === 'outside';\n const currentIntent: SemanticIntent = rule.style?.bgColor ?? rule.style?.textColor ?? 'danger';\n return (\n <div\n key={ruleIndex}\n className=\"p-2 bg-bg-surface rounded-md border border-border-default space-y-2\"\n >\n <div className=\"flex items-center gap-2\">\n <select\n value={rule.operator}\n onChange={(e) =>\n updateRule(index, ruleIndex, { operator: e.target.value as ConditionalOperator })\n }\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_OPERATORS.map((op) => (\n <option key={op.value} value={op.value}>\n {t(op.labelKey, op.labelDefault)}\n </option>\n ))}\n </select>\n <input\n type=\"text\"\n value={rule.value ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value: e.target.value })}\n placeholder={t('bigconsole.widget.config.table.rule.valuePlaceholder', 'value')}\n className={`${CF_FIELD_CLASS} w-20`}\n />\n {needsSecond && (\n <input\n type=\"text\"\n value={rule.value2 ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value2: e.target.value })}\n placeholder={t('bigconsole.widget.config.table.rule.value2Placeholder', 'and')}\n className={`${CF_FIELD_CLASS} w-20`}\n />\n )}\n <button\n type=\"button\"\n onClick={() => removeRule(index, ruleIndex)}\n className=\"text-status-error-text hover:text-status-error-text/80\"\n aria-label={t('bigconsole.widget.config.table.rule.remove', 'Remove rule')}\n >\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"flex items-center gap-2\">\n <select\n value={currentIntent}\n onChange={(e) => updateRuleStyle(index, ruleIndex, e.target.value as SemanticIntent)}\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_INTENTS.map((it) => (\n <option key={it.value} value={it.value}>\n {t(it.labelKey, it.labelDefault)}\n </option>\n ))}\n </select>\n <label className=\"flex items-center gap-1 text-xs text-text-primary\">\n <input\n type=\"checkbox\"\n checked={rule.style?.bold === true}\n onChange={(e) =>\n updateRule(index, ruleIndex, { style: { ...rule.style, bold: e.target.checked } })\n }\n className=\"w-3.5 h-3.5 text-action-primary-bg bg-bg-surface border-border-default rounded focus:ring-action-primary-bg\"\n />\n {t('bigconsole.widget.config.table.rule.bold', 'Bold')}\n </label>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n </div>\n ))}\n\n {columns.length === 0 && (\n <p className=\"text-sm text-text-secondary text-center py-4\">\n {t(\n 'bigconsole.widget.config.table.columns.empty',\n 'No columns configured. Columns will be auto-generated from data.'\n )}\n </p>\n )}\n </div>\n </div>\n\n {/* Toggle Options */}\n <div\n role=\"group\"\n aria-label=\"Display options\"\n className=\"space-y-3 border-t border-[var(--color-border-subtle)] pt-form-gap\"\n >\n {/* Toggles are a different KIND of control from the field stack above,\n so they get their own labelled group instead of being visually\n identical to it (BOFF-5636). */}\n <p className=\"text-xs font-bold uppercase tracking-wider text-text-secondary\">Display options</p>\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showSearch !== false}\n onChange={(e) => handleChange('showSearch', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.table.showSearch', 'Show search box')}\n </span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showPagination !== false}\n onChange={(e) => handleChange('showPagination', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.table.showPagination', 'Show pagination')}\n </span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showExport !== false}\n onChange={(e) => handleChange('showExport', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.table.showExport', 'Show export button')}\n </span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stickyHeader === true}\n onChange={(e) => handleChange('stickyHeader', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.table.stickyHeader', 'Sticky header')}\n </span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stripedRows === true}\n onChange={(e) => handleChange('stripedRows', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.table.stripedRows', 'Striped rows')}\n </span>\n </label>\n </div>\n </div>\n );\n});\n\nexport default TableConfig;\n"],"mappings":";;;;AAwBA,IAAM,IAAyF;CAC7F;EAAE,OAAO;EAAM,UAAU;EAA8C,cAAc;EAAkB;CACvG;EAAE,OAAO;EAAO,UAAU;EAA+C,cAAc;EAAc;CACrG;EAAE,OAAO;EAAM,UAAU;EAA8C,cAAc;EAAe;CACpG;EAAE,OAAO;EAAO,UAAU;EAA+C,cAAc;EAAa;CACpG;EAAE,OAAO;EAAM,UAAU;EAA8C,cAAc;EAAY;CACjG;EAAE,OAAO;EAAO,UAAU;EAA+C,cAAc;EAAe;CACtG;EAAE,OAAO;EAAW,UAAU;EAAmD,cAAc;EAAW;CAC1G;EAAE,OAAO;EAAW,UAAU;EAAmD,cAAc;EAAW;CAC1G;EAAE,OAAO;EAAY,UAAU;EAAoD,cAAc;EAAY;CAC9G,EAGK,IAAkF;CACtF;EAAE,OAAO;EAAU,UAAU;EAAgD,cAAc;EAAgB;CAC3G;EAAE,OAAO;EAAW,UAAU;EAAiD,cAAc;EAAmB;CAChH;EAAE,OAAO;EAAW,UAAU;EAAiD,cAAc;EAAgB;CAC7G;EAAE,OAAO;EAAQ,UAAU;EAA8C,cAAc;EAAe;CACtG;EAAE,OAAO;EAAW,UAAU;EAAiD,cAAc;EAAW;CACzG,EAEK,IACJ,0JAMW,IAAoC,EAAK,SAAqB,EAAE,WAAQ,eAAY;CAC/F,IAAM,EAAE,SAAM,GAAS,EAgBjB,CAAC,GAAS,KAAc,EAbP,SACZ,EAAO,WAAW,EAAE,EAAqC,KAAK,MACjE,OAAO,KAAQ,WACV;EACL,OAAO;EACP,QAAQ,EAAI,OAAO,EAAE,CAAC,aAAa,GAAG,EAAI,MAAM,EAAE,CAAC,QAAQ,MAAM,IAAI;EACtE,GAEI,EACP,EACD,EAAE,CAAC,CAGqE;AAa3E,CAVA,QAAgB;AAId,EAFmB,KAAK,UAAU,EAAO,QAAQ,KAClC,KAAK,UAAU,EAAQ,IACT,EAAQ,SAAS,KAC5C,EAAS;GAAE,GAAG;GAAQ;GAAS,CAAC;IAEjC,CAAC,EAAQ,CAAC,EAGb,QAAgB;AAUd,KATqB,EAAO,WAAW,EAAE,EAAqC,KAAK,MAC7E,OAAO,KAAQ,WACV;GACL,OAAO;GACP,QAAQ,EAAI,OAAO,EAAE,CAAC,aAAa,GAAG,EAAI,MAAM,EAAE,CAAC,QAAQ,MAAM,IAAI;GACtE,GAEI,EACP,CACoB;IACrB,CAAC,EAAO,QAAQ,CAAC;CAEpB,IAAM,IAAe,GACU,GAAQ,MAAyB;AAC5D,IAAS;GAAE,GAAG;IAAS,IAAM;GAAO,CAAC;IAEvC,CAAC,GAAQ,EAAS,CACnB,EAEK,IAAqB,GAAa,GAAe,GAAgC,MAAkB;AACvG,KAAY,MAAS;GACnB,IAAM,IAAa,CAAC,GAAG,EAAK;AAE5B,UADA,EAAW,KAAS;IAAE,GAAG,EAAW;KAAS,IAAQ;IAAO,EACrD;IACP;IACD,EAAE,CAAC,EAIA,IAAoB,GAAa,GAAe,MAA6B;AACjF,KAAY,MAAS;GACnB,IAAM,IAAa,CAAC,GAAG,EAAK;AAE5B,UADA,EAAW,KAAS;IAAE,GAAG,EAAW;IAAQ,kBAAkB;IAAO,EAC9D;IACP;IACD,EAAE,CAAC,EAEA,IAAU,GACb,MAAkB;EACjB,IAAM,IAAW,EAAQ,IAAQ,oBAAoB,EAAE,EACjD,IAAwB;GAC5B,UAAU;GACV,OAAO;GACP,OAAO;IAAE,SAAS;IAAU,WAAW;IAAU,MAAM;IAAM;GAC9D;AACD,IAAkB,GAAO,CAAC,GAAG,GAAU,EAAK,CAAC;IAE/C,CAAC,GAAS,EAAkB,CAC7B,EAEK,IAAa,GAChB,GAAkB,GAAmB,MAAoC;AAGxE,IAAkB,IAFD,EAAQ,IAAW,oBAAoB,EAAE,EACpC,KAAK,GAAG,MAAO,MAAM,IAAY;GAAE,GAAG;GAAG,GAAG;GAAO,GAAG,EAAG,CAC9C;IAEnC,CAAC,GAAS,EAAkB,CAC7B,EAEK,IAAkB,GACrB,GAAkB,GAAmB,MAA2B;AAK/D,IAAkB,IAJD,EAAQ,IAAW,oBAAoB,EAAE,EACpC,KAAK,GAAG,MAC5B,MAAM,IAAY;GAAE,GAAG;GAAG,OAAO;IAAE,GAAG,EAAE;IAAO,SAAS;IAAQ,WAAW;IAAQ;GAAE,GAAG,EACzF,CACgC;IAEnC,CAAC,GAAS,EAAkB,CAC7B,EAEK,IAAa,GAChB,GAAkB,MAAsB;AAEvC,IACE,IAFe,EAAQ,IAAW,oBAAoB,EAAE,EAG/C,QAAQ,GAAG,MAAM,MAAM,EAAU,CAC3C;IAEH,CAAC,GAAS,EAAkB,CAC7B,EAEK,IAAY,QAAkB;AAClC,KAAY,MAAS,CAAC,GAAG,GAAM;GAAE,OAAO;GAAI,QAAQ;GAAI,CAAC,CAAC;IACzD,EAAE,CAAC,EAEA,IAAe,GAAa,MAAkB;AAClD,KAAY,MAAS,EAAK,QAAQ,GAAG,MAAM,MAAM,EAAM,CAAC;IACvD,EAAE,CAAC;AAEN,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;IAAO,WAAU;cACd,EAAE,iDAAiD,YAAY;IAC1D,CAAA,EACR,kBAAC,UAAD;IACE,OAAO,EAAO,YAAY;IAC1B,WAAW,MAAM,EAAa,YAAY,OAAO,EAAE,OAAO,MAAM,CAAC;IACjE,WAAU;cAHZ;KAYE,kBAAC,UAAD;MAAQ,OAAO;gBACZ,EAAE,gDAAgD,kBAAkB,EAAE,OAAO,IAAI,CAAC;MAC5E,CAAA;KACT,kBAAC,UAAD;MAAQ,OAAO;gBACZ,EAAE,gDAAgD,kBAAkB,EAAE,OAAO,IAAI,CAAC;MAC5E,CAAA;KACT,kBAAC,UAAD;MAAQ,OAAO;gBACZ,EAAE,gDAAgD,kBAAkB,EAAE,OAAO,IAAI,CAAC;MAC5E,CAAA;KACT,kBAAC,UAAD;MAAQ,OAAO;gBACZ,EAAE,gDAAgD,kBAAkB,EAAE,OAAO,KAAK,CAAC;MAC7E,CAAA;KACF;MACL,EAAA,CAAA;GAGN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,SAAD;KAAO,WAAU;eACd,EAAE,gDAAgD,UAAU;KACvD,CAAA,EACR,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;eAKT,EAAE,8CAA8C,eAAe;KACzD,CAAA,CACL;OAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAQ,KAAK,GAAK,MACjB,kBAAC,OAAD;KAEE,WAAU;eAFZ;MASE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAE,kDAAkD,oBAAoB,EAAE,OAAO,IAAQ,GAAG,CAAC;QACzF,CAAA,EACP,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAa,EAAM;QAClC,WAAU;kBAEV,kBAAC,OAAD;SAAK,WAAU;SAAU,MAAK;SAAO,QAAO;SAAe,SAAQ;mBACjE,kBAAC,QAAD;UAAM,eAAc;UAAQ,gBAAe;UAAQ,aAAa;UAAG,GAAE;UAAyB,CAAA;SAC1F,CAAA;QACC,CAAA,CACL;;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,SAAD;QACE,MAAK;QACL,OAAO,EAAI,SAAS;QACpB,WAAW,MAAM,EAAmB,GAAO,SAAS,EAAE,OAAO,MAAM;QACnE,aAAa,EAAE,0DAA0D,aAAa;QACtF,WAAU;QAQV,CAAA,EACF,kBAAC,SAAD;QACE,MAAK;QACL,OAAO,EAAI,UAAU;QACrB,WAAW,MAAM,EAAmB,GAAO,UAAU,EAAE,OAAO,MAAM;QACpE,aAAa,EAAE,2DAA2D,eAAe;QACzF,WAAU;QAQV,CAAA,CACE;;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,UAAD;QACE,OAAO,EAAI,UAAU;QACrB,WAAW,MAAM,EAAmB,GAAO,UAAU,EAAE,OAAO,MAAM;QACpE,WAAU;kBAHZ;SAYE,kBAAC,UAAD;UAAQ,OAAM;oBAAQ,EAAE,8CAA8C,OAAO;UAAU,CAAA;SACvF,kBAAC,UAAD;UAAQ,OAAM;oBAAU,EAAE,gDAAgD,SAAS;UAAU,CAAA;SAC7F,kBAAC,UAAD;UAAQ,OAAM;oBAAY,EAAE,kDAAkD,WAAW;UAAU,CAAA;SACnG,kBAAC,UAAD;UAAQ,OAAM;oBACX,EAAE,oDAAoD,aAAa;UAC7D,CAAA;SACT,kBAAC,UAAD;UAAQ,OAAM;oBAAQ,EAAE,8CAA8C,OAAO;UAAU,CAAA;SACvF,kBAAC,UAAD;UAAQ,OAAM;oBAAS,EAAE,+CAA+C,QAAQ;UAAU,CAAA;SACnF;WACT,kBAAC,UAAD;QACE,OAAO,EAAI,SAAS;QACpB,WAAW,MAAM,EAAmB,GAAO,SAAS,EAAE,OAAO,MAAM;QACnE,WAAU;kBAHZ;SAYE,kBAAC,UAAD;UAAQ,OAAM;oBAAQ,EAAE,6CAA6C,OAAO;UAAU,CAAA;SACtF,kBAAC,UAAD;UAAQ,OAAM;oBAAU,EAAE,+CAA+C,SAAS;UAAU,CAAA;SAC5F,kBAAC,UAAD;UAAQ,OAAM;oBAAS,EAAE,8CAA8C,QAAQ;UAAU,CAAA;SAClF;UACL;;MAGN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBACb,EAAE,8DAA8D,yBAAyB;UACrF,CAAA,EACP,kBAAC,UAAD;UACE,MAAK;UACL,eAAe,EAAQ,EAAM;UAC7B,WAAU;oBAET,EAAE,gEAAgE,aAAa;UACzE,CAAA,CACL;;SAEJ,EAAI,kBAAkB,UAAU,OAAO,KACvC,kBAAC,KAAD;SAAG,WAAU;mBACV,EACC,gEACA,yCACD;SACC,CAAA;QAGN,kBAAC,OAAD;SAAK,WAAU;oBACX,EAAI,oBAAoB,EAAE,EAAE,KAAK,GAAM,MAAc;UACrD,IAAM,IAAc,EAAK,aAAa,aAAa,EAAK,aAAa,WAC/D,IAAgC,EAAK,OAAO,WAAW,EAAK,OAAO,aAAa;AACtF,iBACE,kBAAC,OAAD;WAEE,WAAU;qBAFZ,CAIE,kBAAC,OAAD;YAAK,WAAU;sBAAf;aACE,kBAAC,UAAD;cACE,OAAO,EAAK;cACZ,WAAW,MACT,EAAW,GAAO,GAAW,EAAE,UAAU,EAAE,OAAO,OAA8B,CAAC;cAEnF,WAAW,GAAG,EAAe;wBAE5B,EAAa,KAAK,MACjB,kBAAC,UAAD;eAAuB,OAAO,EAAG;yBAC9B,EAAE,EAAG,UAAU,EAAG,aAAa;eACzB,EAFI,EAAG,MAEP,CACT;cACK,CAAA;aACT,kBAAC,SAAD;cACE,MAAK;cACL,OAAO,EAAK,SAAS;cACrB,WAAW,MAAM,EAAW,GAAO,GAAW,EAAE,OAAO,EAAE,OAAO,OAAO,CAAC;cACxE,aAAa,EAAE,wDAAwD,QAAQ;cAC/E,WAAW,GAAG,EAAe;cAC7B,CAAA;aACD,KACC,kBAAC,SAAD;cACE,MAAK;cACL,OAAO,EAAK,UAAU;cACtB,WAAW,MAAM,EAAW,GAAO,GAAW,EAAE,QAAQ,EAAE,OAAO,OAAO,CAAC;cACzE,aAAa,EAAE,yDAAyD,MAAM;cAC9E,WAAW,GAAG,EAAe;cAC7B,CAAA;aAEJ,kBAAC,UAAD;cACE,MAAK;cACL,eAAe,EAAW,GAAO,EAAU;cAC3C,WAAU;cACV,cAAY,EAAE,8CAA8C,cAAc;wBAE1E,kBAAC,OAAD;eAAK,WAAU;eAAc,MAAK;eAAO,QAAO;eAAe,SAAQ;yBACrE,kBAAC,QAAD;gBACE,eAAc;gBACd,gBAAe;gBACf,aAAa;gBACb,GAAE;gBACF,CAAA;eACE,CAAA;cACC,CAAA;aACL;eACN,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,UAAD;aACE,OAAO;aACP,WAAW,MAAM,EAAgB,GAAO,GAAW,EAAE,OAAO,MAAwB;aACpF,WAAW,GAAG,EAAe;uBAE5B,EAAW,KAAK,MACf,kBAAC,UAAD;cAAuB,OAAO,EAAG;wBAC9B,EAAE,EAAG,UAAU,EAAG,aAAa;cACzB,EAFI,EAAG,MAEP,CACT;aACK,CAAA,EACT,kBAAC,SAAD;aAAO,WAAU;uBAAjB,CACE,kBAAC,SAAD;cACE,MAAK;cACL,SAAS,EAAK,OAAO,SAAS;cAC9B,WAAW,MACT,EAAW,GAAO,GAAW,EAAE,OAAO;eAAE,GAAG,EAAK;eAAO,MAAM,EAAE,OAAO;eAAS,EAAE,CAAC;cAEpF,WAAU;cACV,CAAA,EACD,EAAE,4CAA4C,OAAO,CAChD;eACJ;cACF;aAzEC,EAyED;WAER;SACE,CAAA;QACF;;MACF;OA1MC,EA0MD,CACN,EAED,EAAQ,WAAW,KAClB,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,gDACA,mEACD;KACC,CAAA,CAEF;MACF,EAAA,CAAA;GAGN,kBAAC,OAAD;IACE,MAAK;IACL,cAAW;IACX,WAAU;cAHZ;KAQE,kBAAC,KAAD;MAAG,WAAU;gBAAiE;MAAmB,CAAA;KACjG,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,eAAe;OAC/B,WAAW,MAAM,EAAa,cAAc,EAAE,OAAO,QAAQ;OAC7D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAE,6CAA6C,kBAAkB;OAC7D,CAAA,CACD;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,mBAAmB;OACnC,WAAW,MAAM,EAAa,kBAAkB,EAAE,OAAO,QAAQ;OACjE,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAE,iDAAiD,kBAAkB;OACjE,CAAA,CACD;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,eAAe;OAC/B,WAAW,MAAM,EAAa,cAAc,EAAE,OAAO,QAAQ;OAC7D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAE,6CAA6C,qBAAqB;OAChE,CAAA,CACD;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,iBAAiB;OACjC,WAAW,MAAM,EAAa,gBAAgB,EAAE,OAAO,QAAQ;OAC/D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAE,+CAA+C,gBAAgB;OAC7D,CAAA,CACD;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,gBAAgB;OAChC,WAAW,MAAM,EAAa,eAAe,EAAE,OAAO,QAAQ;OAC9D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAE,8CAA8C,eAAe;OAC3D,CAAA,CACD;;KACJ;;GACF;;EAER"}
@@ -119,7 +119,7 @@ var c = 60, l = e(function({ columns: e, sortState: l, onSort: u, sticky: d = !0
119
119
  className: "inline-flex items-center",
120
120
  children: [
121
121
  p && g && /* @__PURE__ */ o("span", {
122
- className: "mr-1 -ml-1 cursor-grab text-text-tertiary opacity-0 group-hover:opacity-100",
122
+ className: "mr-1 -ml-1 cursor-grab text-text-muted opacity-0 group-hover:opacity-100",
123
123
  onClick: (e) => e.stopPropagation(),
124
124
  "aria-hidden": "true",
125
125
  title: "Drag to reorder column",
@@ -1 +1 @@
1
- {"version":3,"file":"TableHeader.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableHeader.tsx"],"sourcesContent":["/**\n * TableHeader Component\n *\n * Sortable table header with column definitions. In edit mode it also supports\n * interactive column resize (drag the right border) and reorder (drag the grip\n * handle), each surfaced through callbacks the parent persists to widget config.\n */\n\nimport { type FC, memo, useCallback, useEffect, useRef, useState } from 'react';\nimport { GripVertical } from 'lucide-react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ColumnDefinition {\n /** Unique key for the column */\n key: string;\n /** Display header text */\n header: string;\n /** Whether column is sortable */\n sortable?: boolean;\n /** Column width (CSS value) */\n width?: string;\n /** Text alignment */\n align?: 'left' | 'center' | 'right';\n}\n\nexport type SortDirection = 'asc' | 'desc' | null;\n\nexport interface SortState {\n column: string | null;\n direction: SortDirection;\n}\n\nexport interface TableHeaderProps {\n /** Column definitions */\n columns: ColumnDefinition[];\n /** Current sort state */\n sortState: SortState;\n /** Callback when sort changes */\n onSort: (column: string) => void;\n /** Whether header is sticky */\n sticky?: boolean;\n /** column key → sticky-left px offset for frozen leading columns */\n frozenLefts?: Record<string, number>;\n /** Enable interactive resize + reorder (edit mode). */\n editable?: boolean;\n /** Called on every resize move with the in-progress width (px) for live feedback. */\n onColumnResize?: (key: string, widthPx: number) => void;\n /** Called once when a resize drag ends with the final width (px) — parent persists. */\n onColumnResizeEnd?: (key: string, widthPx: number) => void;\n /** Called when a column is dropped onto another to reorder — parent persists. */\n onColumnReorder?: (sourceKey: string, targetKey: string) => void;\n}\n\nconst MIN_COLUMN_WIDTH = 60;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableHeader: FC<TableHeaderProps> = memo(function TableHeader({\n columns,\n sortState,\n onSort,\n sticky = true,\n frozenLefts,\n editable = false,\n onColumnResize,\n onColumnResizeEnd,\n onColumnReorder,\n}) {\n const handleSort = useCallback(\n (column: ColumnDefinition) => {\n if (column.sortable !== false) {\n onSort(column.key);\n }\n },\n [onSort]\n );\n\n // Refs to each <th> so a resize drag can read its current rendered width.\n const thRefs = useRef<Record<string, HTMLTableCellElement | null>>({});\n // Key being resized — disabled drag-reorder while resizing, and used for cursor.\n const [resizingKey, setResizingKey] = useState<string | null>(null);\n const [dragOverKey, setDragOverKey] = useState<string | null>(null);\n const dragSourceKey = useRef<string | null>(null);\n // Removes the active resize window-listeners; set during a drag, called on\n // pointer-up and on unmount so a drag interrupted by unmount can't leak.\n const teardownResizeRef = useRef<(() => void) | null>(null);\n\n // Start a resize drag from the right-border handle. Uses window listeners so\n // the pointer can leave the (narrow) handle without dropping the gesture.\n const startResize = useCallback(\n (key: string, startEvent: React.PointerEvent) => {\n startEvent.preventDefault();\n startEvent.stopPropagation();\n const th = thRefs.current[key];\n const startWidth = th ? th.offsetWidth : MIN_COLUMN_WIDTH;\n const startX = startEvent.clientX;\n setResizingKey(key);\n\n let lastWidth = startWidth;\n const onMove = (e: PointerEvent) => {\n lastWidth = Math.max(MIN_COLUMN_WIDTH, Math.round(startWidth + (e.clientX - startX)));\n onColumnResize?.(key, lastWidth);\n };\n const teardown = () => {\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onUp);\n teardownResizeRef.current = null;\n };\n const onUp = () => {\n teardown();\n setResizingKey(null);\n onColumnResizeEnd?.(key, lastWidth);\n };\n teardownResizeRef.current = teardown;\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onUp);\n },\n [onColumnResize, onColumnResizeEnd]\n );\n\n // Detach any in-progress resize listeners if the header unmounts mid-drag.\n useEffect(() => () => teardownResizeRef.current?.(), []);\n\n const getSortIcon = (column: ColumnDefinition) => {\n if (column.sortable === false) return null;\n\n const isActive = sortState.column === column.key;\n const direction = isActive ? sortState.direction : null;\n\n return (\n <span className=\"inline-flex ml-1\">\n {direction === 'asc' && (\n <svg className=\"w-4 h-4 text-action-primary-bg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 15l7-7 7 7\" />\n </svg>\n )}\n {direction === 'desc' && (\n <svg className=\"w-4 h-4 text-action-primary-bg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n )}\n {!direction && (\n <svg\n className=\"w-4 h-4 text-text-secondary opacity-0 group-hover:opacity-100\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4\"\n />\n </svg>\n )}\n </span>\n );\n };\n\n return (\n <thead\n className={`\n bg-bg-sunken\n ${sticky ? 'sticky top-0 z-10' : ''}\n `}\n >\n <tr>\n {columns.map((column) => {\n const frozen = frozenLefts?.[column.key];\n // Width (incl. live resize overrides) is baked into column.width by the parent.\n const width = column.width;\n const reorderable = editable && !!onColumnReorder && resizingKey === null;\n const isDropTarget = dragOverKey === column.key && dragSourceKey.current !== column.key;\n return (\n <th\n key={column.key}\n ref={(el) => {\n thRefs.current[column.key] = el;\n }}\n draggable={reorderable}\n onDragStart={\n reorderable\n ? (e) => {\n dragSourceKey.current = column.key;\n e.dataTransfer.effectAllowed = 'move';\n // Some browsers require data to be set for a drag to start.\n e.dataTransfer.setData('text/plain', column.key);\n }\n : undefined\n }\n onDragOver={\n editable && onColumnReorder\n ? (e) => {\n if (dragSourceKey.current && dragSourceKey.current !== column.key) {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n if (dragOverKey !== column.key) setDragOverKey(column.key);\n }\n }\n : undefined\n }\n onDragLeave={\n editable && onColumnReorder\n ? () => {\n if (dragOverKey === column.key) setDragOverKey(null);\n }\n : undefined\n }\n onDrop={\n editable && onColumnReorder\n ? (e) => {\n e.preventDefault();\n const source = dragSourceKey.current;\n dragSourceKey.current = null;\n setDragOverKey(null);\n if (source && source !== column.key) {\n onColumnReorder(source, column.key);\n }\n }\n : undefined\n }\n onDragEnd={\n reorderable\n ? () => {\n dragSourceKey.current = null;\n setDragOverKey(null);\n }\n : undefined\n }\n className={`\n relative px-4 py-3\n text-xs font-semibold uppercase tracking-wider\n text-text-secondary\n border-b border-border-default\n ${column.sortable !== false ? 'cursor-pointer select-none group hover:bg-bg-surface' : ''}\n ${column.align === 'center' ? 'text-center' : ''}\n ${column.align === 'right' ? 'text-right' : 'text-left'}\n ${frozen != null ? 'sticky z-20 bg-bg-sunken' : ''}\n ${isDropTarget ? 'border-l-2 border-l-action-primary-bg' : ''}\n `}\n style={frozen != null ? { width, left: frozen } : { width }}\n onClick={() => handleSort(column)}\n role={column.sortable !== false ? 'button' : undefined}\n tabIndex={column.sortable !== false ? 0 : undefined}\n onKeyDown={(e) => {\n if (column.sortable !== false && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n handleSort(column);\n }\n }}\n aria-sort={\n sortState.column === column.key\n ? sortState.direction === 'asc'\n ? 'ascending'\n : 'descending'\n : undefined\n }\n >\n <div className=\"inline-flex items-center\">\n {editable && onColumnReorder && (\n // Reorder grip — its own drag surface so dragging it (not the\n // label) starts a reorder, leaving the label click free to sort.\n <span\n className=\"mr-1 -ml-1 cursor-grab text-text-tertiary opacity-0 group-hover:opacity-100\"\n onClick={(e) => e.stopPropagation()}\n aria-hidden=\"true\"\n title=\"Drag to reorder column\"\n >\n <GripVertical className=\"w-3.5 h-3.5\" />\n </span>\n )}\n {column.header}\n {getSortIcon(column)}\n </div>\n {editable && onColumnResize && (\n // Resize handle on the right border. Pointer-only; stops the sort\n // click and the reorder drag from firing.\n <span\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={`Resize ${column.header} column`}\n className={`\n absolute top-0 right-0 z-30 h-full w-1.5\n cursor-col-resize select-none\n hover:bg-action-primary-bg/40\n ${resizingKey === column.key ? 'bg-action-primary-bg/60' : ''}\n `}\n onPointerDown={(e) => startResize(column.key, e)}\n onClick={(e) => e.stopPropagation()}\n draggable={false}\n />\n )}\n </th>\n );\n })}\n </tr>\n </thead>\n );\n});\n\nexport default TableHeader;\n"],"mappings":";;;;AAwDA,IAAM,IAAmB,IAMZ,IAAoC,EAAK,SAAqB,EACzE,YACA,cACA,WACA,YAAS,IACT,gBACA,cAAW,IACX,mBACA,sBACA,sBACC;CACD,IAAM,IAAa,GAChB,MAA6B;AAC5B,EAAI,EAAO,aAAa,MACtB,EAAO,EAAO,IAAI;IAGtB,CAAC,EAAO,CACT,EAGK,IAAS,EAAoD,EAAE,CAAC,EAEhE,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAC7D,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAC7D,IAAgB,EAAsB,KAAK,EAG3C,IAAoB,EAA4B,KAAK,EAIrD,IAAc,GACjB,GAAa,MAAmC;AAE/C,EADA,EAAW,gBAAgB,EAC3B,EAAW,iBAAiB;EAC5B,IAAM,IAAK,EAAO,QAAQ,IACpB,IAAa,IAAK,EAAG,cAAc,GACnC,IAAS,EAAW;AAC1B,IAAe,EAAI;EAEnB,IAAI,IAAY,GACV,KAAU,MAAoB;AAElC,GADA,IAAY,KAAK,IAAI,GAAkB,KAAK,MAAM,KAAc,EAAE,UAAU,GAAQ,CAAC,EACrF,IAAiB,GAAK,EAAU;KAE5B,UAAiB;AAGrB,GAFA,OAAO,oBAAoB,eAAe,EAAO,EACjD,OAAO,oBAAoB,aAAa,EAAK,EAC7C,EAAkB,UAAU;KAExB,UAAa;AAGjB,GAFA,GAAU,EACV,EAAe,KAAK,EACpB,IAAoB,GAAK,EAAU;;AAIrC,EAFA,EAAkB,UAAU,GAC5B,OAAO,iBAAiB,eAAe,EAAO,EAC9C,OAAO,iBAAiB,aAAa,EAAK;IAE5C,CAAC,GAAgB,EAAkB,CACpC;AAGD,eAAsB,EAAkB,WAAW,EAAE,EAAE,CAAC;CAExD,IAAM,KAAe,MAA6B;AAChD,MAAI,EAAO,aAAa,GAAO,QAAO;EAGtC,IAAM,IADW,EAAU,WAAW,EAAO,MAChB,EAAU,YAAY;AAEnD,SACE,kBAAC,QAAD;GAAM,WAAU;aAAhB;IACG,MAAc,SACb,kBAAC,OAAD;KAAK,WAAU;KAAiC,MAAK;KAAO,QAAO;KAAe,SAAQ;eACxF,kBAAC,QAAD;MAAM,eAAc;MAAQ,gBAAe;MAAQ,aAAa;MAAG,GAAE;MAAkB,CAAA;KACnF,CAAA;IAEP,MAAc,UACb,kBAAC,OAAD;KAAK,WAAU;KAAiC,MAAK;KAAO,QAAO;KAAe,SAAQ;eACxF,kBAAC,QAAD;MAAM,eAAc;MAAQ,gBAAe;MAAQ,aAAa;MAAG,GAAE;MAAmB,CAAA;KACpF,CAAA;IAEP,CAAC,KACA,kBAAC,OAAD;KACE,WAAU;KACV,MAAK;KACL,QAAO;KACP,SAAQ;eAER,kBAAC,QAAD;MACE,eAAc;MACd,gBAAe;MACf,aAAa;MACb,GAAE;MACF,CAAA;KACE,CAAA;IAEH;;;AAIX,QACE,kBAAC,SAAD;EACE,WAAW;;UAEP,IAAS,sBAAsB,GAAG;;YAGtC,kBAAC,MAAD,EAAA,UACG,EAAQ,KAAK,MAAW;GACvB,IAAM,IAAS,IAAc,EAAO,MAE9B,IAAQ,EAAO,OACf,IAAc,KAAY,CAAC,CAAC,KAAmB,MAAgB,MAC/D,IAAe,MAAgB,EAAO,OAAO,EAAc,YAAY,EAAO;AACpF,UACE,kBAAC,MAAD;IAEE,MAAM,MAAO;AACX,OAAO,QAAQ,EAAO,OAAO;;IAE/B,WAAW;IACX,aACE,KACK,MAAM;AAIL,KAHA,EAAc,UAAU,EAAO,KAC/B,EAAE,aAAa,gBAAgB,QAE/B,EAAE,aAAa,QAAQ,cAAc,EAAO,IAAI;QAElD,KAAA;IAEN,YACE,KAAY,KACP,MAAM;AACL,KAAI,EAAc,WAAW,EAAc,YAAY,EAAO,QAC5D,EAAE,gBAAgB,EAClB,EAAE,aAAa,aAAa,QACxB,MAAgB,EAAO,OAAK,EAAe,EAAO,IAAI;QAG9D,KAAA;IAEN,aACE,KAAY,UACF;AACJ,KAAI,MAAgB,EAAO,OAAK,EAAe,KAAK;QAEtD,KAAA;IAEN,QACE,KAAY,KACP,MAAM;AACL,OAAE,gBAAgB;KAClB,IAAM,IAAS,EAAc;AAG7B,KAFA,EAAc,UAAU,MACxB,EAAe,KAAK,EAChB,KAAU,MAAW,EAAO,OAC9B,EAAgB,GAAQ,EAAO,IAAI;QAGvC,KAAA;IAEN,WACE,UACU;AAEJ,KADA,EAAc,UAAU,MACxB,EAAe,KAAK;QAEtB,KAAA;IAEN,WAAW;;;;;gBAKT,EAAO,aAAa,KAAiE,KAAzD,uDAA4D;gBACxF,EAAO,UAAU,WAAW,gBAAgB,GAAG;gBAC/C,EAAO,UAAU,UAAU,eAAe,YAAY;gBACtD,KAAU,OAAoC,KAA7B,2BAAgC;gBACjD,IAAe,0CAA0C,GAAG;;IAE9D,OAAO,KAAU,OAAiC,EAAE,UAAO,GAAnC;KAAE;KAAO,MAAM;KAAQ;IAC/C,eAAe,EAAW,EAAO;IACjC,MAAM,EAAO,aAAa,KAAmB,KAAA,IAAX;IAClC,UAAU,EAAO,aAAa,KAAY,KAAA,IAAJ;IACtC,YAAY,MAAM;AAChB,KAAI,EAAO,aAAa,OAAU,EAAE,QAAQ,WAAW,EAAE,QAAQ,SAC/D,EAAE,gBAAgB,EAClB,EAAW,EAAO;;IAGtB,aACE,EAAU,WAAW,EAAO,MACxB,EAAU,cAAc,QACtB,cACA,eACF,KAAA;cAjFR,CAoFE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,KAAY,KAGX,kBAAC,QAAD;OACE,WAAU;OACV,UAAU,MAAM,EAAE,iBAAiB;OACnC,eAAY;OACZ,OAAM;iBAEN,kBAAC,GAAD,EAAc,WAAU,eAAgB,CAAA;OACnC,CAAA;MAER,EAAO;MACP,EAAY,EAAO;MAChB;QACL,KAAY,KAGX,kBAAC,QAAD;KACE,MAAK;KACL,oBAAiB;KACjB,cAAY,UAAU,EAAO,OAAO;KACpC,WAAW;;;;sBAIP,MAAgB,EAAO,MAAM,4BAA4B,GAAG;;KAEhE,gBAAgB,MAAM,EAAY,EAAO,KAAK,EAAE;KAChD,UAAU,MAAM,EAAE,iBAAiB;KACnC,WAAW;KACX,CAAA,CAED;MArHE,EAAO,IAqHT;IAEP,EACC,CAAA;EACC,CAAA;EAEV"}
1
+ {"version":3,"file":"TableHeader.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableHeader.tsx"],"sourcesContent":["/**\n * TableHeader Component\n *\n * Sortable table header with column definitions. In edit mode it also supports\n * interactive column resize (drag the right border) and reorder (drag the grip\n * handle), each surfaced through callbacks the parent persists to widget config.\n */\n\nimport { type FC, memo, useCallback, useEffect, useRef, useState } from 'react';\nimport { GripVertical } from 'lucide-react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ColumnDefinition {\n /** Unique key for the column */\n key: string;\n /** Display header text */\n header: string;\n /** Whether column is sortable */\n sortable?: boolean;\n /** Column width (CSS value) */\n width?: string;\n /** Text alignment */\n align?: 'left' | 'center' | 'right';\n}\n\nexport type SortDirection = 'asc' | 'desc' | null;\n\nexport interface SortState {\n column: string | null;\n direction: SortDirection;\n}\n\nexport interface TableHeaderProps {\n /** Column definitions */\n columns: ColumnDefinition[];\n /** Current sort state */\n sortState: SortState;\n /** Callback when sort changes */\n onSort: (column: string) => void;\n /** Whether header is sticky */\n sticky?: boolean;\n /** column key → sticky-left px offset for frozen leading columns */\n frozenLefts?: Record<string, number>;\n /** Enable interactive resize + reorder (edit mode). */\n editable?: boolean;\n /** Called on every resize move with the in-progress width (px) for live feedback. */\n onColumnResize?: (key: string, widthPx: number) => void;\n /** Called once when a resize drag ends with the final width (px) — parent persists. */\n onColumnResizeEnd?: (key: string, widthPx: number) => void;\n /** Called when a column is dropped onto another to reorder — parent persists. */\n onColumnReorder?: (sourceKey: string, targetKey: string) => void;\n}\n\nconst MIN_COLUMN_WIDTH = 60;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableHeader: FC<TableHeaderProps> = memo(function TableHeader({\n columns,\n sortState,\n onSort,\n sticky = true,\n frozenLefts,\n editable = false,\n onColumnResize,\n onColumnResizeEnd,\n onColumnReorder,\n}) {\n const handleSort = useCallback(\n (column: ColumnDefinition) => {\n if (column.sortable !== false) {\n onSort(column.key);\n }\n },\n [onSort]\n );\n\n // Refs to each <th> so a resize drag can read its current rendered width.\n const thRefs = useRef<Record<string, HTMLTableCellElement | null>>({});\n // Key being resized — disabled drag-reorder while resizing, and used for cursor.\n const [resizingKey, setResizingKey] = useState<string | null>(null);\n const [dragOverKey, setDragOverKey] = useState<string | null>(null);\n const dragSourceKey = useRef<string | null>(null);\n // Removes the active resize window-listeners; set during a drag, called on\n // pointer-up and on unmount so a drag interrupted by unmount can't leak.\n const teardownResizeRef = useRef<(() => void) | null>(null);\n\n // Start a resize drag from the right-border handle. Uses window listeners so\n // the pointer can leave the (narrow) handle without dropping the gesture.\n const startResize = useCallback(\n (key: string, startEvent: React.PointerEvent) => {\n startEvent.preventDefault();\n startEvent.stopPropagation();\n const th = thRefs.current[key];\n const startWidth = th ? th.offsetWidth : MIN_COLUMN_WIDTH;\n const startX = startEvent.clientX;\n setResizingKey(key);\n\n let lastWidth = startWidth;\n const onMove = (e: PointerEvent) => {\n lastWidth = Math.max(MIN_COLUMN_WIDTH, Math.round(startWidth + (e.clientX - startX)));\n onColumnResize?.(key, lastWidth);\n };\n const teardown = () => {\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onUp);\n teardownResizeRef.current = null;\n };\n const onUp = () => {\n teardown();\n setResizingKey(null);\n onColumnResizeEnd?.(key, lastWidth);\n };\n teardownResizeRef.current = teardown;\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onUp);\n },\n [onColumnResize, onColumnResizeEnd]\n );\n\n // Detach any in-progress resize listeners if the header unmounts mid-drag.\n useEffect(() => () => teardownResizeRef.current?.(), []);\n\n const getSortIcon = (column: ColumnDefinition) => {\n if (column.sortable === false) return null;\n\n const isActive = sortState.column === column.key;\n const direction = isActive ? sortState.direction : null;\n\n return (\n <span className=\"inline-flex ml-1\">\n {direction === 'asc' && (\n <svg className=\"w-4 h-4 text-action-primary-bg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 15l7-7 7 7\" />\n </svg>\n )}\n {direction === 'desc' && (\n <svg className=\"w-4 h-4 text-action-primary-bg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n )}\n {!direction && (\n <svg\n className=\"w-4 h-4 text-text-secondary opacity-0 group-hover:opacity-100\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4\"\n />\n </svg>\n )}\n </span>\n );\n };\n\n return (\n <thead\n className={`\n bg-bg-sunken\n ${sticky ? 'sticky top-0 z-10' : ''}\n `}\n >\n <tr>\n {columns.map((column) => {\n const frozen = frozenLefts?.[column.key];\n // Width (incl. live resize overrides) is baked into column.width by the parent.\n const width = column.width;\n const reorderable = editable && !!onColumnReorder && resizingKey === null;\n const isDropTarget = dragOverKey === column.key && dragSourceKey.current !== column.key;\n return (\n <th\n key={column.key}\n ref={(el) => {\n thRefs.current[column.key] = el;\n }}\n draggable={reorderable}\n onDragStart={\n reorderable\n ? (e) => {\n dragSourceKey.current = column.key;\n e.dataTransfer.effectAllowed = 'move';\n // Some browsers require data to be set for a drag to start.\n e.dataTransfer.setData('text/plain', column.key);\n }\n : undefined\n }\n onDragOver={\n editable && onColumnReorder\n ? (e) => {\n if (dragSourceKey.current && dragSourceKey.current !== column.key) {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n if (dragOverKey !== column.key) setDragOverKey(column.key);\n }\n }\n : undefined\n }\n onDragLeave={\n editable && onColumnReorder\n ? () => {\n if (dragOverKey === column.key) setDragOverKey(null);\n }\n : undefined\n }\n onDrop={\n editable && onColumnReorder\n ? (e) => {\n e.preventDefault();\n const source = dragSourceKey.current;\n dragSourceKey.current = null;\n setDragOverKey(null);\n if (source && source !== column.key) {\n onColumnReorder(source, column.key);\n }\n }\n : undefined\n }\n onDragEnd={\n reorderable\n ? () => {\n dragSourceKey.current = null;\n setDragOverKey(null);\n }\n : undefined\n }\n className={`\n relative px-4 py-3\n text-xs font-semibold uppercase tracking-wider\n text-text-secondary\n border-b border-border-default\n ${column.sortable !== false ? 'cursor-pointer select-none group hover:bg-bg-surface' : ''}\n ${column.align === 'center' ? 'text-center' : ''}\n ${column.align === 'right' ? 'text-right' : 'text-left'}\n ${frozen != null ? 'sticky z-20 bg-bg-sunken' : ''}\n ${isDropTarget ? 'border-l-2 border-l-action-primary-bg' : ''}\n `}\n style={frozen != null ? { width, left: frozen } : { width }}\n onClick={() => handleSort(column)}\n role={column.sortable !== false ? 'button' : undefined}\n tabIndex={column.sortable !== false ? 0 : undefined}\n onKeyDown={(e) => {\n if (column.sortable !== false && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n handleSort(column);\n }\n }}\n aria-sort={\n sortState.column === column.key\n ? sortState.direction === 'asc'\n ? 'ascending'\n : 'descending'\n : undefined\n }\n >\n <div className=\"inline-flex items-center\">\n {editable && onColumnReorder && (\n // Reorder grip — its own drag surface so dragging it (not the\n // label) starts a reorder, leaving the label click free to sort.\n <span\n className=\"mr-1 -ml-1 cursor-grab text-text-muted opacity-0 group-hover:opacity-100\"\n onClick={(e) => e.stopPropagation()}\n aria-hidden=\"true\"\n title=\"Drag to reorder column\"\n >\n <GripVertical className=\"w-3.5 h-3.5\" />\n </span>\n )}\n {column.header}\n {getSortIcon(column)}\n </div>\n {editable && onColumnResize && (\n // Resize handle on the right border. Pointer-only; stops the sort\n // click and the reorder drag from firing.\n <span\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={`Resize ${column.header} column`}\n className={`\n absolute top-0 right-0 z-30 h-full w-1.5\n cursor-col-resize select-none\n hover:bg-action-primary-bg/40\n ${resizingKey === column.key ? 'bg-action-primary-bg/60' : ''}\n `}\n onPointerDown={(e) => startResize(column.key, e)}\n onClick={(e) => e.stopPropagation()}\n draggable={false}\n />\n )}\n </th>\n );\n })}\n </tr>\n </thead>\n );\n});\n\nexport default TableHeader;\n"],"mappings":";;;;AAwDA,IAAM,IAAmB,IAMZ,IAAoC,EAAK,SAAqB,EACzE,YACA,cACA,WACA,YAAS,IACT,gBACA,cAAW,IACX,mBACA,sBACA,sBACC;CACD,IAAM,IAAa,GAChB,MAA6B;AAC5B,EAAI,EAAO,aAAa,MACtB,EAAO,EAAO,IAAI;IAGtB,CAAC,EAAO,CACT,EAGK,IAAS,EAAoD,EAAE,CAAC,EAEhE,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAC7D,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAC7D,IAAgB,EAAsB,KAAK,EAG3C,IAAoB,EAA4B,KAAK,EAIrD,IAAc,GACjB,GAAa,MAAmC;AAE/C,EADA,EAAW,gBAAgB,EAC3B,EAAW,iBAAiB;EAC5B,IAAM,IAAK,EAAO,QAAQ,IACpB,IAAa,IAAK,EAAG,cAAc,GACnC,IAAS,EAAW;AAC1B,IAAe,EAAI;EAEnB,IAAI,IAAY,GACV,KAAU,MAAoB;AAElC,GADA,IAAY,KAAK,IAAI,GAAkB,KAAK,MAAM,KAAc,EAAE,UAAU,GAAQ,CAAC,EACrF,IAAiB,GAAK,EAAU;KAE5B,UAAiB;AAGrB,GAFA,OAAO,oBAAoB,eAAe,EAAO,EACjD,OAAO,oBAAoB,aAAa,EAAK,EAC7C,EAAkB,UAAU;KAExB,UAAa;AAGjB,GAFA,GAAU,EACV,EAAe,KAAK,EACpB,IAAoB,GAAK,EAAU;;AAIrC,EAFA,EAAkB,UAAU,GAC5B,OAAO,iBAAiB,eAAe,EAAO,EAC9C,OAAO,iBAAiB,aAAa,EAAK;IAE5C,CAAC,GAAgB,EAAkB,CACpC;AAGD,eAAsB,EAAkB,WAAW,EAAE,EAAE,CAAC;CAExD,IAAM,KAAe,MAA6B;AAChD,MAAI,EAAO,aAAa,GAAO,QAAO;EAGtC,IAAM,IADW,EAAU,WAAW,EAAO,MAChB,EAAU,YAAY;AAEnD,SACE,kBAAC,QAAD;GAAM,WAAU;aAAhB;IACG,MAAc,SACb,kBAAC,OAAD;KAAK,WAAU;KAAiC,MAAK;KAAO,QAAO;KAAe,SAAQ;eACxF,kBAAC,QAAD;MAAM,eAAc;MAAQ,gBAAe;MAAQ,aAAa;MAAG,GAAE;MAAkB,CAAA;KACnF,CAAA;IAEP,MAAc,UACb,kBAAC,OAAD;KAAK,WAAU;KAAiC,MAAK;KAAO,QAAO;KAAe,SAAQ;eACxF,kBAAC,QAAD;MAAM,eAAc;MAAQ,gBAAe;MAAQ,aAAa;MAAG,GAAE;MAAmB,CAAA;KACpF,CAAA;IAEP,CAAC,KACA,kBAAC,OAAD;KACE,WAAU;KACV,MAAK;KACL,QAAO;KACP,SAAQ;eAER,kBAAC,QAAD;MACE,eAAc;MACd,gBAAe;MACf,aAAa;MACb,GAAE;MACF,CAAA;KACE,CAAA;IAEH;;;AAIX,QACE,kBAAC,SAAD;EACE,WAAW;;UAEP,IAAS,sBAAsB,GAAG;;YAGtC,kBAAC,MAAD,EAAA,UACG,EAAQ,KAAK,MAAW;GACvB,IAAM,IAAS,IAAc,EAAO,MAE9B,IAAQ,EAAO,OACf,IAAc,KAAY,CAAC,CAAC,KAAmB,MAAgB,MAC/D,IAAe,MAAgB,EAAO,OAAO,EAAc,YAAY,EAAO;AACpF,UACE,kBAAC,MAAD;IAEE,MAAM,MAAO;AACX,OAAO,QAAQ,EAAO,OAAO;;IAE/B,WAAW;IACX,aACE,KACK,MAAM;AAIL,KAHA,EAAc,UAAU,EAAO,KAC/B,EAAE,aAAa,gBAAgB,QAE/B,EAAE,aAAa,QAAQ,cAAc,EAAO,IAAI;QAElD,KAAA;IAEN,YACE,KAAY,KACP,MAAM;AACL,KAAI,EAAc,WAAW,EAAc,YAAY,EAAO,QAC5D,EAAE,gBAAgB,EAClB,EAAE,aAAa,aAAa,QACxB,MAAgB,EAAO,OAAK,EAAe,EAAO,IAAI;QAG9D,KAAA;IAEN,aACE,KAAY,UACF;AACJ,KAAI,MAAgB,EAAO,OAAK,EAAe,KAAK;QAEtD,KAAA;IAEN,QACE,KAAY,KACP,MAAM;AACL,OAAE,gBAAgB;KAClB,IAAM,IAAS,EAAc;AAG7B,KAFA,EAAc,UAAU,MACxB,EAAe,KAAK,EAChB,KAAU,MAAW,EAAO,OAC9B,EAAgB,GAAQ,EAAO,IAAI;QAGvC,KAAA;IAEN,WACE,UACU;AAEJ,KADA,EAAc,UAAU,MACxB,EAAe,KAAK;QAEtB,KAAA;IAEN,WAAW;;;;;gBAKT,EAAO,aAAa,KAAiE,KAAzD,uDAA4D;gBACxF,EAAO,UAAU,WAAW,gBAAgB,GAAG;gBAC/C,EAAO,UAAU,UAAU,eAAe,YAAY;gBACtD,KAAU,OAAoC,KAA7B,2BAAgC;gBACjD,IAAe,0CAA0C,GAAG;;IAE9D,OAAO,KAAU,OAAiC,EAAE,UAAO,GAAnC;KAAE;KAAO,MAAM;KAAQ;IAC/C,eAAe,EAAW,EAAO;IACjC,MAAM,EAAO,aAAa,KAAmB,KAAA,IAAX;IAClC,UAAU,EAAO,aAAa,KAAY,KAAA,IAAJ;IACtC,YAAY,MAAM;AAChB,KAAI,EAAO,aAAa,OAAU,EAAE,QAAQ,WAAW,EAAE,QAAQ,SAC/D,EAAE,gBAAgB,EAClB,EAAW,EAAO;;IAGtB,aACE,EAAU,WAAW,EAAO,MACxB,EAAU,cAAc,QACtB,cACA,eACF,KAAA;cAjFR,CAoFE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,KAAY,KAGX,kBAAC,QAAD;OACE,WAAU;OACV,UAAU,MAAM,EAAE,iBAAiB;OACnC,eAAY;OACZ,OAAM;iBAEN,kBAAC,GAAD,EAAc,WAAU,eAAgB,CAAA;OACnC,CAAA;MAER,EAAO;MACP,EAAY,EAAO;MAChB;QACL,KAAY,KAGX,kBAAC,QAAD;KACE,MAAK;KACL,oBAAiB;KACjB,cAAY,UAAU,EAAO,OAAO;KACpC,WAAW;;;;sBAIP,MAAgB,EAAO,MAAM,4BAA4B,GAAG;;KAEhE,gBAAgB,MAAM,EAAY,EAAO,KAAK,EAAE;KAChD,UAAU,MAAM,EAAE,iBAAiB;KACnC,WAAW;KACX,CAAA,CAED;MArHE,EAAO,IAqHT;IAEP,EACC,CAAA;EACC,CAAA;EAEV"}
@@ -366,7 +366,7 @@ var h = c(function({ widget: c, data: h = [], onRowClick: g, onDrilldown: _ }) {
366
366
  placeholder: "Search products...",
367
367
  value: w,
368
368
  onChange: (e) => oe(e.target.value),
369
- className: "\n pl-10 pr-4 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg focus:border-action-primary-bg\n w-48 sm:w-64\n placeholder:text-text-tertiary\n "
369
+ className: "\n pl-10 pr-4 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg focus:border-action-primary-bg\n w-48 sm:w-64\n placeholder:text-text-muted\n "
370
370
  })]
371
371
  }), v?.showExport !== !1 && /* @__PURE__ */ p("button", {
372
372
  type: "button",
@@ -1 +1 @@
1
- {"version":3,"file":"TableWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableWidget.tsx"],"sourcesContent":["/**\n * TableWidget Component\n *\n * Data table with sorting, filtering, and pagination.\n */\n\nimport { type FC, memo, useState, useMemo, useCallback, useRef, useEffect } from 'react';\nimport type { Widget, TableConfig, TableColumnConfig } from '../../../types';\nimport { TableHeader, type ColumnDefinition, type SortState, type SortDirection } from './TableHeader';\nimport { TableCell, type CellFormatConfig, type CellChart } from './TableCell';\nimport { TablePagination, type PaginationState } from './TablePagination';\nimport { resolveRowClassName, type ConditionalRule } from '../utils/conditionalFormat';\n// Phase 2: Cross-filtering support\nimport { useWidgetCrossFilter, useCrossFilterContext } from '../../../contexts';\nimport { useIsEditMode } from '../../../store';\nimport { useWidgetConfigPersist } from '../../../hooks';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TableWidgetProps {\n /** Widget configuration */\n widget: Widget;\n /** Table data (array of rows) */\n data?: Record<string, unknown>[];\n /** Click handler for row drilldown */\n onRowClick?: (row: Record<string, unknown>, index: number) => void;\n /** Drilldown handler - receives selected row data */\n onDrilldown?: (selectedData: Record<string, unknown>) => void;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction sortData(data: Record<string, unknown>[], sortState: SortState): Record<string, unknown>[] {\n if (!sortState.column || !sortState.direction) {\n return data;\n }\n\n return [...data].sort((a, b) => {\n const aValue = a[sortState.column!];\n const bValue = b[sortState.column!];\n\n // Handle null/undefined\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return sortState.direction === 'asc' ? 1 : -1;\n if (bValue == null) return sortState.direction === 'asc' ? -1 : 1;\n\n // Compare values\n let comparison = 0;\n if (typeof aValue === 'number' && typeof bValue === 'number') {\n comparison = aValue - bValue;\n } else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n return sortState.direction === 'asc' ? comparison : -comparison;\n });\n}\n\nfunction filterData(\n data: Record<string, unknown>[],\n searchQuery: string,\n columns: ColumnDefinition[]\n): Record<string, unknown>[] {\n if (!searchQuery.trim()) {\n return data;\n }\n\n const query = searchQuery.toLowerCase();\n return data.filter((row) =>\n columns.some((col) => {\n const value = row[col.key];\n return value != null && String(value).toLowerCase().includes(query);\n })\n );\n}\n\n/** Format a footer total respecting the column's cell format. */\nfunction formatTotal(value: number, formatType?: string, currency?: string): string {\n switch (formatType) {\n case 'currency':\n return new Intl.NumberFormat('en-US', { style: 'currency', currency: currency || 'USD' }).format(value);\n case 'percentage':\n return `${(value * 100).toFixed(1)}%`;\n case 'number':\n return new Intl.NumberFormat('en-US').format(value);\n default:\n return Number.isInteger(value) ? String(value) : value.toFixed(2);\n }\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableWidget: FC<TableWidgetProps> = memo(function TableWidget({\n widget,\n data: rawData = [],\n onRowClick,\n onDrilldown,\n}) {\n const config = widget.config as unknown as TableConfig | undefined;\n\n // Normalize data - handle both array and object formats\n const data = useMemo(() => {\n // If it's already an array, use it directly\n if (Array.isArray(rawData)) {\n return rawData;\n }\n\n // If it's an object, try to find an array property\n if (rawData && typeof rawData === 'object') {\n // Check common array property names\n const possibleArrayProps = ['data', 'items', 'rows', 'results', 'records', 'list', 'sales', 'entries', 'values'];\n for (const prop of possibleArrayProps) {\n if (Array.isArray((rawData as Record<string, unknown>)[prop])) {\n return (rawData as Record<string, unknown>)[prop] as Record<string, unknown>[];\n }\n }\n\n // If object has array values, use the first one\n const values = Object.values(rawData);\n for (const value of values) {\n if (Array.isArray(value)) {\n return value as Record<string, unknown>[];\n }\n }\n\n // If it's a single object, wrap it in an array\n return [rawData as Record<string, unknown>];\n }\n\n return [];\n }, [rawData]);\n\n // Phase 2: Cross-filtering support\n const { handleDataClick: triggerCrossFilter, enabled: crossFilterEnabled } = useWidgetCrossFilter(\n widget.id,\n // Map first column to filter ID by default, can be configured\n config?.crossFilterMappings\n );\n const { clearAllCrossFilters, hasCrossFilters } = useCrossFilterContext();\n\n // State\n const [sortState, setSortState] = useState<SortState>({\n column: config?.defaultSortColumn || null,\n direction: (config?.defaultSortDirection as SortDirection) || null,\n });\n const [searchQuery, setSearchQuery] = useState('');\n const [pagination, setPagination] = useState<PaginationState>({\n page: 0,\n pageSize: config?.pageSize || 10,\n totalItems: 0,\n });\n\n // Interactive column resize/reorder (edit mode only). Local overrides give\n // live feedback; the committed layout is persisted to config so it survives\n // reload (see commitColumnLayout).\n const isEditMode = useIsEditMode();\n const { persistConfig } = useWidgetConfigPersist(widget);\n const [widthOverrides, setWidthOverrides] = useState<Record<string, number>>({});\n const [columnOrder, setColumnOrder] = useState<string[] | null>(null);\n\n // Build column definitions from config or data\n const baseColumns: ColumnDefinition[] = useMemo(() => {\n if (config?.columns?.length) {\n return (config.columns as (string | TableColumnConfig)[]).map((col) => {\n // Handle both string and object column definitions\n if (typeof col === 'string') {\n return {\n key: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n sortable: true,\n };\n }\n // Object column definition — accept both .key and .field\n const fieldKey = col.key || col.field || '';\n return {\n key: fieldKey,\n header: col.label || col.header || fieldKey,\n sortable: col.sortable !== false,\n width: col.width != null ? String(col.width) : undefined,\n align: col.align as ColumnDefinition['align'],\n };\n }) as ColumnDefinition[];\n }\n\n // Auto-generate from first data row\n if (data.length > 0) {\n return Object.keys(data[0]).map((key) => ({\n key,\n header: key.charAt(0).toUpperCase() + key.slice(1).replace(/_/g, ' '),\n sortable: true,\n }));\n }\n\n return [];\n }, [config?.columns, data]);\n\n // Apply the live reorder + resize overrides on top of the base columns. Any\n // column not named in columnOrder keeps its original relative position at the\n // end (handles columns added since the order was set).\n const columns: ColumnDefinition[] = useMemo(() => {\n let cols = baseColumns;\n if (columnOrder) {\n const byKey = new Map(baseColumns.map((c) => [c.key, c]));\n const ordered = columnOrder.map((k) => byKey.get(k)).filter((c): c is ColumnDefinition => c !== undefined);\n const rest = baseColumns.filter((c) => !columnOrder.includes(c.key));\n cols = [...ordered, ...rest];\n }\n if (Object.keys(widthOverrides).length > 0) {\n cols = cols.map((c) => (widthOverrides[c.key] != null ? { ...c, width: `${widthOverrides[c.key]}px` } : c));\n }\n return cols;\n }, [baseColumns, columnOrder, widthOverrides]);\n\n // Persist the current column order + widths to config.columns. Builds explicit\n // column objects (preserving any existing per-column config), which also pins\n // a previously auto-generated column set so order/width survive reload.\n const commitColumnLayout = useCallback(\n (orderKeys: string[], widths: Record<string, number>) => {\n const existing = new Map<string, TableColumnConfig>();\n config?.columns?.forEach((c) => {\n const k = c.key || c.field;\n if (k) existing.set(k, c);\n });\n const baseKeys = baseColumns.map((c) => c.key);\n const finalKeys = [\n ...orderKeys.filter((k) => baseKeys.includes(k)),\n ...baseKeys.filter((k) => !orderKeys.includes(k)),\n ];\n const newColumns: TableColumnConfig[] = finalKeys.map((key) => {\n const base = baseColumns.find((c) => c.key === key);\n const prev = existing.get(key);\n const next: TableColumnConfig = { ...(prev ?? {}), key };\n // Preserve a header label for columns that had none in config (auto-generated).\n if (!next.label && !next.header && base?.header) next.label = base.header;\n const w = widths[key];\n if (w != null) next.width = w;\n return next;\n });\n void persistConfig({ columns: newColumns });\n },\n [baseColumns, config?.columns, persistConfig]\n );\n\n const handleColumnResize = useCallback((key: string, widthPx: number) => {\n setWidthOverrides((prev) => ({ ...prev, [key]: widthPx }));\n }, []);\n\n const handleColumnResizeEnd = useCallback(\n (key: string, widthPx: number) => {\n const widths = { ...widthOverrides, [key]: widthPx };\n setWidthOverrides(widths);\n const order = columnOrder ?? baseColumns.map((c) => c.key);\n commitColumnLayout(order, widths);\n },\n [widthOverrides, columnOrder, baseColumns, commitColumnLayout]\n );\n\n const handleColumnReorder = useCallback(\n (sourceKey: string, targetKey: string) => {\n const current = columnOrder ?? baseColumns.map((c) => c.key);\n const from = current.indexOf(sourceKey);\n if (from < 0 || sourceKey === targetKey) return;\n const next = [...current];\n next.splice(from, 1);\n // Insert before the target's *post-removal* index, so dropping onto a\n // column always lands the source just before it regardless of direction.\n const insertAt = next.indexOf(targetKey);\n if (insertAt < 0) return;\n next.splice(insertAt, 0, sourceKey);\n setColumnOrder(next);\n commitColumnLayout(next, widthOverrides);\n },\n [columnOrder, baseColumns, widthOverrides, commitColumnLayout]\n );\n\n // Build cell format configs\n const cellFormats: Record<string, CellFormatConfig> = useMemo(() => {\n const formats: Record<string, CellFormatConfig> = {};\n config?.columns?.forEach((col) => {\n if (col.format && (col.key || col.field)) {\n formats[col.key || col.field || ''] = {\n type: col.format,\n ...(col.linkPattern ? { linkPattern: col.linkPattern } : {}),\n };\n }\n });\n return formats;\n }, [config?.columns]);\n\n // Per-column in-cell chart kind (e.g. sparkline).\n const columnCellCharts: Record<string, CellChart | undefined> = useMemo(() => {\n const map: Record<string, CellChart | undefined> = {};\n config?.columns?.forEach((col) => {\n const fieldKey = col.key || col.field;\n if (fieldKey && col.cellChart) {\n map[fieldKey] = col.cellChart;\n }\n });\n return map;\n }, [config?.columns]);\n\n // Per-column conditional rules (column-level overrides win over table-level).\n const tableRules = config?.conditionalRules;\n // Row-level conditional rules: tint the whole <tr> (escalation/breach rows).\n const rowRules = config?.rowRules;\n const columnRules: Record<string, ConditionalRule[] | undefined> = useMemo(() => {\n const map: Record<string, ConditionalRule[] | undefined> = {};\n config?.columns?.forEach((col) => {\n const fieldKey = col.key || col.field;\n if (fieldKey && col.conditionalRules?.length) {\n map[fieldKey] = col.conditionalRules;\n }\n });\n return map;\n }, [config?.columns]);\n\n // Per-column totals/aggregates for the footer row.\n const columnTotals: Record<string, TableColumnConfig['total']> = useMemo(() => {\n const map: Record<string, TableColumnConfig['total']> = {};\n config?.columns?.forEach((col) => {\n const fieldKey = col.key || col.field;\n if (fieldKey && col.total && col.total !== 'none') {\n map[fieldKey] = col.total;\n }\n });\n return map;\n }, [config?.columns]);\n\n const hasTotals = config?.showTotals === true || Object.keys(columnTotals).length > 0;\n\n // Process data: filter, sort, paginate\n const processedData = useMemo(() => {\n let result = data;\n\n // Filter\n if (config?.showSearch !== false) {\n result = filterData(result, searchQuery, columns);\n }\n\n // Sort\n result = sortData(result, sortState);\n\n return result;\n }, [data, searchQuery, sortState, columns, config?.showSearch]);\n\n // Max absolute numeric value per column — scales in-cell data bars.\n const dataBarMaxes: Record<string, number> = useMemo(() => {\n const maxes: Record<string, number> = {};\n for (const col of columns) {\n let max = 0;\n for (const row of processedData) {\n const v = row[col.key];\n if (typeof v === 'number' && Number.isFinite(v)) {\n max = Math.max(max, Math.abs(v));\n }\n }\n maxes[col.key] = max;\n }\n return maxes;\n }, [columns, processedData]);\n\n // Footer totals/aggregates per column (computed over the filtered set).\n const footerTotals: Record<string, number | null> = useMemo(() => {\n if (!hasTotals) return {};\n const result: Record<string, number | null> = {};\n for (const col of columns) {\n const agg = columnTotals[col.key];\n if (!agg) {\n result[col.key] = null;\n continue;\n }\n const nums = processedData\n .map((row) => row[col.key])\n .filter((v): v is number => typeof v === 'number' && Number.isFinite(v));\n if (agg === 'count') {\n result[col.key] = processedData.length;\n } else if (nums.length === 0) {\n result[col.key] = null;\n } else if (agg === 'sum') {\n result[col.key] = nums.reduce((a, b) => a + b, 0);\n } else if (agg === 'avg') {\n result[col.key] = nums.reduce((a, b) => a + b, 0) / nums.length;\n } else if (agg === 'min') {\n result[col.key] = Math.min(...nums);\n } else if (agg === 'max') {\n result[col.key] = Math.max(...nums);\n } else {\n result[col.key] = null;\n }\n }\n return result;\n }, [hasTotals, columns, columnTotals, processedData]);\n\n // Update total items when data changes\n useMemo(() => {\n setPagination((prev) => ({\n ...prev,\n totalItems: processedData.length,\n }));\n }, [processedData.length]);\n\n // Paginate\n const paginatedData = useMemo(() => {\n if (config?.showPagination === false) {\n return processedData;\n }\n const start = pagination.page * pagination.pageSize;\n return processedData.slice(start, start + pagination.pageSize);\n }, [processedData, pagination, config?.showPagination]);\n\n // ----------------------------------------------------------------------------\n // Row virtualization (windowing) — render only the visible slice of a large\n // dataset. Active when config.virtualized is set; bypasses pagination so the\n // whole filtered set scrolls in one container. No external dependency: a fixed\n // row height + top/bottom spacer rows reproduce the full scroll height.\n // ----------------------------------------------------------------------------\n const virtualized = config?.virtualized === true;\n const rowHeight = config?.rowHeight && config.rowHeight > 0 ? config.rowHeight : 44;\n const scrollRef = useRef<HTMLDivElement>(null);\n const [scrollTop, setScrollTop] = useState(0);\n const [viewportH, setViewportH] = useState(0);\n\n useEffect(() => {\n if (!virtualized) return undefined;\n const el = scrollRef.current;\n if (!el) return undefined;\n setViewportH(el.clientHeight);\n const ro =\n typeof ResizeObserver !== 'undefined' ? new ResizeObserver(() => setViewportH(el.clientHeight)) : undefined;\n ro?.observe(el);\n return () => ro?.disconnect();\n }, [virtualized]);\n\n const OVERSCAN = 6;\n const virtualWindow = useMemo(() => {\n if (!virtualized) return null;\n const total = processedData.length;\n const visibleCount = viewportH > 0 ? Math.ceil(viewportH / rowHeight) : 20;\n const startIndex = Math.max(0, Math.floor(scrollTop / rowHeight) - OVERSCAN);\n const endIndex = Math.min(total, startIndex + visibleCount + OVERSCAN * 2);\n return {\n rows: processedData.slice(startIndex, endIndex),\n topSpacer: startIndex * rowHeight,\n bottomSpacer: Math.max(0, (total - endIndex) * rowHeight),\n startIndex,\n };\n }, [virtualized, processedData, viewportH, scrollTop, rowHeight]);\n\n // The rows actually rendered in <tbody>: windowed slice or the paginated page.\n const renderRows = virtualized && virtualWindow ? virtualWindow.rows : paginatedData;\n const rowBaseIndex = virtualized && virtualWindow ? virtualWindow.startIndex : 0;\n\n // Sticky-left frozen columns: give the first N columns explicit widths so the\n // header and body align, then compute each one's cumulative left offset.\n const frozenCount = config?.frozenColumns && config.frozenColumns > 0 ? config.frozenColumns : 0;\n const FROZEN_DEFAULT_W = 160;\n const { displayColumns, frozenLefts } = useMemo(() => {\n if (frozenCount <= 0) return { displayColumns: columns, frozenLefts: {} as Record<string, number> };\n const lefts: Record<string, number> = {};\n let cursor = 0;\n const cols = columns.map((col, i) => {\n if (i < frozenCount) {\n const widthPx = col.width ? parseInt(col.width, 10) || FROZEN_DEFAULT_W : FROZEN_DEFAULT_W;\n lefts[col.key] = cursor;\n cursor += widthPx;\n return { ...col, width: `${widthPx}px` };\n }\n return col;\n });\n return { displayColumns: cols, frozenLefts: lefts };\n }, [columns, frozenCount]);\n\n // Handlers\n const handleSort = useCallback((column: string) => {\n setSortState((prev) => {\n if (prev.column !== column) {\n return { column, direction: 'asc' };\n }\n const nextDirection: SortDirection = prev.direction === 'asc' ? 'desc' : prev.direction === 'desc' ? null : 'asc';\n return {\n column: nextDirection ? column : null,\n direction: nextDirection,\n };\n });\n }, []);\n\n const handlePageChange = useCallback((page: number) => {\n setPagination((prev) => ({ ...prev, page }));\n }, []);\n\n const handlePageSizeChange = useCallback((pageSize: number) => {\n setPagination((prev) => ({ ...prev, pageSize, page: 0 }));\n }, []);\n\n const handleRowClick = useCallback(\n (row: Record<string, unknown>, index: number) => {\n // Trigger cross-filtering on row click when explicitly enabled via config\n const hasCrossFilterConfig = config?.crossFilterMappings?.length || config?.enableCrossFilter;\n if (crossFilterEnabled && hasCrossFilterConfig) {\n const firstColumn = columns[0]?.key;\n const label = firstColumn ? String(row[firstColumn]) : undefined;\n triggerCrossFilter(row as Record<string, unknown>, label);\n }\n\n // Trigger drilldown if configured\n if (onDrilldown) {\n onDrilldown(row);\n } else if (onRowClick && widget.drilldowns?.length) {\n onRowClick(row, index);\n }\n },\n [\n onRowClick,\n onDrilldown,\n widget.drilldowns,\n crossFilterEnabled,\n triggerCrossFilter,\n columns,\n config?.crossFilterMappings,\n config?.enableCrossFilter,\n ]\n );\n\n // Export to CSV\n const handleExport = useCallback(() => {\n const headers = columns.map((c) => c.header).join(',');\n const rows = processedData.map((row) =>\n columns\n .map((col) => {\n const value = row[col.key];\n if (value == null) return '';\n const str = String(value);\n // Escape quotes and wrap in quotes if contains comma\n if (str.includes(',') || str.includes('\"')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n })\n .join(',')\n );\n const csv = [headers, ...rows].join('\\n');\n const blob = new Blob([csv], { type: 'text/csv' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `${widget.title || 'table'}-${new Date().toISOString().split('T')[0]}.csv`;\n a.click();\n URL.revokeObjectURL(url);\n }, [columns, processedData, widget.title]);\n\n // Row is only clickable if drilldown or cross-filter is explicitly configured\n const hasCrossFilterConfig = config?.crossFilterMappings?.length || config?.enableCrossFilter;\n const isClickable = Boolean(onDrilldown || (onRowClick && widget.drilldowns?.length) || hasCrossFilterConfig);\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Cross-filter active indicator with clear button */}\n {hasCrossFilters && (\n <div className=\"flex items-center gap-2 px-3 py-2 border-b border-border-default\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n clearAllCrossFilters();\n }}\n className=\"\n inline-flex items-center gap-1.5\n px-2.5 py-1 rounded-md\n text-xs font-medium\n bg-action-primary-bg/10 text-action-primary-text\n hover:bg-action-primary-bg/20\n transition-colors\n \"\n >\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M10 19l-7-7m0 0l7-7m-7 7h18\" />\n </svg>\n Clear Filter\n </button>\n </div>\n )}\n\n {/* Toolbar */}\n {(config?.showSearch !== false || config?.showExport !== false) && (\n <div className=\"flex items-center justify-between p-3 border-b border-border-default\">\n {/* Search */}\n {config?.showSearch !== false && (\n <div className=\"relative flex items-center\">\n <svg\n className=\"absolute left-3 w-4 h-4 text-text-secondary pointer-events-none\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\n />\n </svg>\n <input\n type=\"text\"\n placeholder=\"Search products...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"\n pl-10 pr-4 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg focus:border-action-primary-bg\n w-48 sm:w-64\n placeholder:text-text-tertiary\n \"\n />\n </div>\n )}\n\n {/* Export */}\n {config?.showExport !== false && (\n <button\n type=\"button\"\n onClick={handleExport}\n className=\"\n inline-flex items-center gap-2\n px-3 py-2\n text-sm font-medium\n text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n hover:bg-bg-sunken\n transition-colors\n \"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n />\n </svg>\n Export CSV\n </button>\n )}\n </div>\n )}\n\n {/* Table */}\n <div\n ref={scrollRef}\n className=\"flex-1 overflow-auto\"\n onScroll={virtualized ? (e) => setScrollTop((e.target as HTMLDivElement).scrollTop) : undefined}\n >\n <table className=\"w-full\">\n <TableHeader\n columns={displayColumns}\n sortState={sortState}\n onSort={handleSort}\n frozenLefts={frozenCount > 0 ? frozenLefts : undefined}\n editable={isEditMode}\n onColumnResize={isEditMode ? handleColumnResize : undefined}\n onColumnResizeEnd={isEditMode ? handleColumnResizeEnd : undefined}\n onColumnReorder={isEditMode ? handleColumnReorder : undefined}\n />\n <tbody>\n {/* Virtualization top spacer */}\n {virtualized && virtualWindow && virtualWindow.topSpacer > 0 && (\n <tr aria-hidden=\"true\" style={{ height: virtualWindow.topSpacer }}>\n <td colSpan={displayColumns.length} style={{ padding: 0, border: 'none' }} />\n </tr>\n )}\n {renderRows.map((row, i) => {\n const rowIndex = rowBaseIndex + i;\n return (\n <tr\n key={rowIndex}\n className={`\n ${isClickable ? 'cursor-pointer hover:bg-bg-sunken/50' : ''}\n ${rowIndex % 2 === 0 ? 'bg-bg-surface' : 'bg-bg-sunken/30'}\n ${resolveRowClassName(row, rowRules)}\n `}\n style={virtualized ? { height: rowHeight } : undefined}\n onClick={() => handleRowClick(row, rowIndex)}\n >\n {displayColumns.map((column) => (\n <TableCell\n key={column.key}\n value={row[column.key]}\n column={column}\n format={cellFormats[column.key]}\n rowData={row}\n conditionalRules={columnRules[column.key] ?? tableRules}\n dataBarMax={dataBarMaxes[column.key]}\n stickyLeft={frozenLefts[column.key]}\n cellChart={columnCellCharts[column.key]}\n />\n ))}\n </tr>\n );\n })}\n {/* Virtualization bottom spacer */}\n {virtualized && virtualWindow && virtualWindow.bottomSpacer > 0 && (\n <tr aria-hidden=\"true\" style={{ height: virtualWindow.bottomSpacer }}>\n <td colSpan={displayColumns.length} style={{ padding: 0, border: 'none' }} />\n </tr>\n )}\n </tbody>\n {hasTotals && processedData.length > 0 && (\n <tfoot>\n <tr className=\"bg-bg-sunken/50 font-semibold border-t-2 border-border-default\">\n {displayColumns.map((column, colIndex) => {\n const total = footerTotals[column.key];\n const format = cellFormats[column.key];\n const frozen = frozenLefts[column.key];\n return (\n <td\n key={column.key}\n className={`\n px-4 py-3 text-sm text-text-primary\n ${column.align === 'center' ? 'text-center' : ''}\n ${column.align === 'right' ? 'text-right' : 'text-left'}\n ${frozen != null ? 'sticky z-10 bg-bg-sunken' : ''}\n `}\n style={frozen != null ? { left: frozen } : undefined}\n >\n {total != null\n ? formatTotal(total, format?.type, format?.currency)\n : colIndex === 0\n ? 'Total'\n : ''}\n </td>\n );\n })}\n </tr>\n </tfoot>\n )}\n </table>\n\n {processedData.length === 0 && (\n <div className=\"flex items-center justify-center py-12 text-text-secondary\">\n {searchQuery ? 'No matching records found' : 'No data available'}\n </div>\n )}\n </div>\n\n {/* Pagination (suppressed in virtualized mode — the whole set scrolls) */}\n {!virtualized && config?.showPagination !== false && processedData.length > 0 && (\n <TablePagination\n pagination={{ ...pagination, totalItems: processedData.length }}\n onPageChange={handlePageChange}\n onPageSizeChange={handlePageSizeChange}\n />\n )}\n </div>\n );\n});\n\nexport default TableWidget;\n"],"mappings":"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"}
1
+ {"version":3,"file":"TableWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableWidget.tsx"],"sourcesContent":["/**\n * TableWidget Component\n *\n * Data table with sorting, filtering, and pagination.\n */\n\nimport { type FC, memo, useState, useMemo, useCallback, useRef, useEffect } from 'react';\nimport type { Widget, TableConfig, TableColumnConfig } from '../../../types';\nimport { TableHeader, type ColumnDefinition, type SortState, type SortDirection } from './TableHeader';\nimport { TableCell, type CellFormatConfig, type CellChart } from './TableCell';\nimport { TablePagination, type PaginationState } from './TablePagination';\nimport { resolveRowClassName, type ConditionalRule } from '../utils/conditionalFormat';\n// Phase 2: Cross-filtering support\nimport { useWidgetCrossFilter, useCrossFilterContext } from '../../../contexts';\nimport { useIsEditMode } from '../../../store';\nimport { useWidgetConfigPersist } from '../../../hooks';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TableWidgetProps {\n /** Widget configuration */\n widget: Widget;\n /** Table data (array of rows) */\n data?: Record<string, unknown>[];\n /** Click handler for row drilldown */\n onRowClick?: (row: Record<string, unknown>, index: number) => void;\n /** Drilldown handler - receives selected row data */\n onDrilldown?: (selectedData: Record<string, unknown>) => void;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction sortData(data: Record<string, unknown>[], sortState: SortState): Record<string, unknown>[] {\n if (!sortState.column || !sortState.direction) {\n return data;\n }\n\n return [...data].sort((a, b) => {\n const aValue = a[sortState.column!];\n const bValue = b[sortState.column!];\n\n // Handle null/undefined\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return sortState.direction === 'asc' ? 1 : -1;\n if (bValue == null) return sortState.direction === 'asc' ? -1 : 1;\n\n // Compare values\n let comparison = 0;\n if (typeof aValue === 'number' && typeof bValue === 'number') {\n comparison = aValue - bValue;\n } else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n return sortState.direction === 'asc' ? comparison : -comparison;\n });\n}\n\nfunction filterData(\n data: Record<string, unknown>[],\n searchQuery: string,\n columns: ColumnDefinition[]\n): Record<string, unknown>[] {\n if (!searchQuery.trim()) {\n return data;\n }\n\n const query = searchQuery.toLowerCase();\n return data.filter((row) =>\n columns.some((col) => {\n const value = row[col.key];\n return value != null && String(value).toLowerCase().includes(query);\n })\n );\n}\n\n/** Format a footer total respecting the column's cell format. */\nfunction formatTotal(value: number, formatType?: string, currency?: string): string {\n switch (formatType) {\n case 'currency':\n return new Intl.NumberFormat('en-US', { style: 'currency', currency: currency || 'USD' }).format(value);\n case 'percentage':\n return `${(value * 100).toFixed(1)}%`;\n case 'number':\n return new Intl.NumberFormat('en-US').format(value);\n default:\n return Number.isInteger(value) ? String(value) : value.toFixed(2);\n }\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableWidget: FC<TableWidgetProps> = memo(function TableWidget({\n widget,\n data: rawData = [],\n onRowClick,\n onDrilldown,\n}) {\n const config = widget.config as unknown as TableConfig | undefined;\n\n // Normalize data - handle both array and object formats\n const data = useMemo(() => {\n // If it's already an array, use it directly\n if (Array.isArray(rawData)) {\n return rawData;\n }\n\n // If it's an object, try to find an array property\n if (rawData && typeof rawData === 'object') {\n // Check common array property names\n const possibleArrayProps = ['data', 'items', 'rows', 'results', 'records', 'list', 'sales', 'entries', 'values'];\n for (const prop of possibleArrayProps) {\n if (Array.isArray((rawData as Record<string, unknown>)[prop])) {\n return (rawData as Record<string, unknown>)[prop] as Record<string, unknown>[];\n }\n }\n\n // If object has array values, use the first one\n const values = Object.values(rawData);\n for (const value of values) {\n if (Array.isArray(value)) {\n return value as Record<string, unknown>[];\n }\n }\n\n // If it's a single object, wrap it in an array\n return [rawData as Record<string, unknown>];\n }\n\n return [];\n }, [rawData]);\n\n // Phase 2: Cross-filtering support\n const { handleDataClick: triggerCrossFilter, enabled: crossFilterEnabled } = useWidgetCrossFilter(\n widget.id,\n // Map first column to filter ID by default, can be configured\n config?.crossFilterMappings\n );\n const { clearAllCrossFilters, hasCrossFilters } = useCrossFilterContext();\n\n // State\n const [sortState, setSortState] = useState<SortState>({\n column: config?.defaultSortColumn || null,\n direction: (config?.defaultSortDirection as SortDirection) || null,\n });\n const [searchQuery, setSearchQuery] = useState('');\n const [pagination, setPagination] = useState<PaginationState>({\n page: 0,\n pageSize: config?.pageSize || 10,\n totalItems: 0,\n });\n\n // Interactive column resize/reorder (edit mode only). Local overrides give\n // live feedback; the committed layout is persisted to config so it survives\n // reload (see commitColumnLayout).\n const isEditMode = useIsEditMode();\n const { persistConfig } = useWidgetConfigPersist(widget);\n const [widthOverrides, setWidthOverrides] = useState<Record<string, number>>({});\n const [columnOrder, setColumnOrder] = useState<string[] | null>(null);\n\n // Build column definitions from config or data\n const baseColumns: ColumnDefinition[] = useMemo(() => {\n if (config?.columns?.length) {\n return (config.columns as (string | TableColumnConfig)[]).map((col) => {\n // Handle both string and object column definitions\n if (typeof col === 'string') {\n return {\n key: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n sortable: true,\n };\n }\n // Object column definition — accept both .key and .field\n const fieldKey = col.key || col.field || '';\n return {\n key: fieldKey,\n header: col.label || col.header || fieldKey,\n sortable: col.sortable !== false,\n width: col.width != null ? String(col.width) : undefined,\n align: col.align as ColumnDefinition['align'],\n };\n }) as ColumnDefinition[];\n }\n\n // Auto-generate from first data row\n if (data.length > 0) {\n return Object.keys(data[0]).map((key) => ({\n key,\n header: key.charAt(0).toUpperCase() + key.slice(1).replace(/_/g, ' '),\n sortable: true,\n }));\n }\n\n return [];\n }, [config?.columns, data]);\n\n // Apply the live reorder + resize overrides on top of the base columns. Any\n // column not named in columnOrder keeps its original relative position at the\n // end (handles columns added since the order was set).\n const columns: ColumnDefinition[] = useMemo(() => {\n let cols = baseColumns;\n if (columnOrder) {\n const byKey = new Map(baseColumns.map((c) => [c.key, c]));\n const ordered = columnOrder.map((k) => byKey.get(k)).filter((c): c is ColumnDefinition => c !== undefined);\n const rest = baseColumns.filter((c) => !columnOrder.includes(c.key));\n cols = [...ordered, ...rest];\n }\n if (Object.keys(widthOverrides).length > 0) {\n cols = cols.map((c) => (widthOverrides[c.key] != null ? { ...c, width: `${widthOverrides[c.key]}px` } : c));\n }\n return cols;\n }, [baseColumns, columnOrder, widthOverrides]);\n\n // Persist the current column order + widths to config.columns. Builds explicit\n // column objects (preserving any existing per-column config), which also pins\n // a previously auto-generated column set so order/width survive reload.\n const commitColumnLayout = useCallback(\n (orderKeys: string[], widths: Record<string, number>) => {\n const existing = new Map<string, TableColumnConfig>();\n config?.columns?.forEach((c) => {\n const k = c.key || c.field;\n if (k) existing.set(k, c);\n });\n const baseKeys = baseColumns.map((c) => c.key);\n const finalKeys = [\n ...orderKeys.filter((k) => baseKeys.includes(k)),\n ...baseKeys.filter((k) => !orderKeys.includes(k)),\n ];\n const newColumns: TableColumnConfig[] = finalKeys.map((key) => {\n const base = baseColumns.find((c) => c.key === key);\n const prev = existing.get(key);\n const next: TableColumnConfig = { ...(prev ?? {}), key };\n // Preserve a header label for columns that had none in config (auto-generated).\n if (!next.label && !next.header && base?.header) next.label = base.header;\n const w = widths[key];\n if (w != null) next.width = w;\n return next;\n });\n void persistConfig({ columns: newColumns });\n },\n [baseColumns, config?.columns, persistConfig]\n );\n\n const handleColumnResize = useCallback((key: string, widthPx: number) => {\n setWidthOverrides((prev) => ({ ...prev, [key]: widthPx }));\n }, []);\n\n const handleColumnResizeEnd = useCallback(\n (key: string, widthPx: number) => {\n const widths = { ...widthOverrides, [key]: widthPx };\n setWidthOverrides(widths);\n const order = columnOrder ?? baseColumns.map((c) => c.key);\n commitColumnLayout(order, widths);\n },\n [widthOverrides, columnOrder, baseColumns, commitColumnLayout]\n );\n\n const handleColumnReorder = useCallback(\n (sourceKey: string, targetKey: string) => {\n const current = columnOrder ?? baseColumns.map((c) => c.key);\n const from = current.indexOf(sourceKey);\n if (from < 0 || sourceKey === targetKey) return;\n const next = [...current];\n next.splice(from, 1);\n // Insert before the target's *post-removal* index, so dropping onto a\n // column always lands the source just before it regardless of direction.\n const insertAt = next.indexOf(targetKey);\n if (insertAt < 0) return;\n next.splice(insertAt, 0, sourceKey);\n setColumnOrder(next);\n commitColumnLayout(next, widthOverrides);\n },\n [columnOrder, baseColumns, widthOverrides, commitColumnLayout]\n );\n\n // Build cell format configs\n const cellFormats: Record<string, CellFormatConfig> = useMemo(() => {\n const formats: Record<string, CellFormatConfig> = {};\n config?.columns?.forEach((col) => {\n if (col.format && (col.key || col.field)) {\n formats[col.key || col.field || ''] = {\n type: col.format,\n ...(col.linkPattern ? { linkPattern: col.linkPattern } : {}),\n };\n }\n });\n return formats;\n }, [config?.columns]);\n\n // Per-column in-cell chart kind (e.g. sparkline).\n const columnCellCharts: Record<string, CellChart | undefined> = useMemo(() => {\n const map: Record<string, CellChart | undefined> = {};\n config?.columns?.forEach((col) => {\n const fieldKey = col.key || col.field;\n if (fieldKey && col.cellChart) {\n map[fieldKey] = col.cellChart;\n }\n });\n return map;\n }, [config?.columns]);\n\n // Per-column conditional rules (column-level overrides win over table-level).\n const tableRules = config?.conditionalRules;\n // Row-level conditional rules: tint the whole <tr> (escalation/breach rows).\n const rowRules = config?.rowRules;\n const columnRules: Record<string, ConditionalRule[] | undefined> = useMemo(() => {\n const map: Record<string, ConditionalRule[] | undefined> = {};\n config?.columns?.forEach((col) => {\n const fieldKey = col.key || col.field;\n if (fieldKey && col.conditionalRules?.length) {\n map[fieldKey] = col.conditionalRules;\n }\n });\n return map;\n }, [config?.columns]);\n\n // Per-column totals/aggregates for the footer row.\n const columnTotals: Record<string, TableColumnConfig['total']> = useMemo(() => {\n const map: Record<string, TableColumnConfig['total']> = {};\n config?.columns?.forEach((col) => {\n const fieldKey = col.key || col.field;\n if (fieldKey && col.total && col.total !== 'none') {\n map[fieldKey] = col.total;\n }\n });\n return map;\n }, [config?.columns]);\n\n const hasTotals = config?.showTotals === true || Object.keys(columnTotals).length > 0;\n\n // Process data: filter, sort, paginate\n const processedData = useMemo(() => {\n let result = data;\n\n // Filter\n if (config?.showSearch !== false) {\n result = filterData(result, searchQuery, columns);\n }\n\n // Sort\n result = sortData(result, sortState);\n\n return result;\n }, [data, searchQuery, sortState, columns, config?.showSearch]);\n\n // Max absolute numeric value per column — scales in-cell data bars.\n const dataBarMaxes: Record<string, number> = useMemo(() => {\n const maxes: Record<string, number> = {};\n for (const col of columns) {\n let max = 0;\n for (const row of processedData) {\n const v = row[col.key];\n if (typeof v === 'number' && Number.isFinite(v)) {\n max = Math.max(max, Math.abs(v));\n }\n }\n maxes[col.key] = max;\n }\n return maxes;\n }, [columns, processedData]);\n\n // Footer totals/aggregates per column (computed over the filtered set).\n const footerTotals: Record<string, number | null> = useMemo(() => {\n if (!hasTotals) return {};\n const result: Record<string, number | null> = {};\n for (const col of columns) {\n const agg = columnTotals[col.key];\n if (!agg) {\n result[col.key] = null;\n continue;\n }\n const nums = processedData\n .map((row) => row[col.key])\n .filter((v): v is number => typeof v === 'number' && Number.isFinite(v));\n if (agg === 'count') {\n result[col.key] = processedData.length;\n } else if (nums.length === 0) {\n result[col.key] = null;\n } else if (agg === 'sum') {\n result[col.key] = nums.reduce((a, b) => a + b, 0);\n } else if (agg === 'avg') {\n result[col.key] = nums.reduce((a, b) => a + b, 0) / nums.length;\n } else if (agg === 'min') {\n result[col.key] = Math.min(...nums);\n } else if (agg === 'max') {\n result[col.key] = Math.max(...nums);\n } else {\n result[col.key] = null;\n }\n }\n return result;\n }, [hasTotals, columns, columnTotals, processedData]);\n\n // Update total items when data changes\n useMemo(() => {\n setPagination((prev) => ({\n ...prev,\n totalItems: processedData.length,\n }));\n }, [processedData.length]);\n\n // Paginate\n const paginatedData = useMemo(() => {\n if (config?.showPagination === false) {\n return processedData;\n }\n const start = pagination.page * pagination.pageSize;\n return processedData.slice(start, start + pagination.pageSize);\n }, [processedData, pagination, config?.showPagination]);\n\n // ----------------------------------------------------------------------------\n // Row virtualization (windowing) — render only the visible slice of a large\n // dataset. Active when config.virtualized is set; bypasses pagination so the\n // whole filtered set scrolls in one container. No external dependency: a fixed\n // row height + top/bottom spacer rows reproduce the full scroll height.\n // ----------------------------------------------------------------------------\n const virtualized = config?.virtualized === true;\n const rowHeight = config?.rowHeight && config.rowHeight > 0 ? config.rowHeight : 44;\n const scrollRef = useRef<HTMLDivElement>(null);\n const [scrollTop, setScrollTop] = useState(0);\n const [viewportH, setViewportH] = useState(0);\n\n useEffect(() => {\n if (!virtualized) return undefined;\n const el = scrollRef.current;\n if (!el) return undefined;\n setViewportH(el.clientHeight);\n const ro =\n typeof ResizeObserver !== 'undefined' ? new ResizeObserver(() => setViewportH(el.clientHeight)) : undefined;\n ro?.observe(el);\n return () => ro?.disconnect();\n }, [virtualized]);\n\n const OVERSCAN = 6;\n const virtualWindow = useMemo(() => {\n if (!virtualized) return null;\n const total = processedData.length;\n const visibleCount = viewportH > 0 ? Math.ceil(viewportH / rowHeight) : 20;\n const startIndex = Math.max(0, Math.floor(scrollTop / rowHeight) - OVERSCAN);\n const endIndex = Math.min(total, startIndex + visibleCount + OVERSCAN * 2);\n return {\n rows: processedData.slice(startIndex, endIndex),\n topSpacer: startIndex * rowHeight,\n bottomSpacer: Math.max(0, (total - endIndex) * rowHeight),\n startIndex,\n };\n }, [virtualized, processedData, viewportH, scrollTop, rowHeight]);\n\n // The rows actually rendered in <tbody>: windowed slice or the paginated page.\n const renderRows = virtualized && virtualWindow ? virtualWindow.rows : paginatedData;\n const rowBaseIndex = virtualized && virtualWindow ? virtualWindow.startIndex : 0;\n\n // Sticky-left frozen columns: give the first N columns explicit widths so the\n // header and body align, then compute each one's cumulative left offset.\n const frozenCount = config?.frozenColumns && config.frozenColumns > 0 ? config.frozenColumns : 0;\n const FROZEN_DEFAULT_W = 160;\n const { displayColumns, frozenLefts } = useMemo(() => {\n if (frozenCount <= 0) return { displayColumns: columns, frozenLefts: {} as Record<string, number> };\n const lefts: Record<string, number> = {};\n let cursor = 0;\n const cols = columns.map((col, i) => {\n if (i < frozenCount) {\n const widthPx = col.width ? parseInt(col.width, 10) || FROZEN_DEFAULT_W : FROZEN_DEFAULT_W;\n lefts[col.key] = cursor;\n cursor += widthPx;\n return { ...col, width: `${widthPx}px` };\n }\n return col;\n });\n return { displayColumns: cols, frozenLefts: lefts };\n }, [columns, frozenCount]);\n\n // Handlers\n const handleSort = useCallback((column: string) => {\n setSortState((prev) => {\n if (prev.column !== column) {\n return { column, direction: 'asc' };\n }\n const nextDirection: SortDirection = prev.direction === 'asc' ? 'desc' : prev.direction === 'desc' ? null : 'asc';\n return {\n column: nextDirection ? column : null,\n direction: nextDirection,\n };\n });\n }, []);\n\n const handlePageChange = useCallback((page: number) => {\n setPagination((prev) => ({ ...prev, page }));\n }, []);\n\n const handlePageSizeChange = useCallback((pageSize: number) => {\n setPagination((prev) => ({ ...prev, pageSize, page: 0 }));\n }, []);\n\n const handleRowClick = useCallback(\n (row: Record<string, unknown>, index: number) => {\n // Trigger cross-filtering on row click when explicitly enabled via config\n const hasCrossFilterConfig = config?.crossFilterMappings?.length || config?.enableCrossFilter;\n if (crossFilterEnabled && hasCrossFilterConfig) {\n const firstColumn = columns[0]?.key;\n const label = firstColumn ? String(row[firstColumn]) : undefined;\n triggerCrossFilter(row as Record<string, unknown>, label);\n }\n\n // Trigger drilldown if configured\n if (onDrilldown) {\n onDrilldown(row);\n } else if (onRowClick && widget.drilldowns?.length) {\n onRowClick(row, index);\n }\n },\n [\n onRowClick,\n onDrilldown,\n widget.drilldowns,\n crossFilterEnabled,\n triggerCrossFilter,\n columns,\n config?.crossFilterMappings,\n config?.enableCrossFilter,\n ]\n );\n\n // Export to CSV\n const handleExport = useCallback(() => {\n const headers = columns.map((c) => c.header).join(',');\n const rows = processedData.map((row) =>\n columns\n .map((col) => {\n const value = row[col.key];\n if (value == null) return '';\n const str = String(value);\n // Escape quotes and wrap in quotes if contains comma\n if (str.includes(',') || str.includes('\"')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n })\n .join(',')\n );\n const csv = [headers, ...rows].join('\\n');\n const blob = new Blob([csv], { type: 'text/csv' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `${widget.title || 'table'}-${new Date().toISOString().split('T')[0]}.csv`;\n a.click();\n URL.revokeObjectURL(url);\n }, [columns, processedData, widget.title]);\n\n // Row is only clickable if drilldown or cross-filter is explicitly configured\n const hasCrossFilterConfig = config?.crossFilterMappings?.length || config?.enableCrossFilter;\n const isClickable = Boolean(onDrilldown || (onRowClick && widget.drilldowns?.length) || hasCrossFilterConfig);\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Cross-filter active indicator with clear button */}\n {hasCrossFilters && (\n <div className=\"flex items-center gap-2 px-3 py-2 border-b border-border-default\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n clearAllCrossFilters();\n }}\n className=\"\n inline-flex items-center gap-1.5\n px-2.5 py-1 rounded-md\n text-xs font-medium\n bg-action-primary-bg/10 text-action-primary-text\n hover:bg-action-primary-bg/20\n transition-colors\n \"\n >\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M10 19l-7-7m0 0l7-7m-7 7h18\" />\n </svg>\n Clear Filter\n </button>\n </div>\n )}\n\n {/* Toolbar */}\n {(config?.showSearch !== false || config?.showExport !== false) && (\n <div className=\"flex items-center justify-between p-3 border-b border-border-default\">\n {/* Search */}\n {config?.showSearch !== false && (\n <div className=\"relative flex items-center\">\n <svg\n className=\"absolute left-3 w-4 h-4 text-text-secondary pointer-events-none\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\n />\n </svg>\n <input\n type=\"text\"\n placeholder=\"Search products...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"\n pl-10 pr-4 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg focus:border-action-primary-bg\n w-48 sm:w-64\n placeholder:text-text-muted\n \"\n />\n </div>\n )}\n\n {/* Export */}\n {config?.showExport !== false && (\n <button\n type=\"button\"\n onClick={handleExport}\n className=\"\n inline-flex items-center gap-2\n px-3 py-2\n text-sm font-medium\n text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n hover:bg-bg-sunken\n transition-colors\n \"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n />\n </svg>\n Export CSV\n </button>\n )}\n </div>\n )}\n\n {/* Table */}\n <div\n ref={scrollRef}\n className=\"flex-1 overflow-auto\"\n onScroll={virtualized ? (e) => setScrollTop((e.target as HTMLDivElement).scrollTop) : undefined}\n >\n <table className=\"w-full\">\n <TableHeader\n columns={displayColumns}\n sortState={sortState}\n onSort={handleSort}\n frozenLefts={frozenCount > 0 ? frozenLefts : undefined}\n editable={isEditMode}\n onColumnResize={isEditMode ? handleColumnResize : undefined}\n onColumnResizeEnd={isEditMode ? handleColumnResizeEnd : undefined}\n onColumnReorder={isEditMode ? handleColumnReorder : undefined}\n />\n <tbody>\n {/* Virtualization top spacer */}\n {virtualized && virtualWindow && virtualWindow.topSpacer > 0 && (\n <tr aria-hidden=\"true\" style={{ height: virtualWindow.topSpacer }}>\n <td colSpan={displayColumns.length} style={{ padding: 0, border: 'none' }} />\n </tr>\n )}\n {renderRows.map((row, i) => {\n const rowIndex = rowBaseIndex + i;\n return (\n <tr\n key={rowIndex}\n className={`\n ${isClickable ? 'cursor-pointer hover:bg-bg-sunken/50' : ''}\n ${rowIndex % 2 === 0 ? 'bg-bg-surface' : 'bg-bg-sunken/30'}\n ${resolveRowClassName(row, rowRules)}\n `}\n style={virtualized ? { height: rowHeight } : undefined}\n onClick={() => handleRowClick(row, rowIndex)}\n >\n {displayColumns.map((column) => (\n <TableCell\n key={column.key}\n value={row[column.key]}\n column={column}\n format={cellFormats[column.key]}\n rowData={row}\n conditionalRules={columnRules[column.key] ?? tableRules}\n dataBarMax={dataBarMaxes[column.key]}\n stickyLeft={frozenLefts[column.key]}\n cellChart={columnCellCharts[column.key]}\n />\n ))}\n </tr>\n );\n })}\n {/* Virtualization bottom spacer */}\n {virtualized && virtualWindow && virtualWindow.bottomSpacer > 0 && (\n <tr aria-hidden=\"true\" style={{ height: virtualWindow.bottomSpacer }}>\n <td colSpan={displayColumns.length} style={{ padding: 0, border: 'none' }} />\n </tr>\n )}\n </tbody>\n {hasTotals && processedData.length > 0 && (\n <tfoot>\n <tr className=\"bg-bg-sunken/50 font-semibold border-t-2 border-border-default\">\n {displayColumns.map((column, colIndex) => {\n const total = footerTotals[column.key];\n const format = cellFormats[column.key];\n const frozen = frozenLefts[column.key];\n return (\n <td\n key={column.key}\n className={`\n px-4 py-3 text-sm text-text-primary\n ${column.align === 'center' ? 'text-center' : ''}\n ${column.align === 'right' ? 'text-right' : 'text-left'}\n ${frozen != null ? 'sticky z-10 bg-bg-sunken' : ''}\n `}\n style={frozen != null ? { left: frozen } : undefined}\n >\n {total != null\n ? formatTotal(total, format?.type, format?.currency)\n : colIndex === 0\n ? 'Total'\n : ''}\n </td>\n );\n })}\n </tr>\n </tfoot>\n )}\n </table>\n\n {processedData.length === 0 && (\n <div className=\"flex items-center justify-center py-12 text-text-secondary\">\n {searchQuery ? 'No matching records found' : 'No data available'}\n </div>\n )}\n </div>\n\n {/* Pagination (suppressed in virtualized mode — the whole set scrolls) */}\n {!virtualized && config?.showPagination !== false && processedData.length > 0 && (\n <TablePagination\n pagination={{ ...pagination, totalItems: processedData.length }}\n onPageChange={handlePageChange}\n onPageSizeChange={handlePageSizeChange}\n />\n )}\n </div>\n );\n});\n\nexport default TableWidget;\n"],"mappings":"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"}
@@ -33,7 +33,7 @@ var o = {
33
33
  children: /* @__PURE__ */ i("div", {
34
34
  className: "text-center",
35
35
  children: [/* @__PURE__ */ r("svg", {
36
- className: "w-12 h-12 mx-auto mb-2 text-text-tertiary",
36
+ className: "w-12 h-12 mx-auto mb-2 text-text-muted",
37
37
  fill: "none",
38
38
  stroke: "currentColor",
39
39
  viewBox: "0 0 24 24",