@svgrid/grid 3.0.0 → 3.0.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 (304) hide show
  1. package/CHANGELOG.md +116 -88
  2. package/README.md +199 -199
  3. package/dist/FlexRender.svelte +96 -96
  4. package/dist/GridFooter.svelte +190 -181
  5. package/dist/GridFooter.svelte.d.ts +8 -0
  6. package/dist/GridMenus.svelte +18 -10
  7. package/dist/GridMenus.svelte.d.ts +2 -1
  8. package/dist/SvAutoComplete.svelte +169 -169
  9. package/dist/SvAvatar.svelte +75 -75
  10. package/dist/SvCalendar.svelte +503 -503
  11. package/dist/SvCarousel.svelte +141 -141
  12. package/dist/SvCheckBox.svelte +102 -102
  13. package/dist/SvCircularProgress.svelte +109 -109
  14. package/dist/SvColorInput.svelte +181 -181
  15. package/dist/SvComboBox.svelte +279 -279
  16. package/dist/SvContextMenu.svelte +116 -116
  17. package/dist/SvCountryInput.svelte +163 -163
  18. package/dist/SvDrawer.svelte +254 -254
  19. package/dist/SvDropDownList.svelte +378 -378
  20. package/dist/SvDurationInput.svelte +126 -126
  21. package/dist/SvField.svelte +293 -293
  22. package/dist/SvForm.svelte +437 -437
  23. package/dist/SvGrid.controller.svelte.d.ts +17 -0
  24. package/dist/SvGrid.controller.svelte.js +128 -14
  25. package/dist/SvGrid.css +79 -10
  26. package/dist/SvGrid.svelte +191 -186
  27. package/dist/SvGrid.types.d.ts +42 -1
  28. package/dist/SvGridCellEditor.svelte +748 -744
  29. package/dist/SvGridChart.svelte +2246 -1716
  30. package/dist/SvGridChart.svelte.d.ts +63 -1
  31. package/dist/SvGridChartPanel.svelte +633 -485
  32. package/dist/SvGridChartView.svelte +79 -70
  33. package/dist/SvGridChartView.svelte.d.ts +7 -0
  34. package/dist/SvGridDropdown.svelte +728 -728
  35. package/dist/SvGridSelect.svelte +270 -270
  36. package/dist/SvGroupCell.svelte +141 -116
  37. package/dist/SvGroupCell.svelte.d.ts +8 -0
  38. package/dist/SvListBox.svelte +334 -334
  39. package/dist/SvMaskedInput.svelte +122 -122
  40. package/dist/SvMenu.svelte +124 -124
  41. package/dist/SvMenuList.svelte +146 -146
  42. package/dist/SvMultiSelect.svelte +293 -293
  43. package/dist/SvNumberInput.svelte +172 -172
  44. package/dist/SvOtpInput.svelte +158 -158
  45. package/dist/SvPasswordInput.svelte +151 -151
  46. package/dist/SvPhoneInput.svelte +133 -133
  47. package/dist/SvPopover.svelte +197 -197
  48. package/dist/SvProgress.svelte +116 -116
  49. package/dist/SvRadioGroup.svelte +107 -107
  50. package/dist/SvRating.svelte +112 -112
  51. package/dist/SvResult.svelte +73 -73
  52. package/dist/SvRichText.svelte +211 -211
  53. package/dist/SvRowGroupPanel.svelte +186 -170
  54. package/dist/SvRowGroupPanel.svelte.d.ts +8 -0
  55. package/dist/SvScrollArea.svelte +61 -61
  56. package/dist/SvSlider.svelte +203 -203
  57. package/dist/SvSwitchButton.svelte +108 -108
  58. package/dist/SvTagsInput.svelte +115 -115
  59. package/dist/SvTextInput.svelte +147 -147
  60. package/dist/SvTimePicker.svelte +245 -245
  61. package/dist/SvToaster.svelte +159 -159
  62. package/dist/SvToggleButton.svelte +85 -85
  63. package/dist/SvTooltip.svelte +161 -161
  64. package/dist/SvTour.svelte +208 -208
  65. package/dist/SvTree.svelte +444 -444
  66. package/dist/SvTreeSelect.svelte +239 -239
  67. package/dist/ai.d.ts +11 -2
  68. package/dist/ai.js +51 -7
  69. package/dist/cdn/GridMenus-DyFA-QxA.js +602 -0
  70. package/dist/cdn/GridMenus-M2XP9t0_.js +603 -0
  71. package/dist/cdn/{SvDateRangeInput-DflbiP7N.js → SvDateRangeInput-CaOuMs8O.js} +1 -1
  72. package/dist/cdn/{SvDateRangeInput-Bh0A0JkF.js → SvDateRangeInput-DMLKmGEc.js} +1 -1
  73. package/dist/cdn/{SvDateTimePicker-Bivn8dAP.js → SvDateTimePicker-CCbDZNZB.js} +1 -1
  74. package/dist/cdn/{SvDateTimePicker-BWwpfB_o.js → SvDateTimePicker-sonaH0oh.js} +1 -1
  75. package/dist/cdn/{SvGridCellEditor-Ba7rY3eu.js → SvGridCellEditor-BWnTi2N7.js} +2 -2
  76. package/dist/cdn/{SvGridCellEditor-AXL8cHGO.js → SvGridCellEditor-CjEJMJKc.js} +2 -2
  77. package/dist/cdn/SvGridChart-DAb9RbRs.js +1480 -0
  78. package/dist/cdn/SvGridChart-Yl-IXZFO.js +1481 -0
  79. package/dist/cdn/SvGridChartPanel-DayQpDsR.js +834 -0
  80. package/dist/cdn/SvGridChartPanel-aqf8n-vJ.js +810 -0
  81. package/dist/cdn/{SvGridChartView-eSPuJE6g.js → SvGridChartView-CxfakxR0.js} +5 -3
  82. package/dist/cdn/{SvGridChartView-SmPW10dI.js → SvGridChartView-Dm_YEx9L.js} +5 -3
  83. package/dist/cdn/{SvGridDropdown-B1ZcLpgs.js → SvGridDropdown-D0VdjeR8.js} +1 -1
  84. package/dist/cdn/{SvGridDropdown-CtdbHcIS.js → SvGridDropdown-D13MtJ2j.js} +1 -1
  85. package/dist/cdn/cell-formatting-C2Hf5gqd.js +86 -0
  86. package/dist/cdn/chart-CKJRCPOk.js +1652 -0
  87. package/dist/cdn/{date-format-DZT7T1wf.js → date-format-BNii4zeD.js} +2 -2
  88. package/dist/cdn/{date-format-CcP1tafP.js → date-format-BnnHlqGw.js} +2 -2
  89. package/dist/cdn/{export-format-Cv1Dll6k.js → export-format-CUDLy2yn.js} +84 -168
  90. package/dist/cdn/{src-B_YS5AOc.js → src-BJ2opd0j.js} +3642 -3450
  91. package/dist/cdn/{src-DYXXpuSk.js → src-DNbz94Ct.js} +8649 -8457
  92. package/dist/cdn/svgrid.js +16 -15
  93. package/dist/cdn/svgrid.svelte-external.js +16 -15
  94. package/dist/cell-formatting.d.ts +7 -0
  95. package/dist/cell-formatting.js +7 -1
  96. package/dist/chart-export.d.ts +23 -2
  97. package/dist/chart-export.js +88 -14
  98. package/dist/chart.d.ts +410 -18
  99. package/dist/chart.js +824 -24
  100. package/dist/editing.js +22 -13
  101. package/dist/grid-icons.d.ts +49 -0
  102. package/dist/grid-icons.js +86 -0
  103. package/dist/index.d.ts +3 -2
  104. package/dist/index.js +3 -2
  105. package/package.json +1 -1
  106. package/src/FlexRender.svelte +96 -96
  107. package/src/GridFooter.svelte +190 -181
  108. package/src/GridMenus.svelte +18 -10
  109. package/src/SvAutoComplete.svelte +169 -169
  110. package/src/SvAvatar.svelte +75 -75
  111. package/src/SvCalendar.svelte +503 -503
  112. package/src/SvCalendar.test.ts +226 -226
  113. package/src/SvCarousel.svelte +141 -141
  114. package/src/SvCheckBox.svelte +102 -102
  115. package/src/SvCircularProgress.svelte +109 -109
  116. package/src/SvColorInput.svelte +181 -181
  117. package/src/SvComboBox.svelte +279 -279
  118. package/src/SvContextMenu.svelte +116 -116
  119. package/src/SvCountryInput.svelte +163 -163
  120. package/src/SvDrawer.svelte +254 -254
  121. package/src/SvDropDownList.svelte +378 -378
  122. package/src/SvDurationInput.svelte +126 -126
  123. package/src/SvField.svelte +293 -293
  124. package/src/SvForm.svelte +437 -437
  125. package/src/SvForm.test.ts +411 -411
  126. package/src/SvGrid.controller.svelte.ts +146 -13
  127. package/src/SvGrid.css +79 -10
  128. package/src/SvGrid.svelte +191 -186
  129. package/src/SvGrid.types.ts +2133 -2092
  130. package/src/SvGridCellEditor.svelte +748 -744
  131. package/src/SvGridChart.svelte +2246 -1716
  132. package/src/SvGridChart.test.ts +243 -1
  133. package/src/SvGridChartPanel.svelte +633 -485
  134. package/src/SvGridChartView.svelte +79 -70
  135. package/src/SvGridDropdown.svelte +728 -728
  136. package/src/SvGridSelect.svelte +270 -270
  137. package/src/SvGroupCell.svelte +141 -116
  138. package/src/SvListBox.svelte +334 -334
  139. package/src/SvMaskedInput.svelte +122 -122
  140. package/src/SvMenu.svelte +124 -124
  141. package/src/SvMenu.test.ts +97 -97
  142. package/src/SvMenuList.svelte +146 -146
  143. package/src/SvMultiSelect.svelte +293 -293
  144. package/src/SvNumberInput.svelte +172 -172
  145. package/src/SvOtpInput.svelte +158 -158
  146. package/src/SvPasswordInput.svelte +151 -151
  147. package/src/SvPhoneInput.svelte +133 -133
  148. package/src/SvPopover.svelte +197 -197
  149. package/src/SvProgress.svelte +116 -116
  150. package/src/SvRadioGroup.svelte +107 -107
  151. package/src/SvRating.svelte +112 -112
  152. package/src/SvResult.svelte +73 -73
  153. package/src/SvRichText.svelte +211 -211
  154. package/src/SvRowGroupPanel.svelte +186 -170
  155. package/src/SvScrollArea.svelte +61 -61
  156. package/src/SvSlider.svelte +203 -203
  157. package/src/SvSwitchButton.svelte +108 -108
  158. package/src/SvTagsInput.svelte +115 -115
  159. package/src/SvTextInput.svelte +147 -147
  160. package/src/SvTimePicker.svelte +245 -245
  161. package/src/SvToaster.svelte +159 -159
  162. package/src/SvToaster.test.ts +95 -95
  163. package/src/SvToggleButton.svelte +85 -85
  164. package/src/SvTooltip.svelte +161 -161
  165. package/src/SvTour.svelte +208 -208
  166. package/src/SvTree.svelte +444 -444
  167. package/src/SvTreeSelect.svelte +239 -239
  168. package/src/a11y/dismissable.test.ts +119 -119
  169. package/src/a11y/dismissable.ts +114 -114
  170. package/src/a11y.contract.test.ts +49 -49
  171. package/src/a11y.test.ts +59 -59
  172. package/src/a11y.ts +61 -61
  173. package/src/ai.test.ts +561 -502
  174. package/src/ai.ts +1472 -1419
  175. package/src/build-api.coverage.test.ts +633 -633
  176. package/src/build-api.ts +846 -846
  177. package/src/builtin-editors.grid.test.ts +83 -83
  178. package/src/cell-formatting.ts +177 -171
  179. package/src/cell-render.test.ts +513 -513
  180. package/src/cell-render.ts +496 -496
  181. package/src/cell-values.ts +148 -148
  182. package/src/chart-export.test.ts +112 -0
  183. package/src/chart-export.ts +270 -202
  184. package/src/chart-view.svelte.ts +36 -36
  185. package/src/chart.test.ts +830 -1
  186. package/src/chart.ts +3342 -2321
  187. package/src/collaboration.test.ts +104 -104
  188. package/src/collaboration.ts +167 -167
  189. package/src/column-groups.ts +78 -78
  190. package/src/core.performance.test.ts +30 -30
  191. package/src/core.ts +1865 -1865
  192. package/src/createAutocomplete.svelte.ts +132 -132
  193. package/src/createCombobox.svelte.ts +191 -191
  194. package/src/createCountryInput.svelte.ts +157 -157
  195. package/src/createDropdownList.svelte.ts +168 -168
  196. package/src/createForm.svelte.ts +386 -386
  197. package/src/createGrid.svelte.ts +42 -42
  198. package/src/createGrid.test.ts +10 -10
  199. package/src/createGridState.svelte.ts +17 -17
  200. package/src/createListbox.svelte.ts +250 -250
  201. package/src/createMenu.svelte.ts +224 -224
  202. package/src/createPopoverSelect.svelte.ts +213 -213
  203. package/src/createSlider.svelte.ts +191 -191
  204. package/src/createTooltip.svelte.ts +144 -144
  205. package/src/createTree.svelte.ts +322 -322
  206. package/src/datetime/date-core.ts +206 -206
  207. package/src/datetime/date-restrict.ts +61 -61
  208. package/src/datetime/timezone.ts +135 -135
  209. package/src/dock-manager-model.ts +596 -596
  210. package/src/dock-model.ts +374 -374
  211. package/src/editing.test.ts +974 -974
  212. package/src/editing.ts +618 -609
  213. package/src/editor-contract.ts +171 -171
  214. package/src/editor-registry.grid.test.ts +144 -144
  215. package/src/editor-registry.ts +122 -122
  216. package/src/export-data-api.test.ts +126 -126
  217. package/src/export-format.test.ts +107 -107
  218. package/src/export-format.ts +601 -601
  219. package/src/filter-operators.ts +160 -160
  220. package/src/filtering/excel-filters.ts +325 -325
  221. package/src/flex-render.ts +3 -3
  222. package/src/form-field.ts +127 -127
  223. package/src/grid-icons.test.ts +46 -0
  224. package/src/grid-icons.ts +184 -0
  225. package/src/group-display.test.ts +167 -167
  226. package/src/group-display.ts +200 -200
  227. package/src/headless.ts +87 -87
  228. package/src/icon-overrides.grid.test.ts +188 -0
  229. package/src/icon-seam.test.ts +100 -0
  230. package/src/index.ts +19 -0
  231. package/src/js-scroller.svelte.ts +173 -173
  232. package/src/keyboard-handlers.ts +270 -270
  233. package/src/keyboard.test.ts +59 -59
  234. package/src/keyboard.ts +97 -97
  235. package/src/list-nav.test.ts +49 -49
  236. package/src/list-nav.ts +29 -29
  237. package/src/list-option.test.ts +56 -56
  238. package/src/list-option.ts +179 -179
  239. package/src/menus.ts +597 -597
  240. package/src/merge-objects.ts +48 -48
  241. package/src/overlays.test.ts +90 -90
  242. package/src/positioning.ts +268 -268
  243. package/src/render-component.ts +28 -28
  244. package/src/row-drag.test.ts +401 -401
  245. package/src/row-drag.ts +419 -419
  246. package/src/row-resize.test.ts +524 -524
  247. package/src/row-resize.ts +228 -228
  248. package/src/scheduler-ical.ts +181 -181
  249. package/src/scheduler-model.test.ts +562 -562
  250. package/src/scheduler-model.ts +873 -873
  251. package/src/selection.test.ts +885 -885
  252. package/src/server-data-source.test.ts +383 -383
  253. package/src/server-data-source.ts +469 -469
  254. package/src/sparkline.test.ts +68 -68
  255. package/src/sparkline.ts +169 -169
  256. package/src/spreadsheet.test.ts +488 -488
  257. package/src/spreadsheet.ts +312 -312
  258. package/src/static-functions.ts +11 -11
  259. package/src/subscribe.ts +38 -38
  260. package/src/summaries.ts +113 -113
  261. package/src/svgrid-wrapper.types.ts +563 -563
  262. package/src/svgrid.async-editor-options.test.ts +273 -273
  263. package/src/svgrid.auto-row-height.test.ts +204 -204
  264. package/src/svgrid.behavior.test.ts +910 -910
  265. package/src/svgrid.charting.test.ts +654 -534
  266. package/src/svgrid.comments-autocomplete.test.ts +127 -127
  267. package/src/svgrid.context-menu.test.ts +147 -147
  268. package/src/svgrid.features.test.ts +157 -157
  269. package/src/svgrid.filter-depth.test.ts +163 -163
  270. package/src/svgrid.filter-menu-listbox.svelte.test.ts +382 -377
  271. package/src/svgrid.filter-menu-scroll.test.ts +112 -112
  272. package/src/svgrid.grand-total.test.ts +188 -188
  273. package/src/svgrid.group-display-mode.test.ts +171 -171
  274. package/src/svgrid.group-footers.test.ts +121 -121
  275. package/src/svgrid.group-pagination.test.ts +153 -153
  276. package/src/svgrid.new-features.wrapper.test.ts +251 -251
  277. package/src/svgrid.tree-data.test.ts +186 -186
  278. package/src/svgrid.wrapper.test.ts +63 -63
  279. package/src/svgriddropdown.async-panel.svelte.test.ts +195 -195
  280. package/src/test-setup.ts +62 -62
  281. package/src/themes/index.ts +288 -288
  282. package/src/toast-store.svelte.ts +250 -250
  283. package/src/toast-store.test.ts +147 -147
  284. package/src/tree-row-model.test.ts +168 -168
  285. package/src/ui-buttons.test.ts +144 -144
  286. package/src/ui-inputs.test.ts +118 -118
  287. package/src/ui-localization.test.ts +113 -113
  288. package/src/ui-range.test.ts +70 -70
  289. package/src/ui-selection.test.ts +155 -155
  290. package/src/ui-tier1.test.ts +142 -142
  291. package/src/virtual.test.ts +88 -88
  292. package/src/virtualization/column-virtualizer.test.ts +27 -27
  293. package/src/virtualization/column-virtualizer.ts +30 -30
  294. package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
  295. package/src/virtualization/types.ts +30 -30
  296. package/src/virtualization/virtualizer.test.ts +47 -47
  297. package/src/virtualization/virtualizer.ts +322 -322
  298. package/dist/cdn/GridMenus-DMihUtma.js +0 -600
  299. package/dist/cdn/GridMenus-nmNDj1a3.js +0 -601
  300. package/dist/cdn/SvGridChart-Bs2GIR2Q.js +0 -1202
  301. package/dist/cdn/SvGridChart-CwhFz7GV.js +0 -1203
  302. package/dist/cdn/SvGridChartPanel-1WXuStzM.js +0 -561
  303. package/dist/cdn/SvGridChartPanel-e5_nqNP9.js +0 -585
  304. package/dist/cdn/chart-i4XcXyHJ.js +0 -1214
