@svgrid/grid 3.0.3 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/README.md +5 -4
  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 +122 -41
  8. package/dist/SvGrid.controller.svelte.js +845 -207
  9. package/dist/SvGrid.css +178 -2
  10. package/dist/SvGrid.svelte +467 -516
  11. package/dist/SvGrid.types.d.ts +315 -12
  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 +119 -28
  29. package/dist/cdn/GridMenus-CLI93jke.js +635 -0
  30. package/dist/cdn/{GridMenus-DhdPF700.js → GridMenus-CwooL3QA.js} +240 -207
  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/server-block-cache-CGoWz-87.js +237 -0
  67. package/dist/cdn/{src-D6XvA1Ij.js → src-B6HXdfHY.js} +10448 -10049
  68. package/dist/cdn/{src-Bugf5XlI.js → src-C6Iowdvs.js} +6908 -6509
  69. package/dist/cdn/svgrid.js +27 -15
  70. package/dist/cdn/svgrid.svelte-external.js +27 -15
  71. package/dist/cdn/validate-CchXzyrX.js +76 -0
  72. package/dist/chart-axes.d.ts +53 -0
  73. package/dist/chart-axes.js +351 -0
  74. package/dist/chart-cartesian.d.ts +88 -0
  75. package/dist/chart-cartesian.js +1862 -0
  76. package/dist/chart-decimate.d.ts +51 -0
  77. package/dist/chart-decimate.js +199 -0
  78. package/dist/chart-export-pdf.d.ts +47 -0
  79. package/dist/chart-export-pdf.js +187 -0
  80. package/dist/chart-export.d.ts +2 -1
  81. package/dist/chart-export.js +18 -3
  82. package/dist/chart-financial.d.ts +91 -0
  83. package/dist/chart-financial.js +175 -0
  84. package/dist/chart-flow.d.ts +10 -0
  85. package/dist/chart-flow.js +298 -0
  86. package/dist/chart-format.d.ts +18 -0
  87. package/dist/chart-format.js +65 -0
  88. package/dist/chart-grid.d.ts +8 -0
  89. package/dist/chart-grid.js +190 -0
  90. package/dist/chart-hierarchy.d.ts +17 -0
  91. package/dist/chart-hierarchy.js +146 -0
  92. package/dist/chart-indicators.d.ts +115 -0
  93. package/dist/chart-indicators.js +389 -0
  94. package/dist/chart-messages.d.ts +95 -0
  95. package/dist/chart-messages.js +92 -0
  96. package/dist/chart-motion.d.ts +16 -0
  97. package/dist/chart-motion.js +141 -0
  98. package/dist/chart-panel-messages.d.ts +265 -0
  99. package/dist/chart-panel-messages.js +285 -0
  100. package/dist/chart-pivot.d.ts +87 -0
  101. package/dist/chart-pivot.js +156 -0
  102. package/dist/chart-polar.d.ts +25 -0
  103. package/dist/chart-polar.js +700 -0
  104. package/dist/chart-samples.d.ts +16 -0
  105. package/dist/chart-samples.js +153 -0
  106. package/dist/chart-scale.d.ts +113 -0
  107. package/dist/chart-scale.js +405 -0
  108. package/dist/chart-stats.d.ts +111 -0
  109. package/dist/chart-stats.js +419 -0
  110. package/dist/chart-stream.d.ts +45 -0
  111. package/dist/chart-stream.js +91 -0
  112. package/dist/chart-summary.d.ts +27 -0
  113. package/dist/chart-summary.js +205 -0
  114. package/dist/chart-sync.svelte.d.ts +32 -0
  115. package/dist/chart-sync.svelte.js +23 -0
  116. package/dist/chart-table.d.ts +35 -0
  117. package/dist/chart-table.js +165 -0
  118. package/dist/chart-trend.d.ts +19 -0
  119. package/dist/chart-trend.js +61 -0
  120. package/dist/chart-types.d.ts +1456 -0
  121. package/dist/chart-types.js +6 -0
  122. package/dist/chart-validate.d.ts +43 -0
  123. package/dist/chart-validate.js +272 -0
  124. package/dist/chart-zoom.d.ts +40 -0
  125. package/dist/chart-zoom.js +145 -0
  126. package/dist/chart.d.ts +186 -865
  127. package/dist/chart.js +460 -2204
  128. package/dist/clipboard.d.ts +1 -0
  129. package/dist/clipboard.js +137 -18
  130. package/dist/column-resize.d.ts +3 -0
  131. package/dist/column-resize.js +4 -1
  132. package/dist/columns.js +3 -0
  133. package/dist/command-context.d.ts +19 -0
  134. package/dist/command-context.js +116 -0
  135. package/dist/core.d.ts +7 -0
  136. package/dist/core.js +36 -13
  137. package/dist/createPopoverSelect.svelte.d.ts +2 -2
  138. package/dist/editing.d.ts +2 -8
  139. package/dist/editing.js +272 -33
  140. package/dist/fill-patterns.d.ts +0 -5
  141. package/dist/fill-patterns.js +56 -2
  142. package/dist/grid-icons.d.ts +2 -2
  143. package/dist/grid-icons.js +2 -2
  144. package/dist/grid-messages.d.ts +12 -3
  145. package/dist/grid-messages.js +7 -0
  146. package/dist/history.d.ts +83 -0
  147. package/dist/history.js +133 -0
  148. package/dist/index.d.ts +27 -10
  149. package/dist/index.js +22 -5
  150. package/dist/keyboard-handlers.js +88 -31
  151. package/dist/keyboard.d.ts +55 -0
  152. package/dist/keyboard.js +132 -0
  153. package/dist/menus.d.ts +3 -1
  154. package/dist/menus.js +7 -2
  155. package/dist/merges.d.ts +97 -0
  156. package/dist/merges.js +147 -0
  157. package/dist/row-model.d.ts +133 -0
  158. package/dist/row-model.js +16 -0
  159. package/dist/row-resize.d.ts +3 -0
  160. package/dist/row-resize.js +14 -0
  161. package/dist/scroll-sync.d.ts +1 -0
  162. package/dist/scroll-sync.js +24 -0
  163. package/dist/selection.d.ts +18 -1
  164. package/dist/selection.js +138 -18
  165. package/dist/server-block-cache.d.ts +214 -0
  166. package/dist/server-block-cache.js +531 -0
  167. package/dist/server-data-source.d.ts +240 -6
  168. package/dist/server-data-source.js +220 -20
  169. package/dist/server.d.ts +13 -0
  170. package/dist/server.js +13 -0
  171. package/dist/shortcut-registry.d.ts +145 -0
  172. package/dist/shortcut-registry.js +44 -0
  173. package/dist/svgrid-wrapper.types.d.ts +213 -22
  174. package/dist/validate.d.ts +2 -0
  175. package/dist/validate.js +8 -3
  176. package/dist/virtualization/virtualizer.js +38 -17
  177. package/package.json +11 -1
  178. package/src/GridMenus.svelte +44 -2
  179. package/src/SvChartMenu.svelte +69 -0
  180. package/src/SvChartPanes.svelte +113 -0
  181. package/src/SvChartPanes.test.ts +66 -0
  182. package/src/SvGrid.controller.svelte.ts +818 -179
  183. package/src/SvGrid.css +178 -2
  184. package/src/SvGrid.svelte +467 -516
  185. package/src/SvGrid.types.ts +293 -11
  186. package/src/SvGridCellEditor.svelte +17 -0
  187. package/src/SvGridChart.svelte +2257 -329
  188. package/src/SvGridChart.test.ts +1419 -1
  189. package/src/SvGridChart.types.ts +336 -0
  190. package/src/SvGridChartBuilder.svelte +323 -0
  191. package/src/SvGridChartPanel.svelte +221 -275
  192. package/src/SvGridChartPickers.svelte +417 -0
  193. package/src/SvGridChartView.svelte +13 -14
  194. package/src/SvModal.svelte +7 -1
  195. package/src/SvModal.test.ts +9 -0
  196. package/src/ai.test.ts +57 -2
  197. package/src/ai.ts +166 -22
  198. package/src/aria.d.ts +11 -0
  199. package/src/build-api.coverage.test.ts +184 -0
  200. package/src/build-api.ts +118 -22
  201. package/src/chart-axes.test.ts +573 -0
  202. package/src/chart-axes.ts +342 -0
  203. package/src/chart-cartesian.ts +1863 -0
  204. package/src/chart-decimate.test.ts +249 -0
  205. package/src/chart-decimate.ts +186 -0
  206. package/src/chart-export-pdf.test.ts +91 -0
  207. package/src/chart-export-pdf.ts +207 -0
  208. package/src/chart-export.test.ts +14 -0
  209. package/src/chart-export.ts +13 -3
  210. package/src/chart-financial.ts +208 -0
  211. package/src/chart-flow.ts +286 -0
  212. package/src/chart-format.ts +67 -0
  213. package/src/chart-grid.ts +179 -0
  214. package/src/chart-hierarchy.ts +135 -0
  215. package/src/chart-indicators.test.ts +443 -0
  216. package/src/chart-indicators.ts +384 -0
  217. package/src/chart-messages.test.ts +21 -0
  218. package/src/chart-messages.ts +184 -0
  219. package/src/chart-motion.test.ts +71 -0
  220. package/src/chart-motion.ts +148 -0
  221. package/src/chart-panel-messages.test.ts +29 -0
  222. package/src/chart-panel-messages.ts +550 -0
  223. package/src/chart-pivot.test.ts +54 -0
  224. package/src/chart-pivot.ts +225 -0
  225. package/src/chart-polar.ts +674 -0
  226. package/src/chart-samples.ts +106 -0
  227. package/src/chart-scale.ts +394 -0
  228. package/src/chart-series-types.test.ts +714 -0
  229. package/src/chart-stats.ts +409 -0
  230. package/src/chart-stream.test.ts +75 -0
  231. package/src/chart-stream.ts +114 -0
  232. package/src/chart-summary.test.ts +90 -0
  233. package/src/chart-summary.ts +197 -0
  234. package/src/chart-sync.svelte.ts +41 -0
  235. package/src/chart-table.test.ts +76 -0
  236. package/src/chart-table.ts +178 -0
  237. package/src/chart-trend.ts +47 -0
  238. package/src/chart-types.ts +1309 -0
  239. package/src/chart-validate.test.ts +100 -0
  240. package/src/chart-validate.ts +247 -0
  241. package/src/chart-zoom.test.ts +137 -0
  242. package/src/chart-zoom.ts +124 -0
  243. package/src/chart.coverage.test.ts +81 -0
  244. package/src/chart.test.ts +56 -3
  245. package/src/chart.ts +557 -2784
  246. package/src/clipboard.test.ts +151 -0
  247. package/src/clipboard.ts +145 -16
  248. package/src/column-resize.ts +7 -1
  249. package/src/columns.ts +2 -0
  250. package/src/command-context.test.ts +200 -0
  251. package/src/command-context.ts +137 -0
  252. package/src/core.rowmodel-cache.test.ts +51 -0
  253. package/src/core.ts +40 -12
  254. package/src/editing.test.ts +281 -3
  255. package/src/editing.ts +264 -38
  256. package/src/fill-patterns.test.ts +35 -0
  257. package/src/fill-patterns.ts +56 -2
  258. package/src/grid-icons.ts +2 -2
  259. package/src/grid-messages.ts +21 -3
  260. package/src/history.test.ts +196 -0
  261. package/src/history.ts +162 -0
  262. package/src/icon-seam.test.ts +5 -6
  263. package/src/index.ts +169 -12
  264. package/src/keyboard-handlers.coverage.test.ts +126 -6
  265. package/src/keyboard-handlers.ts +91 -30
  266. package/src/keyboard-shortcuts.seam.test.ts +200 -0
  267. package/src/keyboard.test.ts +124 -1
  268. package/src/keyboard.ts +142 -0
  269. package/src/menus.test.ts +26 -0
  270. package/src/menus.ts +10 -3
  271. package/src/merges.test.ts +112 -0
  272. package/src/merges.ts +168 -0
  273. package/src/pivot.grid.test.ts +40 -5
  274. package/src/row-model.ts +146 -0
  275. package/src/row-resize.test.ts +44 -0
  276. package/src/row-resize.ts +17 -0
  277. package/src/scroll-sync.test.ts +42 -1
  278. package/src/scroll-sync.ts +25 -0
  279. package/src/selection.multi-range.test.ts +34 -0
  280. package/src/selection.test.ts +33 -2
  281. package/src/selection.ts +143 -21
  282. package/src/server-block-cache.test.ts +645 -0
  283. package/src/server-block-cache.ts +677 -0
  284. package/src/server-data-source.infinite.test.ts +343 -0
  285. package/src/server-data-source.ts +450 -27
  286. package/src/server.ts +47 -0
  287. package/src/shortcut-registry.test.ts +97 -0
  288. package/src/shortcut-registry.ts +181 -0
  289. package/src/svgrid-wrapper.types.ts +184 -13
  290. package/src/svgrid.behavior.test.ts +135 -0
  291. package/src/svgrid.charting.test.ts +513 -3
  292. package/src/svgrid.context-menu.test.ts +31 -0
  293. package/src/svgrid.new-features.wrapper.test.ts +10 -3
  294. package/src/svgrid.row-model-prop.svelte.test.ts +352 -0
  295. package/src/svgrid.row-model-seam.svelte.test.ts +289 -0
  296. package/src/validate.test.ts +10 -0
  297. package/src/validate.ts +10 -3
  298. package/src/virtualization/virtualizer.ts +39 -17
  299. package/dist/SvGroupCell.svelte +0 -141
  300. package/dist/SvGroupCell.svelte.d.ts +0 -49
  301. package/dist/SvRowGroupPanel.svelte +0 -186
  302. package/dist/SvRowGroupPanel.svelte.d.ts +0 -25
  303. package/dist/cdn/GridMenus-CHOMnW-c.js +0 -602
  304. package/dist/cdn/SvDateTimePicker-CCbDZNZB.js +0 -816
  305. package/dist/cdn/SvGridChart-1PMSp2LZ.js +0 -1481
  306. package/dist/cdn/SvGridChart-D02avhyr.js +0 -1480
  307. package/dist/cdn/SvGridChartPanel-DJnViOv4.js +0 -834
  308. package/dist/cdn/SvGridChartPanel-vPTNerFZ.js +0 -810
  309. package/dist/cdn/SvGridChartView-C--HhdUo.js +0 -56
  310. package/dist/cdn/SvGridChartView-KyyFG-wY.js +0 -55
  311. package/dist/cdn/chart-DLg3_zTQ.js +0 -1652
  312. package/dist/cdn/validate-_CDJzgIo.js +0 -75
  313. package/dist/server-group-model.d.ts +0 -98
  314. package/dist/server-group-model.js +0 -263
  315. package/src/SvGroupCell.svelte +0 -141
  316. package/src/SvRowGroupPanel.svelte +0 -186
  317. package/src/server-group-model.test.ts +0 -294
  318. package/src/server-group-model.ts +0 -370
