@svgrid/grid 3.0.2 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/GridMenus.svelte +44 -2
- package/dist/SvChartMenu.svelte +69 -0
- package/dist/SvChartMenu.svelte.d.ts +11 -0
- package/dist/SvChartPanes.svelte +113 -0
- package/dist/SvChartPanes.svelte.d.ts +20 -0
- package/dist/SvGrid.controller.svelte.d.ts +110 -39
- package/dist/SvGrid.controller.svelte.js +655 -200
- package/dist/SvGrid.css +105 -2
- package/dist/SvGrid.svelte +386 -514
- package/dist/SvGrid.types.d.ts +210 -9
- package/dist/SvGridCellEditor.svelte +17 -0
- package/dist/SvGridChart.svelte +2257 -329
- package/dist/SvGridChart.svelte.d.ts +6 -106
- package/dist/SvGridChart.types.d.ts +338 -0
- package/dist/SvGridChart.types.js +1 -0
- package/dist/SvGridChartBuilder.svelte +323 -0
- package/dist/SvGridChartBuilder.svelte.d.ts +34 -0
- package/dist/SvGridChartPanel.svelte +221 -275
- package/dist/SvGridChartPickers.svelte +417 -0
- package/dist/SvGridChartPickers.svelte.d.ts +70 -0
- package/dist/SvGridChartView.svelte +13 -14
- package/dist/SvModal.svelte +7 -1
- package/dist/SvModal.svelte.d.ts +5 -0
- package/dist/ai.d.ts +40 -8
- package/dist/ai.js +135 -24
- package/dist/aria.d.ts +11 -0
- package/dist/build-api.js +108 -22
- package/dist/cdn/GridMenus-7kbpnnBW.js +635 -0
- package/dist/cdn/GridMenus-BL7ZgQvU.js +636 -0
- package/dist/cdn/SvChartMenu-Bl6PBbkT.js +58 -0
- package/dist/cdn/SvChartMenu-FBSMINA6.js +59 -0
- package/dist/cdn/{SvDateRangeInput-DMLKmGEc.js → SvDateRangeInput-BeU_TkbQ.js} +15 -14
- package/dist/cdn/{SvDateRangeInput-CaOuMs8O.js → SvDateRangeInput-yX8vzleW.js} +38 -37
- package/dist/cdn/{SvDateTimePicker-sonaH0oh.js → SvDateTimePicker-DQwt4UAs.js} +139 -180
- package/dist/cdn/SvDateTimePicker-vNU6bZ-q.js +775 -0
- package/dist/cdn/{SvGridCellEditor-CjEJMJKc.js → SvGridCellEditor-B1p-vCK5.js} +188 -178
- package/dist/cdn/{SvGridCellEditor-BWnTi2N7.js → SvGridCellEditor-D_0q4xAu.js} +98 -88
- package/dist/cdn/SvGridChart-C3EWAZaM.js +3574 -0
- package/dist/cdn/SvGridChart-DzLkSwCH.js +3572 -0
- package/dist/cdn/SvGridChartBuilder-BE2T1ykB.js +783 -0
- package/dist/cdn/SvGridChartBuilder-CfII62sZ.js +784 -0
- package/dist/cdn/SvGridChartPanel-CCX5_Wgd.js +675 -0
- package/dist/cdn/SvGridChartPanel-xf4sWVTo.js +699 -0
- package/dist/cdn/SvGridChartView-CfuXmY5I.js +48 -0
- package/dist/cdn/SvGridChartView-DYwabQWj.js +47 -0
- package/dist/cdn/SvMenuList-CLN8OuIK.js +452 -0
- package/dist/cdn/SvMenuList-DkGhNKjf.js +451 -0
- package/dist/cdn/SvModal-BAE-pjZX.js +396 -0
- package/dist/cdn/SvModal-CIZWCcad.js +397 -0
- package/dist/cdn/chart-Dz7SqMXH.js +4341 -0
- package/dist/cdn/chart-export-BXqueeWJ.js +135 -0
- package/dist/cdn/chart-export-pdf-DONFUnNY.js +110 -0
- package/dist/cdn/chart-panel-messages-CUbf2R4i.js +1052 -0
- package/dist/cdn/chart-panel-messages-CmNrMdsr.js +1053 -0
- package/dist/cdn/chart-summary-BJW_tg_X.js +138 -0
- package/dist/cdn/chart-trend-CaN9mDEV.js +50 -0
- package/dist/cdn/chart-validate-HcOVFAfJ.js +188 -0
- package/dist/cdn/{column-resize-DsfNXMom.js → column-resize-DpmOLfRp.js} +3 -3
- package/dist/cdn/{date-format-BnnHlqGw.js → date-format-CtquV-p3.js} +583 -603
- package/dist/cdn/{date-format-BNii4zeD.js → date-format-D6KFzU_W.js} +347 -367
- package/dist/cdn/dismissable-DAHetSNk.js +44 -0
- package/dist/cdn/editor-contract-LXgQJAgd.js +22 -0
- package/dist/cdn/focus-trap-BBOQYBma.js +65 -0
- package/dist/cdn/{row-resize-BRcimkUT.js → row-resize-niQCp040.js} +44 -36
- package/dist/cdn/{src-DNbz94Ct.js → src-BKhZ6eXd.js} +10227 -9787
- package/dist/cdn/{src-BJ2opd0j.js → src-V1uu8iE9.js} +6568 -6128
- package/dist/cdn/svgrid.js +26 -15
- package/dist/cdn/svgrid.svelte-external.js +26 -15
- package/dist/chart-axes.d.ts +53 -0
- package/dist/chart-axes.js +351 -0
- package/dist/chart-cartesian.d.ts +88 -0
- package/dist/chart-cartesian.js +1862 -0
- package/dist/chart-decimate.d.ts +51 -0
- package/dist/chart-decimate.js +199 -0
- package/dist/chart-export-pdf.d.ts +47 -0
- package/dist/chart-export-pdf.js +187 -0
- package/dist/chart-export.d.ts +2 -1
- package/dist/chart-export.js +18 -3
- package/dist/chart-financial.d.ts +91 -0
- package/dist/chart-financial.js +175 -0
- package/dist/chart-flow.d.ts +10 -0
- package/dist/chart-flow.js +298 -0
- package/dist/chart-format.d.ts +18 -0
- package/dist/chart-format.js +65 -0
- package/dist/chart-grid.d.ts +8 -0
- package/dist/chart-grid.js +190 -0
- package/dist/chart-hierarchy.d.ts +17 -0
- package/dist/chart-hierarchy.js +146 -0
- package/dist/chart-indicators.d.ts +115 -0
- package/dist/chart-indicators.js +389 -0
- package/dist/chart-messages.d.ts +95 -0
- package/dist/chart-messages.js +92 -0
- package/dist/chart-motion.d.ts +16 -0
- package/dist/chart-motion.js +141 -0
- package/dist/chart-panel-messages.d.ts +265 -0
- package/dist/chart-panel-messages.js +285 -0
- package/dist/chart-pivot.d.ts +87 -0
- package/dist/chart-pivot.js +156 -0
- package/dist/chart-polar.d.ts +25 -0
- package/dist/chart-polar.js +700 -0
- package/dist/chart-samples.d.ts +16 -0
- package/dist/chart-samples.js +153 -0
- package/dist/chart-scale.d.ts +113 -0
- package/dist/chart-scale.js +405 -0
- package/dist/chart-stats.d.ts +111 -0
- package/dist/chart-stats.js +419 -0
- package/dist/chart-stream.d.ts +45 -0
- package/dist/chart-stream.js +91 -0
- package/dist/chart-summary.d.ts +27 -0
- package/dist/chart-summary.js +205 -0
- package/dist/chart-sync.svelte.d.ts +32 -0
- package/dist/chart-sync.svelte.js +23 -0
- package/dist/chart-table.d.ts +35 -0
- package/dist/chart-table.js +165 -0
- package/dist/chart-trend.d.ts +19 -0
- package/dist/chart-trend.js +61 -0
- package/dist/chart-types.d.ts +1456 -0
- package/dist/chart-types.js +6 -0
- package/dist/chart-validate.d.ts +43 -0
- package/dist/chart-validate.js +272 -0
- package/dist/chart-zoom.d.ts +40 -0
- package/dist/chart-zoom.js +145 -0
- package/dist/chart.d.ts +186 -865
- package/dist/chart.js +460 -2204
- package/dist/clipboard.d.ts +1 -0
- package/dist/clipboard.js +137 -18
- package/dist/column-resize.d.ts +3 -0
- package/dist/column-resize.js +4 -1
- package/dist/columns.js +3 -0
- package/dist/command-context.d.ts +19 -0
- package/dist/command-context.js +116 -0
- package/dist/core.d.ts +7 -0
- package/dist/createPopoverSelect.svelte.d.ts +2 -2
- package/dist/editing.d.ts +2 -8
- package/dist/editing.js +262 -33
- package/dist/fill-patterns.d.ts +0 -5
- package/dist/fill-patterns.js +56 -2
- package/dist/grid-messages.d.ts +10 -3
- package/dist/grid-messages.js +5 -0
- package/dist/history.d.ts +83 -0
- package/dist/history.js +133 -0
- package/dist/index.d.ts +24 -6
- package/dist/index.js +20 -2
- package/dist/keyboard-handlers.js +88 -31
- package/dist/keyboard.d.ts +55 -0
- package/dist/keyboard.js +132 -0
- package/dist/menus.d.ts +3 -1
- package/dist/menus.js +7 -2
- package/dist/merges.d.ts +97 -0
- package/dist/merges.js +147 -0
- package/dist/row-resize.d.ts +3 -0
- package/dist/row-resize.js +14 -0
- package/dist/scroll-sync.d.ts +1 -0
- package/dist/scroll-sync.js +24 -0
- package/dist/selection.d.ts +16 -0
- package/dist/selection.js +108 -16
- package/dist/shortcut-registry.d.ts +145 -0
- package/dist/shortcut-registry.js +44 -0
- package/dist/svgrid-wrapper.types.d.ts +213 -22
- package/dist/virtualization/virtualizer.js +38 -17
- package/package.json +6 -1
- package/src/GridMenus.svelte +44 -2
- package/src/SvChartMenu.svelte +69 -0
- package/src/SvChartPanes.svelte +113 -0
- package/src/SvChartPanes.test.ts +66 -0
- package/src/SvGrid.controller.svelte.ts +629 -172
- package/src/SvGrid.css +105 -2
- package/src/SvGrid.svelte +386 -514
- package/src/SvGrid.types.ts +188 -8
- package/src/SvGridCellEditor.svelte +17 -0
- package/src/SvGridChart.svelte +2257 -329
- package/src/SvGridChart.test.ts +1419 -1
- package/src/SvGridChart.types.ts +336 -0
- package/src/SvGridChartBuilder.svelte +323 -0
- package/src/SvGridChartPanel.svelte +221 -275
- package/src/SvGridChartPickers.svelte +417 -0
- package/src/SvGridChartView.svelte +13 -14
- package/src/SvModal.svelte +7 -1
- package/src/SvModal.test.ts +9 -0
- package/src/ai.test.ts +57 -2
- package/src/ai.ts +166 -22
- package/src/aria.d.ts +11 -0
- package/src/build-api.coverage.test.ts +184 -0
- package/src/build-api.ts +107 -18
- package/src/chart-axes.test.ts +573 -0
- package/src/chart-axes.ts +342 -0
- package/src/chart-cartesian.ts +1863 -0
- package/src/chart-decimate.test.ts +249 -0
- package/src/chart-decimate.ts +186 -0
- package/src/chart-export-pdf.test.ts +91 -0
- package/src/chart-export-pdf.ts +207 -0
- package/src/chart-export.test.ts +14 -0
- package/src/chart-export.ts +13 -3
- package/src/chart-financial.ts +208 -0
- package/src/chart-flow.ts +286 -0
- package/src/chart-format.ts +67 -0
- package/src/chart-grid.ts +179 -0
- package/src/chart-hierarchy.ts +135 -0
- package/src/chart-indicators.test.ts +443 -0
- package/src/chart-indicators.ts +384 -0
- package/src/chart-messages.test.ts +21 -0
- package/src/chart-messages.ts +184 -0
- package/src/chart-motion.test.ts +71 -0
- package/src/chart-motion.ts +148 -0
- package/src/chart-panel-messages.test.ts +29 -0
- package/src/chart-panel-messages.ts +550 -0
- package/src/chart-pivot.test.ts +54 -0
- package/src/chart-pivot.ts +225 -0
- package/src/chart-polar.ts +674 -0
- package/src/chart-samples.ts +106 -0
- package/src/chart-scale.ts +394 -0
- package/src/chart-series-types.test.ts +714 -0
- package/src/chart-stats.ts +409 -0
- package/src/chart-stream.test.ts +75 -0
- package/src/chart-stream.ts +114 -0
- package/src/chart-summary.test.ts +90 -0
- package/src/chart-summary.ts +197 -0
- package/src/chart-sync.svelte.ts +41 -0
- package/src/chart-table.test.ts +76 -0
- package/src/chart-table.ts +178 -0
- package/src/chart-trend.ts +47 -0
- package/src/chart-types.ts +1309 -0
- package/src/chart-validate.test.ts +100 -0
- package/src/chart-validate.ts +247 -0
- package/src/chart-zoom.test.ts +137 -0
- package/src/chart-zoom.ts +124 -0
- package/src/chart.coverage.test.ts +81 -0
- package/src/chart.test.ts +56 -3
- package/src/chart.ts +557 -2784
- package/src/clipboard.test.ts +151 -0
- package/src/clipboard.ts +145 -16
- package/src/column-resize.ts +7 -1
- package/src/columns.ts +2 -0
- package/src/command-context.test.ts +200 -0
- package/src/command-context.ts +137 -0
- package/src/core.ts +7 -0
- package/src/editing.test.ts +281 -3
- package/src/editing.ts +256 -38
- package/src/fill-patterns.test.ts +35 -0
- package/src/fill-patterns.ts +56 -2
- package/src/grid-messages.ts +16 -3
- package/src/history.test.ts +196 -0
- package/src/history.ts +162 -0
- package/src/icon-seam.test.ts +3 -2
- package/src/index.ts +150 -2
- package/src/keyboard-handlers.coverage.test.ts +126 -6
- package/src/keyboard-handlers.ts +91 -30
- package/src/keyboard-shortcuts.seam.test.ts +200 -0
- package/src/keyboard.test.ts +124 -1
- package/src/keyboard.ts +142 -0
- package/src/menus.test.ts +26 -0
- package/src/menus.ts +10 -3
- package/src/merges.test.ts +112 -0
- package/src/merges.ts +168 -0
- package/src/pivot.grid.test.ts +40 -5
- package/src/row-resize.test.ts +44 -0
- package/src/row-resize.ts +17 -0
- package/src/scroll-sync.test.ts +42 -1
- package/src/scroll-sync.ts +25 -0
- package/src/selection.multi-range.test.ts +34 -0
- package/src/selection.test.ts +30 -2
- package/src/selection.ts +111 -19
- package/src/shortcut-registry.test.ts +97 -0
- package/src/shortcut-registry.ts +181 -0
- package/src/svgrid-wrapper.types.ts +184 -13
- package/src/svgrid.behavior.test.ts +135 -0
- package/src/svgrid.charting.test.ts +513 -3
- package/src/svgrid.context-menu.test.ts +31 -0
- package/src/svgrid.new-features.wrapper.test.ts +10 -3
- package/src/virtualization/virtualizer.ts +39 -17
- package/dist/cdn/GridMenus-DyFA-QxA.js +0 -602
- package/dist/cdn/GridMenus-M2XP9t0_.js +0 -603
- package/dist/cdn/SvDateTimePicker-CCbDZNZB.js +0 -816
- package/dist/cdn/SvGridChart-DAb9RbRs.js +0 -1480
- package/dist/cdn/SvGridChart-Yl-IXZFO.js +0 -1481
- package/dist/cdn/SvGridChartPanel-DayQpDsR.js +0 -834
- package/dist/cdn/SvGridChartPanel-aqf8n-vJ.js +0 -810
- package/dist/cdn/SvGridChartView-CxfakxR0.js +0 -56
- package/dist/cdn/SvGridChartView-Dm_YEx9L.js +0 -55
- package/dist/cdn/chart-CKJRCPOk.js +0 -1652
package/dist/history.js
ADDED
|
@@ -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
|
|
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';
|
|
@@ -210,15 +217,26 @@ export { default as SvGroupCell } from './SvGroupCell.svelte';
|
|
|
210
217
|
export { default as SvRowGroupPanel } from './SvRowGroupPanel.svelte';
|
|
211
218
|
export { createNamedViews, memoryViews, localStorageViews, attachAutoSavedView, type SavedView, type ViewStorage, type NamedViews, type AutoSavedViewOptions, } from './named-views.js';
|
|
212
219
|
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';
|
|
220
|
+
export { defaultGridMessages, resolveGridMessages, type GridMessages, type GridChromeMessages, } from './grid-messages.js';
|
|
221
|
+
export { defaultChartMessages, resolveChartMessages, chartMessage, type ChartMessages, } from './chart-messages.js';
|
|
222
|
+
export { defaultChartPanelMessages, resolveChartPanelMessages, chartPanelMessage, type GridChartPanelMessages, } from './chart-panel-messages.js';
|
|
223
|
+
export { validateChartSpec, warnChartSpec, nearestKey as nearestChartKey, CHART_TYPES, KNOWN_SPEC_KEYS, KNOWN_SERIES_KEYS, type ChartDiagnostic, } from './chart-validate.js';
|
|
224
|
+
export { chartSummary, type ChartSummaryOptions } from './chart-summary.js';
|
|
225
|
+
export { appendPoints, type ChartPoint, type AppendPointsOptions } from './chart-stream.js';
|
|
226
|
+
export { pivotResultToChartSpec, pivotChartType, pivotFilterColumn, type PivotResultChartOptions, type PivotResultLike } from './chart-pivot.js';
|
|
227
|
+
export { chartSpecToTable, type ChartTable, type ChartTableColumn } from './chart-table.js';
|
|
214
228
|
export { GRID_ICON_GLYPHS, GRID_ICON_NAMES, type GridIconName, type GridIcons, } from './grid-icons.js';
|
|
215
229
|
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';
|
|
230
|
+
export { getKeyboardIntent, getNextActiveCell, getEntryStep, pastCollapsed, type GridKeyboardIntent, type EntryIntent, type EntryRect, type EntryStep, type Collapsed } from './keyboard.js';
|
|
231
|
+
export { buildMergeIndex, mergeAt, isCovered, originOf, endOf, expandRectToMerges, stepPastMerge, mergeDrawAt, type MergedCell, type MergeIndex, type MergeRect, type MergeDraw } from './merges.js';
|
|
232
|
+
export { buildFillPattern } from './fill-patterns.js';
|
|
233
|
+
export { registerGridShortcuts, hasGridShortcuts, clearGridShortcuts, type GridShortcutHandler, type GridCommandContext, } from './shortcut-registry.js';
|
|
234
|
+
export type { HistoryStep } from './history.js';
|
|
217
235
|
export { createVirtualizer } from './virtualization/virtualizer.js';
|
|
218
236
|
export { createSvelteVirtualizer } from './virtualization/svelte-virtualizer.svelte.js';
|
|
219
237
|
export { createColumnVirtualizer } from './virtualization/column-virtualizer.js';
|
|
220
238
|
export type { VirtualItem, VirtualizerOptions, VirtualizerState } from './virtualization/types.js';
|
|
221
|
-
export type { SvGridApi, SvGridFilterOperator, SvGridViewState, SvGridWrapperProps, } from './svgrid-wrapper.types.js';
|
|
239
|
+
export type { SvGridApi, SvGridFilterOperator, SvGridViewState, SvGridWrapperProps, SvGridSelectedRange, SvGridCellCoords, ChartTabSnapshot, SavedChart, } from './svgrid-wrapper.types.js';
|
|
222
240
|
export { parseEditorValue, normalizeEditorOptions, type CellEditorType, type CellEditorOption, } from './editors/cell-editors.js';
|
|
223
241
|
export { applyExcelFilter, compileExcelFilter, normalizeForFilter, splitInTokens, joinInTokens, trailingInToken, type CompiledExcelFilter, type ExcelFilter, type ExcelFilterOperator, type ExcelFilterOptions, } from './filtering/excel-filters.js';
|
|
224
242
|
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 {
|
|
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
|
|
@@ -253,9 +259,21 @@ export { default as SvRowGroupPanel } from './SvRowGroupPanel.svelte';
|
|
|
253
259
|
export { createNamedViews, memoryViews, localStorageViews, attachAutoSavedView, } from './named-views.js';
|
|
254
260
|
export { resolveCellFormat, computeColumnStat, lerpColor, rgba, contrastText, formatNeedsStats, formatsNeedingStats, } from './conditional-formatting.js';
|
|
255
261
|
export { defaultGridMessages, resolveGridMessages, } from './grid-messages.js';
|
|
262
|
+
export { defaultChartMessages, resolveChartMessages, chartMessage, } from './chart-messages.js';
|
|
263
|
+
export { defaultChartPanelMessages, resolveChartPanelMessages, chartPanelMessage, } from './chart-panel-messages.js';
|
|
264
|
+
export { validateChartSpec, warnChartSpec, nearestKey as nearestChartKey, CHART_TYPES, KNOWN_SPEC_KEYS, KNOWN_SERIES_KEYS, } from './chart-validate.js';
|
|
265
|
+
export { chartSummary } from './chart-summary.js';
|
|
266
|
+
export { appendPoints } from './chart-stream.js';
|
|
267
|
+
export { pivotResultToChartSpec, pivotChartType, pivotFilterColumn } from './chart-pivot.js';
|
|
268
|
+
export { chartSpecToTable } from './chart-table.js';
|
|
256
269
|
export { GRID_ICON_GLYPHS, GRID_ICON_NAMES, } from './grid-icons.js';
|
|
257
270
|
export { insertGroupFooters, buildAutoGroupColumns, paginateGroupedRows, } from './group-display.js';
|
|
258
|
-
export { getKeyboardIntent, getNextActiveCell } from './keyboard.js';
|
|
271
|
+
export { getKeyboardIntent, getNextActiveCell, getEntryStep, pastCollapsed } from './keyboard.js';
|
|
272
|
+
export { buildMergeIndex, mergeAt, isCovered, originOf, endOf, expandRectToMerges, stepPastMerge, mergeDrawAt } from './merges.js';
|
|
273
|
+
// The fill handle's series (2, 4, 6; Jan, Feb; dates by the day), for a host
|
|
274
|
+
// that wants to show what a fill will write before it lands.
|
|
275
|
+
export { buildFillPattern } from './fill-patterns.js';
|
|
276
|
+
export { registerGridShortcuts, hasGridShortcuts, clearGridShortcuts, } from './shortcut-registry.js';
|
|
259
277
|
export { createVirtualizer } from './virtualization/virtualizer.js';
|
|
260
278
|
export { createSvelteVirtualizer } from './virtualization/svelte-virtualizer.svelte.js';
|
|
261
279
|
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
|
-
|
|
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
|
-
|
|
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
|
|
191
|
+
const bounds = {
|
|
182
192
|
maxRow: Math.max(ctx.allRows.length - 1, 0),
|
|
183
193
|
maxCol: Math.max(ctx.allColumns.length - 1, 0),
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
|
|
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
|
-
|
|
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
|
-
|
|
200
|
-
|
|
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)) {
|
package/dist/keyboard.d.ts
CHANGED
|
@@ -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;
|
package/dist/keyboard.js
CHANGED
|
@@ -4,6 +4,18 @@ export function getKeyboardIntent(event) {
|
|
|
4
4
|
return 'gridStart';
|
|
5
5
|
if (event.ctrlKey && event.key === 'End')
|
|
6
6
|
return 'gridEnd';
|
|
7
|
+
// Ctrl/Cmd + arrow is Excel's "jump to the edge of the data region". The
|
|
8
|
+
// grid does not implement that itself - it is a paid command registered
|
|
9
|
+
// through `registerGridShortcuts`, which runs before this function is ever
|
|
10
|
+
// called. If we get here the key was NOT claimed, and the right answer is to
|
|
11
|
+
// do nothing: moving one cell is a silently wrong response to a shortcut
|
|
12
|
+
// every spreadsheet user presses. Alt is excluded so a browser or OS
|
|
13
|
+
// combination still falls through untouched.
|
|
14
|
+
if ((event.ctrlKey || event.metaKey) && !event.altKey) {
|
|
15
|
+
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight' ||
|
|
16
|
+
event.key === 'ArrowUp' || event.key === 'ArrowDown')
|
|
17
|
+
return 'noop';
|
|
18
|
+
}
|
|
7
19
|
if (event.key === 'ArrowLeft')
|
|
8
20
|
return 'moveLeft';
|
|
9
21
|
if (event.key === 'ArrowRight')
|
|
@@ -89,3 +101,123 @@ export function getNextActiveCell(current, intent, bounds) {
|
|
|
89
101
|
cellId: current.cellId,
|
|
90
102
|
};
|
|
91
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Where a move lands once collapsed rows and columns are stepped over.
|
|
106
|
+
*
|
|
107
|
+
* A sheet's arrow keys never rest on a hidden row or column: the cursor
|
|
108
|
+
* goes on in the direction of travel to the next one that shows, and when
|
|
109
|
+
* nothing shows in that direction it comes back to the nearest one before
|
|
110
|
+
* the landing, which for End on a sheet whose last columns are hidden is the
|
|
111
|
+
* last visible column. An axis the move did not touch is left alone, so a
|
|
112
|
+
* cursor sitting on a row the user has just hidden still moves sideways.
|
|
113
|
+
* With every cell in the direction of travel hidden the cursor stays put.
|
|
114
|
+
*/
|
|
115
|
+
export function pastCollapsed(from, next, bounds, collapsed) {
|
|
116
|
+
const axis = (fromIdx, nextIdx, max, isCollapsed) => {
|
|
117
|
+
if (nextIdx === fromIdx)
|
|
118
|
+
return nextIdx;
|
|
119
|
+
const dir = nextIdx > fromIdx ? 1 : -1;
|
|
120
|
+
let i = nextIdx;
|
|
121
|
+
while (i >= 0 && i <= max && isCollapsed(i))
|
|
122
|
+
i += dir;
|
|
123
|
+
if (i >= 0 && i <= max)
|
|
124
|
+
return i;
|
|
125
|
+
i = nextIdx - dir;
|
|
126
|
+
while (i !== fromIdx && isCollapsed(i))
|
|
127
|
+
i -= dir;
|
|
128
|
+
return i;
|
|
129
|
+
};
|
|
130
|
+
const rowIndex = axis(from.rowIndex, next.rowIndex, bounds.maxRow, collapsed.isRowCollapsed);
|
|
131
|
+
const colIndex = axis(from.colIndex, next.colIndex, bounds.maxCol, collapsed.isColumnCollapsed);
|
|
132
|
+
return rowIndex === next.rowIndex && colIndex === next.colIndex ? next : { rowIndex, colIndex, cellId: next.cellId };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Where Enter and Tab put the cursor, the way a sheet's data entry expects.
|
|
136
|
+
*
|
|
137
|
+
* Two rules on top of `getNextActiveCell`. A run of Tabs remembers the
|
|
138
|
+
* column it started in, and the Enter that ends the run goes down from
|
|
139
|
+
* THAT column, not from the last cell: type across A1, B1, C1 with Tab and
|
|
140
|
+
* Enter lands on A2, ready for the next record. Any other move clears the
|
|
141
|
+
* memory, which the callers do by resetting `tabOrigin` on every plain
|
|
142
|
+
* `setActiveCell`. And inside a selection of more than one cell the cursor
|
|
143
|
+
* stays inside it: Enter walks down a column and wraps to the top of the
|
|
144
|
+
* next, Tab walks along a row and wraps to the start of the next, both
|
|
145
|
+
* back to the first cell after the last, and the selection is left
|
|
146
|
+
* standing, so a block can be filled without ever reaching for the mouse.
|
|
147
|
+
* Arrow keys are not entry keys and never come here.
|
|
148
|
+
*/
|
|
149
|
+
export function getEntryStep(current, intent, opts) {
|
|
150
|
+
const step = entryStep(current, intent, opts);
|
|
151
|
+
const collapsed = opts.collapsed;
|
|
152
|
+
if (!collapsed)
|
|
153
|
+
return step;
|
|
154
|
+
const hidden = (c) => collapsed.isRowCollapsed(c.rowIndex) || collapsed.isColumnCollapsed(c.colIndex);
|
|
155
|
+
if (!hidden(step.cell))
|
|
156
|
+
return step;
|
|
157
|
+
if (!step.withinRange)
|
|
158
|
+
return { ...step, cell: pastCollapsed(current, step.cell, opts, collapsed) };
|
|
159
|
+
// Walking a block: the same step again from the hidden cell, until one
|
|
160
|
+
// shows. A block with nothing showing leaves the cursor where it is.
|
|
161
|
+
let cell = step.cell;
|
|
162
|
+
for (let guard = (opts.range.maxRow - opts.range.minRow + 1) * (opts.range.maxCol - opts.range.minCol + 1); guard > 0 && hidden(cell); guard -= 1) {
|
|
163
|
+
cell = entryStep(cell, intent, opts).cell;
|
|
164
|
+
}
|
|
165
|
+
return { ...step, cell: hidden(cell) ? current : cell };
|
|
166
|
+
}
|
|
167
|
+
function entryStep(current, intent, opts) {
|
|
168
|
+
const range = opts.range;
|
|
169
|
+
const inRange = range !== null &&
|
|
170
|
+
(range.maxRow > range.minRow || range.maxCol > range.minCol) &&
|
|
171
|
+
current.rowIndex >= range.minRow && current.rowIndex <= range.maxRow &&
|
|
172
|
+
current.colIndex >= range.minCol && current.colIndex <= range.maxCol;
|
|
173
|
+
if (inRange) {
|
|
174
|
+
let { rowIndex, colIndex } = current;
|
|
175
|
+
if (intent === 'moveDown') {
|
|
176
|
+
rowIndex += 1;
|
|
177
|
+
if (rowIndex > range.maxRow) {
|
|
178
|
+
rowIndex = range.minRow;
|
|
179
|
+
colIndex += 1;
|
|
180
|
+
}
|
|
181
|
+
if (colIndex > range.maxCol)
|
|
182
|
+
colIndex = range.minCol;
|
|
183
|
+
}
|
|
184
|
+
else if (intent === 'moveUp') {
|
|
185
|
+
rowIndex -= 1;
|
|
186
|
+
if (rowIndex < range.minRow) {
|
|
187
|
+
rowIndex = range.maxRow;
|
|
188
|
+
colIndex -= 1;
|
|
189
|
+
}
|
|
190
|
+
if (colIndex < range.minCol)
|
|
191
|
+
colIndex = range.maxCol;
|
|
192
|
+
}
|
|
193
|
+
else if (intent === 'tabNext') {
|
|
194
|
+
colIndex += 1;
|
|
195
|
+
if (colIndex > range.maxCol) {
|
|
196
|
+
colIndex = range.minCol;
|
|
197
|
+
rowIndex += 1;
|
|
198
|
+
}
|
|
199
|
+
if (rowIndex > range.maxRow)
|
|
200
|
+
rowIndex = range.minRow;
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
colIndex -= 1;
|
|
204
|
+
if (colIndex < range.minCol) {
|
|
205
|
+
colIndex = range.maxCol;
|
|
206
|
+
rowIndex -= 1;
|
|
207
|
+
}
|
|
208
|
+
if (rowIndex < range.minRow)
|
|
209
|
+
rowIndex = range.maxRow;
|
|
210
|
+
}
|
|
211
|
+
return { cell: { rowIndex, colIndex, cellId: current.cellId }, withinRange: true, tabOrigin: null };
|
|
212
|
+
}
|
|
213
|
+
const bounds = { maxRow: opts.maxRow, maxCol: opts.maxCol };
|
|
214
|
+
if (intent === 'tabNext' || intent === 'tabPrev') {
|
|
215
|
+
return {
|
|
216
|
+
cell: getNextActiveCell(current, intent, bounds),
|
|
217
|
+
withinRange: false,
|
|
218
|
+
tabOrigin: opts.tabOrigin ?? current.colIndex,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
const from = opts.tabOrigin === null ? current : { ...current, colIndex: opts.tabOrigin };
|
|
222
|
+
return { cell: getNextActiveCell(from, intent, bounds), withinRange: false, tabOrigin: null };
|
|
223
|
+
}
|
package/dist/menus.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type RowData, type TableFeatures } from "./index.js";
|
|
2
2
|
import "./sv-grid-scrollbar.js";
|
|
3
|
-
import type { FilterOperator } from "./SvGrid.types.js";
|
|
3
|
+
import type { ContextMenuIcon, FilterOperator } from "./SvGrid.types.js";
|
|
4
|
+
import type { GridIconName } from "./grid-icons.js";
|
|
4
5
|
export declare function createMenus<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(ctx: any): {
|
|
5
6
|
updateFilterRow: (columnId: string, value: string) => void;
|
|
6
7
|
updateFilterOperator: (columnId: string, operator: FilterOperator) => void;
|
|
@@ -37,6 +38,7 @@ export declare function createMenus<TFeatures extends TableFeatures = TableFeatu
|
|
|
37
38
|
contextMenuItems: () => {
|
|
38
39
|
key: string;
|
|
39
40
|
label: string;
|
|
41
|
+
icon?: GridIconName | ContextMenuIcon;
|
|
40
42
|
separator?: boolean;
|
|
41
43
|
disabled?: boolean;
|
|
42
44
|
run?: () => void;
|
package/dist/menus.js
CHANGED
|
@@ -487,11 +487,16 @@ export function createMenus(ctx) {
|
|
|
487
487
|
}
|
|
488
488
|
if (entry.hidden?.(target))
|
|
489
489
|
continue;
|
|
490
|
+
// An object on a built-in's key with no action of its own is that
|
|
491
|
+
// built-in with an icon (or a label) of the consumer's choosing.
|
|
492
|
+
const b = builtins[entry.key];
|
|
493
|
+
const builtinLabel = b ? ((b.msg && messages?.[b.msg]) || b.label) : entry.key;
|
|
490
494
|
out.push({
|
|
491
495
|
key: entry.key,
|
|
492
|
-
label: entry.label,
|
|
496
|
+
label: entry.label ?? builtinLabel,
|
|
497
|
+
icon: entry.icon,
|
|
493
498
|
disabled: entry.disabled?.(target) ?? false,
|
|
494
|
-
run: () => entry.action(target),
|
|
499
|
+
run: entry.action ? () => entry.action(target) : b ? () => b.run(target) : undefined,
|
|
495
500
|
});
|
|
496
501
|
}
|
|
497
502
|
// Drop leading/trailing/double separators.
|