@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
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Undo / redo over the grid's history array, group-aware.
3
+ *
4
+ * The history is one ordered array of per-cell steps plus a pointer to the
5
+ * last applied step (the model lives in SvGrid.controller.svelte.ts). A step
6
+ * describes ONE cell, which is right for a single edit and wrong for anything
7
+ * that writes many cells at once: `applyMoveRange` in clipboard.ts pushes one
8
+ * step per moved cell, so undoing a 15x20 range move takes 300 presses of
9
+ * Ctrl+Z, and with UNDO_LIMIT at 200 the same move evicts the entire history
10
+ * behind it.
11
+ *
12
+ * `groupId` fixes that without changing the storage model. Steps written
13
+ * inside one logical action share an id; undo and redo walk the whole run of
14
+ * steps carrying that id and apply them together, so a paste, a fill-down or
15
+ * a range move is one press, the way it is in a spreadsheet. Steps with no
16
+ * groupId behave exactly as before, one step per press.
17
+ *
18
+ * Undo applies a group in REVERSE order. Two steps that touched the same cell
19
+ * inside one action have to be unwound newest-first or the older `before`
20
+ * value is overwritten by the newer one and the cell lands on the wrong value.
21
+ */
22
+ export type HistoryStep = {
23
+ rowId: string;
24
+ columnId: string;
25
+ field: string;
26
+ before: unknown;
27
+ after: unknown;
28
+ /** Set when this step is part of a multi-cell action. Steps sharing an id
29
+ * are contiguous in the array and undo / redo as one. */
30
+ groupId?: string;
31
+ /**
32
+ * A step that is not a cell write: something outside the grid's data that
33
+ * still belongs in the same Ctrl+Z stream, such as a cell format kept in a
34
+ * consumer's store. The cell fields are empty on such a step and the two
35
+ * functions do the work. Never serialised, since a closure cannot be.
36
+ */
37
+ custom?: {
38
+ undo: () => void;
39
+ redo: () => void;
40
+ };
41
+ };
42
+ /** Ctx surface these helpers touch. The controller satisfies it structurally. */
43
+ type HistoryCtx = {
44
+ history: HistoryStep[];
45
+ historyPtr: number;
46
+ historyVersion: number;
47
+ UNDO_LIMIT: number;
48
+ /** Set while a `runHistoryGroup` call is on the stack. Every step pushed
49
+ * inside it joins that group, so a command does not have to thread a group
50
+ * id down through the writers it calls. */
51
+ historyGroupId: string | undefined;
52
+ applyHistoryStep(step: HistoryStep, direction: 'undo' | 'redo'): void;
53
+ };
54
+ /** Undo one action. Returns false when there is nothing left to undo. */
55
+ export declare function undoHistory(ctx: HistoryCtx): boolean;
56
+ /** Redo one action. Returns false when there is nothing left to redo. */
57
+ export declare function redoHistory(ctx: HistoryCtx): boolean;
58
+ /**
59
+ * Append steps at the pointer, truncating any forward history (the standard
60
+ * "an edit invalidates redo" rule) and capping the buffer at UNDO_LIMIT by
61
+ * dropping the OLDEST entries.
62
+ *
63
+ * Every writer goes through here rather than open-coding the slice / push /
64
+ * cap dance, which editing.ts and clipboard.ts previously did three times
65
+ * with three slightly different shapes.
66
+ */
67
+ export declare function pushHistory(ctx: HistoryCtx, steps: ReadonlyArray<HistoryStep>, groupId?: string): void;
68
+ /** A fresh group id. Monotonic, not random: ids never leave the session and a
69
+ * counter is comparable in a test snapshot. */
70
+ export declare function nextGroupId(): string;
71
+ /**
72
+ * Run `fn` with every history step it writes tagged as one undoable action.
73
+ *
74
+ * This is ambient rather than a wrapper that re-tags afterwards, because
75
+ * `pushHistory` can drop the oldest entries when the buffer hits UNDO_LIMIT.
76
+ * A re-tagging implementation would compute its slice bounds from a length
77
+ * that had shifted underneath it and stamp the wrong steps.
78
+ *
79
+ * Nested calls join the outer group: one user action is one undo, however many
80
+ * layers of helper it goes through.
81
+ */
82
+ export declare function runHistoryGroup<T>(ctx: HistoryCtx, fn: () => T): T;
83
+ export {};
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Undo / redo over the grid's history array, group-aware.
3
+ *
4
+ * The history is one ordered array of per-cell steps plus a pointer to the
5
+ * last applied step (the model lives in SvGrid.controller.svelte.ts). A step
6
+ * describes ONE cell, which is right for a single edit and wrong for anything
7
+ * that writes many cells at once: `applyMoveRange` in clipboard.ts pushes one
8
+ * step per moved cell, so undoing a 15x20 range move takes 300 presses of
9
+ * Ctrl+Z, and with UNDO_LIMIT at 200 the same move evicts the entire history
10
+ * behind it.
11
+ *
12
+ * `groupId` fixes that without changing the storage model. Steps written
13
+ * inside one logical action share an id; undo and redo walk the whole run of
14
+ * steps carrying that id and apply them together, so a paste, a fill-down or
15
+ * a range move is one press, the way it is in a spreadsheet. Steps with no
16
+ * groupId behave exactly as before, one step per press.
17
+ *
18
+ * Undo applies a group in REVERSE order. Two steps that touched the same cell
19
+ * inside one action have to be unwound newest-first or the older `before`
20
+ * value is overwritten by the newer one and the cell lands on the wrong value.
21
+ */
22
+ /** Index of the first step in the group that ends at `end`, or `end` itself
23
+ * when that step is ungrouped. */
24
+ function groupStart(history, end) {
25
+ const id = history[end]?.groupId;
26
+ if (!id)
27
+ return end;
28
+ let i = end;
29
+ while (i > 0 && history[i - 1]?.groupId === id)
30
+ i -= 1;
31
+ return i;
32
+ }
33
+ /** Index of the last step in the group that begins at `start`, or `start`
34
+ * itself when that step is ungrouped. */
35
+ function groupEnd(history, start) {
36
+ const id = history[start]?.groupId;
37
+ if (!id)
38
+ return start;
39
+ let i = start;
40
+ while (i < history.length - 1 && history[i + 1]?.groupId === id)
41
+ i += 1;
42
+ return i;
43
+ }
44
+ /** Undo one action. Returns false when there is nothing left to undo. */
45
+ export function undoHistory(ctx) {
46
+ if (ctx.historyPtr < 0)
47
+ return false;
48
+ const end = ctx.historyPtr;
49
+ if (!ctx.history[end])
50
+ return false;
51
+ const start = groupStart(ctx.history, end);
52
+ // Reverse order: see the note at the top of the file.
53
+ for (let i = end; i >= start; i -= 1) {
54
+ const step = ctx.history[i];
55
+ if (step)
56
+ ctx.applyHistoryStep(step, 'undo');
57
+ }
58
+ ctx.historyPtr = start - 1;
59
+ ctx.historyVersion += 1;
60
+ return true;
61
+ }
62
+ /** Redo one action. Returns false when there is nothing left to redo. */
63
+ export function redoHistory(ctx) {
64
+ if (ctx.historyPtr >= ctx.history.length - 1)
65
+ return false;
66
+ const start = ctx.historyPtr + 1;
67
+ if (!ctx.history[start])
68
+ return false;
69
+ const end = groupEnd(ctx.history, start);
70
+ for (let i = start; i <= end; i += 1) {
71
+ const step = ctx.history[i];
72
+ if (step)
73
+ ctx.applyHistoryStep(step, 'redo');
74
+ }
75
+ ctx.historyPtr = end;
76
+ ctx.historyVersion += 1;
77
+ return true;
78
+ }
79
+ /**
80
+ * Append steps at the pointer, truncating any forward history (the standard
81
+ * "an edit invalidates redo" rule) and capping the buffer at UNDO_LIMIT by
82
+ * dropping the OLDEST entries.
83
+ *
84
+ * Every writer goes through here rather than open-coding the slice / push /
85
+ * cap dance, which editing.ts and clipboard.ts previously did three times
86
+ * with three slightly different shapes.
87
+ */
88
+ export function pushHistory(ctx, steps, groupId) {
89
+ if (!steps.length)
90
+ return;
91
+ // An ambient group wins: inside runHistoryGroup even a single step has to be
92
+ // tagged, because a later push in the same action must join it.
93
+ //
94
+ // Outside one, a group of one is just a step. Tagging it would make undo do
95
+ // the same work through a slower path and would show up in serialized state.
96
+ const id = ctx.historyGroupId ?? (groupId && steps.length > 1 ? groupId : undefined);
97
+ let next = ctx.history.slice(0, ctx.historyPtr + 1);
98
+ for (const step of steps)
99
+ next.push(id ? { ...step, groupId: id } : step);
100
+ if (next.length > ctx.UNDO_LIMIT)
101
+ next = next.slice(next.length - ctx.UNDO_LIMIT);
102
+ ctx.history = next;
103
+ ctx.historyPtr = ctx.history.length - 1;
104
+ ctx.historyVersion += 1;
105
+ }
106
+ let groupCounter = 0;
107
+ /** A fresh group id. Monotonic, not random: ids never leave the session and a
108
+ * counter is comparable in a test snapshot. */
109
+ export function nextGroupId() {
110
+ groupCounter += 1;
111
+ return `g${groupCounter}`;
112
+ }
113
+ /**
114
+ * Run `fn` with every history step it writes tagged as one undoable action.
115
+ *
116
+ * This is ambient rather than a wrapper that re-tags afterwards, because
117
+ * `pushHistory` can drop the oldest entries when the buffer hits UNDO_LIMIT.
118
+ * A re-tagging implementation would compute its slice bounds from a length
119
+ * that had shifted underneath it and stamp the wrong steps.
120
+ *
121
+ * Nested calls join the outer group: one user action is one undo, however many
122
+ * layers of helper it goes through.
123
+ */
124
+ export function runHistoryGroup(ctx, fn) {
125
+ const outer = ctx.historyGroupId;
126
+ ctx.historyGroupId = outer ?? nextGroupId();
127
+ try {
128
+ return fn();
129
+ }
130
+ finally {
131
+ ctx.historyGroupId = outer;
132
+ }
133
+ }
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export { subscribeGrid, subscribeSvGrid } from './subscribe.js';
7
7
  export { default as SvGrid } from './SvGrid.svelte';
