@svgrid/grid 3.0.2 → 3.0.4

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 (281) hide show
  1. package/README.md +2 -1
  2. package/dist/GridMenus.svelte +44 -2
  3. package/dist/SvChartMenu.svelte +69 -0
  4. package/dist/SvChartMenu.svelte.d.ts +11 -0
  5. package/dist/SvChartPanes.svelte +113 -0
  6. package/dist/SvChartPanes.svelte.d.ts +20 -0
  7. package/dist/SvGrid.controller.svelte.d.ts +110 -39
  8. package/dist/SvGrid.controller.svelte.js +655 -200
  9. package/dist/SvGrid.css +105 -2
  10. package/dist/SvGrid.svelte +386 -514
  11. package/dist/SvGrid.types.d.ts +210 -9
  12. package/dist/SvGridCellEditor.svelte +17 -0
  13. package/dist/SvGridChart.svelte +2257 -329
  14. package/dist/SvGridChart.svelte.d.ts +6 -106
  15. package/dist/SvGridChart.types.d.ts +338 -0
  16. package/dist/SvGridChart.types.js +1 -0
  17. package/dist/SvGridChartBuilder.svelte +323 -0
  18. package/dist/SvGridChartBuilder.svelte.d.ts +34 -0
  19. package/dist/SvGridChartPanel.svelte +221 -275
  20. package/dist/SvGridChartPickers.svelte +417 -0
  21. package/dist/SvGridChartPickers.svelte.d.ts +70 -0
  22. package/dist/SvGridChartView.svelte +13 -14
  23. package/dist/SvModal.svelte +7 -1
  24. package/dist/SvModal.svelte.d.ts +5 -0
  25. package/dist/ai.d.ts +40 -8
  26. package/dist/ai.js +135 -24
  27. package/dist/aria.d.ts +11 -0
  28. package/dist/build-api.js +108 -22
  29. package/dist/cdn/GridMenus-7kbpnnBW.js +635 -0
  30. package/dist/cdn/GridMenus-BL7ZgQvU.js +636 -0
  31. package/dist/cdn/SvChartMenu-Bl6PBbkT.js +58 -0
  32. package/dist/cdn/SvChartMenu-FBSMINA6.js +59 -0
  33. package/dist/cdn/{SvDateRangeInput-DMLKmGEc.js → SvDateRangeInput-BeU_TkbQ.js} +15 -14
  34. package/dist/cdn/{SvDateRangeInput-CaOuMs8O.js → SvDateRangeInput-yX8vzleW.js} +38 -37
  35. package/dist/cdn/{SvDateTimePicker-sonaH0oh.js → SvDateTimePicker-DQwt4UAs.js} +139 -180
  36. package/dist/cdn/SvDateTimePicker-vNU6bZ-q.js +775 -0
  37. package/dist/cdn/{SvGridCellEditor-CjEJMJKc.js → SvGridCellEditor-B1p-vCK5.js} +188 -178
  38. package/dist/cdn/{SvGridCellEditor-BWnTi2N7.js → SvGridCellEditor-D_0q4xAu.js} +98 -88
  39. package/dist/cdn/SvGridChart-C3EWAZaM.js +3574 -0
  40. package/dist/cdn/SvGridChart-DzLkSwCH.js +3572 -0
  41. package/dist/cdn/SvGridChartBuilder-BE2T1ykB.js +783 -0
  42. package/dist/cdn/SvGridChartBuilder-CfII62sZ.js +784 -0
  43. package/dist/cdn/SvGridChartPanel-CCX5_Wgd.js +675 -0
  44. package/dist/cdn/SvGridChartPanel-xf4sWVTo.js +699 -0
  45. package/dist/cdn/SvGridChartView-CfuXmY5I.js +48 -0
  46. package/dist/cdn/SvGridChartView-DYwabQWj.js +47 -0
  47. package/dist/cdn/SvMenuList-CLN8OuIK.js +452 -0
  48. package/dist/cdn/SvMenuList-DkGhNKjf.js +451 -0
  49. package/dist/cdn/SvModal-BAE-pjZX.js +396 -0
  50. package/dist/cdn/SvModal-CIZWCcad.js +397 -0
  51. package/dist/cdn/chart-Dz7SqMXH.js +4341 -0
  52. package/dist/cdn/chart-export-BXqueeWJ.js +135 -0
  53. package/dist/cdn/chart-export-pdf-DONFUnNY.js +110 -0
  54. package/dist/cdn/chart-panel-messages-CUbf2R4i.js +1052 -0
  55. package/dist/cdn/chart-panel-messages-CmNrMdsr.js +1053 -0
  56. package/dist/cdn/chart-summary-BJW_tg_X.js +138 -0
  57. package/dist/cdn/chart-trend-CaN9mDEV.js +50 -0
  58. package/dist/cdn/chart-validate-HcOVFAfJ.js +188 -0
  59. package/dist/cdn/{column-resize-DsfNXMom.js → column-resize-DpmOLfRp.js} +3 -3
  60. package/dist/cdn/{date-format-BnnHlqGw.js → date-format-CtquV-p3.js} +583 -603
  61. package/dist/cdn/{date-format-BNii4zeD.js → date-format-D6KFzU_W.js} +347 -367
  62. package/dist/cdn/dismissable-DAHetSNk.js +44 -0
  63. package/dist/cdn/editor-contract-LXgQJAgd.js +22 -0
  64. package/dist/cdn/focus-trap-BBOQYBma.js +65 -0
  65. package/dist/cdn/{row-resize-BRcimkUT.js → row-resize-niQCp040.js} +44 -36
  66. package/dist/cdn/{src-DNbz94Ct.js → src-BKhZ6eXd.js} +10227 -9787
  67. package/dist/cdn/{src-BJ2opd0j.js → src-V1uu8iE9.js} +6568 -6128
  68. package/dist/cdn/svgrid.js +26 -15
  69. package/dist/cdn/svgrid.svelte-external.js +26 -15
  70. package/dist/chart-axes.d.ts +53 -0
  71. package/dist/chart-axes.js +351 -0
  72. package/dist/chart-cartesian.d.ts +88 -0
  73. package/dist/chart-cartesian.js +1862 -0
  74. package/dist/chart-decimate.d.ts +51 -0
  75. package/dist/chart-decimate.js +199 -0
  76. package/dist/chart-export-pdf.d.ts +47 -0
  77. package/dist/chart-export-pdf.js +187 -0
  78. package/dist/chart-export.d.ts +2 -1
  79. package/dist/chart-export.js +18 -3
  80. package/dist/chart-financial.d.ts +91 -0
  81. package/dist/chart-financial.js +175 -0
  82. package/dist/chart-flow.d.ts +10 -0
  83. package/dist/chart-flow.js +298 -0
  84. package/dist/chart-format.d.ts +18 -0
  85. package/dist/chart-format.js +65 -0
  86. package/dist/chart-grid.d.ts +8 -0
  87. package/dist/chart-grid.js +190 -0
  88. package/dist/chart-hierarchy.d.ts +17 -0
  89. package/dist/chart-hierarchy.js +146 -0
  90. package/dist/chart-indicators.d.ts +115 -0
  91. package/dist/chart-indicators.js +389 -0
  92. package/dist/chart-messages.d.ts +95 -0
  93. package/dist/chart-messages.js +92 -0
  94. package/dist/chart-motion.d.ts +16 -0
  95. package/dist/chart-motion.js +141 -0
  96. package/dist/chart-panel-messages.d.ts +265 -0
  97. package/dist/chart-panel-messages.js +285 -0
  98. package/dist/chart-pivot.d.ts +87 -0
  99. package/dist/chart-pivot.js +156 -0
  100. package/dist/chart-polar.d.ts +25 -0
  101. package/dist/chart-polar.js +700 -0
  102. package/dist/chart-samples.d.ts +16 -0
  103. package/dist/chart-samples.js +153 -0
  104. package/dist/chart-scale.d.ts +113 -0
  105. package/dist/chart-scale.js +405 -0
  106. package/dist/chart-stats.d.ts +111 -0
  107. package/dist/chart-stats.js +419 -0
  108. package/dist/chart-stream.d.ts +45 -0
  109. package/dist/chart-stream.js +91 -0
  110. package/dist/chart-summary.d.ts +27 -0
  111. package/dist/chart-summary.js +205 -0
  112. package/dist/chart-sync.svelte.d.ts +32 -0
  113. package/dist/chart-sync.svelte.js +23 -0
  114. package/dist/chart-table.d.ts +35 -0
  115. package/dist/chart-table.js +165 -0
  116. package/dist/chart-trend.d.ts +19 -0
  117. package/dist/chart-trend.js +61 -0
  118. package/dist/chart-types.d.ts +1456 -0
  119. package/dist/chart-types.js +6 -0
  120. package/dist/chart-validate.d.ts +43 -0
  121. package/dist/chart-validate.js +272 -0
  122. package/dist/chart-zoom.d.ts +40 -0
  123. package/dist/chart-zoom.js +145 -0
  124. package/dist/chart.d.ts +186 -865
  125. package/dist/chart.js +460 -2204
  126. package/dist/clipboard.d.ts +1 -0
  127. package/dist/clipboard.js +137 -18
  128. package/dist/column-resize.d.ts +3 -0
  129. package/dist/column-resize.js +4 -1
  130. package/dist/columns.js +3 -0
  131. package/dist/command-context.d.ts +19 -0
  132. package/dist/command-context.js +116 -0
  133. package/dist/core.d.ts +7 -0
  134. package/dist/createPopoverSelect.svelte.d.ts +2 -2
  135. package/dist/editing.d.ts +2 -8
  136. package/dist/editing.js +262 -33
  137. package/dist/fill-patterns.d.ts +0 -5
  138. package/dist/fill-patterns.js +56 -2
  139. package/dist/grid-messages.d.ts +10 -3
  140. package/dist/grid-messages.js +5 -0
  141. package/dist/history.d.ts +83 -0
  142. package/dist/history.js +133 -0
  143. package/dist/index.d.ts +24 -6
  144. package/dist/index.js +20 -2
  145. package/dist/keyboard-handlers.js +88 -31
  146. package/dist/keyboard.d.ts +55 -0
  147. package/dist/keyboard.js +132 -0
  148. package/dist/menus.d.ts +3 -1
  149. package/dist/menus.js +7 -2
  150. package/dist/merges.d.ts +97 -0
  151. package/dist/merges.js +147 -0
  152. package/dist/row-resize.d.ts +3 -0
  153. package/dist/row-resize.js +14 -0
  154. package/dist/scroll-sync.d.ts +1 -0
  155. package/dist/scroll-sync.js +24 -0
  156. package/dist/selection.d.ts +16 -0
  157. package/dist/selection.js +108 -16
  158. package/dist/shortcut-registry.d.ts +145 -0
  159. package/dist/shortcut-registry.js +44 -0
  160. package/dist/svgrid-wrapper.types.d.ts +213 -22
  161. package/dist/virtualization/virtualizer.js +38 -17
  162. package/package.json +6 -1
  163. package/src/GridMenus.svelte +44 -2
  164. package/src/SvChartMenu.svelte +69 -0
  165. package/src/SvChartPanes.svelte +113 -0
  166. package/src/SvChartPanes.test.ts +66 -0
  167. package/src/SvGrid.controller.svelte.ts +629 -172
  168. package/src/SvGrid.css +105 -2
  169. package/src/SvGrid.svelte +386 -514
  170. package/src/SvGrid.types.ts +188 -8
  171. package/src/SvGridCellEditor.svelte +17 -0
  172. package/src/SvGridChart.svelte +2257 -329
  173. package/src/SvGridChart.test.ts +1419 -1
  174. package/src/SvGridChart.types.ts +336 -0
  175. package/src/SvGridChartBuilder.svelte +323 -0
  176. package/src/SvGridChartPanel.svelte +221 -275
  177. package/src/SvGridChartPickers.svelte +417 -0
  178. package/src/SvGridChartView.svelte +13 -14
  179. package/src/SvModal.svelte +7 -1
  180. package/src/SvModal.test.ts +9 -0
  181. package/src/ai.test.ts +57 -2
  182. package/src/ai.ts +166 -22
  183. package/src/aria.d.ts +11 -0
  184. package/src/build-api.coverage.test.ts +184 -0
  185. package/src/build-api.ts +107 -18
  186. package/src/chart-axes.test.ts +573 -0
  187. package/src/chart-axes.ts +342 -0
  188. package/src/chart-cartesian.ts +1863 -0
  189. package/src/chart-decimate.test.ts +249 -0
  190. package/src/chart-decimate.ts +186 -0
  191. package/src/chart-export-pdf.test.ts +91 -0
  192. package/src/chart-export-pdf.ts +207 -0
  193. package/src/chart-export.test.ts +14 -0
  194. package/src/chart-export.ts +13 -3
  195. package/src/chart-financial.ts +208 -0
  196. package/src/chart-flow.ts +286 -0
  197. package/src/chart-format.ts +67 -0
  198. package/src/chart-grid.ts +179 -0
  199. package/src/chart-hierarchy.ts +135 -0
  200. package/src/chart-indicators.test.ts +443 -0
  201. package/src/chart-indicators.ts +384 -0
  202. package/src/chart-messages.test.ts +21 -0
  203. package/src/chart-messages.ts +184 -0
  204. package/src/chart-motion.test.ts +71 -0
  205. package/src/chart-motion.ts +148 -0
  206. package/src/chart-panel-messages.test.ts +29 -0
  207. package/src/chart-panel-messages.ts +550 -0
  208. package/src/chart-pivot.test.ts +54 -0
  209. package/src/chart-pivot.ts +225 -0
  210. package/src/chart-polar.ts +674 -0
  211. package/src/chart-samples.ts +106 -0
  212. package/src/chart-scale.ts +394 -0
  213. package/src/chart-series-types.test.ts +714 -0
  214. package/src/chart-stats.ts +409 -0
  215. package/src/chart-stream.test.ts +75 -0
  216. package/src/chart-stream.ts +114 -0
  217. package/src/chart-summary.test.ts +90 -0
  218. package/src/chart-summary.ts +197 -0
  219. package/src/chart-sync.svelte.ts +41 -0
  220. package/src/chart-table.test.ts +76 -0
  221. package/src/chart-table.ts +178 -0
  222. package/src/chart-trend.ts +47 -0
  223. package/src/chart-types.ts +1309 -0
  224. package/src/chart-validate.test.ts +100 -0
  225. package/src/chart-validate.ts +247 -0
  226. package/src/chart-zoom.test.ts +137 -0
  227. package/src/chart-zoom.ts +124 -0
  228. package/src/chart.coverage.test.ts +81 -0
  229. package/src/chart.test.ts +56 -3
  230. package/src/chart.ts +557 -2784
  231. package/src/clipboard.test.ts +151 -0
  232. package/src/clipboard.ts +145 -16
  233. package/src/column-resize.ts +7 -1
  234. package/src/columns.ts +2 -0
  235. package/src/command-context.test.ts +200 -0
  236. package/src/command-context.ts +137 -0
  237. package/src/core.ts +7 -0
  238. package/src/editing.test.ts +281 -3
  239. package/src/editing.ts +256 -38
  240. package/src/fill-patterns.test.ts +35 -0
  241. package/src/fill-patterns.ts +56 -2
  242. package/src/grid-messages.ts +16 -3
  243. package/src/history.test.ts +196 -0
  244. package/src/history.ts +162 -0
  245. package/src/icon-seam.test.ts +3 -2
  246. package/src/index.ts +150 -2
  247. package/src/keyboard-handlers.coverage.test.ts +126 -6
  248. package/src/keyboard-handlers.ts +91 -30
  249. package/src/keyboard-shortcuts.seam.test.ts +200 -0
  250. package/src/keyboard.test.ts +124 -1
  251. package/src/keyboard.ts +142 -0
  252. package/src/menus.test.ts +26 -0
  253. package/src/menus.ts +10 -3
  254. package/src/merges.test.ts +112 -0
  255. package/src/merges.ts +168 -0
  256. package/src/pivot.grid.test.ts +40 -5
  257. package/src/row-resize.test.ts +44 -0
  258. package/src/row-resize.ts +17 -0
  259. package/src/scroll-sync.test.ts +42 -1
  260. package/src/scroll-sync.ts +25 -0
  261. package/src/selection.multi-range.test.ts +34 -0
  262. package/src/selection.test.ts +30 -2
  263. package/src/selection.ts +111 -19
  264. package/src/shortcut-registry.test.ts +97 -0
  265. package/src/shortcut-registry.ts +181 -0
  266. package/src/svgrid-wrapper.types.ts +184 -13
  267. package/src/svgrid.behavior.test.ts +135 -0
  268. package/src/svgrid.charting.test.ts +513 -3
  269. package/src/svgrid.context-menu.test.ts +31 -0
  270. package/src/svgrid.new-features.wrapper.test.ts +10 -3
  271. package/src/virtualization/virtualizer.ts +39 -17
  272. package/dist/cdn/GridMenus-DyFA-QxA.js +0 -602
  273. package/dist/cdn/GridMenus-M2XP9t0_.js +0 -603
  274. package/dist/cdn/SvDateTimePicker-CCbDZNZB.js +0 -816
  275. package/dist/cdn/SvGridChart-DAb9RbRs.js +0 -1480
  276. package/dist/cdn/SvGridChart-Yl-IXZFO.js +0 -1481
  277. package/dist/cdn/SvGridChartPanel-DayQpDsR.js +0 -834
  278. package/dist/cdn/SvGridChartPanel-aqf8n-vJ.js +0 -810
  279. package/dist/cdn/SvGridChartView-CxfakxR0.js +0 -56
  280. package/dist/cdn/SvGridChartView-Dm_YEx9L.js +0 -55
  281. package/dist/cdn/chart-CKJRCPOk.js +0 -1652
