@svgrid/grid 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +137 -39
- package/dist/GridFooter.svelte +164 -0
- package/dist/GridFooter.svelte.d.ts +29 -0
- package/dist/GridMenus.svelte +570 -0
- package/dist/GridMenus.svelte.d.ts +31 -0
- package/dist/SvGrid.controller.svelte.d.ts +429 -0
- package/dist/SvGrid.controller.svelte.js +1732 -0
- package/dist/SvGrid.css +1709 -0
- package/dist/SvGrid.helpers.d.ts +35 -0
- package/dist/SvGrid.helpers.js +160 -0
- package/dist/SvGrid.svelte +344 -7043
- package/dist/SvGrid.svelte.d.ts +4 -357
- package/dist/SvGrid.types.d.ts +436 -0
- package/dist/SvGrid.types.js +1 -0
- package/dist/SvGridChart.svelte +1060 -23
- package/dist/SvGridChart.svelte.d.ts +17 -0
- package/dist/build-api.d.ts +5 -0
- package/dist/build-api.js +527 -0
- package/dist/cell-render.d.ts +15 -0
- package/dist/cell-render.js +246 -0
- package/dist/cell-values.d.ts +28 -0
- package/dist/cell-values.js +89 -0
- package/dist/chart.d.ts +370 -3
- package/dist/chart.js +1135 -42
- package/dist/clipboard.d.ts +15 -0
- package/dist/clipboard.js +356 -0
- package/dist/columns.d.ts +30 -0
- package/dist/columns.js +277 -0
- package/dist/core.d.ts +1 -1
- package/dist/css.d.ts +3 -0
- package/dist/editing.d.ts +24 -0
- package/dist/editing.js +343 -0
- package/dist/editors/cell-editors.d.ts +1 -1
- package/dist/facet-buckets.d.ts +13 -0
- package/dist/facet-buckets.js +54 -0
- package/dist/features.d.ts +5 -0
- package/dist/features.js +30 -0
- package/dist/filter-operators.d.ts +16 -0
- package/dist/filter-operators.js +69 -0
- package/dist/hyperformula-adapter.d.ts +82 -0
- package/dist/hyperformula-adapter.js +73 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +5 -2
- package/dist/keyboard-handlers.d.ts +7 -0
- package/dist/keyboard-handlers.js +197 -0
- package/dist/menus.d.ts +40 -0
- package/dist/menus.js +389 -0
- package/dist/named-views.d.ts +27 -0
- package/dist/named-views.js +39 -0
- package/dist/row-resize.d.ts +43 -0
- package/dist/row-resize.js +158 -0
- package/dist/scroll-sync.d.ts +9 -0
- package/dist/scroll-sync.js +86 -0
- package/dist/selection.d.ts +26 -0
- package/dist/selection.js +387 -0
- package/dist/spreadsheet.d.ts +80 -0
- package/dist/spreadsheet.js +194 -0
- package/dist/summaries.d.ts +12 -0
- package/dist/summaries.js +65 -0
- package/dist/svgrid-wrapper.types.d.ts +12 -1
- package/dist/svgrid.comments-autocomplete.test.d.ts +1 -0
- package/dist/svgrid.comments-autocomplete.test.js +96 -0
- package/dist/svgrid.context-menu.test.d.ts +1 -0
- package/dist/svgrid.context-menu.test.js +102 -0
- package/dist/svgrid.new-features.wrapper.test.js +30 -4
- package/dist/svgrid.wrapper.test.js +27 -1
- package/dist/virtualization/column-virtualizer.d.ts +2 -0
- package/dist/virtualization/scroll-scaling.d.ts +28 -0
- package/dist/virtualization/scroll-scaling.js +64 -0
- package/dist/virtualization/scroll-scaling.test.d.ts +1 -0
- package/dist/virtualization/scroll-scaling.test.js +86 -0
- package/dist/virtualization/svelte-virtualizer.svelte.d.ts +2 -0
- package/dist/virtualization/svelte-virtualizer.svelte.js +2 -0
- package/dist/virtualization/virtualizer.d.ts +7 -0
- package/dist/virtualization/virtualizer.js +30 -0
- package/package.json +1 -1
- package/src/GridFooter.svelte +164 -0
- package/src/GridMenus.svelte +570 -0
- package/src/SvGrid.controller.svelte.ts +2195 -0
- package/src/SvGrid.css +1747 -0
- package/src/SvGrid.helpers.test.ts +415 -0
- package/src/SvGrid.helpers.ts +185 -0
- package/src/SvGrid.svelte +348 -7043
- package/src/SvGrid.types.ts +456 -0
- package/src/SvGridChart.svelte +1060 -23
- package/src/build-api.coverage.test.ts +532 -0
- package/src/build-api.ts +663 -0
- package/src/cell-render.test.ts +451 -0
- package/src/cell-render.ts +426 -0
- package/src/cell-values.ts +114 -0
- package/src/chart-export.test.ts +370 -0
- package/src/chart.coverage.test.ts +814 -0
- package/src/chart.ts +1352 -47
- package/src/clipboard.test.ts +731 -0
- package/src/clipboard.ts +524 -0
- package/src/collaboration.coverage.test.ts +220 -0
- package/src/columns.test.ts +702 -0
- package/src/columns.ts +419 -0
- package/src/core.ts +8 -0
- package/src/css.d.ts +3 -0
- package/src/editing.test.ts +837 -0
- package/src/editing.ts +513 -0
- package/src/editors/cell-editors.coverage.test.ts +156 -0
- package/src/editors/cell-editors.ts +1 -0
- package/src/facet-buckets.test.ts +353 -0
- package/src/facet-buckets.ts +67 -0
- package/src/features.ts +128 -0
- package/src/filter-operators.test.ts +174 -0
- package/src/filter-operators.ts +87 -0
- package/src/hyperformula-adapter.test.ts +256 -0
- package/src/hyperformula-adapter.ts +124 -0
- package/src/index.ts +37 -0
- package/src/keyboard-handlers.coverage.test.ts +560 -0
- package/src/keyboard-handlers.ts +353 -0
- package/src/keyboard.ts +97 -97
- package/src/menus.test.ts +620 -0
- package/src/menus.ts +554 -0
- package/src/named-views.coverage.test.ts +210 -0
- package/src/named-views.ts +48 -0
- package/src/row-resize.test.ts +369 -0
- package/src/row-resize.ts +171 -0
- package/src/scroll-sync.test.ts +330 -0
- package/src/scroll-sync.ts +216 -0
- package/src/selection.test.ts +722 -0
- package/src/selection.ts +545 -0
- package/src/server-data-source.coverage.test.ts +180 -0
- package/src/spreadsheet.test.ts +445 -0
- package/src/spreadsheet.ts +246 -0
- package/src/summaries.ts +204 -0
- package/src/sv-grid-scrollbar.ts +13 -1
- package/src/svgrid-wrapper.types.ts +12 -1
- package/src/svgrid.behavior.test.ts +22 -0
- package/src/svgrid.comments-autocomplete.test.ts +112 -0
- package/src/svgrid.context-menu.test.ts +126 -0
- package/src/svgrid.interaction.test.ts +30 -0
- package/src/svgrid.new-features.wrapper.test.ts +65 -4
- package/src/svgrid.wrapper.test.ts +27 -1
- package/src/test-setup.ts +9 -6
- package/src/virtualization/scroll-scaling.test.ts +148 -0
- package/src/virtualization/scroll-scaling.ts +121 -0
- package/src/virtualization/svelte-virtualizer.svelte.ts +2 -0
- package/src/virtualization/virtualizer.ts +26 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HyperFormula adapter — Excel-class formula evaluation for SvGrid.
|
|
3
|
+
*
|
|
4
|
+
* `hyperformula` is an OPTIONAL peer dependency. Consumers who want
|
|
5
|
+
* full Excel-compatible formulas install it themselves:
|
|
6
|
+
*
|
|
7
|
+
* ```bash
|
|
8
|
+
* pnpm add hyperformula
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* The adapter wraps an HF instance around the grid's flat-row data:
|
|
12
|
+
*
|
|
13
|
+
* - Treats each `data[]` row as a spreadsheet row
|
|
14
|
+
* - Each registered field maps to a spreadsheet column
|
|
15
|
+
* - Values that start with `=` are evaluated by HF
|
|
16
|
+
* - The adapter returns the computed rows ready to render
|
|
17
|
+
* - On edit, call `update(rowIdx, field, value)` and the adapter
|
|
18
|
+
* re-evaluates only the cells HF tells it are dirty
|
|
19
|
+
*
|
|
20
|
+
* Why not bundle HF: it's ~1MB minified and 99% of grids never need it.
|
|
21
|
+
* Keeping it peer-optional means tiny default bundle + heavy-formula
|
|
22
|
+
* users get the ~400 functions (VLOOKUP, INDIRECT, IFS, XLOOKUP, full
|
|
23
|
+
* date/time/financial libraries) on demand.
|
|
24
|
+
*/
|
|
25
|
+
/** Build a live spreadsheet adapter around a HyperFormula instance.
|
|
26
|
+
* Returns computed rows + an `update()` hook to push edits back into
|
|
27
|
+
* the engine. */
|
|
28
|
+
export function createHyperFormulaSheet(config) {
|
|
29
|
+
const { hyperformula: hf, rows, fields } = config;
|
|
30
|
+
const sheetId = config.sheetId ?? 0;
|
|
31
|
+
const colByField = new Map();
|
|
32
|
+
fields.forEach((f, i) => colByField.set(f, i));
|
|
33
|
+
// 1. Seed HF with every cell. HF expects raw strings for formulas
|
|
34
|
+
// (`'=A1+B1'`) and primitives for everything else.
|
|
35
|
+
for (let r = 0; r < rows.length; r += 1) {
|
|
36
|
+
const row = rows[r];
|
|
37
|
+
for (let c = 0; c < fields.length; c += 1) {
|
|
38
|
+
const field = fields[c];
|
|
39
|
+
hf.setCellContents({ sheet: sheetId, row: r, col: c }, row[field]);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Pull computed values out of HF into a fresh row array. Preserves
|
|
43
|
+
* any non-formula fields (i.e. those not in `fields`) untouched. */
|
|
44
|
+
function snapshot() {
|
|
45
|
+
const out = new Array(rows.length);
|
|
46
|
+
for (let r = 0; r < rows.length; r += 1) {
|
|
47
|
+
const next = { ...rows[r] };
|
|
48
|
+
for (let c = 0; c < fields.length; c += 1) {
|
|
49
|
+
const field = fields[c];
|
|
50
|
+
const v = hf.getCellValue({ sheet: sheetId, row: r, col: c });
|
|
51
|
+
next[field] = v;
|
|
52
|
+
}
|
|
53
|
+
out[r] = next;
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
function rawSnapshot() {
|
|
58
|
+
return rows.map((r) => ({ ...r }));
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
computed: snapshot(),
|
|
62
|
+
raw: rawSnapshot(),
|
|
63
|
+
update(rowIndex, field, value) {
|
|
64
|
+
const col = colByField.get(field);
|
|
65
|
+
if (col !== undefined) {
|
|
66
|
+
hf.setCellContents({ sheet: sheetId, row: rowIndex, col }, value);
|
|
67
|
+
}
|
|
68
|
+
rows[rowIndex] = { ...rows[rowIndex], [field]: value };
|
|
69
|
+
return { computed: snapshot(), raw: rawSnapshot() };
|
|
70
|
+
},
|
|
71
|
+
destroy() { hf.destroy(); },
|
|
72
|
+
};
|
|
73
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,12 +7,15 @@ export { default as SvGrid } from './SvGrid.svelte';
|
|
|
7
7
|
export { default as FlexRender } from './FlexRender.svelte';
|
|
8
8
|
export { renderComponent, renderSnippet } from './render-component';
|
|
9
9
|
export { default as SvGridChart } from './SvGridChart.svelte';
|
|
10
|
-
export { buildChart, rowsToChartSpec, niceScale, DEFAULT_PALETTE, type ChartType, type ChartSpec, type ChartSeries, type ChartGeometry, type ChartBar, type ChartLine, type ChartLinePoint, type ChartPieSlice, type ChartSelection, type ChartReferenceLine, type ChartRefLineGeo, type ChartRefLineGeoV, type ChartScatterDot, type ScatterPoint, type NiceScale, } from './chart';
|
|
10
|
+
export { buildChart, rowsToChartSpec, niceScale, niceLogScale, linearTrend, simpleMovingAverage, exponentialMovingAverage, computeOverlay, buildLinePath, sampleGradient, pickContrastText, DEFAULT_PALETTE, type ChartType, type ChartSpec, type ChartSeries, type ChartGeometry, type ChartBar, 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 TreeNode, } from './chart';
|
|
11
11
|
export { chartToSvgString, downloadChartSvg, chartToPngBlob, downloadChartPng, type ChartExportOptions, } from './chart-export';
|
|
12
12
|
export { buildSparkline, toSparklineValues, type SparklineConfig, type SparklineType, type SparklineGeometry, } from './sparkline';
|
|
13
|
+
export { spreadsheetLayout, type SpreadsheetActionOptions, type MergeSpec, type CellBorderSpec, type BorderSpec, } from './spreadsheet';
|
|
14
|
+
export { rowResize, type RowResizeOptions } from './row-resize';
|
|
15
|
+
export { createHyperFormulaSheet, type HyperFormulaSheet, type HyperFormulaSheetConfig, type HyperFormulaInstance, } from './hyperformula-adapter';
|
|
13
16
|
export { createCollaboration, broadcastChannelTransport, type CollabUser, type CollabCell, type CollabPresence, type CollabMessage, type CollabTransport, type Collaboration, } from './collaboration';
|
|
14
17
|
export { createServerDataSource, type ServerDataSource, type ServerRequest, type ServerResult, type ServerController, type ServerState, type ServerSortModel, type ServerFilterModel, } from './server-data-source';
|
|
15
|
-
export { createNamedViews, memoryViews, localStorageViews, type SavedView, type ViewStorage, type NamedViews, } from './named-views';
|
|
18
|
+
export { createNamedViews, memoryViews, localStorageViews, attachAutoSavedView, type SavedView, type ViewStorage, type NamedViews, type AutoSavedViewOptions, } from './named-views';
|
|
16
19
|
export { resolveCellFormat, computeColumnStat, lerpColor, contrastText, type ConditionalFormat, type ConditionalFormatSpec, type ColorScaleFormat, type DataBarFormat, type IconSetFormat, type RuleFormat, type ResolvedCellFormat, } from './conditional-formatting';
|
|
17
20
|
export { getKeyboardIntent, getNextActiveCell, type GridKeyboardIntent } from './keyboard';
|
|
18
21
|
export { createVirtualizer } from './virtualization/virtualizer';
|
package/dist/index.js
CHANGED
|
@@ -7,12 +7,15 @@ export { default as SvGrid } from './SvGrid.svelte';
|
|
|
7
7
|
export { default as FlexRender } from './FlexRender.svelte';
|
|
8
8
|
export { renderComponent, renderSnippet } from './render-component';
|
|
9
9
|
export { default as SvGridChart } from './SvGridChart.svelte';
|
|
10
|
-
export { buildChart, rowsToChartSpec, niceScale, DEFAULT_PALETTE, } from './chart';
|
|
10
|
+
export { buildChart, rowsToChartSpec, niceScale, niceLogScale, linearTrend, simpleMovingAverage, exponentialMovingAverage, computeOverlay, buildLinePath, sampleGradient, pickContrastText, DEFAULT_PALETTE, } from './chart';
|
|
11
11
|
export { chartToSvgString, downloadChartSvg, chartToPngBlob, downloadChartPng, } from './chart-export';
|
|
12
12
|
export { buildSparkline, toSparklineValues, } from './sparkline';
|
|
13
|
+
export { spreadsheetLayout, } from './spreadsheet';
|
|
14
|
+
export { rowResize } from './row-resize';
|
|
15
|
+
export { createHyperFormulaSheet, } from './hyperformula-adapter';
|
|
13
16
|
export { createCollaboration, broadcastChannelTransport, } from './collaboration';
|
|
14
17
|
export { createServerDataSource, } from './server-data-source';
|
|
15
|
-
export { createNamedViews, memoryViews, localStorageViews, } from './named-views';
|
|
18
|
+
export { createNamedViews, memoryViews, localStorageViews, attachAutoSavedView, } from './named-views';
|
|
16
19
|
export { resolveCellFormat, computeColumnStat, lerpColor, contrastText, } from './conditional-formatting';
|
|
17
20
|
export { getKeyboardIntent, getNextActiveCell } from './keyboard';
|
|
18
21
|
export { createVirtualizer } from './virtualization/virtualizer';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type RowData, type TableFeatures } from "./index";
|
|
2
|
+
import "./sv-grid-scrollbar";
|
|
3
|
+
export declare function createKeyboard<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(ctx: any): {
|
|
4
|
+
onGridKeyDown: (event: KeyboardEvent) => void;
|
|
5
|
+
onWindowKeydown: (event: KeyboardEvent) => void;
|
|
6
|
+
onHeaderSortClick: (event: MouseEvent, columnId: string) => void;
|
|
7
|
+
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import "./sv-grid-scrollbar";
|
|
2
|
+
import { getKeyboardIntent, getNextActiveCell } from "./keyboard";
|
|
3
|
+
export function createKeyboard(ctx) {
|
|
4
|
+
function onGridKeyDown(event) {
|
|
5
|
+
// Only the grid root drives navigation - keys on header buttons, menus,
|
|
6
|
+
// or the cell editor are handled by those controls themselves.
|
|
7
|
+
if (event.target !== event.currentTarget)
|
|
8
|
+
return;
|
|
9
|
+
if (ctx.editingCell)
|
|
10
|
+
return;
|
|
11
|
+
if ((event.ctrlKey || event.metaKey) && !event.altKey) {
|
|
12
|
+
const lower = event.key.toLowerCase();
|
|
13
|
+
if (lower === "c") {
|
|
14
|
+
event.preventDefault();
|
|
15
|
+
ctx.copySelectionToClipboard();
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (lower === "v") {
|
|
19
|
+
event.preventDefault();
|
|
20
|
+
void ctx.pasteFromClipboard();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (lower === "x") {
|
|
24
|
+
event.preventDefault();
|
|
25
|
+
void ctx.cutSelectionToClipboard();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// Ctrl+Z (Cmd+Z) undoes the most recent cell edit. Ctrl+Shift+Z
|
|
29
|
+
// and Ctrl+Y both redo. Mirrors VSCode / Sheets / Excel.
|
|
30
|
+
if (lower === "z" && !event.shiftKey) {
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
if (ctx.historyPtr >= 0) {
|
|
33
|
+
const step = ctx.history[ctx.historyPtr];
|
|
34
|
+
if (step) {
|
|
35
|
+
ctx.applyHistoryStep(step, 'undo');
|
|
36
|
+
ctx.historyPtr -= 1;
|
|
37
|
+
ctx.historyVersion += 1;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if ((lower === "z" && event.shiftKey) || lower === "y") {
|
|
43
|
+
event.preventDefault();
|
|
44
|
+
if (ctx.historyPtr < ctx.history.length - 1) {
|
|
45
|
+
const step = ctx.history[ctx.historyPtr + 1];
|
|
46
|
+
if (step) {
|
|
47
|
+
ctx.applyHistoryStep(step, 'redo');
|
|
48
|
+
ctx.historyPtr += 1;
|
|
49
|
+
ctx.historyVersion += 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Ctrl+F opens the find overlay.
|
|
55
|
+
if (lower === "f") {
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
ctx.findOpen = true;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Esc closes find when nothing else owns the key.
|
|
62
|
+
if (event.key === "Escape" && ctx.findOpen) {
|
|
63
|
+
event.preventDefault();
|
|
64
|
+
ctx.findOpen = false;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Delete / Backspace clears every editable cell in the selection
|
|
68
|
+
// range. No clipboard interaction - this is the "blank the cells I
|
|
69
|
+
// have selected" gesture, distinct from Ctrl/Cmd+X.
|
|
70
|
+
if ((event.key === "Delete" || event.key === "Backspace") &&
|
|
71
|
+
!event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
72
|
+
if (ctx.clearSelectedCells()) {
|
|
73
|
+
event.preventDefault();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const current = ctx.grid.getState().activeCell ?? {
|
|
78
|
+
rowIndex: 0,
|
|
79
|
+
colIndex: 0,
|
|
80
|
+
cellId: null,
|
|
81
|
+
};
|
|
82
|
+
if (event.key === "F2") {
|
|
83
|
+
event.preventDefault();
|
|
84
|
+
ctx.onCellDoubleClick(current.rowIndex, current.colIndex);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const intent = getKeyboardIntent(event);
|
|
88
|
+
if (intent === "noop") {
|
|
89
|
+
// A printable character on the active cell starts editing seeded with it.
|
|
90
|
+
if (event.key.length === 1 &&
|
|
91
|
+
!event.ctrlKey &&
|
|
92
|
+
!event.metaKey &&
|
|
93
|
+
!event.altKey) {
|
|
94
|
+
if (ctx.startEditingWithChar(current.rowIndex, current.colIndex, event.key)) {
|
|
95
|
+
event.preventDefault();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
if (intent === "clearCells") {
|
|
102
|
+
// Excel `Delete` - clear contents of every cell in the selection
|
|
103
|
+
// (or the active cell if no range). Formatting is left alone, only
|
|
104
|
+
// the underlying value is wiped.
|
|
105
|
+
ctx.clearSelectedCellValues();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (intent === "activate") {
|
|
109
|
+
const row = ctx.allRows[current.rowIndex];
|
|
110
|
+
const column = ctx.allColumns[current.colIndex];
|
|
111
|
+
if (event.key === " ") {
|
|
112
|
+
row?.toggleSelected?.();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (event.ctrlKey && row?.getCanExpand?.()) {
|
|
116
|
+
row.toggleExpanded?.();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (column?.columnDef.editorType === "checkbox") {
|
|
120
|
+
ctx.toggleBooleanCell(current.rowIndex, current.colIndex);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
ctx.onCellDoubleClick(current.rowIndex, current.colIndex);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// Excel-style page step: PageUp/PageDown jump by ~one visible
|
|
127
|
+
// page minus one row of overlap. Falls back to grid pagination's
|
|
128
|
+
// pageSize when pagination is on, or 10 as a final fallback.
|
|
129
|
+
function pageStep() {
|
|
130
|
+
const pageSize = ctx.grid.getState().pagination?.pageSize;
|
|
131
|
+
if (pageSize && pageSize > 0)
|
|
132
|
+
return pageSize;
|
|
133
|
+
const clientHeight = ctx.scrollContainer?.clientHeight ?? 0;
|
|
134
|
+
const headerHeight = ctx.headerHeight ?? 0;
|
|
135
|
+
const rowHeight = typeof ctx.props.rowHeight === 'function'
|
|
136
|
+
? (ctx.props.rowHeight(current.rowIndex) ?? 30)
|
|
137
|
+
: (ctx.props.rowHeight ?? 30);
|
|
138
|
+
const usable = Math.max(0, clientHeight - headerHeight);
|
|
139
|
+
return Math.max(1, Math.floor(usable / Math.max(rowHeight, 1)) - 1);
|
|
140
|
+
}
|
|
141
|
+
const next = getNextActiveCell(current, intent, {
|
|
142
|
+
maxRow: Math.max(ctx.allRows.length - 1, 0),
|
|
143
|
+
maxCol: Math.max(ctx.allColumns.length - 1, 0),
|
|
144
|
+
pageSize: pageStep(),
|
|
145
|
+
});
|
|
146
|
+
ctx.setActiveCell(next.rowIndex, next.colIndex);
|
|
147
|
+
ctx.scrollActiveCellIntoView(next.rowIndex, next.colIndex);
|
|
148
|
+
// Shift extends the selection ONLY for arrow keys (Excel-style).
|
|
149
|
+
// Shift+Enter / Shift+Tab just change direction; they don't grow the
|
|
150
|
+
// range, otherwise hammering Shift+Tab to backspace through a row
|
|
151
|
+
// would paint a creeping rectangle behind the cursor.
|
|
152
|
+
const shouldExtend = event.shiftKey &&
|
|
153
|
+
(intent === "moveLeft" ||
|
|
154
|
+
intent === "moveRight" ||
|
|
155
|
+
intent === "moveUp" ||
|
|
156
|
+
intent === "moveDown");
|
|
157
|
+
if (shouldExtend)
|
|
158
|
+
ctx.extendSelection(next.rowIndex, next.colIndex);
|
|
159
|
+
else
|
|
160
|
+
ctx.setSelection(next.rowIndex, next.colIndex);
|
|
161
|
+
}
|
|
162
|
+
function onWindowKeydown(event) {
|
|
163
|
+
if (event.key === "Escape" && (ctx.columnMenuFor || ctx.operatorMenuFor)) {
|
|
164
|
+
ctx.closeMenus();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function onHeaderSortClick(event, columnId) {
|
|
168
|
+
const column = ctx.allColumns.find((entry) => entry.id === columnId);
|
|
169
|
+
if (!column?.getCanSort?.())
|
|
170
|
+
return;
|
|
171
|
+
const clauses = ctx.grid.getState().sorting ?? [];
|
|
172
|
+
const current = clauses.find((entry) => entry.id === columnId);
|
|
173
|
+
if (!event.shiftKey) {
|
|
174
|
+
// Single-sort: cycle this column's direction and clear all other
|
|
175
|
+
// sorts. Cycle order: none → asc → desc → none.
|
|
176
|
+
const nextClause = !current
|
|
177
|
+
? [{ id: columnId, desc: false }]
|
|
178
|
+
: current.desc
|
|
179
|
+
? []
|
|
180
|
+
: [{ id: columnId, desc: true }];
|
|
181
|
+
ctx.grid.store.setState((prev) => ({ ...prev, sorting: nextClause }));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
// Shift-click: append/toggle as part of a multi-sort.
|
|
185
|
+
const nextClause = !current
|
|
186
|
+
? [...clauses, { id: columnId, desc: false }]
|
|
187
|
+
: current.desc
|
|
188
|
+
? clauses.filter((entry) => entry.id !== columnId)
|
|
189
|
+
: clauses.map((entry) => entry.id === columnId ? { ...entry, desc: true } : entry);
|
|
190
|
+
ctx.grid.store.setState((prev) => ({ ...prev, sorting: nextClause }));
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
onGridKeyDown,
|
|
194
|
+
onWindowKeydown,
|
|
195
|
+
onHeaderSortClick,
|
|
196
|
+
};
|
|
197
|
+
}
|
package/dist/menus.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type RowData, type TableFeatures } from "./index";
|
|
2
|
+
import "./sv-grid-scrollbar";
|
|
3
|
+
import type { FilterOperator } from "./SvGrid.types";
|
|
4
|
+
export declare function createMenus<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(ctx: any): {
|
|
5
|
+
updateFilterRow: (columnId: string, value: string) => void;
|
|
6
|
+
updateFilterOperator: (columnId: string, operator: FilterOperator) => void;
|
|
7
|
+
updateFilterMenuValue: (columnId: string, value: string) => void;
|
|
8
|
+
updateFilterMenuValueTo: (columnId: string, valueTo: string) => void;
|
|
9
|
+
toggleCheckboxWithKeyboard: (event: KeyboardEvent, toggle: () => void) => void;
|
|
10
|
+
isColumnFiltered: (columnId: string) => boolean;
|
|
11
|
+
closeMenus: () => void;
|
|
12
|
+
openChooseColumns: (event: MouseEvent) => void;
|
|
13
|
+
openColumnMenu: (event: MouseEvent, columnId: string) => void;
|
|
14
|
+
openFilterMenu: (event: MouseEvent, columnId: string) => void;
|
|
15
|
+
openOperatorMenu: (event: MouseEvent, columnId: string) => void;
|
|
16
|
+
sortColumnFromMenu: (columnId: string, desc: boolean) => void;
|
|
17
|
+
clearColumnSort: (columnId: string) => void;
|
|
18
|
+
groupByColumnFromMenu: (columnId: string) => void;
|
|
19
|
+
clearGroupingFromMenu: (columnId: string) => void;
|
|
20
|
+
isFacetChecked: (columnId: string, value: string) => any;
|
|
21
|
+
toggleFacetValue: (columnId: string, value: string) => void;
|
|
22
|
+
isAllFacetsChecked: (columnId: string) => boolean;
|
|
23
|
+
toggleAllFacets: (columnId: string) => void;
|
|
24
|
+
clearColumnFilter: (columnId: string) => void;
|
|
25
|
+
changePage: (delta: number) => void;
|
|
26
|
+
goToPage: (pageIndex: number) => void;
|
|
27
|
+
setPageSize: (pageSize: number) => void;
|
|
28
|
+
openContextMenu: (event: MouseEvent, rowIndex: number, colIndex: number, columnId: string) => void;
|
|
29
|
+
closeContextMenu: () => void;
|
|
30
|
+
contextMenuItems: () => {
|
|
31
|
+
key: string;
|
|
32
|
+
label: string;
|
|
33
|
+
separator?: boolean;
|
|
34
|
+
disabled?: boolean;
|
|
35
|
+
run?: () => void;
|
|
36
|
+
}[];
|
|
37
|
+
saveComment: () => void;
|
|
38
|
+
removeComment: () => void;
|
|
39
|
+
closeCommentEditor: () => void;
|
|
40
|
+
};
|