@@ -371,6 +371,11 @@ export declare function createSvGridController<TFeatures extends TableFeatures =
371
371
  field: string;
372
372
  label: string;
373
373
  }[];
374
+ dates: {
375
+ id: string;
376
+ field: string;
377
+ label: string;
378
+ }[];
374
379
  };
375
380
  readonly chartSpec: ChartSpec | null;
376
381
  applyChartCrossFilter: (category: string) => void;
@@ -389,6 +394,11 @@ export declare function createSvGridController<TFeatures extends TableFeatures =
389
394
  dimension: string | null;
390
395
  series: string | null;
391
396
  measure: string | null;
397
+ measure2: string | null;
398
+ orientation: "horizontal" | "vertical" | null;
399
+ stacked100: boolean | null;
400
+ donut: boolean | null;
401
+ palette: string[] | null;
392
402
  reduce: "sum" | "avg" | "count";
393
403
  stacked: boolean | null;
394
404
  dataLabels: boolean | null;
@@ -397,6 +407,13 @@ export declare function createSvGridController<TFeatures extends TableFeatures =
397
407
  valueFormat: ChartValueFormat | null;
398
408
  }[];
399
409
  applyChartsState(list: ReadonlyArray<Record<string, unknown>>, active?: number): void;
410
+ readonly chartCrossFilterable: boolean;
411
+ chartOrientation: "horizontal" | "vertical";
412
+ chartStacked100: boolean;
413
+ chartDonut: boolean;
414
+ chartPalette: string[] | null;
415
+ chartMeasure2Id: string | null;
416
+ readonly effectiveChartMeasure2Id: string | null;
400
417
  chartAiHandler: ((prompt: string) => Promise<Record<string, unknown> | null>) | null;