8
8
  export type { BoardConfig, BoardLane, BoardCardMoveEvent, BoardCardCommitEvent, BoardLayout, BoardSubtask, BoardComment, BoardMenuContext, BoardLaneMenuContext, BoardDrawerConfig } from './SvGrid.types.js';
9
9
  export { registerBoardView, getBoardView, hasBoardView } from './board-view.svelte.js';
10
- export type { SelectionBarAction, SelectionBarTarget, ContextMenuItem, ContextMenuTarget, } from './SvGrid.types.js';
10
+ export type { SelectionBarAction, SelectionBarTarget, ContextMenuIcon, ContextMenuItem, ContextMenuTarget, } from './SvGrid.types.js';
11
11
  export * from './ai.js';
12
12
  export { registerExportProvider, getExportProvider, type GridExportProvider, type GridExportRunOptions, } from './export-provider.js';
13
13
  export type { SchedulerConfig, SchedulerDrawerConfig, SchedulerEventMoveEvent, SchedulerEventResizeEvent, SchedulerEventCommitEvent, SchedulerRangeSelection, SchedulerView, SchedulerResource, SchedulerCollisionMode, SchedulerException, SchedulerEditScope, SchedulerOccurrenceChangeEvent, } from './SvGrid.types.js';
@@ -190,11 +190,18 @@ export { renderComponent, renderSnippet } from './render-component.js';
190
190
  export { default as SvGridChart } from './SvGridChart.svelte';