@@ -1,75 +0,0 @@
1
- //#region src/validate.ts
2
- var e = "https://svgrid.com/docs/getting-started/3-data-and-columns/";
3
- function t(e, n = []) {
4
- for (let r of e) r.columns?.length ? t(r.columns, n) : n.push(r);
5
- return n;
6
- }
7
- function n(n) {
8
- let i = [], a = t(n.columns ?? []), o = (n.data ?? []).slice(0, 10);
9
- if (o.length) {
10
- let t = /* @__PURE__ */ new Set();
11
- for (let e of o) if (e && typeof e == "object") for (let n of Object.keys(e)) t.add(n);
12
- for (let n of a) {
13
- let a = n.field;
14
- if (!a || n.fieldFn || t.has(a)) continue;
15
- let o = r(a, [...t]);
16
- i.push(`[svgrid] Column field "${a}" does not exist on your row data, so that column renders empty.${o ? ` Did you mean "${o}"?` : ""} Available keys: ${[...t].slice(0, 12).join(", ")}. See ${e}`);
17
- }
18
- }
19
- let s = /* @__PURE__ */ new Map();
20
- for (let e of a) {
21
- let t = e.id ?? e.field;
22
- t && s.set(t, (s.get(t) ?? 0) + 1);
23
- }
24
- for (let [t, n] of s) n > 1 && i.push(`[svgrid] ${n} columns share the id "${t}". Column state (sorting, filtering, pinning, width) is keyed by id, so they will act as one. Give each an explicit \`id\`. See ${e}`);
25
- let c = n.pageable === void 0 && n.showPagination === void 0;
26
- n.pageSize !== void 0 && c && i.push("[svgrid] `pageSize` is set but pagination was never turned on, so it has no effect and every row renders. Add `pageable` to switch the pager on."), !(n.sortable === !0 || n.features?.rowSortingFeature) && a.some((e) => e.sortable === !0) && i.push("[svgrid] A column sets `sortable: true`, but sorting is not enabled on the grid, so its header does nothing. Add `sortable` to <SvGrid> (it registers the sorting feature for you).");
27
- let l = /* @__PURE__ */ new Set();
28
- for (let e of a) {
29
- let t = e.id ?? e.field;
30
- t && l.add(t);
31
- }
32
- for (let e of n.groupBy ?? []) {
33
- if (l.has(e)) continue;
34
- let t = r(e, [...l]);
35
- i.push(`[svgrid] \`groupBy\` refers to column "${e}", which does not exist, so that grouping level is ignored.${t ? ` Did you mean "${t}"?` : ""} Column ids: ${[...l].slice(0, 12).join(", ")}`);
36
- }
37
- let u = n.treeData?.column;
38
- if (u && !l.has(u) && i.push(`[svgrid] \`treeData.column\` refers to column "${u}", which does not exist, so the expander falls back to the first visible column.`), o.length && n.treeData) {
39
- let e = /* @__PURE__ */ new Set();
40
- for (let t of o) if (t && typeof t == "object") for (let n of Object.keys(t)) e.add(n);
41
- let t = n.treeData.parentField;
42
- if (t && !e.has(t)) {
43
- let n = r(t, [...e]);
44
- i.push(`[svgrid] \`treeData.parentField\` is "${t}", which is not on your row data, so every row becomes a root and no hierarchy appears.${n ? ` Did you mean "${n}"?` : ""}`);
45
- }
46
- let a = n.treeData.idField;
47
- a && !e.has(a) && i.push(`[svgrid] \`treeData.idField\` is "${a}", which is not on your row data, so parent lookups cannot match and the tree stays flat.`);
48
- }
49
- return (n.initialColumnPinning?.left?.length ?? 0) + (n.initialColumnPinning?.right?.length ?? 0) > 0 && n.columnVirtualization !== !1 && i.push("[svgrid] `initialColumnPinning` is set while column virtualization is on (its default), so the pinned columns will not stick - the virtualizer recycles column nodes. Add `columnVirtualization={false}`."), n.externalPagination === !0 && n.rowCount === void 0 && i.push("[svgrid] `externalPagination` is on but `rowCount` is not set, so the pager cannot know how many pages exist. Pass the server total as `rowCount`."), n.externalSort === !0 && !n.onSortingChange && i.push("[svgrid] `externalSort` is on but there is no `onSortingChange` handler, so clicking a header changes nothing - the grid stopped sorting and nobody is listening. Add `onSortingChange` and re-fetch in your handler."), n.externalFilter === !0 && !n.onFiltersChange && i.push("[svgrid] `externalFilter` is on but there is no `onFiltersChange` handler, so filtering the grid changes nothing. Add `onFiltersChange` and re-fetch in your handler."), i;
50
- }
51
- function r(e, t) {
52
- let n, r = Infinity;
53
- for (let a of t) {
54
- let t = i(e.toLowerCase(), a.toLowerCase());
55
- t < r && (r = t, n = a);
56
- }
57
- let a = Math.min(3, Math.floor(e.length / 3) + 1);
58
- return r <= a ? n : void 0;
59
- }
60
- function i(e, t) {
61
- if (e === t) return 0;
62
- let n = Array(t.length + 1);
63
- for (let e = 0; e <= t.length; e++) n[e] = e;
64
- for (let r = 1; r <= e.length; r++) {
65
- let i = n[0];
66
- n[0] = r;
67
- for (let a = 1; a <= t.length; a++) {
68
- let o = Math.min(n[a] + 1, n[a - 1] + 1, i + (e[r - 1] === t[a - 1] ? 0 : 1));
69
- i = n[a], n[a] = o;
70
- }
71
- }
72
- return n[t.length];
73
- }
74
- //#endregion
75
- export { n as validateGridConfig };
@@ -1,98 +0,0 @@
1
- /**
2
- * Server-side GROUP row model (SSRM grouping) - the first-class
3
- * companion to `createServerDataSource`. Grouping, aggregation, and lazy
4
- * expansion all flow through the SAME `ServerDataSource.getRows` contract:
5
- *
6
- * - The request carries `groupBy` (the columns grouped on) and `groupKeys`
7
- * (the path of the group being expanded). While `groupKeys.length <
8
- * groupBy.length` the server returns GROUP rows (one per distinct key at
9
- * that level, carrying the key + aggregate values); at the bottom level it
10
- * returns the leaf rows under that path.
11
- * - Expanding a group is just another `getRows` with `groupKeys` set to that
12
- * group's path. This controller owns the group tree: expand / collapse,
13
- * per-node lazy fetch + cache, race-safety, and flattening to a display
14
- * list the grid renders (group rows with an expander, leaves underneath).
15
- *
16
- * Headless and framework-agnostic on purpose: render from `state.displayRows`
17
- * and call `toggleGroup` from the group cell's expander.
18
- */
19
- import type { ServerAggregation, ServerDataSource, ServerDisplayRow, ServerFilterModel, ServerGroupRow, ServerSortModel } from './server-data-source.js';
20
- export type ServerGroupState<TData> = {
21
- /** The flattened tree: top-level groups, with expanded groups' children spliced in. */
22
- displayRows: ServerDisplayRow<TData>[];
23
- groupBy: string[];
24
- /** True during the initial top-level fetch (before the root has ever loaded). */
25
- loading: boolean;
26
- /** The rejection from the last failed top-level fetch, else null. */
27
- error: unknown;
28
- sortModel: ServerSortModel;
29
- filterModel: ServerFilterModel;
30
- /** Ids (JSON of the path) of the currently expanded groups. */
31
- expandedGroups: string[];
32
- };
33
- export type ServerGroupControllerOptions<TData> = {
34
- /** Columns to group on, outer to inner. Empty in `treeData` mode. */
35
- groupBy?: string[];
36
- /** Value columns to roll up per group. */
37
- aggregations?: ServerAggregation[];
38
- /** Max children fetched per group in one request. Default 200. */
39
- pageSize?: number;
40
- /**
41
- * Self-referential tree mode: instead of grouping flat rows by columns, each
42
- * row is a node whose children are fetched on expand. Requires `getRowId`
43
- * (the node id, which builds the `groupKeys` path) and `hasChildren` (whether
44
- * a node is expandable). `getRows` receives `groupKeys` = the path to the
45
- * node being expanded, and returns that node's direct children.
46
- */
47
- treeData?: boolean;
48
- /** Node id, used to build the `groupKeys` path. Required in `treeData` mode. */
49
- getRowId?: (row: TData) => string;
50
- /** Whether a node can be expanded. Required in `treeData` mode. */
51
- hasChildren?: (row: TData) => boolean;
52
- /** Emit a subtotal "footer" row after each expanded group's children. */
53
- groupFooters?: boolean;
54
- /** Placeholder rows shown while a group's first block is loading. Default 3. */
55
- skeletonRows?: number;
56
- onChange: (state: ServerGroupState<TData>) => void;
57
- };
58
- export type ServerGroupController<TData> = {
59
- /** (Re-)fetch the tree from the top. Call once to load the first level. */
60
- refresh(): void;
61
- setSort(sortModel: ServerSortModel): void;
62
- setFilter(filterModel: ServerFilterModel): void;
63
- /** Change the grouping columns. Collapses everything and reloads the top level. */
64
- setGroupBy(groupBy: string[]): void;
65
- /** Expand or collapse a group row (from its expander). */
66
- toggleGroup(row: ServerGroupRow<TData>): void;
67
- expandGroup(path: string[]): void;
68
- collapseGroup(path: string[]): void;
69
- /** Fetch the next block of a group's children (intra-group paging). */
70
- loadMoreChildren(path: string[]): void;
71
- isExpanded(path: string[]): boolean;
72
- getState(): ServerGroupState<TData>;
73
- /** Stop accepting in-flight responses. Call on unmount. */
74
- dispose(): void;
75
- };
76
- /**
77
- * Map a `ServerGroupState.displayRows` to grid rows: each row's data spread at
78
- * the top level (so normal `field` columns show group subtotals on group rows
79
- * and cell values on leaves) plus a `__group` marker the built-in `SvGroupCell`
80
- * reads to draw the expander + indentation. Feed the result to `<SvGrid data>`.
81
- */
82
- export type ServerGroupGridRow<TData> = TData & {
83
- __group: ServerDisplayRow<TData>;
84
- };
85
- export declare function serverGroupRows<TData>(state: ServerGroupState<TData> | undefined | null): ServerGroupGridRow<TData>[];
86
- /**
87
- * Build the `serverGroup` prop for `<SvGrid>` from a controller, so the grid's
88
- * built-in tree keyboard (ArrowRight / ArrowLeft expand / collapse) and treegrid
89
- * a11y work with no app-level key handling. Reads the `__group` marker that
90
- * `serverGroupRows` attaches. Usage: `<SvGrid ... serverGroup={serverGroupNav(ctl)} />`.
91
- */
92
- export declare function serverGroupNav<TData>(ctl: ServerGroupController<TData>): {
93
- isGroup: (row: ServerGroupGridRow<TData>) => boolean;
94
- level: (row: ServerGroupGridRow<TData>) => number;
95
- expanded: (row: ServerGroupGridRow<TData>) => boolean;
96
- onToggle: (row: ServerGroupGridRow<TData>) => void;
97
- };
98
- export declare function createServerGroupModel<TData>(source: ServerDataSource<TData>, options: ServerGroupControllerOptions<TData>): ServerGroupController<TData>;
@@ -1,263 +0,0 @@
1
- export function serverGroupRows(state) {
2
- return (state?.displayRows ?? []).map((r) => ({ ...('data' in r ? r.data : {}), __group: r }));
3
- }
4
- /**
5
- * Build the `serverGroup` prop for `<SvGrid>` from a controller, so the grid's
6
- * built-in tree keyboard (ArrowRight / ArrowLeft expand / collapse) and treegrid
7
- * a11y work with no app-level key handling. Reads the `__group` marker that
8
- * `serverGroupRows` attaches. Usage: `<SvGrid ... serverGroup={serverGroupNav(ctl)} />`.
9
- */
10
- export function serverGroupNav(ctl) {
11
- return {
12
- isGroup: (row) => row.__group?.kind === 'group',
13
- level: (row) => row.__group?.level ?? 0,
14
- expanded: (row) => row.__group?.kind === 'group' ? row.__group.expanded : false,
15
- onToggle: (row) => {
16
- if (row.__group?.kind === 'group')
17
- ctl.toggleGroup(row.__group);
18
- else if (row.__group?.kind === 'more')
19
- ctl.loadMoreChildren(row.__group.path);
20
- },
21
- };
22
- }
23
- const keyOf = (path) => JSON.stringify(path);
24
- export function createServerGroupModel(source, options) {
25
- let groupBy = [...(options.groupBy ?? [])];
26
- const aggregations = options.aggregations ?? [];
27
- const pageSize = options.pageSize ?? 200;
28
- const treeData = !!options.treeData;
29
- if (treeData && (!options.getRowId || !options.hasChildren)) {
30
- throw new Error('createServerGroupModel: treeData requires getRowId and hasChildren');
31
- }
32
- const getRowId = options.getRowId;
33
- const hasChildren = options.hasChildren;
34
- const groupFooters = !!options.groupFooters;
35
- const skeletonRows = Math.max(0, options.skeletonRows ?? 3);
36
- let sortModel = [];
37
- let filterModel = {};
38
- const nodes = new Map();
39
- const expanded = new Set(); // path keys
40
- // Generation guard: bumped on any tree reset so every fetch in flight for the
41
- // previous shape is discarded when it lands (the classic stale-response bug).
42
- let generation = 0;
43
- let disposed = false;
44
- const rootKey = keyOf([]);
45
- function ensureNode(key) {
46
- let node = nodes.get(key);
47
- if (!node) {
48
- node = { loaded: false, loading: false, error: null, count: 0, children: [] };
49
- nodes.set(key, node);
50
- }
51
- return node;
52
- }
53
- // Walk the loaded tree from the root, splicing expanded groups' children in.
54
- function flatten() {
55
- const out = [];
56
- const walk = (path) => {
57
- const node = nodes.get(keyOf(path));
58
- if (!node?.loaded)
59
- return;
60
- for (const child of node.children) {
61
- if (child.kind === 'leaf') {
62
- out.push({ kind: 'leaf', id: child.id, level: child.level, data: child.data });
63
- continue;
64
- }
65
- const cid = keyOf(child.path);
66
- const cnode = nodes.get(cid);
67
- const isExp = expanded.has(cid);
68
- out.push({
69
- kind: 'group',
70
- id: cid,
71
- path: child.path,
72
- field: child.field,
73
- key: child.key,
74
- level: child.level,
75
- expanded: isExp,
76
- loading: !!cnode?.loading,
77
- aggregates: child.aggregates,
78
- data: child.data,
79
- });
80
- if (isExp) {
81
- if (cnode?.loaded) {
82
- walk(child.path);
83
- // Subtotal row after the group's children.
84
- if (groupFooters) {
85
- out.push({
86
- kind: 'footer',
87
- id: cid + 'footer',
88
- level: child.level + 1,
89
- path: child.path,
90
- key: child.key,
91
- aggregates: child.aggregates,
92
- data: child.data,
93
- });
94
- }
95
- }
96
- else if (cnode?.loading) {
97
- // First block in flight: placeholder skeleton rows.
98
- for (let i = 0; i < skeletonRows; i += 1) {
99
- out.push({ kind: 'skeleton', id: cid + 'sk' + i, level: child.level + 1 });
100
- }
101
- }
102
- }
103
- }
104
- // Intra-group paging: emit a "load more" affordance when only part of this
105
- // node's children have been fetched.
106
- if (node.children.length < node.count) {
107
- out.push({
108
- kind: 'more',
109
- id: keyOf([...path, 'more']),
110
- level: path.length,
111
- path,
112
- remaining: node.count - node.children.length,
113
- loading: node.loading,
114
- });
115
- }
116
- };
117
- walk([]);
118
- return out;
119
- }
120
- function emit() {
121
- if (disposed)
122
- return;
123
- const root = nodes.get(rootKey);
124
- options.onChange({
125
- displayRows: flatten(),
126
- groupBy: [...groupBy],
127
- loading: !!root?.loading && !root?.loaded,
128
- error: root?.error ?? null,
129
- sortModel,
130
- filterModel,
131
- expandedGroups: [...expanded],
132
- });
133
- }
134
- // append=false loads the first block of a node's children (on expand);
135
- // append=true fetches the NEXT block and concatenates (intra-group paging).
136
- async function fetchNode(path, append = false) {
137
- if (disposed)
138
- return;
139
- const gen = generation;
140
- const key = keyOf(path);
141
- const node = ensureNode(key);
142
- if (node.loading)
143
- return; // a fetch for this node is already in flight
144
- node.loading = true;
145
- node.error = null;
146
- emit();
147
- const level = path.length;
148
- const groupField = groupBy[level];
149
- const startRow = append ? node.children.length : 0;
150
- try {
151
- const res = await source.getRows({
152
- startRow,
153
- endRow: startRow + pageSize,
154
- pageIndex: Math.floor(startRow / pageSize),
155
- pageSize,
156
- sortModel,
157
- filterModel,
158
- groupBy,
159
- groupKeys: path,
160
- aggregations,
161
- });
162
- if (disposed || gen !== generation)
163
- return; // stale: the tree was reset
164
- node.count = res.rowCount;
165
- const block = res.rows.map((data, i) => {
166
- // A row is an expandable "group" when: (tree mode) the source says it has
167
- // children, or (grouping mode) we are above the innermost groupBy level.
168
- const isGroup = treeData ? hasChildren(data) : level < groupBy.length;
169
- if (isGroup) {
170
- const gk = treeData
171
- ? getRowId(data)
172
- : ((v) => (v == null ? '' : String(v)))(data[groupField]);
173
- const aggregates = {};
174
- for (const a of aggregations)
175
- aggregates[a.col] = data[a.col];
176
- return { kind: 'group', path: [...path, gk], field: treeData ? '' : groupField, key: gk, level, aggregates, data };
177
- }
178
- const id = treeData && getRowId ? `${key}:${getRowId(data)}` : `${key}:${startRow + i}`;
179
- return { kind: 'leaf', id, level, data };
180
- });
181
- node.children = append ? [...node.children, ...block] : block;
182
- node.loaded = true;
183
- node.loading = false;
184
- emit();
185
- }
186
- catch (err) {
187
- if (disposed || gen !== generation)
188
- return;
189
- node.error = err;
190
- if (!append)
191
- node.loaded = false;
192
- node.loading = false;
193
- emit();
194
- }
195
- }
196
- // Clear the cache and reload the root plus any still-expanded paths (in
197
- // parallel; flatten only descends into loaded nodes, so children appear as
198
- // each level lands).
199
- function resetTree() {
200
- generation += 1;
201
- nodes.clear();
202
- void fetchNode([]);
203
- for (const k of expanded)
204
- void fetchNode(JSON.parse(k));
205
- }
206
- function expandGroup(path) {
207
- const key = keyOf(path);
208
- if (expanded.has(key))
209
- return;
210
- expanded.add(key);
211
- const node = nodes.get(key);
212
- if (!node?.loaded && !node?.loading)
213
- void fetchNode(path);
214
- else
215
- emit();
216
- }
217
- function collapseGroup(path) {
218
- if (expanded.delete(keyOf(path)))
219
- emit();
220
- }
221
- return {
222
- refresh: resetTree,
223
- setSort(next) {
224
- sortModel = next;
225
- resetTree();
226
- },
227
- setFilter(next) {
228
- filterModel = next;
229
- resetTree();
230
- },
231
- setGroupBy(next) {
232
- groupBy = [...next];
233
- expanded.clear();
234
- resetTree();
235
- },
236
- toggleGroup(row) {
237
- if (expanded.has(row.id))
238
- collapseGroup(row.path);
239
- else
240
- expandGroup(row.path);
241
- },
242
- expandGroup,
243
- collapseGroup,
244
- loadMoreChildren: (path) => void fetchNode(path, true),
245
- isExpanded: (path) => expanded.has(keyOf(path)),
246
- getState() {
247
- const root = nodes.get(rootKey);
248
- return {
249
- displayRows: flatten(),
250
- groupBy: [...groupBy],
251
- loading: !!root?.loading && !root?.loaded,
252
- error: root?.error ?? null,
253
- sortModel,
254
- filterModel,
255
- expandedGroups: [...expanded],
256
- };
257
- },
258
- dispose() {
259
- disposed = true;
260
- generation += 1;
261
- },
262
- };
263
- }
@@ -1,141 +0,0 @@
1
- <!--
2
- Built-in group cell for the server-side group/tree model. Drop it into the
3
- grouping column and it draws the expander + indentation for group rows (and an
4
- indented leaf value) - no hand-written cell recipe. Pair with `serverGroupRows`
5
- to feed `<SvGrid data>`, and wire `onToggle` to the controller's `toggleGroup`.
6
-
7
- cell: (ctx) => renderComponent(SvGroupCell, {
8
- row: ctx.row.original, onToggle: ctl.toggleGroup, leafField: 'name',
9
- })
10
- -->
11
- <script lang="ts" generics="TData">
12
- import type { ServerDisplayRow } from './server-data-source'
13
- import type { GridIcons } from './grid-icons'
14
-
15
- type GroupGridRow = { __group?: ServerDisplayRow<TData> } & Record<string, unknown>
16
- type Props = {
17
- /** The grid row from `serverGroupRows` (carries the `__group` marker). */
18
- row: GroupGridRow
19
- /**
20
- * Expand / collapse a group, or load more children. Receives the grid row;
21
- * wire to `serverGroupNav(ctl).onToggle` (which drives clicks and keyboard).
22
- */
23
- onToggle: (row: GroupGridRow) => void
24
- /** Field to show for leaf rows in the group column (blank if omitted). */
25
- leafField?: string
26
- /** Pixels of indentation per level. Default 18. */
27
- indent?: number
28
- /**
29
- * Icon overrides, the same map `<SvGrid icons>` takes. Only
30
- * `chevron-right` is drawn here. You mount this component yourself, so it
31
- * cannot inherit the grid's icons - pass the same object to both to keep
32
- * the expander consistent with the rest of the chrome.
33
- */
34
- icons?: GridIcons
35
- }
36
-
37
- let { row, onToggle, leafField, indent = 18, icons }: Props = $props()
38
- const chevron = $derived(icons?.['chevron-right'])
39
- const meta = $derived(row.__group)
40
- </script>
41
-
42
- {#if meta && meta.kind === 'group'}
43
- <button
44
- type="button"
45
- class="sv-group-cell"
46
- style={`padding-inline-start: ${meta.level * indent}px`}
47
- aria-expanded={meta.expanded}
48
- aria-label={meta.expanded ? 'Collapse group' : 'Expand group'}
49
- onclick={() => onToggle(row)}
50
- >
51
- <!-- Same chevron the grid's own expanders and SvTree draw, so every
52
- expander in the library looks identical. -->
53
- <span class="sv-group-chev" class:open={meta.expanded} aria-hidden="true">
54
- {#if chevron}
55
- {@render chevron()}
56
- {:else}
57
- <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor"
58
- stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6" /></svg>
59
- {/if}
60
- </span>
61
- <span class="sv-group-key">{meta.key}</span>
62
- {#if meta.loading}<span class="sv-group-load" aria-hidden="true">…</span>{/if}
63
- </button>
64
- {:else if meta && meta.kind === 'more'}
65
- <button
66
- type="button"
67
- class="sv-group-more"
68
- style={`padding-inline-start: ${meta.level * indent}px`}
69
- disabled={meta.loading}
70
- onclick={() => onToggle(row)}
71
- >
72
- {meta.loading ? 'Loading...' : `Load ${meta.remaining} more`}
73
- </button>
74
- {:else if meta && meta.kind === 'footer'}
75
- <span class="sv-group-footer" style={`padding-inline-start: ${meta.level * indent}px`}>Total</span>
76
- {:else if meta && meta.kind === 'skeleton'}
77
- <span class="sv-group-skeleton" style={`margin-inline-start: ${meta.level * indent}px`} aria-hidden="true"></span>
78
- {:else if meta}
79
- <span class="sv-group-leaf" style={`padding-inline-start: ${(meta.level + 1) * indent}px`}>
80
- {leafField ? (row[leafField] ?? '') : ''}
81
- </span>
82
- {/if}
83
-
84
- <style>
85
- .sv-group-cell {
86
- display: inline-flex;
87
- align-items: center;
88
- gap: 6px;
89
- background: none;
90
- border: 0;
91
- padding: 0;
92
- font: inherit;
93
- color: inherit;
94
- cursor: pointer;
95
- }
96
- .sv-group-chev {
97
- display: inline-flex;
98
- align-items: center;
99
- justify-content: center;
100
- width: 12px;
101
- height: 12px;
102
- transition: transform 0.15s;
103
- color: var(--sg-muted, #64748b);
104
- }
105
- /* An `icons` override renders inside this wrapper, and this style block is
106
- scoped, so its markup needs :global() to be reached. Sizing it here means
107
- a custom chevron lands in the same box as the built-in and rotates with
108
- the wrapper rather than needing to know the rule exists. */
109
- .sv-group-chev :global(svg),
110
- .sv-group-chev :global(img) {
111
- width: 100%;
112
- height: 100%;
113
- display: block;
114
- }
115
- .sv-group-chev.open { transform: rotate(90deg); }
116
- .sv-group-key { font-weight: 600; }
117
- .sv-group-load { color: var(--sg-muted, #64748b); font-size: 12px; }
118
- .sv-group-leaf { color: var(--sg-muted, #475569); }
119
- .sv-group-more {
120
- background: none;
121
- border: 0;
122
- padding: 0;
123
- font: inherit;
124
- font-size: 13px;
125
- color: var(--sg-accent, #2563eb);
126
- cursor: pointer;
127
- }
128
- .sv-group-more:disabled { color: var(--sg-muted, #64748b); cursor: default; }
129
- .sv-group-footer { font-weight: 600; color: var(--sg-muted, #64748b); font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; }
130
- .sv-group-skeleton {
131
- display: inline-block;
132
- width: 60%;
133
- height: 10px;
134
- border-radius: 5px;
135
- background: linear-gradient(90deg, var(--sg-border, #e2e8f0) 25%, var(--sg-header-bg, #f1f5f9) 50%, var(--sg-border, #e2e8f0) 75%);
136
- background-size: 200% 100%;
137
- animation: sv-group-shimmer 1.2s infinite;
138
- }
139
- @keyframes sv-group-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
140
- @media (prefers-reduced-motion: reduce) { .sv-group-skeleton { animation: none; } }
141
- </style>