@svgrid/grid 3.0.3 → 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-D6XvA1Ij.js → src-BKhZ6eXd.js} +10227 -9787
- package/dist/cdn/{src-Bugf5XlI.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-CHOMnW-c.js +0 -602
- package/dist/cdn/GridMenus-DhdPF700.js +0 -603
- package/dist/cdn/SvDateTimePicker-CCbDZNZB.js +0 -816
- package/dist/cdn/SvGridChart-1PMSp2LZ.js +0 -1481
- package/dist/cdn/SvGridChart-D02avhyr.js +0 -1480
- package/dist/cdn/SvGridChartPanel-DJnViOv4.js +0 -834
- package/dist/cdn/SvGridChartPanel-vPTNerFZ.js +0 -810
- package/dist/cdn/SvGridChartView-C--HhdUo.js +0 -56
- package/dist/cdn/SvGridChartView-KyyFG-wY.js +0 -55
- package/dist/cdn/chart-DLg3_zTQ.js +0 -1652
package/dist/merges.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merged cells: a rectangle of cells drawn as one, the way a spreadsheet's
|
|
3
|
+
* Merge & Center does. The grid takes them as `mergedCells`, a list of
|
|
4
|
+
* origins with their spans in display indices, and this module is the
|
|
5
|
+
* pure part: an index over them, the questions the renderer, the
|
|
6
|
+
* selection and the keyboard ask, and nothing that touches the DOM.
|
|
7
|
+
*
|
|
8
|
+
* A merge is drawn by its origin td, which takes `rowspan` and `colspan`;
|
|
9
|
+
* the cells it covers are not emitted. Selection rectangles grow to whole
|
|
10
|
+
* merges (a merge is selected as one), the active cell inside a merge is
|
|
11
|
+
* its origin, and an arrow key moving into a merge lands on the origin
|
|
12
|
+
* and moving out of one steps past its far edge.
|
|
13
|
+
*/
|
|
14
|
+
export type MergedCell = {
|
|
15
|
+
/** Top-left cell of the merge, display indices. */
|
|
16
|
+
rowIndex: number;
|
|
17
|
+
colIndex: number;
|
|
18
|
+
/** How many rows and columns it covers, 1 or more. */
|
|
19
|
+
rowSpan: number;
|
|
20
|
+
colSpan: number;
|
|
21
|
+
};
|
|
22
|
+
export type MergeIndex = {
|
|
23
|
+
readonly list: ReadonlyArray<MergedCell>;
|
|
24
|
+
/** Every cell a merge covers (origin included) -> its merge. */
|
|
25
|
+
readonly byCell: ReadonlyMap<string, MergedCell>;
|
|
26
|
+
};
|
|
27
|
+
export type MergeRect = {
|
|
28
|
+
minRow: number;
|
|
29
|
+
maxRow: number;
|
|
30
|
+
minCol: number;
|
|
31
|
+
maxCol: number;
|
|
32
|
+
};
|
|
33
|
+
/** An index over the merges, or null when there are none (the common case). */
|
|
34
|
+
export declare function buildMergeIndex(merges: ReadonlyArray<MergedCell> | undefined | null): MergeIndex | null;
|
|
35
|
+
/** The merge covering (r, c), origin included, or undefined. */
|
|
36
|
+
export declare function mergeAt(index: MergeIndex | null, r: number, c: number): MergedCell | undefined;
|
|
37
|
+
/** Whether (r, c) is inside a merge without being its origin. */
|
|
38
|
+
export declare function isCovered(index: MergeIndex | null, r: number, c: number): boolean;
|
|
39
|
+
/** The origin of the merge (r, c) sits in, or (r, c) itself. */
|
|
40
|
+
export declare function originOf(index: MergeIndex | null, r: number, c: number): {
|
|
41
|
+
rowIndex: number;
|
|
42
|
+
colIndex: number;
|
|
43
|
+
};
|
|
44
|
+
/** The far corner of the merge (r, c) sits in, or (r, c) itself. */
|
|
45
|
+
export declare function endOf(index: MergeIndex | null, r: number, c: number): {
|
|
46
|
+
rowIndex: number;
|
|
47
|
+
colIndex: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* The rectangle grown to hold every merge it touches, to a fixed point: a
|
|
51
|
+
* merge that pokes out of the rectangle pulls the edge out, which can
|
|
52
|
+
* reach another merge, and so on, as a spreadsheet's selection does.
|
|
53
|
+
*/
|
|
54
|
+
export declare function expandRectToMerges(index: MergeIndex | null, rect: MergeRect): MergeRect;
|
|
55
|
+
/**
|
|
56
|
+
* Where a move from `from` to `next` really lands. A step into a merge
|
|
57
|
+
* lands on its origin; a step that stays inside the merge the move started
|
|
58
|
+
* in carries on past its far edge (right from a three-wide merge reaches
|
|
59
|
+
* the column after it), clamped to the bounds; a step that then lands in
|
|
60
|
+
* another merge takes that one's origin.
|
|
61
|
+
*/
|
|
62
|
+
export declare function stepPastMerge(index: MergeIndex | null, from: {
|
|
63
|
+
rowIndex: number;
|
|
64
|
+
colIndex: number;
|
|
65
|
+
}, next: {
|
|
66
|
+
rowIndex: number;
|
|
67
|
+
colIndex: number;
|
|
68
|
+
}, bounds: {
|
|
69
|
+
maxRow: number;
|
|
70
|
+
maxCol: number;
|
|
71
|
+
}): {
|
|
72
|
+
rowIndex: number;
|
|
73
|
+
colIndex: number;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* How a td at (r, c) draws inside a rendered window of rows and columns.
|
|
77
|
+
* A merge is drawn once per window, by the top-left cell of the part of it
|
|
78
|
+
* the window holds: the origin when the origin is in the window (`origin`),
|
|
79
|
+
* else the first covered cell the window shows (`continuation`, which
|
|
80
|
+
* draws the origin's content itself), with the spans clamped to the window
|
|
81
|
+
* so a table never spans into rows it has not drawn. Every other cell of
|
|
82
|
+
* the merge is `skip`: no td, the drawn one covers its slot.
|
|
83
|
+
*/
|
|
84
|
+
export type MergeDraw = {
|
|
85
|
+
kind: 'skip';
|
|
86
|
+
} | {
|
|
87
|
+
kind: 'origin' | 'continuation';
|
|
88
|
+
merge: MergedCell;
|
|
89
|
+
rowSpan: number;
|
|
90
|
+
colSpan: number;
|
|
91
|
+
};
|
|
92
|
+
export declare function mergeDrawAt(index: MergeIndex | null, r: number, c: number, window: {
|
|
93
|
+
firstRow: number;
|
|
94
|
+
lastRow: number;
|
|
95
|
+
firstCol: number;
|
|
96
|
+
lastCol: number;
|
|
97
|
+
}): MergeDraw | null;
|
package/dist/merges.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merged cells: a rectangle of cells drawn as one, the way a spreadsheet's
|
|
3
|
+
* Merge & Center does. The grid takes them as `mergedCells`, a list of
|
|
4
|
+
* origins with their spans in display indices, and this module is the
|
|
5
|
+
* pure part: an index over them, the questions the renderer, the
|
|
6
|
+
* selection and the keyboard ask, and nothing that touches the DOM.
|
|
7
|
+
*
|
|
8
|
+
* A merge is drawn by its origin td, which takes `rowspan` and `colspan`;
|
|
9
|
+
* the cells it covers are not emitted. Selection rectangles grow to whole
|
|
10
|
+
* merges (a merge is selected as one), the active cell inside a merge is
|
|
11
|
+
* its origin, and an arrow key moving into a merge lands on the origin
|
|
12
|
+
* and moving out of one steps past its far edge.
|
|
13
|
+
*/
|
|
14
|
+
const key = (r, c) => `${r}:${c}`;
|
|
15
|
+
/** An index over the merges, or null when there are none (the common case). */
|
|
16
|
+
export function buildMergeIndex(merges) {
|
|
17
|
+
if (!merges || merges.length === 0)
|
|
18
|
+
return null;
|
|
19
|
+
const byCell = new Map();
|
|
20
|
+
const list = [];
|
|
21
|
+
for (const raw of merges) {
|
|
22
|
+
const rowSpan = Math.max(1, Math.floor(raw.rowSpan));
|
|
23
|
+
const colSpan = Math.max(1, Math.floor(raw.colSpan));
|
|
24
|
+
if (rowSpan === 1 && colSpan === 1)
|
|
25
|
+
continue;
|
|
26
|
+
const merge = { rowIndex: raw.rowIndex, colIndex: raw.colIndex, rowSpan, colSpan };
|
|
27
|
+
list.push(merge);
|
|
28
|
+
for (let r = merge.rowIndex; r < merge.rowIndex + rowSpan; r += 1) {
|
|
29
|
+
for (let c = merge.colIndex; c < merge.colIndex + colSpan; c += 1)
|
|
30
|
+
byCell.set(key(r, c), merge);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return list.length ? { list, byCell } : null;
|
|
34
|
+
}
|
|
35
|
+
/** The merge covering (r, c), origin included, or undefined. */
|
|
36
|
+
export function mergeAt(index, r, c) {
|
|
37
|
+
return index?.byCell.get(key(r, c));
|
|
38
|
+
}
|
|
39
|
+
/** Whether (r, c) is inside a merge without being its origin. */
|
|
40
|
+
export function isCovered(index, r, c) {
|
|
41
|
+
const m = mergeAt(index, r, c);
|
|
42
|
+
return !!m && (m.rowIndex !== r || m.colIndex !== c);
|
|
43
|
+
}
|
|
44
|
+
/** The origin of the merge (r, c) sits in, or (r, c) itself. */
|
|
45
|
+
export function originOf(index, r, c) {
|
|
46
|
+
const m = mergeAt(index, r, c);
|
|
47
|
+
return m ? { rowIndex: m.rowIndex, colIndex: m.colIndex } : { rowIndex: r, colIndex: c };
|
|
48
|
+
}
|
|
49
|
+
/** The far corner of the merge (r, c) sits in, or (r, c) itself. */
|
|
50
|
+
export function endOf(index, r, c) {
|
|
51
|
+
const m = mergeAt(index, r, c);
|
|
52
|
+
return m
|
|
53
|
+
? { rowIndex: m.rowIndex + m.rowSpan - 1, colIndex: m.colIndex + m.colSpan - 1 }
|
|
54
|
+
: { rowIndex: r, colIndex: c };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The rectangle grown to hold every merge it touches, to a fixed point: a
|
|
58
|
+
* merge that pokes out of the rectangle pulls the edge out, which can
|
|
59
|
+
* reach another merge, and so on, as a spreadsheet's selection does.
|
|
60
|
+
*/
|
|
61
|
+
export function expandRectToMerges(index, rect) {
|
|
62
|
+
if (!index)
|
|
63
|
+
return rect;
|
|
64
|
+
let { minRow, maxRow, minCol, maxCol } = rect;
|
|
65
|
+
for (let guard = 0; guard < 64; guard += 1) {
|
|
66
|
+
let grew = false;
|
|
67
|
+
for (const m of index.list) {
|
|
68
|
+
const r2 = m.rowIndex + m.rowSpan - 1;
|
|
69
|
+
const c2 = m.colIndex + m.colSpan - 1;
|
|
70
|
+
const touches = m.rowIndex <= maxRow && r2 >= minRow && m.colIndex <= maxCol && c2 >= minCol;
|
|
71
|
+
if (!touches)
|
|
72
|
+
continue;
|
|
73
|
+
if (m.rowIndex < minRow) {
|
|
74
|
+
minRow = m.rowIndex;
|
|
75
|
+
grew = true;
|
|
76
|
+
}
|
|
77
|
+
if (r2 > maxRow) {
|
|
78
|
+
maxRow = r2;
|
|
79
|
+
grew = true;
|
|
80
|
+
}
|
|
81
|
+
if (m.colIndex < minCol) {
|
|
82
|
+
minCol = m.colIndex;
|
|
83
|
+
grew = true;
|
|
84
|
+
}
|
|
85
|
+
if (c2 > maxCol) {
|
|
86
|
+
maxCol = c2;
|
|
87
|
+
grew = true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (!grew)
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
return minRow === rect.minRow && maxRow === rect.maxRow && minCol === rect.minCol && maxCol === rect.maxCol
|
|
94
|
+
? rect
|
|
95
|
+
: { minRow, maxRow, minCol, maxCol };
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Where a move from `from` to `next` really lands. A step into a merge
|
|
99
|
+
* lands on its origin; a step that stays inside the merge the move started
|
|
100
|
+
* in carries on past its far edge (right from a three-wide merge reaches
|
|
101
|
+
* the column after it), clamped to the bounds; a step that then lands in
|
|
102
|
+
* another merge takes that one's origin.
|
|
103
|
+
*/
|
|
104
|
+
export function stepPastMerge(index, from, next, bounds) {
|
|
105
|
+
if (!index)
|
|
106
|
+
return next;
|
|
107
|
+
const target = mergeAt(index, next.rowIndex, next.colIndex);
|
|
108
|
+
if (!target)
|
|
109
|
+
return next;
|
|
110
|
+
const source = mergeAt(index, from.rowIndex, from.colIndex);
|
|
111
|
+
if (source !== target)
|
|
112
|
+
return { rowIndex: target.rowIndex, colIndex: target.colIndex };
|
|
113
|
+
// Still inside the merge the move began in: keep going in that direction.
|
|
114
|
+
const dr = Math.sign(next.rowIndex - from.rowIndex);
|
|
115
|
+
const dc = Math.sign(next.colIndex - from.colIndex);
|
|
116
|
+
if (dr === 0 && dc === 0)
|
|
117
|
+
return { rowIndex: target.rowIndex, colIndex: target.colIndex };
|
|
118
|
+
let rowIndex = next.rowIndex;
|
|
119
|
+
let colIndex = next.colIndex;
|
|
120
|
+
if (dr > 0)
|
|
121
|
+
rowIndex = target.rowIndex + target.rowSpan;
|
|
122
|
+
else if (dr < 0)
|
|
123
|
+
rowIndex = target.rowIndex - 1;
|
|
124
|
+
if (dc > 0)
|
|
125
|
+
colIndex = target.colIndex + target.colSpan;
|
|
126
|
+
else if (dc < 0)
|
|
127
|
+
colIndex = target.colIndex - 1;
|
|
128
|
+
if (rowIndex < 0 || rowIndex > bounds.maxRow || colIndex < 0 || colIndex > bounds.maxCol) {
|
|
129
|
+
// Nowhere further to go: the merge itself stays current.
|
|
130
|
+
return { rowIndex: target.rowIndex, colIndex: target.colIndex };
|
|
131
|
+
}
|
|
132
|
+
const landed = mergeAt(index, rowIndex, colIndex);
|
|
133
|
+
return landed ? { rowIndex: landed.rowIndex, colIndex: landed.colIndex } : { rowIndex, colIndex };
|
|
134
|
+
}
|
|
135
|
+
export function mergeDrawAt(index, r, c, window) {
|
|
136
|
+
const m = mergeAt(index, r, c);
|
|
137
|
+
if (!m)
|
|
138
|
+
return null;
|
|
139
|
+
const anchorRow = Math.max(m.rowIndex, window.firstRow);
|
|
140
|
+
const anchorCol = Math.max(m.colIndex, window.firstCol);
|
|
141
|
+
if (r !== anchorRow || c !== anchorCol)
|
|
142
|
+
return { kind: 'skip' };
|
|
143
|
+
const isOrigin = anchorRow === m.rowIndex && anchorCol === m.colIndex;
|
|
144
|
+
const rowSpan = Math.max(1, Math.min(m.rowIndex + m.rowSpan - r, window.lastRow - r + 1));
|
|
145
|
+
const colSpan = Math.max(1, Math.min(m.colIndex + m.colSpan - c, window.lastCol - c + 1));
|
|
146
|
+
return { kind: isOrigin ? 'origin' : 'continuation', merge: m, rowSpan, colSpan };
|
|
147
|
+
}
|
package/dist/row-resize.d.ts
CHANGED
|
@@ -30,6 +30,9 @@ export type RowResizeOptions = {
|
|
|
30
30
|
onResize: (rowIndex: number, height: number) => void;
|
|
31
31
|
/** Optional callback fired during the drag (every pointermove). */
|
|
32
32
|
onResizeMove?: (rowIndex: number, height: number) => void;
|
|
33
|
+
/** Double-click on the strip: size the row to its content, the
|
|
34
|
+
* spreadsheet gesture. Without it a double-click does nothing. */
|
|
35
|
+
onAutosize?: (rowIndex: number) => void;
|
|
33
36
|
/** Min row height in px. Default 20. */
|
|
34
37
|
min?: number;
|
|
35
38
|
/** Max row height in px. Default 320. */
|
package/dist/row-resize.js
CHANGED
|
@@ -29,6 +29,8 @@ const STRIP_CLASS = 'sv-grid-row-resize-handle';
|
|
|
29
29
|
export function rowResize(node, opts) {
|
|
30
30
|
let current = opts;
|
|
31
31
|
let drag = null;
|
|
32
|
+
/** The last press on a strip, for telling a double-click from two drags. */
|
|
33
|
+
let lastPress = null;
|
|
32
34
|
function rowIndexOf(tr) {
|
|
33
35
|
const dataRow = tr.querySelector('[data-svgrid-row]');
|
|
34
36
|
const val = dataRow?.dataset.svgridRow;
|
|
@@ -109,6 +111,18 @@ export function rowResize(node, opts) {
|
|
|
109
111
|
return;
|
|
110
112
|
e.preventDefault();
|
|
111
113
|
e.stopPropagation();
|
|
114
|
+
// The second press of a double-click: size the row to its content
|
|
115
|
+
// instead of starting another drag. Timed here rather than read from
|
|
116
|
+
// a dblclick event, whose target is the row once the first press's
|
|
117
|
+
// resize has re-rendered the strip; pointerdown carries no count.
|
|
118
|
+
const now = e.timeStamp;
|
|
119
|
+
const again = lastPress !== null && lastPress.rowIndex === rowIndex && now - lastPress.at < 400;
|
|
120
|
+
lastPress = { rowIndex, at: now };
|
|
121
|
+
if (again && current.onAutosize) {
|
|
122
|
+
lastPress = null;
|
|
123
|
+
current.onAutosize(rowIndex);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
112
126
|
t.classList.add('is-resizing');
|
|
113
127
|
drag = {
|
|
114
128
|
rowIndex,
|
package/dist/scroll-sync.d.ts
CHANGED
|
@@ -5,5 +5,6 @@ export declare function createScrollSync<TFeatures extends TableFeatures = Table
|
|
|
5
5
|
hideTooltip: () => void;
|
|
6
6
|
flushScheduledScrollSync: () => void;
|
|
7
7
|
scheduleScrollSync: (scrollTop: number, scrollLeft: number) => void;
|
|
8
|
+
syncScrollNow: (scrollTop: number, scrollLeft: number) => void;
|
|
8
9
|
onBodyScroll: (event: Event) => void;
|
|
9
10
|
};
|
package/dist/scroll-sync.js
CHANGED
|
@@ -57,6 +57,29 @@ export function createScrollSync(ctx) {
|
|
|
57
57
|
return;
|
|
58
58
|
ctx.scrollSyncRaf = requestAnimationFrame(flushScheduledScrollSync);
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Sync the virtualizers to a scroll position NOW instead of on the next
|
|
62
|
+
* animation frame.
|
|
63
|
+
*
|
|
64
|
+
* For a scroll the grid made itself - keyboard navigation bringing the
|
|
65
|
+
* active cell into view - the position is already known, and going through
|
|
66
|
+
* the browser's `scroll` event and then the rAF above put the row-window
|
|
67
|
+
* update one frame behind the key press: the keydown's own flush painted
|
|
68
|
+
* the active cell on the OLD rows, and the rows only caught up on the next
|
|
69
|
+
* frame. Two painted frames per arrow key. Syncing inline folds the window
|
|
70
|
+
* update into the same flush as the active-cell change, so the key press
|
|
71
|
+
* paints once. The `scroll` event still fires afterwards and re-syncs to
|
|
72
|
+
* the same offset, which the virtualizers treat as a no-op.
|
|
73
|
+
*/
|
|
74
|
+
function syncScrollNow(scrollTop, scrollLeft) {
|
|
75
|
+
if (ctx.scrollSyncRaf !== null) {
|
|
76
|
+
cancelAnimationFrame(ctx.scrollSyncRaf);
|
|
77
|
+
ctx.scrollSyncRaf = null;
|
|
78
|
+
}
|
|
79
|
+
ctx.pendingScrollTop = scrollTop;
|
|
80
|
+
ctx.pendingScrollLeft = scrollLeft;
|
|
81
|
+
flushScheduledScrollSync();
|
|
82
|
+
}
|
|
60
83
|
function onBodyScroll(event) {
|
|
61
84
|
const container = event.currentTarget;
|
|
62
85
|
if (!container)
|
|
@@ -84,6 +107,7 @@ export function createScrollSync(ctx) {
|
|
|
84
107
|
hideTooltip,
|
|
85
108
|
flushScheduledScrollSync,
|
|
86
109
|
scheduleScrollSync,
|
|
110
|
+
syncScrollNow,
|
|
87
111
|
onBodyScroll,
|
|
88
112
|
};
|
|
89
113
|
}
|
package/dist/selection.d.ts
CHANGED
|
@@ -15,6 +15,22 @@ export declare function createSelection<TFeatures extends TableFeatures = TableF
|
|
|
15
15
|
left: boolean;
|
|
16
16
|
right: boolean;
|
|
17
17
|
} | null;
|
|
18
|
+
activeRangeRect: () => {
|
|
19
|
+
minRow: number;
|
|
20
|
+
maxRow: number;
|
|
21
|
+
minCol: number;
|
|
22
|
+
maxCol: number;
|
|
23
|
+
} | null;
|
|
24
|
+
cellSelectionState: (rowIndex: number, colIndex: number) => {
|
|
25
|
+
active: boolean;
|
|
26
|
+
edges: {
|
|
27
|
+
top: boolean;
|
|
28
|
+
bottom: boolean;
|
|
29
|
+
left: boolean;
|
|
30
|
+
right: boolean;
|
|
31
|
+
} | null;
|
|
32
|
+
fillHandle: boolean;
|
|
33
|
+
} | null;
|
|
18
34
|
fillMarqueeEdges: (rowIndex: number, colIndex: number) => {
|
|
19
35
|
top: boolean;
|
|
20
36
|
bottom: boolean;
|
package/dist/selection.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { getGridCellDomId, } from "./index.js";
|
|
5
5
|
import "./sv-grid-scrollbar.js";
|
|
6
6
|
import { getColumnBaseValue, isGroupRow, } from "./cell-values.js";
|
|
7
|
+
import { expandRectToMerges, originOf, endOf } from "./merges.js";
|
|
7
8
|
export function createSelection(ctx) {
|
|
8
9
|
function isRowSelected(rowId) {
|
|
9
10
|
return Boolean(ctx.rowSelectionState[rowId]);
|
|
@@ -26,7 +27,18 @@ export function createSelection(ctx) {
|
|
|
26
27
|
});
|
|
27
28
|
}
|
|
28
29
|
function setActiveCell(rowIndex, colIndex) {
|
|
30
|
+
// The active cell inside a merge is its origin: the one that draws, the
|
|
31
|
+
// one the formula bar shows, the one an edit writes.
|
|
32
|
+
({ rowIndex, colIndex } = originOf(ctx.mergeIndex, rowIndex, colIndex));
|
|
29
33
|
ctx.userHasActivatedCell = true;
|
|
34
|
+
// A click, an arrow, a jump: the Tab run is over. The Tab and Enter
|
|
35
|
+
// paths put the origin back after this call when it should live on.
|
|
36
|
+
// Activating the cell the cursor is already on (typing into it, F2, a
|
|
37
|
+
// double-click) is not a move and keeps the run.
|
|
38
|
+
const prev = ctx.grid.getState().activeCell;
|
|
39
|
+
if (!prev || prev.rowIndex !== rowIndex || prev.colIndex !== colIndex) {
|
|
40
|
+
ctx.tabRunOrigin = null;
|
|
41
|
+
}
|
|
30
42
|
ctx.grid.setActiveCell({
|
|
31
43
|
rowIndex,
|
|
32
44
|
colIndex,
|
|
@@ -51,7 +63,16 @@ export function createSelection(ctx) {
|
|
|
51
63
|
return;
|
|
52
64
|
if (colIndex < 0 || colIndex >= ctx.allColumns.length)
|
|
53
65
|
return;
|
|
54
|
-
|
|
66
|
+
const container = ctx.scrollContainer;
|
|
67
|
+
const topBefore = container.scrollTop;
|
|
68
|
+
const leftBefore = container.scrollLeft;
|
|
69
|
+
// A frozen row is always in view; only the column may need to move.
|
|
70
|
+
const frozen = ctx.frozenRowCount ?? 0;
|
|
71
|
+
const frozenBand = ctx.frozenBandHeight ?? 0;
|
|
72
|
+
if (rowIndex < frozen) {
|
|
73
|
+
// Always in view; only the column below may need to move.
|
|
74
|
+
}
|
|
75
|
+
else if (ctx.rowVirtualizationEnabled) {
|
|
55
76
|
// Prefer the browser's native `scrollIntoView({ block: 'nearest' })`
|
|
56
77
|
// when the target row is already mounted. It does Excel-style
|
|
57
78
|
// minimum-scroll, respects the sticky thead via the
|
|
@@ -99,8 +120,10 @@ export function createSelection(ctx) {
|
|
|
99
120
|
const rowHeight = ctx.virtualizer.getSizeForIndex(rowIndex);
|
|
100
121
|
const rowBottom = rowTopScroll + rowHeight;
|
|
101
122
|
let nextTop = currentTop;
|
|
102
|
-
|
|
103
|
-
|
|
123
|
+
// The frozen band sits under the header, so a row is hidden until
|
|
124
|
+
// it clears both.
|
|
125
|
+
if (rowTopScroll < currentTop + headerHeight + frozenBand) {
|
|
126
|
+
nextTop = rowTopScroll - headerHeight - frozenBand;
|
|
104
127
|
}
|
|
105
128
|
else if (rowBottom > currentTop + clientHeight) {
|
|
106
129
|
nextTop = rowBottom - clientHeight;
|
|
@@ -154,34 +177,65 @@ export function createSelection(ctx) {
|
|
|
154
177
|
else if (cellEnd > viewEnd) {
|
|
155
178
|
ctx.scrollContainer.scrollLeft = cellEnd - ctx.scrollContainer.clientWidth;
|
|
156
179
|
}
|
|
157
|
-
//
|
|
158
|
-
//
|
|
180
|
+
// The scroll position is known right here, so hand it to the
|
|
181
|
+
// virtualizers now rather than waiting for the `scroll` event + rAF:
|
|
182
|
+
// that put the new row window one painted frame behind the active-cell
|
|
183
|
+
// move (see `syncScrollNow`). Reading the position back is cheap - the
|
|
184
|
+
// scrollIntoView / scrollTop writes above already laid the tree out.
|
|
185
|
+
const topAfter = container.scrollTop;
|
|
186
|
+
const leftAfter = container.scrollLeft;
|
|
187
|
+
if (topAfter !== topBefore || leftAfter !== leftBefore) {
|
|
188
|
+
ctx.syncScrollNow(topAfter, leftAfter);
|
|
189
|
+
}
|
|
159
190
|
}
|
|
160
|
-
// Normalize a range to a rectangle, or null when incomplete.
|
|
191
|
+
// Normalize a range to a rectangle, or null when incomplete. A merge
|
|
192
|
+
// the rectangle touches is in it whole, as a spreadsheet's selection
|
|
193
|
+
// has it: a merged cell is one cell.
|
|
161
194
|
function rangeRect(range) {
|
|
162
195
|
const a = range?.anchor;
|
|
163
196
|
const f = range?.focus;
|
|
164
197
|
if (!a || !f)
|
|
165
198
|
return null;
|
|
166
|
-
return {
|
|
199
|
+
return expandRectToMerges(ctx.mergeIndex, {
|
|
167
200
|
minRow: Math.min(a.rowIndex, f.rowIndex),
|
|
168
201
|
maxRow: Math.max(a.rowIndex, f.rowIndex),
|
|
169
202
|
minCol: Math.min(a.colIndex, f.colIndex),
|
|
170
203
|
maxCol: Math.max(a.colIndex, f.colIndex),
|
|
171
|
-
};
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/** The active range as a rectangle, or null while nothing is anchored. */
|
|
207
|
+
function activeRangeRect() {
|
|
208
|
+
return rangeRect(ctx.selectionRange);
|
|
172
209
|
}
|
|
210
|
+
// Memo for `getSelectionRects`, keyed on the identity of its two inputs.
|
|
211
|
+
// Both are replaced wholesale on every change and never mutated in place,
|
|
212
|
+
// so identity is a complete change check. Without it, every rendered
|
|
213
|
+
// cell's outline derived rebuilt this array on every arrow key - ~300
|
|
214
|
+
// arrays plus their rect objects per key press, for a result that is the
|
|
215
|
+
// same until the selection moves.
|
|
216
|
+
let rectsForRange = null;
|
|
217
|
+
let rectsForRanges = null;
|
|
218
|
+
let rectsMemo = [];
|
|
173
219
|
// Every selected rectangle: the committed extra ranges plus the active one.
|
|
174
220
|
// Order matters for copy (added-order); the active range comes last.
|
|
221
|
+
// Callers must treat the result as read-only.
|
|
175
222
|
function getSelectionRects() {
|
|
223
|
+
const range = ctx.selectionRange;
|
|
224
|
+
const ranges = ctx.selectionRanges ?? [];
|
|
225
|
+
if (range === rectsForRange && ranges === rectsForRanges)
|
|
226
|
+
return rectsMemo;
|
|
176
227
|
const rects = [];
|
|
177
|
-
for (const r of
|
|
228
|
+
for (const r of ranges) {
|
|
178
229
|
const rect = rangeRect(r);
|
|
179
230
|
if (rect)
|
|
180
231
|
rects.push(rect);
|
|
181
232
|
}
|
|
182
|
-
const active = rangeRect(
|
|
233
|
+
const active = rangeRect(range);
|
|
183
234
|
if (active)
|
|
184
235
|
rects.push(active);
|
|
236
|
+
rectsForRange = range;
|
|
237
|
+
rectsForRanges = ranges;
|
|
238
|
+
rectsMemo = rects;
|
|
185
239
|
return rects;
|
|
186
240
|
}
|
|
187
241
|
function setSelection(rowIndex, colIndex, additive = false) {
|
|
@@ -240,6 +294,9 @@ export function createSelection(ctx) {
|
|
|
240
294
|
// that work to return null every time.
|
|
241
295
|
if (!hasAnySelectionRect())
|
|
242
296
|
return null;
|
|
297
|
+
// A td inside a merge draws to the merge's far corner, so its bottom and
|
|
298
|
+
// right edges are the merge's, not the cell's.
|
|
299
|
+
const end = endOf(ctx.mergeIndex, rowIndex, colIndex);
|
|
243
300
|
for (const rect of getSelectionRects()) {
|
|
244
301
|
if (rowIndex < rect.minRow ||
|
|
245
302
|
rowIndex > rect.maxRow ||
|
|
@@ -249,13 +306,39 @@ export function createSelection(ctx) {
|
|
|
249
306
|
}
|
|
250
307
|
return {
|
|
251
308
|
top: rowIndex === rect.minRow,
|
|
252
|
-
bottom: rowIndex === rect.maxRow,
|
|
309
|
+
bottom: end.rowIndex === rect.maxRow,
|
|
253
310
|
left: colIndex === rect.minCol,
|
|
254
|
-
right: colIndex === rect.maxCol,
|
|
311
|
+
right: end.colIndex === rect.maxCol,
|
|
255
312
|
};
|
|
256
313
|
}
|
|
257
314
|
return null;
|
|
258
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Everything a cell's outline needs from the selection model, in ONE value:
|
|
318
|
+
* whether it is the active cell, which range edges it sits on (`edges` is
|
|
319
|
+
* null when it is in no range) and whether it carries the fill handle.
|
|
320
|
+
* `null` for a cell that is none of those - nearly every cell.
|
|
321
|
+
*
|
|
322
|
+
* One value on purpose. The view reads it through a single `{@const}`, so
|
|
323
|
+
* an active-cell move re-marks one derived per rendered cell instead of
|
|
324
|
+
* three (active flag, range edges, fill handle) plus the fill handle's
|
|
325
|
+
* `{#if}`. With ~300 cells rendered, that marking was the largest single
|
|
326
|
+
* cost of an arrow key that does not scroll. A plain cell returns the same
|
|
327
|
+
* `null` it returned before the move, so its attribute effect stays put.
|
|
328
|
+
*/
|
|
329
|
+
function cellSelectionState(rowIndex, colIndex) {
|
|
330
|
+
const a = ctx.activeCell;
|
|
331
|
+
const active = !!a && a.rowIndex === rowIndex && a.colIndex === colIndex;
|
|
332
|
+
const edges = getCellRangeEdges(rowIndex, colIndex);
|
|
333
|
+
const fh = ctx.fillHandleCell;
|
|
334
|
+
// The handle sits on the range's bottom-right cell; when that is inside
|
|
335
|
+
// a merge, the td that draws the merge carries it.
|
|
336
|
+
const end = fh ? endOf(ctx.mergeIndex, rowIndex, colIndex) : null;
|
|
337
|
+
const fillHandle = !!fh && !!end && fh.rowIndex === end.rowIndex && fh.colIndex === end.colIndex;
|
|
338
|
+
if (!active && !edges && !fillHandle)
|
|
339
|
+
return null;
|
|
340
|
+
return { active, edges, fillHandle };
|
|
341
|
+
}
|
|
259
342
|
/**
|
|
260
343
|
* The rectangle a drag is currently promising, or null when no drag is in
|
|
261
344
|
* flight. A fill grows the source rectangle out to the pointer; a move
|
|
@@ -368,8 +451,13 @@ export function createSelection(ctx) {
|
|
|
368
451
|
? { rowIndex: active.rowIndex, colIndex: active.colIndex }
|
|
369
452
|
: null;
|
|
370
453
|
if (event.shiftKey) {
|
|
454
|
+
// The range grows to the clicked cell and the active cell stays where
|
|
455
|
+
// it is, as in Excel: it is the cell the formula bar shows and the
|
|
456
|
+
// one the next keystroke edits. Used to jump to the clicked corner,
|
|
457
|
+
// so a Shift+click to select B2:D5 then typing wrote into D5.
|
|
371
458
|
extendSelection(rowIndex, colIndex);
|
|
372
|
-
|
|
459
|
+
if (!active)
|
|
460
|
+
setActiveCell(rowIndex, colIndex);
|
|
373
461
|
}
|
|
374
462
|
else {
|
|
375
463
|
setActiveCell(rowIndex, colIndex);
|
|
@@ -390,8 +478,9 @@ export function createSelection(ctx) {
|
|
|
390
478
|
const row = ctx.allRows[rowIndex];
|
|
391
479
|
if (!row || isGroupRow(row))
|
|
392
480
|
return;
|
|
481
|
+
// The active cell is where the drag began; only the range's far corner
|
|
482
|
+
// follows the pointer.
|
|
393
483
|
extendSelection(rowIndex, colIndex);
|
|
394
|
-
setActiveCell(rowIndex, colIndex);
|
|
395
484
|
}
|
|
396
485
|
/** `event` is the window `pointerup` when this comes from the real gesture,
|
|
397
486
|
* and absent when `onWindowPointerMove` calls it to recover from a release
|
|
@@ -516,11 +605,12 @@ export function createSelection(ctx) {
|
|
|
516
605
|
return;
|
|
517
606
|
}
|
|
518
607
|
// onCellPointerDown already set active+selection for data cells. Only
|
|
519
|
-
// decide whether to enter edit mode (click on the previously-active cell
|
|
608
|
+
// decide whether to enter edit mode (click on the previously-active cell,
|
|
609
|
+
// unless the grid was told a second click is just a click).
|
|
520
610
|
const wasActive = ctx.activeAtPointerDown !== null &&
|
|
521
611
|
ctx.activeAtPointerDown.rowIndex === rowIndex &&
|
|
522
612
|
ctx.activeAtPointerDown.colIndex === colIndex;
|
|
523
|
-
if (wasActive && ctx.editingEnabled) {
|
|
613
|
+
if (wasActive && ctx.editingEnabled && ctx.props.editOnSecondClick !== false) {
|
|
524
614
|
ctx.onCellDoubleClick(rowIndex, colIndex);
|
|
525
615
|
return;
|
|
526
616
|
}
|
|
@@ -562,6 +652,8 @@ export function createSelection(ctx) {
|
|
|
562
652
|
extendSelection,
|
|
563
653
|
isCellInSelectedRange,
|
|
564
654
|
getCellRangeEdges,
|
|
655
|
+
activeRangeRect,
|
|
656
|
+
cellSelectionState,
|
|
565
657
|
fillMarqueeEdges,
|
|
566
658
|
getSelectionRects,
|
|
567
659
|
isInFillPreview,
|