191
191
  export { default as SvGridChartPanel } from './SvGridChartPanel.svelte';
192
192
  export { default as SvChart } from './SvGridChart.svelte';
193
+ export type { SvChartProps, ChartRenderContext, ChartTooltipContext, ChartTooltipRow, ChartLegendItemContext, ChartLegendPosition, ChartZoomConfig, ChartAnimateConfig, ChartContextTarget, ChartHoverPoint, } from './SvGridChart.types.js';
194
+ export { wheelWindow, panWindow, pinchWindow, presetWindow, nearestIndexByTime, type ChartRangePreset, } from './chart-zoom.js';
195
+ export { interpolateGeometry } from './chart-motion.js';
196
+ export { drillTree, pathTo } from './chart-hierarchy.js';
197
+ export { syncGroupState, publishSyncHover, publishSyncZoom, type ChartSyncState } from './chart-sync.svelte.js';
193
198
  export { default as SvChartPanel } from './SvGridChartPanel.svelte';
194
- export type { ChartingConfig, ChartAggregateRequest, ChartAggregateBucket } from './SvGrid.types.js';
199
+ export { default as SvChartPanes } from './SvChartPanes.svelte';
200
+ export type { ChartingConfig, ChartAggregateRequest, ChartAggregateBucket, ChartPanelInfo } from './SvGrid.types.js';
195
201
  export type { GridLocalization } from './SvGrid.types.js';
196
- export { buildChart, formatChartValue, rowsToChartSpec, rowsToBoxSpec, rowsToDirectSpec, boxStats, sliceChartWindow, chartScales, ordinalDateTicks, niceScale, niceLogScale, linearTrend, simpleMovingAverage, exponentialMovingAverage, computeOverlay, buildLinePath, sampleGradient, pickContrastText, DEFAULT_PALETTE, type ChartType, type ChartSpec, type ChartSeries, type ChartGeometry, type ChartScales, type ChartBar, type ChartCandle, type ChartBox, type ChartErrorBar, type BoxStats, type OhlcBar, type ChartLine, type ChartLinePoint, type ChartPieSlice, type ChartSelection, type ChartReferenceLine, type ChartRefLineGeo, type ChartRefLineGeoV, type ChartScatterDot, type ScatterPoint, type NiceScale, type SeriesOverlay, type SeriesPattern, type ChartAnnotation, type ChartHeatmapCell, type ChartFunnelSegment, type ChartRadarSeries, type ChartRadarAxis, type ChartTreemapCell, type ChartCalendarCell, type ChartGaugeLayout, type ChartSankeyNode, type ChartSankeyLink, type ChartValueFormat, type TreeNode, } from './chart.js';
202
+ export { buildChart, formatChartValue, rowsToChartSpec, rowsToBoxSpec, rowsToDirectSpec, rowsToScatterSpec, rowsToGaugeSpec, rowsToHistogramSpec, rowsToRangeSpec, paretoSpec, specToTreemap, specToCalendar, specToSankey, binValues, heikinAshi, resampleOhlc, rowsToOhlcSpec, guessOhlcColumns, splitPanelIndicators, applyChartFormat, CHART_RESPONSIVE_PRESETS, type ChartFormatState, type OhlcColumns, type ChartPanelIndicator, bollingerBands, rsi, macd, vwap, atr, stochastic, wma, obv, indicatorPane, type ChartIndicatorSpec, arcPath, streamBaseline, boxStats, sliceChartWindow, matchResponsiveRules, resolveResponsive, chartStyleVars, chartScales, ordinalDateTicks, niceScale, niceLogScale, linearTrend, linearFit, polynomialFit, exponentialFit, logarithmicFit, powerFit, rSquared, pearson, type RegressionFit, simpleMovingAverage, exponentialMovingAverage, computeOverlay, computeOverlayFit, regressionFit, overlayName, buildLinePath, layoutDataLabels, markerPath, decimateSpec, pickCategories, lttb, minMaxIndices, reduceValues, percentile, bucketStart, PER_CATEGORY_SERIES_KEYS, sampleGradient, pickContrastText, DEFAULT_PALETTE, type ChartType, type ChartSpec, type ChartSeries, type ChartGeometry, type ChartScales, type ChartBar, type ChartCandle, type ChartBox, type ChartErrorBar, type BoxStats, type OhlcBar, type ChartLine, type ChartLinePoint, type ChartPieSlice, type ChartResponsiveRule, type ChartStyle, type ChartSeriesLabel, type ChartSelection, type ChartReferenceLine, type ChartRefLineGeo, type ChartRefLineGeoV, type ChartScatterDot, type ScatterPoint, type NiceScale, type SeriesOverlay, type SeriesPattern, type ChartAnnotation, type ChartHeatmapCell, type ChartFunnelSegment, type ChartRadarSeries, type ChartRadarAxis, type ChartTreemapCell, type ChartCalendarCell, type ChartGaugeLayout, type ChartSankeyNode, type ChartSankeyLink, type ChartValueFormat, type TreeNode, type ChartAxisConfig, type ChartReferenceBand, type ChartRefBandGeo, type ChartMarker, type ChartMarkerShape, type ChartDataLabelConfig, type ChartDataLabel, type ChartDecimateConfig, type ChartReducer, type ChartTimeBucket, type ChartFrame, type ChartLineStyle, type ChartBins, type ChartStem, type ChartArc, type ChartChordRibbon, type ChartBullet, type ChartZoomWindow, type ChartPointRef, type ChartDrawing, type ChartDrawingKind, type ChartDrawingGeo, } from './chart.js';
197
203
  export { chartToSvgString, downloadChartSvg, chartToPngBlob, downloadChartPng, chartCsvExportable, chartSpecToCsv, downloadChartCsv, type ChartExportOptions, } from './chart-export.js';