401
418
  applyChartConfig(config: {
402
419
  open?: boolean;
@@ -1661,6 +1661,11 @@ export function createSvGridController(rawProps, domIdBase) {
1661
1661
  dimensionId: null,
1662
1662
  measureId: null,
1663
1663
  seriesId: undefined,
1664
+ measure2Id: null,
1665
+ orientation: null,
1666
+ stacked100: null,
1667
+ donut: null,
1668
+ palette: null,
1664
1669
  stacked: null,
1665
1670
  dataLabels: null,
1666
1671
  logScale: null,
@@ -1703,6 +1708,11 @@ export function createSvGridController(rawProps, domIdBase) {
1703
1708
  const chartableColumns = $derived.by(function chartableColumns_d() {
1704
1709
  const dims = [];
1705
1710
  const measures = [];
1711
+ // Dates are a subset of dims, tracked separately so the panel can tell
1712
+ // whether a calendar chart is possible at all before the user picks
1713
+ // anything. Offering a type that can only render blank is worse than not
1714
+ // offering it.
1715
+ const dates = [];
1706
1716
  for (const col of allColumns) {
1707
1717
  const field = col.columnDef.field;
1708
1718
  if (!field)
@@ -1710,10 +1720,13 @@ export function createSvGridController(rawProps, domIdBase) {
1710
1720
  const entry = { id: col.id, field, label: columnLabel(col) };
1711
1721
  if (isNumericColumn(col))
1712
1722
  measures.push(entry);
1713
- else
1723
+ else {
1714
1724
  dims.push(entry);
1725
+ if (columnIsDate(col))
1726
+ dates.push(entry);
1727
+ }
1715
1728
  }
1716
- return { dims, measures };
1729
+ return { dims, measures, dates };
1717
1730
  });
1718
1731
  const chartColumnDefaults = $derived.by(function chartColumnDefaults_d() {
1719
1732
  const { dims, measures } = chartableColumns;
@@ -1759,6 +1772,15 @@ export function createSvGridController(rawProps, domIdBase) {
1759
1772
  return configured;
1760
1773
  return chartColumnDefaults.measureIds;
1761
1774
  });
1775
+ /** Scatter's Y measure. Defaults to the second numeric column, so picking
1776
+ * scatter plots something immediately rather than nothing. */
1777
+ const effectiveChartMeasure2Id = $derived(activeChart.measure2Id ??
1778
+ chartableColumns.measures.find((m) => m.id !== effectiveChartMeasureId)?.id ??
1779
+ null);
1780
+ const effectiveChartOrientation = $derived(activeChart.orientation ?? chartCfg?.orientation ?? "vertical");
1781
+ const effectiveChartStacked100 = $derived(activeChart.stacked100 ?? chartCfg?.stacked100 === true);
1782
+ const effectiveChartDonut = $derived(activeChart.donut ?? !!chartCfg?.donut);
1783
+ const effectiveChartPalette = $derived(activeChart.palette ?? chartCfg?.palette ?? null);
1762
1784
  const effectiveChartStacked = $derived(chartStacked ?? chartCfg?.stacked ?? false);
1763
1785
  const effectiveChartDataLabels = $derived(chartDataLabels ?? chartCfg?.dataLabels ?? false);
1764
1786
  const effectiveChartLogScale = $derived(chartLogScale ?? chartCfg?.yScale === "log");
@@ -1784,8 +1806,13 @@ export function createSvGridController(rawProps, domIdBase) {
1784
1806
  ? "Count"
1785
1807
  : `${chartReduce === "avg" ? "Average" : "Sum"} of ${label}`;
1786
1808
  });
1787
- const chartDimensionIsDate = $derived.by(() => {
1788
- const col = allColumns.find((c) => c.id === effectiveChartDimensionId);
1809
+ /**
1810
+ * Does this column hold dates? Declared type first, then a probe of the
1811
+ * first non-empty value. Lifted out of `chartDimensionIsDate` so the chart
1812
+ * panel can also ask it of columns the user has NOT picked yet, which is
1813
+ * what decides whether a calendar chart is offerable at all.
1814
+ */
1815
+ function columnIsDate(col) {
1789
1816
  if (!col)
1790
1817
  return false;
1791
1818
  if (col.columnDef.cellDataType === "date")
@@ -1801,7 +1828,8 @@ export function createSvGridController(rawProps, domIdBase) {
1801
1828
  return typeof v === "string" && /^\d{4}-\d{2}(-\d{2})?/.test(v);
1802
1829
  }
1803
1830
  return false;
1804
- });
1831
+ }
1832
+ const chartDimensionIsDate = $derived.by(() => columnIsDate(allColumns.find((c) => c.id === effectiveChartDimensionId)));
1805
1833
  const chartRows = $derived.by(() => {
1806
1834
  const rects = getSelectionRects();
1807
1835
  const pushLeaf = (out, row) => {
@@ -1893,11 +1921,27 @@ export function createSvGridController(rawProps, domIdBase) {
1893
1921
  // null until it resolves, a tick after the panel itself starts loading (which it
1894
1922
  // already does). The `getAggregate` server path uses the local bucketsToSpec and
1895
1923
  // does not need the engine.
1924
+ // The whole module, not just `rowsToChartSpec`: the panel can now reach
1925
+ // every chart type, and the ones that do not read a categories-by-series
1926
+ // grid (scatter, gauge, treemap, calendar, sankey) need their own builders
1927
+ // from the same lazy chunk. Same `import()`, same boundary.
1896
1928
  let chartEngine = $state(null);
1897
1929
  $effect(() => {
1898
1930
  if (chartingEnabled && !chartEngine)
1899
- import("./chart.js").then((m) => (chartEngine = m.rowsToChartSpec));
1900
- });
1931
+ import("./chart.js").then((m) => (chartEngine = m));
1932
+ });
1933
+ /** Put the chart's numbers in the same locale as the grid's. A grid that set
1934
+ * `localization.locale` has already said which locale its data is in, and a
1935
+ * chart of that data reading in a different one is a bug nobody would think
1936
+ * to look for; `charting.locale` overrides when they really should differ.
1937
+ * Currency has no such default - only the app knows what the numbers are. */
1938
+ const applyChartLocale = (spec) => {
1939
+ const locale = chartCfg?.locale ?? props.localization?.locale;
1940
+ if (locale)
1941
+ spec.locale = locale;
1942
+ if (chartCfg?.currency)
1943
+ spec.currency = chartCfg.currency;
1944
+ };
1901
1945
  const chartSpec = $derived.by(() => {
1902
1946
  if (!chartingEnabled || !chartCfg)
1903
1947
  return null;
@@ -1917,6 +1961,7 @@ export function createSvGridController(rawProps, domIdBase) {
1917
1961
  spec.yScale = "log";
1918
1962
  if (effectiveChartValueFormat)
1919
1963
  spec.valueFormat = effectiveChartValueFormat;
1964
+ applyChartLocale(spec);
1920
1965
  return spec;
1921
1966
  }
1922
1967
  if (chartCfg.buildSpec)
@@ -1929,33 +1974,69 @@ export function createSvGridController(rawProps, domIdBase) {
1929
1974
  if (!chartEngine)
1930
1975
  return null;
1931
1976
  const seriesField = fieldOf(effectiveChartSeriesId);
1932
- const spec = chartEngine(chartRows, {
1977
+ const rowsForChart = chartRows;
1978
+ // Some types read the rows directly rather than a grouped grid: a scatter
1979
+ // point is one row, a gauge has no category axis at all, and a box plot
1980
+ // needs the whole sample per group rather than one reduced number. The
1981
+ // engine owns that dispatch - naming each type here would put them in the
1982
+ // base bundle, which every grid pays for whether or not it ever charts.
1983
+ // Everything else falls through to the aggregation below and is reshaped
1984
+ // afterwards, so reduce / sort / topN / "Other" keep working for all of it.
1985
+ const direct = chartEngine.rowsToDirectSpec(chartType, rowsForChart, {
1986
+ category: category,
1987
+ ...(values[0] ? { value: values[0] } : {}),
1988
+ ...(fieldOf(effectiveChartMeasure2Id) ? { value2: fieldOf(effectiveChartMeasure2Id) } : {}),
1989
+ ...(seriesField ? { series: seriesField } : {}),
1990
+ reduce: chartReduce,
1991
+ ...(effectiveChartPalette ? { palette: effectiveChartPalette } : {}),
1992
+ });
1993
+ if (direct)
1994
+ return direct;
1995
+ // A direct type that could not build (scatter with no Y picked yet, for
1996
+ // instance) must not fall through to the bar-chart path and draw the wrong
1997
+ // chart - it renders the panel's empty state instead.
1998
+ if (chartType === "scatter" || chartType === "gauge" || chartType === "boxplot")
1999
+ return null;
2000
+ const spec = chartEngine.rowsToChartSpec(rowsForChart, {
1933
2001
  type: chartType,
1934
2002
  category: category,
1935
2003
  value: values.length === 1 ? values[0] : values,
1936
2004
  ...(seriesField ? { series: seriesField } : {}),
1937
2005
  reduce: chartReduce,
1938
- stacked: effectiveChartStacked || chartCfg.stacked100 === true,
1939
- stacked100: chartCfg.stacked100 === true,
1940
- ...(chartCfg.palette ? { palette: chartCfg.palette } : {}),
2006
+ stacked: effectiveChartStacked || effectiveChartStacked100,
2007
+ stacked100: effectiveChartStacked100,
2008
+ ...(effectiveChartPalette ? { palette: effectiveChartPalette } : {}),
1941
2009
  ...(chartCfg.topN ? { topN: chartCfg.topN } : {}),
1942
2010
  ...(chartCfg.otherLabel ? { otherLabel: chartCfg.otherLabel } : {}),
1943
2011
  ...(chartCfg.sort ? { sort: chartCfg.sort } : {}),
1944
2012
  });
1945
- if (chartCfg.orientation)
1946
- spec.orientation = chartCfg.orientation;
2013
+ // Reshape the aggregated grid into whatever this type actually reads.
2014
+ // These run AFTER the aggregation so grouping, reduce, sort, topN and the
2015
+ // "Other" bucket apply to them exactly as they do to a bar chart.
2016
+ if (chartType === "treemap")
2017
+ spec.treemap = chartEngine.specToTreemap(spec);
2018
+ else if (chartType === "calendar")
2019
+ spec.calendarValues = chartEngine.specToCalendar(spec);
2020
+ else if (chartType === "sankey") {
2021
+ const flow = chartEngine.specToSankey(spec);
2022
+ spec.sankeyNodes = flow.nodes;
2023
+ spec.sankeyLinks = flow.links;
2024
+ }
2025
+ if (effectiveChartOrientation === "horizontal")
2026
+ spec.orientation = "horizontal";
1947
2027
  if (effectiveChartTimeAxis)
1948
2028
  spec.xType = "time";
1949
2029
  if (effectiveChartLogScale)
1950
2030
  spec.yScale = "log";
1951
2031
  if (effectiveChartValueFormat)
1952
2032
  spec.valueFormat = effectiveChartValueFormat;
2033
+ applyChartLocale(spec);
1953
2034
  if (chartType !== "pie" && spec.orientation !== "horizontal" && !spec.yAxisTitle && chartAutoYAxisTitle) {
1954
2035
  spec.yAxisTitle = chartAutoYAxisTitle;
1955
2036
  }
1956
2037
  if (effectiveChartValueFormat && activeChart.valueFormat === null) { /* inherited default */ }
1957
2038
  if (chartType === "pie") {
1958
- if (chartCfg.donut)
2039
+ if (effectiveChartDonut)
1959
2040
  spec.innerRadius = typeof chartCfg.donut === "number" ? chartCfg.donut : 0.6;
1960
2041
  }
1961
2042
  if (chartCfg.annotations)
@@ -1982,7 +2063,18 @@ export function createSvGridController(rawProps, domIdBase) {
1982
2063
  }
1983
2064
  return spec;
1984
2065
  });
2066
+ /**
2067
+ * Can a click on this chart be turned back into a grid filter?
2068
+ *
2069
+ * Only where a clicked mark maps to exactly one value of the charted
2070
+ * dimension. It does not for a sankey (clicking a TARGET would filter the
2071
+ * SOURCE column by a target value and empty the grid), a gauge (no category
2072
+ * at all), or a scatter (the mark carries a point label, not a group).
2073
+ */
2074
+ const chartCrossFilterable = $derived(chartType !== "sankey" && chartType !== "gauge" && chartType !== "scatter");
1985
2075
  function applyChartCrossFilter(category) {
2076
+ if (!chartCrossFilterable)
2077
+ return;
1986
2078
  const dimId = effectiveChartDimensionId;
1987
2079
  if (!dimId)
1988
2080
  return;
@@ -3418,6 +3510,11 @@ export function createSvGridController(rawProps, domIdBase) {
3418
3510
  dimension: c.dimensionId,
3419
3511
  series: c.seriesId ?? null,
3420
3512
  measure: c.measureId,
3513
+ measure2: c.measure2Id,
3514
+ orientation: c.orientation,
3515
+ stacked100: c.stacked100,
3516
+ donut: c.donut,
3517
+ palette: c.palette,
3421
3518
  reduce: c.reduce,
3422
3519
  stacked: c.stacked,
3423
3520
  dataLabels: c.dataLabels,
@@ -3435,6 +3532,11 @@ export function createSvGridController(rawProps, domIdBase) {
3435
3532
  dimensionId: c.dimension ?? null,
3436
3533
  measureId: c.measure ?? null,
3437
3534
  seriesId: c.series,
3535
+ measure2Id: c.measure2 ?? null,
3536
+ orientation: c.orientation ?? null,
3537
+ stacked100: c.stacked100 ?? null,
3538
+ donut: c.donut ?? null,
3539
+ palette: c.palette ?? null,
3438
3540
  stacked: c.stacked ?? null,
3439
3541
  dataLabels: c.dataLabels ?? null,
3440
3542
  logScale: c.logScale ?? null,
@@ -3444,6 +3546,18 @@ export function createSvGridController(rawProps, domIdBase) {
3444
3546
  charts = restored.length ? restored : [makeChart("Chart 1")];
3445
3547
  activeChartIndex = Math.max(0, Math.min(charts.length - 1, active ?? 0));
3446
3548
  },
3549
+ get chartCrossFilterable() { return chartCrossFilterable; },
3550
+ get chartOrientation() { return effectiveChartOrientation; },
3551
+ set chartOrientation(v) { activeChart.orientation = v; },
3552
+ get chartStacked100() { return effectiveChartStacked100; },
3553
+ set chartStacked100(v) { activeChart.stacked100 = v; },
3554
+ get chartDonut() { return effectiveChartDonut; },
3555
+ set chartDonut(v) { activeChart.donut = v; },
3556
+ get chartPalette() { return effectiveChartPalette; },
3557
+ set chartPalette(v) { activeChart.palette = v; },
3558
+ get chartMeasure2Id() { return activeChart.measure2Id; },
3559
+ set chartMeasure2Id(v) { activeChart.measure2Id = v; },
3560
+ get effectiveChartMeasure2Id() { return effectiveChartMeasure2Id; },
3447
3561
  get chartAiHandler() { return chartAiHandler; },
3448
3562
  set chartAiHandler(v) { chartAiHandler = v; },
3449
3563
  applyChartConfig(config) {
package/dist/SvGrid.css CHANGED
@@ -153,6 +153,10 @@
153
153
  /* Advanced-filter indicator. Reads as state rather than as another action, so
154
154
  it uses the accent fill the toolbar buttons reserve for `is-active` instead
155
155
  of the neutral button shell. */
156
+ .sv-grid-advf-chip > .sv-grid-icon {
157
+ width: 13px;
158
+ height: 13px;
159
+ }
156
160
  .sv-grid-advf-chip {
157
161
  display: inline-flex;
158
162
  align-items: center;
@@ -261,6 +265,12 @@
261
265
  flex-shrink: 0;
262
266
  }
263
267
  .sv-grid-tool-panel-btn {
268
+ /* Centred as flex because these draw an icon now, not a bare character: a
269
+ glyph default still centres, and an SVG override no longer sits on the
270
+ text baseline. */
271
+ display: inline-flex;
272
+ align-items: center;
273
+ justify-content: center;
264
274
  width: 22px;
265
275
  height: 22px;
266
276
  border: 0;
@@ -807,9 +817,18 @@
807
817
  color: var(--sg-accent, #2563eb);
808
818
  }
809
819
  .sv-grid-group-caret {
820
+ display: inline-flex;
821
+ align-items: center;
822
+ justify-content: center;
823
+ width: 10px;
824
+ height: 10px;
810
825
  flex-shrink: 0;
811
826
  transition: transform 140ms ease;
812
827
  }
828
+ .sv-grid-group-caret > .sv-grid-icon {
829
+ width: 100%;
830
+ height: 100%;
831
+ }
813
832
  /* Collapsed: point the caret right (like a closed disclosure). */
814
833
  .sv-grid-group-toggle.is-collapsed .sv-grid-group-caret {
815
834
  transform: rotate(-90deg);
@@ -1855,6 +1874,23 @@ select.sv-grid-fr-editor {
1855
1874
  display: block;
1856
1875
  flex: none;
1857
1876
  }
1877
+ /* A consumer icon from the `icons` prop. SvGrid wraps the override in this box
1878
+ rather than asking the consumer to add `.sv-grid-icon` themselves, so it
1879
+ inherits every per-site size rule below and the expander's rotate-on-open
1880
+ without needing to know those rules exist. Must stay AFTER .sv-grid-icon:
1881
+ equal specificity, and this display has to win. */
1882
+ .sv-grid-icon-custom {
1883
+ display: inline-flex;
1884
+ align-items: center;
1885
+ justify-content: center;
1886
+ line-height: 0;
1887
+ }
1888
+ .sv-grid-icon-custom > svg,
1889
+ .sv-grid-icon-custom > img {
1890
+ width: 100%;
1891
+ height: 100%;
1892
+ display: block;
1893
+ }
1858
1894
 
1859
1895
  .sv-grid-header-cell {
1860
1896
  display: flex;
@@ -2453,14 +2489,19 @@ select.sv-grid-fr-editor {
2453
2489
  group banners and auto-group columns, SvGroupCell and SvTree all draw the
2454
2490
  same `chevron-right` and rotate it open, rather than swapping between two
2455
2491
  different glyphs. */
2456
- .sv-grid-tree-toggle .sv-grid-icon,
2457
- .sv-grid-group-toggle .sv-grid-icon {
2492
+ /* Direct child, not descendant. The column-group header button also carries
2493
+ `sv-grid-group-toggle` + `aria-expanded`, and its caret is wrapped one level
2494
+ deeper - a descendant selector would rotate that caret 90deg too, so an
2495
+ expanded down-caret would point left. The three row/tree expanders render
2496
+ their icon as an immediate child, so `>` changes nothing for them. */
2497
+ .sv-grid-tree-toggle > .sv-grid-icon,
2498
+ .sv-grid-group-toggle > .sv-grid-icon {
2458
2499
  width: 12px;
2459
2500
  height: 12px;
2460
2501
  transition: transform 0.15s ease;
2461
2502
  }
2462
- .sv-grid-tree-toggle[aria-expanded="true"] .sv-grid-icon,
2463
- .sv-grid-group-toggle[aria-expanded="true"] .sv-grid-icon {
2503
+ .sv-grid-tree-toggle[aria-expanded="true"] > .sv-grid-icon,
2504
+ .sv-grid-group-toggle[aria-expanded="true"] > .sv-grid-icon {
2464
2505
  transform: rotate(90deg);
2465
2506
  }
2466
2507
  .sv-grid-tree-toggle:focus-visible {
@@ -2624,7 +2665,7 @@ select.sv-grid-fr-editor {
2624
2665
  box-shadow: 0 10px 25px rgba(15, 23, 42, 0.18);
2625
2666
  min-width: 280px;
2626
2667
  }
2627
- .sv-grid-find-icon {
2668
+ .sv-grid-find > .sv-grid-icon {
2628
2669
  width: 14px; height: 14px;
2629
2670
  color: var(--sg-muted, #94a3b8);
2630
2671
  flex: none;
@@ -2868,13 +2909,26 @@ select.sv-grid-fr-editor {
2868
2909
  opacity: 1;
2869
2910
  }
2870
2911
 
2871
- /* Magnifier prefix on the menu's search input. */
2912
+ /* Magnifier prefix on the menu's search input. Real markup rather than a
2913
+ background-image, so it follows the theme and the `icons` prop can replace
2914
+ it; the input keeps its own class because focusFilterPanel() and a test both
2915
+ resolve `.sv-grid-menu-search`. */
2872
2916
  .sv-grid-menu-search {
2873
2917
  padding-left: 28px;
2874
- background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='6'/%3E%3Cpath d='M20 20l-4.5-4.5'/%3E%3C/svg%3E");
2875
- background-position: 8px center;
2876
- background-repeat: no-repeat;
2877
- background-size: 14px 14px;
2918
+ }
2919
+ .sv-grid-menu-search-wrap {
2920
+ position: relative;
2921
+ display: block;
2922
+ }
2923
+ .sv-grid-menu-search-wrap > .sv-grid-icon {
2924
+ position: absolute;
2925
+ left: 8px;
2926
+ top: 50%;
2927
+ transform: translateY(-50%);
2928
+ width: 14px;
2929
+ height: 14px;
2930
+ color: var(--sg-muted, #94a3b8);
2931
+ pointer-events: none;
2878
2932
  }
2879
2933
 
2880
2934
  /* Filter menu vertical rhythm. */
@@ -2910,6 +2964,11 @@ select.sv-grid-fr-editor {
2910
2964
  opacity: 1;
2911
2965
  }
2912
2966
 
2967
+ .sv-grid-board-search > .sv-grid-icon {
2968
+ width: 14px;
2969
+ height: 14px;
2970
+ }
2971
+
2913
2972
  /* Kanban board mode search box (board.searchable) */
2914
2973
  .sv-grid-board-search {
2915
2974
  display: flex;
@@ -3048,6 +3107,16 @@ select.sv-grid-fr-editor {
3048
3107
  .sv-grid-chart-actions { display: inline-flex; align-items: center; gap: 6px; }
3049
3108
  .sv-grid-chart-controls { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
3050
3109
  .sv-grid-chart-controls:empty { display: none; }
3110
+ /* Says why the chosen chart type cannot draw yet - a missing Split by, too few
3111
+ groups. The picker deliberately does NOT hide such a type: options that come
3112
+ and go as the user filters are worse than one sentence of explanation. */
3113
+ .sv-grid-chart-hint {
3114
+ flex-basis: 100%;
3115
+ margin: 2px 0 0;
3116
+ font-size: 11.5px;
3117
+ font-weight: 400;
3118
+ color: var(--sg-muted, #64748b);
3119
+ }
3051
3120
  .sv-grid-chart-ctl { display: flex; flex-direction: column; gap: 2px; font-size: 11px; font-weight: 600; color: var(--sg-muted, #64748b); }
3052
3121
  .sv-grid-chart-ctl select {
3053
3122
  font: inherit; font-size: 12.5px; font-weight: 400; color: var(--sg-fg, #0f172a);