@@ -0,0 +1,417 @@
1
+ <script lang="ts" module>
2
+ /**
3
+ * The chart panel's pickers: type, the columns a chart reads, the
4
+ * aggregate, and the per-type switches (stacked, horizontal, donut, log
5
+ * scale, labels, bucket, date axis, bins, funnel shape, candle style,
6
+ * indicator chips), plus the sentence that says why the chosen type cannot
7
+ * draw yet. One component rendered twice: as a row under the panel head,
8
+ * and as a form on the builder's Data tab, so the two never disagree about
9
+ * what a type needs.
10
+ *
11
+ * Every label comes from `GridChartPanelMessages`, so the panel and the
12
+ * builder localize together through `localization.text`.
13
+ */
14
+ import type { ChartReducer, ChartType } from "./chart-types";
15
+ import type { ChartPanelIndicator } from "./chart-financial";
16
+ import type { ChartTimeBucket } from "./chart-stats";
17
+ import type { GridChartPanelMessages } from "./chart-panel-messages";
18
+
19
+ /** What the type picker knows about a chart type. */
20
+ export type ChartPanelTypeDef = { value: ChartType; label: string; group: string };
21
+ type Shape = { dims: unknown[]; measures: unknown[]; dates: unknown[] };
22
+ type TypeSeed = { value: ChartType; label: keyof GridChartPanelMessages; group: keyof GridChartPanelMessages; needs?: (c: Shape) => boolean };
23
+
24
+ /**
25
+ * The chart types the picker offers, grouped by what they are FOR.
26
+ *
27
+ * `needs` gates on COLUMN SHAPE only, never on the data. Column shape is
28
+ * stable while the user filters; row counts are not, and a picker whose
29
+ * options vanish mid-session because a filter emptied a group is worse than
30
+ * one that explains itself. Data-level problems get a sentence instead, see
31
+ * `typeIssue` below.
32
+ */
33
+ const TYPES: TypeSeed[] = [
34
+ { value: "bar", label: "chartTypeBar", group: "chartGroupCompare" },
35
+ { value: "line", label: "chartTypeLine", group: "chartGroupCompare" },
36
+ { value: "area", label: "chartTypeArea", group: "chartGroupCompare" },
37
+ { value: "lollipop", label: "chartTypeLollipop", group: "chartGroupCompare" },
38
+ { value: "pareto", label: "chartTypePareto", group: "chartGroupCompare" },
39
+ { value: "range-bar", label: "chartTypeRangeBar", group: "chartGroupCompare", needs: (c) => c.measures.length >= 2 },
40
+ { value: "range-area", label: "chartTypeRangeArea", group: "chartGroupCompare", needs: (c) => c.measures.length >= 2 },
41
+ { value: "dumbbell", label: "chartTypeDumbbell", group: "chartGroupCompare", needs: (c) => c.measures.length >= 2 },
42
+ { value: "radial-column", label: "chartTypeRadialColumn", group: "chartGroupCompare" },
43
+ { value: "radial-bar", label: "chartTypeRadialBar", group: "chartGroupCompare" },
44
+ { value: "nightingale", label: "chartTypeNightingale", group: "chartGroupCompare" },
45
+ { value: "pie", label: "chartTypePie", group: "chartGroupPartOfWhole" },
46
+ { value: "treemap", label: "chartTypeTreemap", group: "chartGroupPartOfWhole" },
47
+ { value: "sunburst", label: "chartTypeSunburst", group: "chartGroupPartOfWhole" },
48
+ { value: "funnel", label: "chartTypeFunnel", group: "chartGroupFlow" },
49
+ { value: "waterfall", label: "chartTypeWaterfall", group: "chartGroupFlow" },
50
+ { value: "sankey", label: "chartTypeSankey", group: "chartGroupFlow", needs: (c) => c.dims.length >= 2 },
51
+ { value: "chord", label: "chartTypeChord", group: "chartGroupFlow", needs: (c) => c.dims.length >= 2 },
52
+ { value: "radar", label: "chartTypeRadar", group: "chartGroupDistribution" },
53
+ { value: "heatmap", label: "chartTypeHeatmap", group: "chartGroupDistribution", needs: (c) => c.dims.length >= 2 },
54
+ { value: "scatter", label: "chartTypeScatter", group: "chartGroupDistribution", needs: (c) => c.measures.length >= 2 },
55
+ { value: "boxplot", label: "chartTypeBoxplot", group: "chartGroupDistribution" },
56
+ { value: "histogram", label: "chartTypeHistogram", group: "chartGroupDistribution" },
57
+ { value: "gauge", label: "chartTypeGauge", group: "chartGroupSingleValue" },
58
+ { value: "bullet", label: "chartTypeBullet", group: "chartGroupSingleValue" },
59
+ { value: "calendar", label: "chartTypeCalendar", group: "chartGroupOverTime", needs: (c) => c.dates.length >= 1 },
60
+ { value: "stream", label: "chartTypeStream", group: "chartGroupOverTime", needs: (c) => c.dims.length >= 2 },
61
+ { value: "candlestick", label: "chartTypeCandlestick", group: "chartGroupOverTime", needs: (c) => c.dates.length >= 1 && c.measures.length >= 4 },
62
+ { value: "ohlc", label: "chartTypeOhlc", group: "chartGroupOverTime", needs: (c) => c.dates.length >= 1 && c.measures.length >= 4 },
63
+ ];
64
+
65
+ /** The types the panel offers for these columns, labelled in the given language. */
66
+ export function chartPanelTypes(columns: Shape, m: GridChartPanelMessages): ChartPanelTypeDef[] {
67
+ return TYPES.filter((t) => !t.needs || t.needs(columns)).map((t) => ({ value: t.value, label: m[t.label], group: m[t.group] }));
68
+ }
69
+
70
+ /** The reducers the Aggregate picker offers, in its order. */
71
+ export function chartPanelReducers(m: GridChartPanelMessages): Array<{ value: ChartReducer; label: string }> {
72
+ return [
73
+ { value: "sum", label: m.chartReduceSum },
74
+ { value: "avg", label: m.chartReduceAvg },
75
+ { value: "count", label: m.chartReduceCount },
76
+ { value: "min", label: m.chartReduceMin },
77
+ { value: "max", label: m.chartReduceMax },
78
+ { value: "median", label: m.chartReduceMedian },
79
+ { value: "p90", label: m.chartReduceP90 },
80
+ { value: "first", label: m.chartReduceFirst },
81
+ { value: "last", label: m.chartReduceLast },
82
+ { value: "countDistinct", label: m.chartReduceCountDistinct },
83
+ ];
84
+ }
85
+
86
+ /** Named series palettes. "Theme" defers to --sg-chart-1..8 and the defaults. */
87
+ export const CHART_PANEL_PALETTES: Array<{ key: string; label: keyof GridChartPanelMessages; colors: string[] | null }> = [
88
+ { key: "theme", label: "chartPaletteTheme", colors: null },
89
+ { key: "ocean", label: "chartPaletteOcean", colors: ["#0ea5e9", "#14b8a6", "#6366f1", "#8b5cf6", "#06b6d4"] },
90
+ { key: "sunset", label: "chartPaletteSunset", colors: ["#f59e0b", "#ef4444", "#ec4899", "#8b5cf6", "#f97316"] },
91
+ { key: "forest", label: "chartPaletteForest", colors: ["#16a34a", "#65a30d", "#0d9488", "#4d7c0f", "#0891b2"] },
92
+ { key: "slate", label: "chartPaletteSlate", colors: ["#475569", "#0ea5e9", "#64748b", "#38bdf8", "#94a3b8"] },
93
+ ];
94
+
95
+ /** The indicator chips a price chart offers: panes first, then overlays. */
96
+ const INDICATORS: Array<{ value: ChartPanelIndicator; label: keyof GridChartPanelMessages; title: keyof GridChartPanelMessages }> = [
97
+ { value: "volume", label: "chartIndVolume", title: "chartIndVolumeTitle" },
98
+ { value: "rsi", label: "chartIndRsi", title: "chartIndRsiTitle" },
99
+ { value: "macd", label: "chartIndMacd", title: "chartIndMacdTitle" },
100
+ { value: "stochastic", label: "chartIndStochastic", title: "chartIndStochasticTitle" },
101
+ { value: "atr", label: "chartIndAtr", title: "chartIndAtrTitle" },
102
+ { value: "obv", label: "chartIndObv", title: "chartIndObvTitle" },
103
+ { value: "sma", label: "chartIndSma", title: "chartIndSmaTitle" },
104
+ { value: "ema", label: "chartIndEma", title: "chartIndEmaTitle" },
105
+ { value: "bb", label: "chartIndBb", title: "chartIndBbTitle" },
106
+ { value: "vwap", label: "chartIndVwap", title: "chartIndVwapTitle" },
107
+ ];
108
+ const OVERLAY_KINDS: ChartPanelIndicator[] = ["sma", "ema", "bb", "vwap"];
109
+ /** The price columns a candlestick / OHLC chart reads, in picker order. */
110
+ const OHLC_FIELDS: Array<{ key: "open" | "high" | "low" | "close" | "volume"; label: keyof GridChartPanelMessages }> = [
111
+ { key: "open", label: "chartOpen" },
112
+ { key: "high", label: "chartHigh" },
113
+ { key: "low", label: "chartLow" },
114
+ { key: "close", label: "chartClosePrice" },
115
+ { key: "volume", label: "chartVolume" },
116
+ ];
117
+
118
+ // Which controls this type can actually use. Allow-lists rather than "not
119
+ // pie" guards: with thirty types, "everything except pie" hands a gauge a
120
+ // Stacked checkbox.
121
+ const CARTESIAN: ChartType[] = ["bar", "line", "area", "lollipop", "pareto", "range-bar", "range-area", "dumbbell", "stream"];
122
+ /** Types whose second measure is the HIGH end (or the target) rather than a Y. */
123
+ const TWO_MEASURE: ChartType[] = ["range-bar", "range-area", "dumbbell"];
124
+ const BUCKETS: Array<{ value: ChartTimeBucket | ""; label: keyof GridChartPanelMessages }> = [
125
+ { value: "", label: "chartBucketExact" },
126
+ { value: "day", label: "chartBucketDay" },
127
+ { value: "week", label: "chartBucketWeek" },
128
+ { value: "month", label: "chartBucketMonth" },
129
+ { value: "quarter", label: "chartBucketQuarter" },
130
+ { value: "year", label: "chartBucketYear" },
131
+ ];
132
+ </script>
133
+
134
+ <script lang="ts" generics="TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData">
135
+ import type { RowData, TableFeatures } from "./index";
136
+ import type { SvGridController } from "./SvGrid.controller.svelte";
137
+ import { pivotChartType } from "./chart-pivot";
138
+
139
+ let {
140
+ ctrl,
141
+ messages: m,
142
+ scope = "panel",
143
+ }: {
144
+ ctrl: SvGridController<TFeatures, TData>;
145
+ messages: GridChartPanelMessages;
146
+ /** `panel`: the row under the panel head, Type first. `builder`: the
147
+ * Data tab's form, without Type (the gallery picks it). */
148
+ scope?: "panel" | "builder";
149
+ } = $props();
150
+
151
+ const columns = $derived(ctrl.chartableColumns);
152
+ /** Pivot mode: the pivot on screen is the chart, so the data pickers go and the
153
+ * type list keeps the shapes a pivot can take (no scatter, gauge, ranges, candles). */
154
+ const pivot = $derived(ctrl.pivotResult != null);
155
+ const availableTypes = $derived(chartPanelTypes(columns, m).filter((t) => !pivot || pivotChartType(t.value) === t.value));
156
+ const typeGroups = $derived([...new Set(availableTypes.map((t) => t.group))]);
157
+ const reducers = $derived(chartPanelReducers(m));
158
+
159
+ function toggleIndicator(kind: ChartPanelIndicator) {
160
+ const on = ctrl.chartIndicators.includes(kind);
161
+ // One overlay at a time: a series carries a single `overlay`.
162
+ const base = OVERLAY_KINDS.includes(kind) ? ctrl.chartIndicators.filter((k) => !OVERLAY_KINDS.includes(k)) : ctrl.chartIndicators;
163
+ ctrl.chartIndicators = on ? base.filter((k) => k !== kind) : [...base, kind];
164
+ }
165
+
166
+ const activePalette = $derived(
167
+ CHART_PANEL_PALETTES.find((x) => x.colors && ctrl.chartPalette && x.colors.join() === ctrl.chartPalette.join())?.key ?? "theme",
168
+ );
169
+ const wantsHorizontal = $derived(ctrl.chartType === "bar");
170
+ const wantsDonut = $derived(ctrl.chartType === "pie" || ctrl.chartType === "sunburst");
171
+ const wantsGroupBy = $derived(!pivot && ctrl.chartType !== "gauge" && ctrl.chartType !== "histogram");
172
+ const wantsSplitBy = $derived(
173
+ !pivot && columns.dims.length > 1 &&
174
+ !["pie", "gauge", "waterfall", "funnel", "calendar", "bullet", "pareto", "radial-bar"].includes(ctrl.chartType),
175
+ );
176
+ const wantsStacked = $derived(["bar", "line", "area", "radial-column"].includes(ctrl.chartType));
177
+ const wantsLogScale = $derived(
178
+ CARTESIAN.includes(ctrl.chartType) || ctrl.chartType === "scatter" || ctrl.chartType === "boxplot" || ctrl.chartType === "histogram",
179
+ );
180
+ const wantsDataLabels = $derived(
181
+ !["gauge", "sankey", "calendar", "treemap", "scatter", "boxplot", "chord", "sunburst", "stream"].includes(ctrl.chartType),
182
+ );
183
+ const wantsSecondMeasure = $derived(!pivot && (ctrl.chartType === "scatter" || TWO_MEASURE.includes(ctrl.chartType) || ctrl.chartType === "bullet"));
184
+ /** What the second measure picker is labelled: Y for a scatter, High for a
185
+ * range, Target for a bullet. */
186
+ const secondMeasureLabel = $derived(ctrl.chartType === "scatter" ? m.chartY : ctrl.chartType === "bullet" ? m.chartTarget : m.chartHigh);
187
+ const wantsFunnelShape = $derived(ctrl.chartType === "funnel");
188
+ const wantsCandleStyle = $derived(ctrl.chartType === "candlestick");
189
+ const wantsOhlc = $derived(!pivot && ctrl.chartIsOhlc);
190
+ const wantsBins = $derived(!pivot && ctrl.chartType === "histogram");
191
+ const wantsValue = $derived(!pivot && !ctrl.chartIsOhlc);
192
+ /**
193
+ * A box plot is the one type that reduces its groups itself: the whole point
194
+ * is the spread of the sample, so `sum | avg | count` has nothing to say
195
+ * about it. Showing an Aggregate select that changes nothing is worse than
196
+ * not showing one.
197
+ */
198
+ const wantsReduce = $derived(!pivot && ctrl.chartType !== "scatter" && ctrl.chartType !== "boxplot" && ctrl.chartType !== "histogram" && !ctrl.chartIsOhlc);
199
+
200
+ /**
201
+ * Why the current type cannot draw anything useful yet, as a sentence.
202
+ *
203
+ * The alternative - removing the option - means a chart can disappear from
204
+ * under the user when they filter. Saying what is missing keeps the picker
205
+ * honest without making it unstable.
206
+ */
207
+ const typeIssue = $derived.by<string | null>(() => {
208
+ const t = ctrl.chartType;
209
+ const cats = ctrl.chartSpec?.categories.length ?? 0;
210
+ if (t === "heatmap" && !ctrl.chartSeriesId && columns.dims.length > 1) return m.chartIssueHeatmap;
211
+ if (t === "sankey" && !ctrl.chartSeriesId) return m.chartIssueSankey;
212
+ if (t === "radar" && cats > 0 && cats < 3) return m.chartIssueRadar;
213
+ if (t === "funnel" && cats === 1) return m.chartIssueFunnel;
214
+ if (t === "chord" && !ctrl.chartSeriesId) return m.chartIssueChord;
215
+ if (t === "stream" && !ctrl.chartSeriesId) return m.chartIssueStream;
216
+ if (TWO_MEASURE.includes(t) && !ctrl.effectiveChartMeasure2Id) return m.chartIssueSecondMeasure;
217
+ if (ctrl.chartIsOhlc) {
218
+ const o = ctrl.chartOhlc;
219
+ if (!ctrl.chartOhlcDateId) return m.chartIssueOhlcDate;
220
+ if (!o.open || !o.high || !o.low || !o.close) return m.chartIssueOhlcColumns;
221
+ }
222
+ return null;
223
+ });
224
+ </script>
225
+
226
+ <div class="sv-grid-chart-controls" class:is-form={scope === "builder"} data-scope={scope}>
227
+ {#if scope === "panel"}
228
+ <label class="sv-grid-chart-ctl">
229
+ <span class="sv-grid-chart-ctl-lbl">{m.chartType}</span>
230
+ <select value={ctrl.chartType} onchange={(e) => (ctrl.chartType = e.currentTarget.value as ChartType)}>
231
+ <!-- Grouped: a flat thirty-item list is a wall. optgroup is native,
232
+ so this costs no new component. -->
233
+ {#each typeGroups as g (g)}
234
+ <optgroup label={g}>
235
+ {#each availableTypes.filter((t) => t.group === g) as t (t.value)}
236
+ <option value={t.value}>{t.label}</option>
237
+ {/each}
238
+ </optgroup>
239
+ {/each}
240
+ </select>
241
+ </label>
242
+ {/if}
243
+ {#if wantsOhlc}
244
+ <label class="sv-grid-chart-ctl">
245
+ <span class="sv-grid-chart-ctl-lbl">{m.chartDate}</span>
246
+ <select value={ctrl.chartOhlcDateId ?? ""} onchange={(e) => (ctrl.chartDimensionId = e.currentTarget.value || null)}>
247
+ {#each columns.dates as d (d.id)}<option value={d.id}>{d.label}</option>{/each}
248
+ </select>
249
+ </label>
250
+ {#each OHLC_FIELDS as f (f.key)}
251
+ <label class="sv-grid-chart-ctl">
252
+ <span class="sv-grid-chart-ctl-lbl">{m[f.label]}</span>
253
+ <select value={ctrl.chartOhlc[f.key] ?? ""} onchange={(e) => (ctrl.chartOhlc = { ...ctrl.chartOhlc, [f.key]: e.currentTarget.value || null })}>
254
+ {#if f.key === "volume"}<option value="">{m.chartNone}</option>{/if}
255
+ {#each columns.measures as c (c.id)}<option value={c.id}>{c.label}</option>{/each}
256
+ </select>
257
+ </label>
258
+ {/each}
259
+ {:else if wantsGroupBy}
260
+ <label class="sv-grid-chart-ctl">
261
+ <span class="sv-grid-chart-ctl-lbl">{ctrl.chartType === "sankey" ? m.chartFrom : ctrl.chartType === "heatmap" ? m.chartColumns : m.chartGroupBy}</span>
262
+ <select value={ctrl.chartDimensionId ?? ""} onchange={(e) => (ctrl.chartDimensionId = e.currentTarget.value || null)}>
263
+ {#each columns.dims as d (d.id)}<option value={d.id}>{d.label}</option>{/each}
264
+ </select>
265
+ </label>
266
+ {/if}
267
+ {#if wantsSplitBy}
268
+ <label class="sv-grid-chart-ctl">
269
+ <span class="sv-grid-chart-ctl-lbl">{ctrl.chartType === "sankey" ? m.chartTo : ctrl.chartType === "heatmap" ? m.chartRows : m.chartSplitBy}</span>
270
+ <select value={ctrl.chartSeriesId ?? ""} onchange={(e) => (ctrl.chartSeriesId = e.currentTarget.value || null)}>
271
+ <option value="">{m.chartNone}</option>
272
+ {#each columns.dims as d (d.id)}<option value={d.id}>{d.label}</option>{/each}
273
+ </select>
274
+ </label>
275
+ {/if}
276
+ {#if wantsValue}
277
+ <label class="sv-grid-chart-ctl">
278
+ <span class="sv-grid-chart-ctl-lbl">{ctrl.chartType === "scatter" ? m.chartX : TWO_MEASURE.includes(ctrl.chartType) ? m.chartLow : ctrl.chartType === "gauge" ? m.chartMetric : m.chartValue}</span>
279
+ <select value={ctrl.chartMeasureId ?? ""} onchange={(e) => (ctrl.chartMeasureId = e.currentTarget.value || null)}>
280
+ {#each columns.measures as c (c.id)}<option value={c.id}>{c.label}</option>{/each}
281
+ </select>
282
+ </label>
283
+ {/if}
284
+ {#if wantsSecondMeasure}
285
+ <label class="sv-grid-chart-ctl">
286
+ <span class="sv-grid-chart-ctl-lbl">{secondMeasureLabel}</span>
287
+ <select value={ctrl.effectiveChartMeasure2Id ?? ""} onchange={(e) => (ctrl.chartMeasure2Id = e.currentTarget.value || null)}>
288
+ {#each columns.measures as c (c.id)}<option value={c.id}>{c.label}</option>{/each}
289
+ </select>
290
+ </label>
291
+ {/if}
292
+ {#if wantsReduce}
293
+ <label class="sv-grid-chart-ctl">
294
+ <span class="sv-grid-chart-ctl-lbl">{m.chartAggregate}</span>
295
+ <select value={ctrl.chartReduce} onchange={(e) => (ctrl.chartReduce = e.currentTarget.value as ChartReducer)}>
296
+ {#each reducers as r (r.value)}<option value={r.value}>{r.label}</option>{/each}
297
+ </select>
298
+ </label>
299
+ {/if}
300
+ {#if wantsBins}
301
+ <label class="sv-grid-chart-ctl" title={m.chartBinsTitle}>
302
+ <span class="sv-grid-chart-ctl-lbl">{m.chartBins}</span>
303
+ <input class="sv-grid-chart-num" type="number" min="1" max="200" value={ctrl.chartBins ?? ""} placeholder={m.chartBuilderAuto} onchange={(e) => (ctrl.chartBins = e.currentTarget.value ? Number(e.currentTarget.value) : null)} />
304
+ </label>
305
+ {/if}
306
+ {#if wantsFunnelShape}
307
+ <label class="sv-grid-chart-ctl">
308
+ <span class="sv-grid-chart-ctl-lbl">{m.chartShape}</span>
309
+ <select value={ctrl.chartFunnelShape ?? "trapezoid"} onchange={(e) => (ctrl.chartFunnelShape = e.currentTarget.value as "trapezoid" | "pyramid" | "cone")}>
310
+ <option value="trapezoid">{m.chartShapeFunnel}</option>
311
+ <option value="pyramid">{m.chartShapePyramid}</option>
312
+ <option value="cone">{m.chartShapeCone}</option>
313
+ </select>
314
+ </label>
315
+ {/if}
316
+ {#if wantsCandleStyle}
317
+ <label class="sv-grid-chart-ctl">
318
+ <span class="sv-grid-chart-ctl-lbl">{m.chartCandles}</span>
319
+ <select value={ctrl.chartCandleStyle ?? "classic"} onchange={(e) => (ctrl.chartCandleStyle = e.currentTarget.value as "classic" | "hollow" | "heikin-ashi")}>
320
+ <option value="classic">{m.chartCandlesClassic}</option>
321
+ <option value="hollow">{m.chartCandlesHollow}</option>
322
+ <option value="heikin-ashi">{m.chartCandlesHeikinAshi}</option>
323
+ </select>
324
+ </label>
325
+ {/if}
326
+ {#if wantsOhlc}
327
+ <span class="sv-grid-chart-ctl sv-grid-chart-indicators" role="group" aria-label={m.chartIndicators}>
328
+ <span class="sv-grid-chart-ctl-lbl">{m.chartIndicators}</span>
329
+ <span class="sv-grid-chart-chips">
330
+ {#each INDICATORS as ind (ind.value)}
331
+ <button
332
+ type="button"
333
+ class="sv-grid-chart-chip"
334
+ class:is-on={ctrl.chartIndicators.includes(ind.value)}
335
+ aria-pressed={ctrl.chartIndicators.includes(ind.value)}
336
+ title={m[ind.title]}
337
+ onclick={() => toggleIndicator(ind.value)}
338
+ >{m[ind.label]}</button>
339
+ {/each}
340
+ </span>
341
+ </span>
342
+ {/if}
343
+ <label class="sv-grid-chart-ctl">
344
+ <span class="sv-grid-chart-ctl-lbl">{m.chartFormat}</span>
345
+ <select value={ctrl.chartValueFormat} onchange={(e) => (ctrl.chartValueFormat = e.currentTarget.value as "number" | "currency" | "percent")}>
346
+ <option value="number">{m.chartFormatNumber}</option>
347
+ <option value="currency">{m.chartFormatCurrency}</option>
348
+ <option value="percent">{m.chartFormatPercent}</option>
349
+ </select>
350
+ </label>
351
+ {#if wantsStacked}
352
+ <label class="sv-grid-chart-toggle">
353
+ <input type="checkbox" checked={ctrl.chartStacked} onchange={(e) => (ctrl.chartStacked = e.currentTarget.checked)} />
354
+ {m.chartStacked}
355
+ </label>
356
+ <label class="sv-grid-chart-toggle" title={m.chartStacked100Title}>
357
+ <input type="checkbox" checked={ctrl.chartStacked100} onchange={(e) => (ctrl.chartStacked100 = e.currentTarget.checked)} />
358
+ {m.chartStacked100}
359
+ </label>
360
+ {/if}
361
+ {#if wantsHorizontal}
362
+ <label class="sv-grid-chart-toggle" title={m.chartHorizontalTitle}>
363
+ <input
364
+ type="checkbox"
365
+ checked={ctrl.chartOrientation === "horizontal"}
366
+ onchange={(e) => (ctrl.chartOrientation = e.currentTarget.checked ? "horizontal" : "vertical")}
367
+ />
368
+ {m.chartHorizontal}
369
+ </label>
370
+ {/if}
371
+ {#if wantsDonut}
372
+ <label class="sv-grid-chart-toggle">
373
+ <input type="checkbox" checked={ctrl.chartDonut} onchange={(e) => (ctrl.chartDonut = e.currentTarget.checked)} />
374
+ {m.chartDonut}
375
+ </label>
376
+ {/if}
377
+ <label class="sv-grid-chart-ctl">
378
+ <span class="sv-grid-chart-ctl-lbl">{m.chartColours}</span>
379
+ <select
380
+ value={activePalette}
381
+ onchange={(e) => (ctrl.chartPalette = CHART_PANEL_PALETTES.find((x) => x.key === e.currentTarget.value)?.colors ?? null)}
382
+ >
383
+ {#each CHART_PANEL_PALETTES as pal (pal.key)}<option value={pal.key}>{m[pal.label]}</option>{/each}
384
+ </select>
385
+ </label>
386
+ {#if wantsDataLabels}
387
+ <label class="sv-grid-chart-toggle">
388
+ <input type="checkbox" checked={ctrl.chartDataLabels} onchange={(e) => (ctrl.chartDataLabels = e.currentTarget.checked)} />
389
+ {m.chartLabels}
390
+ </label>
391
+ {/if}
392
+ {#if wantsLogScale}
393
+ <label class="sv-grid-chart-toggle" title={m.chartLogScaleTitle}>
394
+ <input type="checkbox" checked={ctrl.chartLogScale} onchange={(e) => (ctrl.chartLogScale = e.currentTarget.checked)} />
395
+ {m.chartLogScale}
396
+ </label>
397
+ {/if}
398
+ {#if ctrl.chartDimensionIsDate && wantsGroupBy}
399
+ <label class="sv-grid-chart-ctl" title={m.chartBucketTitle}>
400
+ <span class="sv-grid-chart-ctl-lbl">{m.chartBucket}</span>
401
+ <select value={ctrl.chartBucket ?? ""} onchange={(e) => (ctrl.chartBucket = (e.currentTarget.value || null) as ChartTimeBucket | null)}>
402
+ {#each BUCKETS as b (b.value)}<option value={b.value}>{m[b.label]}</option>{/each}
403
+ </select>
404
+ </label>
405
+ {/if}
406
+ {#if ctrl.chartDimensionIsDate && CARTESIAN.includes(ctrl.chartType)}
407
+ <label class="sv-grid-chart-toggle" title={m.chartDateAxisTitle}>
408
+ <input type="checkbox" checked={ctrl.chartTimeAxis} onchange={(e) => (ctrl.chartTimeAxis = e.currentTarget.checked)} />
409
+ {m.chartDateAxis}
410
+ </label>
411
+ {/if}
412
+ {#if pivot}
413
+ <p class="sv-grid-chart-hint sv-grid-chart-pivot-hint" role="note">{m.chartPivotHint}</p>
414
+ {:else if typeIssue}
415
+ <p class="sv-grid-chart-hint" role="note">{typeIssue}</p>
416
+ {/if}
417
+ </div>
@@ -0,0 +1,70 @@
1
+ /**
2
+ * The chart panel's pickers: type, the columns a chart reads, the
3
+ * aggregate, and the per-type switches (stacked, horizontal, donut, log
4
+ * scale, labels, bucket, date axis, bins, funnel shape, candle style,
5
+ * indicator chips), plus the sentence that says why the chosen type cannot
6
+ * draw yet. One component rendered twice: as a row under the panel head,
7
+ * and as a form on the builder's Data tab, so the two never disagree about
8
+ * what a type needs.
9
+ *
10
+ * Every label comes from `GridChartPanelMessages`, so the panel and the
11
+ * builder localize together through `localization.text`.
12
+ */
13
+ import type { ChartReducer, ChartType } from "./chart-types.js";
14
+ import type { GridChartPanelMessages } from "./chart-panel-messages.js";
15
+ /** What the type picker knows about a chart type. */
16
+ export type ChartPanelTypeDef = {
17
+ value: ChartType;
18
+ label: string;
19
+ group: string;
20
+ };
21
+ type Shape = {
22
+ dims: unknown[];
23
+ measures: unknown[];
24
+ dates: unknown[];
25
+ };
26
+ /** The types the panel offers for these columns, labelled in the given language. */
27
+ export declare function chartPanelTypes(columns: Shape, m: GridChartPanelMessages): ChartPanelTypeDef[];
28
+ /** The reducers the Aggregate picker offers, in its order. */
29
+ export declare function chartPanelReducers(m: GridChartPanelMessages): Array<{
30
+ value: ChartReducer;
31
+ label: string;
32
+ }>;
33
+ /** Named series palettes. "Theme" defers to --sg-chart-1..8 and the defaults. */
34
+ export declare const CHART_PANEL_PALETTES: Array<{
35
+ key: string;
36
+ label: keyof GridChartPanelMessages;
37
+ colors: string[] | null;
38
+ }>;
39
+ import type { RowData, TableFeatures } from "./index.js";
40
+ import type { SvGridController } from "./SvGrid.controller.svelte.js";
41
+ declare function $$render<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(): {
42
+ props: {
43
+ ctrl: SvGridController<TFeatures, TData>;
44
+ messages: GridChartPanelMessages;
45
+ /** `panel`: the row under the panel head, Type first. `builder`: the
46
+ * Data tab's form, without Type (the gallery picks it). */
47
+ scope?: "panel" | "builder";
48
+ };
49
+ exports: {};
50
+ bindings: "";
51
+ slots: {};
52
+ events: {};
53
+ };
54
+ declare class __sveltets_Render<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData> {
55
+ props(): ReturnType<typeof $$render<TFeatures, TData>>['props'];
56
+ events(): ReturnType<typeof $$render<TFeatures, TData>>['events'];
57
+ slots(): ReturnType<typeof $$render<TFeatures, TData>>['slots'];
58
+ bindings(): "";
59
+ exports(): {};
60
+ }
61
+ interface $$IsomorphicComponent {
62
+ new <TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TFeatures, TData>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TFeatures, TData>['props']>, ReturnType<__sveltets_Render<TFeatures, TData>['events']>, ReturnType<__sveltets_Render<TFeatures, TData>['slots']>> & {
63
+ $$bindings?: ReturnType<__sveltets_Render<TFeatures, TData>['bindings']>;
64
+ } & ReturnType<__sveltets_Render<TFeatures, TData>['exports']>;
65
+ <TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(internal: unknown, props: ReturnType<__sveltets_Render<TFeatures, TData>['props']> & {}): ReturnType<__sveltets_Render<TFeatures, TData>['exports']>;
66
+ z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
67
+ }
68
+ declare const SvGridChartPickers: $$IsomorphicComponent;
69
+ type SvGridChartPickers<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData> = InstanceType<typeof SvGridChartPickers<TFeatures, TData>>;
70
+ export default SvGridChartPickers;
@@ -31,10 +31,9 @@
31
31
  localization?: { locale?: string | ReadonlyArray<string> };
32
32
  } = $props();
33
33
 
34
- // Container size -> chart viewBox, so the chart fills the grid area and
35
- // re-lays out on resize (the same responsive behaviour a table view has).
36
- let w = $state(0);
37
- let h = $state(0);
34
+ // The chart fills the grid area and re-lays out on resize (the same
35
+ // responsive behaviour a table view has) through its own `autosize`, which
36
+ // also keeps its legend inside the box instead of below it.
38
37
 
39
38
  const spec = $derived.by<ChartSpec>(() => {
40
39
  const s = rowsToChartSpec((data ?? []) as ReadonlyArray<Record<string, unknown>>, {
@@ -57,20 +56,20 @@
57
56
  });
58
57
  </script>
59
58
 
60
- <div class="sv-grid-chart-view" bind:clientWidth={w} bind:clientHeight={h}>
61
- {#if w > 0 && h > 0}
62
- <SvGridChart
63
- {spec}
64
- width={w}
65
- height={h}
66
- legend={chart.legend ?? true}
67
- dataLabels={chart.dataLabels ?? false}
68
- />
69
- {/if}
59
+ <div class="sv-grid-chart-view">
60
+ <SvGridChart
61
+ {spec}
62
+ autosize
63
+ legend={chart.legend ?? true}
64
+ dataLabels={chart.dataLabels ?? false}
65
+ />
70
66
  </div>
71
67
 
72
68
  <style>
69
+ /* A grid, so the autosized chart is stretched to the full height rather
70
+ than asking for a percentage of it (which cannot be measured reliably). */
73
71
  .sv-grid-chart-view {
72
+ display: grid;
74
73
  width: 100%;
75
74
  height: 100%;
76
75
  min-height: 0;
@@ -22,6 +22,11 @@
22
22
  onClose?: () => void
23
23
  title?: string
24
24
  size?: 'sm' | 'md' | 'lg'
25
+ /**
26
+ * Panel width in px, when the three presets miss the content's natural
27
+ * width. Wins over `size`; the user's own resize wins over both.
28
+ */
29
+ width?: number
25
30
  draggable?: boolean
26
31
  resizable?: boolean
27
32
  closeOnBackdrop?: boolean
@@ -37,6 +42,7 @@
37
42
  onClose,
38
43
  title,
39
44
  size = 'md',
45
+ width,
40
46
  draggable = false,
41
47
  resizable = false,
42
48
  closeOnBackdrop = true,
@@ -118,7 +124,7 @@
118
124
  class:is-resized={!!box}
119
125
  {...overlay.dialogProps({ labelledBy: title ? titleId : undefined })}
120
126
  style:transform={`translate(calc(-50% + ${drag.x}px), calc(-50% + ${drag.y}px))`}
121
- style:width={box ? `${box.w}px` : undefined}
127
+ style:width={box ? `${box.w}px` : width ? `${width}px` : undefined}
122
128
  style:height={box ? `${box.h}px` : undefined}
123
129
  >
124
130
  {#if title || !hideClose}
@@ -17,6 +17,11 @@ type Props = {
17
17
  onClose?: () => void;
18
18
  title?: string;
19
19
  size?: 'sm' | 'md' | 'lg';
20
+ /**
21
+ * Panel width in px, when the three presets miss the content's natural
22
+ * width. Wins over `size`; the user's own resize wins over both.
23
+ */
24
+ width?: number;
20
25
  draggable?: boolean;
21
26
  resizable?: boolean;
22
27
  closeOnBackdrop?: boolean;