204
+ export { chartToPdfBlob, downloadChartPdf, printChart, buildChartPdf, type ChartPdfOptions } from './chart-export-pdf.js';
198
205
  export { buildSparkline, toSparklineValues, type SparklineConfig, type SparklineType, type SparklineGeometry, } from './sparkline.js';
199
206
  export { spreadsheetLayout, spansToMerges, type SpanColumn, type SpreadsheetActionOptions, type MergeSpec, type CellBorderSpec, type BorderSpec, } from './spreadsheet.js';
200
207
  export { rowResize, type RowResizeOptions } from './row-resize.js';
@@ -204,21 +211,31 @@ export { resolveColumnTypes, inferCellDataType, type CellDataType } from './colu
204
211
  export { computeColumnGroupMeta, hiddenLeavesForCollapse, type ColumnGroupMeta, type ColumnGroupShow, } from './column-groups.js';
205
212
  export { createHyperFormulaSheet, type HyperFormulaSheet, type HyperFormulaSheetConfig, type HyperFormulaInstance, } from './hyperformula-adapter.js';
206
213
  export { createCollaboration, broadcastChannelTransport, type CollabUser, type CollabCell, type CollabPresence, type CollabMessage, type CollabTransport, type Collaboration, } from './collaboration.js';
207
- export { createServerDataSource, type ServerDataSource, type ServerRequest, type ServerResult, type ServerController, type ServerState, type ServerSortModel, type ServerFilterModel, type ServerAggregation, type ServerGroupRow, type ServerLeafRow, type ServerMoreRow, type ServerFooterRow, type ServerSkeletonRow, type ServerDisplayRow, } from './server-data-source.js';
208
- export { createServerGroupModel, serverGroupRows, serverGroupNav, type ServerGroupController, type ServerGroupControllerOptions, type ServerGroupState, type ServerGroupGridRow, } from './server-group-model.js';
209
- export { default as SvGroupCell } from './SvGroupCell.svelte';
210
- export { default as SvRowGroupPanel } from './SvRowGroupPanel.svelte';
214
+ export { createServerDataSource, type ServerDataSource, type ServerSelectionRule, type ServerRequest, type ServerResult, type ServerController, type ServerControllerOptions, type ServerState, type ServerSortModel, type ServerFilterModel, type ServerAggregation, type ServerGroupRow, type ServerLeafRow, type ServerMoreRow, type ServerFooterRow, type ServerSkeletonRow, type ServerGrandTotalRow, type ServerPlaceholderRow, type ServerDisplayRow, } from './server-data-source.js';
215
+ export { createBlockCache, createRowPlaceholder, rowPlaceholderState, type BlockCache, type BlockCacheOptions, type BlockCacheState, type BlockFetchResult, type BlockState, } from './server-block-cache.js';
216
+ export { toServerFilterColumns, type GridRowModel, type GridFilterState, type GridRowModelSort, } from './row-model.js';
211
217
  export { createNamedViews, memoryViews, localStorageViews, attachAutoSavedView, type SavedView, type ViewStorage, type NamedViews, type AutoSavedViewOptions, } from './named-views.js';
212
218
  export { resolveCellFormat, computeColumnStat, lerpColor, rgba, contrastText, formatNeedsStats, formatsNeedingStats, type ConditionalFormat, type ConditionalFormatSpec, type ColorScaleFormat, type ColorScaleStop, type ScaleBounds, type DataBarFormat, type IconSetFormat, type RuleFormat, type ResolvedCellFormat, } from './conditional-formatting.js';
213
- export { defaultGridMessages, resolveGridMessages, type GridMessages, } from './grid-messages.js';
219
+ export { defaultGridMessages, resolveGridMessages, type GridMessages, type GridChromeMessages, } from './grid-messages.js';
220
+ export { defaultChartMessages, resolveChartMessages, chartMessage, type ChartMessages, } from './chart-messages.js';
221
+ export { defaultChartPanelMessages, resolveChartPanelMessages, chartPanelMessage, type GridChartPanelMessages, } from './chart-panel-messages.js';
222
+ export { validateChartSpec, warnChartSpec, nearestKey as nearestChartKey, CHART_TYPES, KNOWN_SPEC_KEYS, KNOWN_SERIES_KEYS, type ChartDiagnostic, } from './chart-validate.js';
223
+ export { chartSummary, type ChartSummaryOptions } from './chart-summary.js';
224
+ export { appendPoints, type ChartPoint, type AppendPointsOptions } from './chart-stream.js';
225
+ export { pivotResultToChartSpec, pivotChartType, pivotFilterColumn, type PivotResultChartOptions, type PivotResultLike } from './chart-pivot.js';
226
+ export { chartSpecToTable, type ChartTable, type ChartTableColumn } from './chart-table.js';
214
227
  export { GRID_ICON_GLYPHS, GRID_ICON_NAMES, type GridIconName, type GridIcons, } from './grid-icons.js';
215
228
  export { insertGroupFooters, buildAutoGroupColumns, paginateGroupedRows, type GroupDisplayType, type GroupFooterOptions, type AutoGroupColumnSpec, type AutoGroupResult, type GroupPaginationOptions, type GroupPaginationResult, } from './group-display.js';
216
- export { getKeyboardIntent, getNextActiveCell, type GridKeyboardIntent } from './keyboard.js';
229
+ export { getKeyboardIntent, getNextActiveCell, getEntryStep, pastCollapsed, type GridKeyboardIntent, type EntryIntent, type EntryRect, type EntryStep, type Collapsed } from './keyboard.js';
230
+ export { buildMergeIndex, mergeAt, isCovered, originOf, endOf, expandRectToMerges, stepPastMerge, mergeDrawAt, type MergedCell, type MergeIndex, type MergeRect, type MergeDraw } from './merges.js';
231
+ export { buildFillPattern } from './fill-patterns.js';
232
+ export { registerGridShortcuts, hasGridShortcuts, clearGridShortcuts, type GridShortcutHandler, type GridCommandContext, } from './shortcut-registry.js';
233
+ export type { HistoryStep } from './history.js';
217
234
  export { createVirtualizer } from './virtualization/virtualizer.js';
218
235
  export { createSvelteVirtualizer } from './virtualization/svelte-virtualizer.svelte.js';
219
236
  export { createColumnVirtualizer } from './virtualization/column-virtualizer.js';
220
237
  export type { VirtualItem, VirtualizerOptions, VirtualizerState } from './virtualization/types.js';
221
- export type { SvGridApi, SvGridFilterOperator, SvGridViewState, SvGridWrapperProps, } from './svgrid-wrapper.types.js';
238
+ export type { SvGridApi, SvGridFilterOperator, SvGridViewState, SvGridWrapperProps, SvGridSelectedRange, SvGridCellCoords, ChartTabSnapshot, SavedChart, } from './svgrid-wrapper.types.js';
222
239
  export { parseEditorValue, normalizeEditorOptions, type CellEditorType, type CellEditorOption, } from './editors/cell-editors.js';
223
240
  export { applyExcelFilter, compileExcelFilter, normalizeForFilter, splitInTokens, joinInTokens, trailingInToken, type CompiledExcelFilter, type ExcelFilter, type ExcelFilterOperator, type ExcelFilterOptions, } from './filtering/excel-filters.js';
224
241
  export { ALL_FILTER_OPERATORS, SET_OPERATOR_IDS, VALUELESS_OPERATOR_IDS, RANGE_OPERATOR_IDS, isSetOperator, isValuelessOperator, isRangeOperator, type FilterValueType, } from './filtering/filter-operator-catalogue.js';
package/dist/index.js CHANGED
@@ -229,9 +229,15 @@ export { default as SvGridChartPanel } from './SvGridChartPanel.svelte';
229
229
  // unprefixed siblings SvGauge / SvSparkline. The `SvGrid*` names remain exported
230
230
  // as aliases so existing imports keep working.
231
231
  export { default as SvChart } from './SvGridChart.svelte';
232
+ export { wheelWindow, panWindow, pinchWindow, presetWindow, nearestIndexByTime, } from './chart-zoom.js';
233
+ export { interpolateGeometry } from './chart-motion.js';
234
+ export { drillTree, pathTo } from './chart-hierarchy.js';
235
+ export { syncGroupState, publishSyncHover, publishSyncZoom } from './chart-sync.svelte.js';
232
236
  export { default as SvChartPanel } from './SvGridChartPanel.svelte';
233
- export { buildChart, formatChartValue, rowsToChartSpec, rowsToBoxSpec, rowsToDirectSpec, boxStats, sliceChartWindow, chartScales, ordinalDateTicks, niceScale, niceLogScale, linearTrend, simpleMovingAverage, exponentialMovingAverage, computeOverlay, buildLinePath, sampleGradient, pickContrastText, DEFAULT_PALETTE, } from './chart.js';
237
+ export { default as SvChartPanes } from './SvChartPanes.svelte';
238
+ export { buildChart, formatChartValue, rowsToChartSpec, rowsToBoxSpec, rowsToDirectSpec, rowsToScatterSpec, rowsToGaugeSpec, rowsToHistogramSpec, rowsToRangeSpec, paretoSpec, specToTreemap, specToCalendar, specToSankey, binValues, heikinAshi, resampleOhlc, rowsToOhlcSpec, guessOhlcColumns, splitPanelIndicators, applyChartFormat, CHART_RESPONSIVE_PRESETS, bollingerBands, rsi, macd, vwap, atr, stochastic, wma, obv, indicatorPane, arcPath, streamBaseline, boxStats, sliceChartWindow, matchResponsiveRules, resolveResponsive, chartStyleVars, chartScales, ordinalDateTicks, niceScale, niceLogScale, linearTrend, linearFit, polynomialFit, exponentialFit, logarithmicFit, powerFit, rSquared, pearson, simpleMovingAverage, exponentialMovingAverage, computeOverlay, computeOverlayFit, regressionFit, overlayName, buildLinePath, layoutDataLabels, markerPath, decimateSpec, pickCategories, lttb, minMaxIndices, reduceValues, percentile, bucketStart, PER_CATEGORY_SERIES_KEYS, sampleGradient, pickContrastText, DEFAULT_PALETTE, } from './chart.js';
234
239
  export { chartToSvgString, downloadChartSvg, chartToPngBlob, downloadChartPng, chartCsvExportable, chartSpecToCsv, downloadChartCsv, } from './chart-export.js';
240
+ export { chartToPdfBlob, downloadChartPdf, printChart, buildChartPdf } from './chart-export-pdf.js';
235
241
  export { buildSparkline, toSparklineValues, } from './sparkline.js';
236
242
  export { spreadsheetLayout, spansToMerges, } from './spreadsheet.js';
237
243
  // The two resize actions, exported as a matched pair. `<SvGrid>` drives both
@@ -247,15 +253,26 @@ export { computeColumnGroupMeta, hiddenLeavesForCollapse, } from './column-group
247
253
  export { createHyperFormulaSheet, } from './hyperformula-adapter.js';
248
254
  export { createCollaboration, broadcastChannelTransport, } from './collaboration.js';
249
255
  export { createServerDataSource, } from './server-data-source.js';
250
- export { createServerGroupModel, serverGroupRows, serverGroupNav, } from './server-group-model.js';
251
- export { default as SvGroupCell } from './SvGroupCell.svelte';
252
- export { default as SvRowGroupPanel } from './SvRowGroupPanel.svelte';
256
+ export { createBlockCache, createRowPlaceholder, rowPlaceholderState, } from './server-block-cache.js';
257
+ export { toServerFilterColumns, } from './row-model.js';
253
258
  export { createNamedViews, memoryViews, localStorageViews, attachAutoSavedView, } from './named-views.js';
254
259
  export { resolveCellFormat, computeColumnStat, lerpColor, rgba, contrastText, formatNeedsStats, formatsNeedingStats, } from './conditional-formatting.js';
255
260
  export { defaultGridMessages, resolveGridMessages, } from './grid-messages.js';
261
+ export { defaultChartMessages, resolveChartMessages, chartMessage, } from './chart-messages.js';
262
+ export { defaultChartPanelMessages, resolveChartPanelMessages, chartPanelMessage, } from './chart-panel-messages.js';
263
+ export { validateChartSpec, warnChartSpec, nearestKey as nearestChartKey, CHART_TYPES, KNOWN_SPEC_KEYS, KNOWN_SERIES_KEYS, } from './chart-validate.js';
264
+ export { chartSummary } from './chart-summary.js';
265
+ export { appendPoints } from './chart-stream.js';
266
+ export { pivotResultToChartSpec, pivotChartType, pivotFilterColumn } from './chart-pivot.js';
267
+ export { chartSpecToTable } from './chart-table.js';
256
268
  export { GRID_ICON_GLYPHS, GRID_ICON_NAMES, } from './grid-icons.js';
257
269
  export { insertGroupFooters, buildAutoGroupColumns, paginateGroupedRows, } from './group-display.js';
258
- export { getKeyboardIntent, getNextActiveCell } from './keyboard.js';
270
+ export { getKeyboardIntent, getNextActiveCell, getEntryStep, pastCollapsed } from './keyboard.js';
271
+ export { buildMergeIndex, mergeAt, isCovered, originOf, endOf, expandRectToMerges, stepPastMerge, mergeDrawAt } from './merges.js';
272
+ // The fill handle's series (2, 4, 6; Jan, Feb; dates by the day), for a host
273
+ // that wants to show what a fill will write before it lands.
274
+ export { buildFillPattern } from './fill-patterns.js';
275
+ export { registerGridShortcuts, hasGridShortcuts, clearGridShortcuts, } from './shortcut-registry.js';
259
276
  export { createVirtualizer } from './virtualization/virtualizer.js';
260
277
  export { createSvelteVirtualizer } from './virtualization/svelte-virtualizer.svelte.js';
261
278
  export { createColumnVirtualizer } from './virtualization/column-virtualizer.js';
@@ -1,11 +1,27 @@
1
1
  import "./sv-grid-scrollbar.js";
2
- import { getKeyboardIntent, getNextActiveCell } from "./keyboard.js";
2
+ import { getKeyboardIntent, getNextActiveCell, getEntryStep, pastCollapsed } from "./keyboard.js";
3
+ import { stepPastMerge } from "./merges.js";
4
+ import { hasGridShortcuts, runGridShortcuts } from "./shortcut-registry.js";
5
+ import { undoHistory, redoHistory } from "./history.js";
6
+ import { buildCommandContext } from "./command-context.js";
3
7
  export function createKeyboard(ctx) {
4
8
  function onGridKeyDown(event) {
5
9
  // Only the grid root drives navigation - keys on header buttons, menus,
6
10
  // or the cell editor are handled by those controls themselves.
11
+ //
12
+ // The command chain runs AFTER this guard, not before. Running it first
13
+ // meant a key typed into a filter-row input reached the sheet commands,
14
+ // so Ctrl+A or Ctrl+D while filtering mutated grid cells. The editor has
15
+ // its own chain call in editing.ts, which is what Alt+Enter needs.
7
16
  if (event.target !== event.currentTarget)
8
17
  return;
18
+ // Registered commands get the key BEFORE the grid interprets it. That is
19
+ // how @svgrid/enterprise binds Ctrl+Arrow, Ctrl+D and the rest without
20
+ // widening the closed GridKeyboardIntent union, which is public API. A
21
+ // grid with nothing registered pays one array-length read.
22
+ if (hasGridShortcuts() && runGridShortcuts(event, buildCommandContext(ctx, false))) {
23
+ return;
24
+ }
9
25
  if (ctx.editingCell)
10
26
  return;
11
27
  if ((event.ctrlKey || event.metaKey) && !event.altKey) {
@@ -16,6 +32,14 @@ export function createKeyboard(ctx) {
16
32
  return;
17
33
  }
18
34
  if (lower === "v") {
35
+ // A consumer taking the paste over wants the browser's own `paste`
36
+ // event, which carries the clipboard's HTML unsanitised; the key is
37
+ // left alone and the async API is armed as the fallback for a
38
+ // browser that never delivers the event to a non-editable element.
39
+ if (ctx.props.onPasteClipboard) {
40
+ ctx.armPasteFallback();
41
+ return;
42
+ }
19
43
  // Secure context: read via the async Clipboard API and swallow the
20
44
  // key. Insecure context (no navigator.clipboard): DON'T preventDefault
21
45
  // so the browser delivers a native `paste` event to `onGridPaste`.
@@ -34,26 +58,12 @@ export function createKeyboard(ctx) {
34
58
  // and Ctrl+Y both redo. Mirrors VSCode / Sheets / Excel.
35
59
  if (lower === "z" && !event.shiftKey) {
36
60
  event.preventDefault();
37
- if (ctx.historyPtr >= 0) {
38
- const step = ctx.history[ctx.historyPtr];
39
- if (step) {
40
- ctx.applyHistoryStep(step, 'undo');
41
- ctx.historyPtr -= 1;
42
- ctx.historyVersion += 1;
43
- }
44
- }
61
+ undoHistory(ctx);
45
62
  return;
46
63
  }
47
64
  if ((lower === "z" && event.shiftKey) || lower === "y") {
48
65
  event.preventDefault();
49
- if (ctx.historyPtr < ctx.history.length - 1) {
50
- const step = ctx.history[ctx.historyPtr + 1];
51
- if (step) {
52
- ctx.applyHistoryStep(step, 'redo');
53
- ctx.historyPtr += 1;
54
- ctx.historyVersion += 1;
55
- }
56
- }
66
+ redoHistory(ctx);
57
67
  return;
58
68
  }
59
69
  // Ctrl+F opens the find overlay.
@@ -178,26 +188,73 @@ export function createKeyboard(ctx) {
178
188
  const usable = Math.max(0, clientHeight - headerHeight);
179
189
  return Math.max(1, Math.floor(usable / Math.max(rowHeight, 1)) - 1);
180
190
  }
181
- const next = getNextActiveCell(current, intent, {
191
+ const bounds = {
182
192
  maxRow: Math.max(ctx.allRows.length - 1, 0),
183
193
  maxCol: Math.max(ctx.allColumns.length - 1, 0),
184
- pageSize: pageStep(),
185
- });
186
- ctx.setActiveCell(next.rowIndex, next.colIndex);
187
- ctx.scrollActiveCellIntoView(next.rowIndex, next.colIndex);
188
- // Shift extends the selection ONLY for arrow keys (Excel-style).
189
- // Shift+Enter / Shift+Tab just change direction; they don't grow the
190
- // range, otherwise hammering Shift+Tab to backspace through a row
191
- // would paint a creeping rectangle behind the cursor.
192
- const shouldExtend = event.shiftKey &&
194
+ };
195
+ // Collapsed rows and columns are stepped over, as a sheet's hidden ones.
196
+ const collapsed = {
197
+ isRowCollapsed: (i) => ctx.isRowCollapsed(i),
198
+ isColumnCollapsed: (i) => !!ctx.collapsedColumns[ctx.allColumns[i]?.id],
199
+ };
200
+ // Enter and Tab are entry keys: they remember a Tab run and stay inside
201
+ // a selected block (getEntryStep). ArrowDown shares the moveDown intent
202
+ // and is a plain move, hence the key check.
203
+ if ((event.key === "Enter" || event.key === "Tab") &&
204
+ (intent === "moveDown" || intent === "moveUp" || intent === "tabNext" || intent === "tabPrev")) {
205
+ const step = getEntryStep(current, intent, {
206
+ ...bounds,
207
+ tabOrigin: ctx.tabRunOrigin,
208
+ range: ctx.activeRangeRect(),
209
+ collapsed,
210
+ });
211
+ const landed = stepPastMerge(ctx.mergeIndex, current, step.cell, bounds);
212
+ ctx.setActiveCell(landed.rowIndex, landed.colIndex);
213
+ ctx.tabRunOrigin = step.tabOrigin;
214
+ ctx.scrollActiveCellIntoView(landed.rowIndex, landed.colIndex);
215
+ if (!step.withinRange)
216
+ ctx.setSelection(landed.rowIndex, landed.colIndex);
217
+ return;
218
+ }
219
+ // Shift+Arrow grows the range from its far corner, and the active cell
220
+ // stays where it is, as in Excel: it is the cell the formula bar shows
221
+ // and the one the next keystroke edits. Shift+Home, Shift+End,
222
+ // Shift+PageUp / PageDown and Ctrl+Shift+Home / End grow it the same
223
+ // way, to where the plain key would have moved. Shift+Enter and
224
+ // Shift+Tab never come this way (they are entry keys, above), so
225
+ // hammering Shift+Tab back through a row cannot paint a creeping
226
+ // rectangle. A grid without cell selection has no range to grow and
227
+ // moves the active cell instead.
228
+ const extending = event.shiftKey &&
229
+ ctx.enableCellSelectionEffective !== false &&
193
230
  (intent === "moveLeft" ||
194
231
  intent === "moveRight" ||
195
232
  intent === "moveUp" ||
196
- intent === "moveDown");
197
- if (shouldExtend)
233
+ intent === "moveDown" ||
234
+ intent === "rowStart" ||
235
+ intent === "rowEnd" ||
236
+ intent === "pageUp" ||
237
+ intent === "pageDown" ||
238
+ intent === "gridStart" ||
239
+ intent === "gridEnd");
240
+ if (extending) {
241
+ const anchored = !!ctx.selectionRange?.anchor;
242
+ if (!anchored)
243
+ ctx.setSelection(current.rowIndex, current.colIndex);
244
+ const from = anchored ? ctx.selectionRange.focus ?? current : current;
245
+ const next = stepPastMerge(ctx.mergeIndex, from, pastCollapsed(from, getNextActiveCell(from, intent, { ...bounds, pageSize: pageStep() }), bounds, collapsed), bounds);
198
246
  ctx.extendSelection(next.rowIndex, next.colIndex);
199
- else
200
- ctx.setSelection(next.rowIndex, next.colIndex);
247
+ // Scroll along the axis of the key only, as Excel does: Shift+Right
248
+ // brings the new column into view without moving the rows, so a
249
+ // whole-column selection (its far corner on the last row) stays put.
250
+ const sideways = intent === "moveLeft" || intent === "moveRight" || intent === "rowStart" || intent === "rowEnd";
251
+ ctx.scrollActiveCellIntoView(sideways ? current.rowIndex : next.rowIndex, sideways ? next.colIndex : current.colIndex);
252
+ return;
253
+ }
254
+ const next = stepPastMerge(ctx.mergeIndex, current, pastCollapsed(current, getNextActiveCell(current, intent, { ...bounds, pageSize: pageStep() }), bounds, collapsed), bounds);
255
+ ctx.setActiveCell(next.rowIndex, next.colIndex);
256
+ ctx.scrollActiveCellIntoView(next.rowIndex, next.colIndex);
257
+ ctx.setSelection(next.rowIndex, next.colIndex);
201
258
  }
202
259
  function onWindowKeydown(event) {
203
260
  if (event.key === "Escape" && (ctx.columnMenuFor || ctx.operatorMenuFor)) {
@@ -6,3 +6,58 @@ export declare function getNextActiveCell(current: ActiveCellState, intent: Grid
6
6
  maxCol: number;
7
7
  pageSize?: number;
8
8
  }): ActiveCellState;
9
+ export type Collapsed = {
10
+ isRowCollapsed: (rowIndex: number) => boolean;
11
+ isColumnCollapsed: (colIndex: number) => boolean;
12
+ };
13
+ /**
14
+ * Where a move lands once collapsed rows and columns are stepped over.
15
+ *
16
+ * A sheet's arrow keys never rest on a hidden row or column: the cursor
17
+ * goes on in the direction of travel to the next one that shows, and when
18
+ * nothing shows in that direction it comes back to the nearest one before
19
+ * the landing, which for End on a sheet whose last columns are hidden is the
20
+ * last visible column. An axis the move did not touch is left alone, so a
21
+ * cursor sitting on a row the user has just hidden still moves sideways.
22
+ * With every cell in the direction of travel hidden the cursor stays put.
23
+ */
24
+ export declare function pastCollapsed(from: ActiveCellState, next: ActiveCellState, bounds: {
25
+ maxRow: number;
26
+ maxCol: number;
27
+ }, collapsed: Collapsed): ActiveCellState;
28
+ export type EntryIntent = 'moveDown' | 'moveUp' | 'tabNext' | 'tabPrev';
29
+ export type EntryRect = {
30
+ minRow: number;
31
+ maxRow: number;
32
+ minCol: number;
33
+ maxCol: number;
34
+ };
35
+ export type EntryStep = {
36
+ cell: ActiveCellState;
37
+ /** The move stayed inside a multi-cell selection, which is kept. */
38
+ withinRange: boolean;
39
+ /** The column a run of Tabs began in, for the Enter that ends it. */
40
+ tabOrigin: number | null;
41
+ };
42
+ /**
43
+ * Where Enter and Tab put the cursor, the way a sheet's data entry expects.
44
+ *
45
+ * Two rules on top of `getNextActiveCell`. A run of Tabs remembers the
46
+ * column it started in, and the Enter that ends the run goes down from
47
+ * THAT column, not from the last cell: type across A1, B1, C1 with Tab and
48
+ * Enter lands on A2, ready for the next record. Any other move clears the
49
+ * memory, which the callers do by resetting `tabOrigin` on every plain
50
+ * `setActiveCell`. And inside a selection of more than one cell the cursor
51
+ * stays inside it: Enter walks down a column and wraps to the top of the
52
+ * next, Tab walks along a row and wraps to the start of the next, both
53
+ * back to the first cell after the last, and the selection is left
54
+ * standing, so a block can be filled without ever reaching for the mouse.
55
+ * Arrow keys are not entry keys and never come here.
56
+ */
57
+ export declare function getEntryStep(current: ActiveCellState, intent: EntryIntent, opts: {
58
+ maxRow: number;
59
+ maxCol: number;
60
+ tabOrigin: number | null;
61
+ range: EntryRect | null;
62
+ collapsed?: Collapsed;
63
+ }): EntryStep;