@svgrid/grid 1.0.0 → 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/sv-grid-scrollbar.js +7 -1
- 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 +21 -2
- 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,15 @@
|
|
|
1
|
+
import { type RowData, type TableFeatures } from "./index";
|
|
2
|
+
import "./sv-grid-scrollbar";
|
|
3
|
+
export declare function createClipboard<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(ctx: any): {
|
|
4
|
+
readCellRaw: (rowIndex: number, columnId: string) => unknown;
|
|
5
|
+
writeCellRaw: (rowIndex: number, columnId: string, value: unknown) => void;
|
|
6
|
+
applyFillPattern: () => void;
|
|
7
|
+
clearSelectedCellValues: () => void;
|
|
8
|
+
startFillDrag: (event: PointerEvent, rowIndex: number, colIndex: number) => void;
|
|
9
|
+
onFillPointerMove: (event: PointerEvent) => void;
|
|
10
|
+
onFillPointerUp: () => void;
|
|
11
|
+
toggleBooleanCell: (rowIndex: number, colIndex: number) => void;
|
|
12
|
+
copySelectionToClipboard: () => void;
|
|
13
|
+
clearSelectedCells: () => boolean;
|
|
14
|
+
cutSelectionToClipboard: () => Promise<void>;
|
|
15
|
+
};
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
// clipboard handlers extracted from the controller. Imperative event handlers
|
|
2
|
+
// that read/write controller state via the `ctx` handle; the reactive core
|
|
3
|
+
// ($state/$derived/$effect) stays in the controller.
|
|
4
|
+
import { parseEditorValue, } from "./index";
|
|
5
|
+
import "./sv-grid-scrollbar";
|
|
6
|
+
import { buildFillPattern } from "./fill-patterns";
|
|
7
|
+
import { getCellKey, } from "./SvGrid.helpers";
|
|
8
|
+
import { getColumnBaseValue, isGroupRow, } from "./cell-values";
|
|
9
|
+
export function createClipboard(ctx) {
|
|
10
|
+
/** Read the raw underlying value for the cell at (rowIndex, columnId)
|
|
11
|
+
* for pattern extraction. */
|
|
12
|
+
function readCellRaw(rowIndex, columnId) {
|
|
13
|
+
const row = ctx.internalData[rowIndex];
|
|
14
|
+
const column = ctx.findColumnById(columnId);
|
|
15
|
+
if (!row || !column?.columnDef.field)
|
|
16
|
+
return undefined;
|
|
17
|
+
return row[column.columnDef.field];
|
|
18
|
+
}
|
|
19
|
+
/** Write a value into (rowIndex, columnId) without going through the
|
|
20
|
+
* edit lifecycle. Fires `onCellValueChange` per write so consumers
|
|
21
|
+
* can react (formula recompute, autosave, etc.). */
|
|
22
|
+
function writeCellRaw(rowIndex, columnId, value) {
|
|
23
|
+
const row = ctx.internalData[rowIndex];
|
|
24
|
+
const column = ctx.findColumnById(columnId);
|
|
25
|
+
if (!row || !column?.columnDef.field)
|
|
26
|
+
return;
|
|
27
|
+
const field = column.columnDef.field;
|
|
28
|
+
const oldValue = row[field];
|
|
29
|
+
if (oldValue === value)
|
|
30
|
+
return;
|
|
31
|
+
// Resolve the row's id BEFORE swapping internalData - otherwise the
|
|
32
|
+
// recomputed `allRows` references the new row object and the
|
|
33
|
+
// `r.original === row` lookup fails, dropping our edit out of the
|
|
34
|
+
// `editedCellValues` map (which getCellDisplayValue consults first).
|
|
35
|
+
const rowId = ctx.allRows.find((r) => r.original === row)?.id;
|
|
36
|
+
const next = ctx.internalData.slice();
|
|
37
|
+
next[rowIndex] = { ...row, [field]: value };
|
|
38
|
+
ctx.internalData = next;
|
|
39
|
+
if (rowId) {
|
|
40
|
+
const key = getCellKey(rowId, columnId);
|
|
41
|
+
ctx.editedCellValues = { ...ctx.editedCellValues, [key]: value };
|
|
42
|
+
}
|
|
43
|
+
ctx.props.onCellValueChange?.({
|
|
44
|
+
rowIndex,
|
|
45
|
+
columnId,
|
|
46
|
+
oldValue,
|
|
47
|
+
newValue: value,
|
|
48
|
+
row: next[rowIndex],
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** Apply the pattern fill on pointerup. Each NEW row (or column) is
|
|
52
|
+
* filled from a pattern derived from the matching column (or row) of
|
|
53
|
+
* the source. Handles all four drag directions. */
|
|
54
|
+
function applyFillPattern() {
|
|
55
|
+
const d = ctx.fillDrag;
|
|
56
|
+
if (!d)
|
|
57
|
+
return;
|
|
58
|
+
// Clear fillDrag FIRST so a thrown error doesn't leave the grid
|
|
59
|
+
// stuck tracking the pointer.
|
|
60
|
+
ctx.fillDrag = null;
|
|
61
|
+
const newMinRow = Math.min(d.sourceMinRow, d.targetRow);
|
|
62
|
+
const newMaxRow = Math.max(d.sourceMaxRow, d.targetRow);
|
|
63
|
+
const newMinCol = Math.min(d.sourceMinCol, d.targetCol);
|
|
64
|
+
const newMaxCol = Math.max(d.sourceMaxCol, d.targetCol);
|
|
65
|
+
const verticalExtension = newMaxRow > d.sourceMaxRow || newMinRow < d.sourceMinRow;
|
|
66
|
+
const horizontalExtension = newMaxCol > d.sourceMaxCol || newMinCol < d.sourceMinCol;
|
|
67
|
+
if (verticalExtension) {
|
|
68
|
+
// For each column in the source range, build a pattern from the
|
|
69
|
+
// column's source values and apply to the new rows (above or below).
|
|
70
|
+
for (let c = d.sourceMinCol; c <= d.sourceMaxCol; c += 1) {
|
|
71
|
+
const column = ctx.allColumns[c];
|
|
72
|
+
if (!column?.columnDef.field)
|
|
73
|
+
continue;
|
|
74
|
+
if (column.columnDef.editable === false)
|
|
75
|
+
continue;
|
|
76
|
+
const sourceColValues = [];
|
|
77
|
+
for (let r = d.sourceMinRow; r <= d.sourceMaxRow; r += 1) {
|
|
78
|
+
sourceColValues.push(readCellRaw(r, column.id));
|
|
79
|
+
}
|
|
80
|
+
if (newMaxRow > d.sourceMaxRow) {
|
|
81
|
+
const targetRows = newMaxRow - d.sourceMaxRow;
|
|
82
|
+
const fills = buildFillPattern(sourceColValues, targetRows);
|
|
83
|
+
for (let i = 0; i < targetRows; i += 1) {
|
|
84
|
+
const targetRow = d.sourceMaxRow + 1 + i;
|
|
85
|
+
if (ctx.isCellEditableAt(targetRow, c))
|
|
86
|
+
writeCellRaw(targetRow, column.id, fills[i]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (newMinRow < d.sourceMinRow) {
|
|
90
|
+
// Filling upward - reverse-extrapolate.
|
|
91
|
+
const reversed = sourceColValues.slice().reverse();
|
|
92
|
+
const targetRows = d.sourceMinRow - newMinRow;
|
|
93
|
+
const fills = buildFillPattern(reversed, targetRows);
|
|
94
|
+
for (let i = 0; i < targetRows; i += 1) {
|
|
95
|
+
const targetRow = d.sourceMinRow - 1 - i;
|
|
96
|
+
if (ctx.isCellEditableAt(targetRow, c))
|
|
97
|
+
writeCellRaw(targetRow, column.id, fills[i]);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else if (horizontalExtension) {
|
|
103
|
+
// For each row in source range, build pattern from the row's source
|
|
104
|
+
// values across columns and apply to new columns.
|
|
105
|
+
for (let r = d.sourceMinRow; r <= d.sourceMaxRow; r += 1) {
|
|
106
|
+
const sourceRowValues = [];
|
|
107
|
+
for (let c = d.sourceMinCol; c <= d.sourceMaxCol; c += 1) {
|
|
108
|
+
const col = ctx.allColumns[c];
|
|
109
|
+
if (!col)
|
|
110
|
+
continue;
|
|
111
|
+
sourceRowValues.push(readCellRaw(r, col.id));
|
|
112
|
+
}
|
|
113
|
+
if (newMaxCol > d.sourceMaxCol) {
|
|
114
|
+
const targetCols = newMaxCol - d.sourceMaxCol;
|
|
115
|
+
const fills = buildFillPattern(sourceRowValues, targetCols);
|
|
116
|
+
for (let i = 0; i < targetCols; i += 1) {
|
|
117
|
+
const targetCol = d.sourceMaxCol + 1 + i;
|
|
118
|
+
const col = ctx.allColumns[targetCol];
|
|
119
|
+
if (col && ctx.isCellEditableAt(r, targetCol))
|
|
120
|
+
writeCellRaw(r, col.id, fills[i]);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (newMinCol < d.sourceMinCol) {
|
|
124
|
+
const reversed = sourceRowValues.slice().reverse();
|
|
125
|
+
const targetCols = d.sourceMinCol - newMinCol;
|
|
126
|
+
const fills = buildFillPattern(reversed, targetCols);
|
|
127
|
+
for (let i = 0; i < targetCols; i += 1) {
|
|
128
|
+
const targetCol = d.sourceMinCol - 1 - i;
|
|
129
|
+
const col = ctx.allColumns[targetCol];
|
|
130
|
+
if (col && ctx.isCellEditableAt(r, targetCol))
|
|
131
|
+
writeCellRaw(r, col.id, fills[i]);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Extend the selection to the new range so the user can immediately
|
|
137
|
+
// see what got filled.
|
|
138
|
+
ctx.selectionRange = {
|
|
139
|
+
anchor: { rowIndex: newMinRow, colIndex: newMinCol },
|
|
140
|
+
focus: { rowIndex: newMaxRow, colIndex: newMaxCol },
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/** Clear the underlying value of every cell in the current selection
|
|
144
|
+
* range (or just the active cell when nothing is range-selected).
|
|
145
|
+
* Mirrors Excel's `Delete` key - values go to `null`, formatting and
|
|
146
|
+
* the row identity stay intact. */
|
|
147
|
+
function clearSelectedCellValues() {
|
|
148
|
+
const anchor = ctx.selectionRange.anchor;
|
|
149
|
+
const focus = ctx.selectionRange.focus;
|
|
150
|
+
if (anchor && focus) {
|
|
151
|
+
const minRow = Math.min(anchor.rowIndex, focus.rowIndex);
|
|
152
|
+
const maxRow = Math.max(anchor.rowIndex, focus.rowIndex);
|
|
153
|
+
const minCol = Math.min(anchor.colIndex, focus.colIndex);
|
|
154
|
+
const maxCol = Math.max(anchor.colIndex, focus.colIndex);
|
|
155
|
+
for (let r = minRow; r <= maxRow; r += 1) {
|
|
156
|
+
for (let c = minCol; c <= maxCol; c += 1) {
|
|
157
|
+
const col = ctx.allColumns[c];
|
|
158
|
+
if (col?.columnDef.field && ctx.isCellEditableAt(r, c)) {
|
|
159
|
+
writeCellRaw(r, col.id, null);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const a = ctx.grid.getState().activeCell;
|
|
166
|
+
if (a && ctx.userHasActivatedCell) {
|
|
167
|
+
const col = ctx.allColumns[a.colIndex];
|
|
168
|
+
if (col?.columnDef.field && ctx.isCellEditableAt(a.rowIndex, a.colIndex)) {
|
|
169
|
+
writeCellRaw(a.rowIndex, col.id, null);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/** Fill-handle pointerdown - seed the drag with the current selection
|
|
174
|
+
* range (or active cell as a 1x1) and start tracking the pointer. */
|
|
175
|
+
function startFillDrag(event, rowIndex, colIndex) {
|
|
176
|
+
event.stopPropagation();
|
|
177
|
+
event.preventDefault();
|
|
178
|
+
const anchor = ctx.selectionRange.anchor;
|
|
179
|
+
const focus = ctx.selectionRange.focus;
|
|
180
|
+
if (anchor && focus) {
|
|
181
|
+
ctx.fillDrag = {
|
|
182
|
+
sourceMinRow: Math.min(anchor.rowIndex, focus.rowIndex),
|
|
183
|
+
sourceMaxRow: Math.max(anchor.rowIndex, focus.rowIndex),
|
|
184
|
+
sourceMinCol: Math.min(anchor.colIndex, focus.colIndex),
|
|
185
|
+
sourceMaxCol: Math.max(anchor.colIndex, focus.colIndex),
|
|
186
|
+
targetRow: rowIndex,
|
|
187
|
+
targetCol: colIndex,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
ctx.fillDrag = {
|
|
192
|
+
sourceMinRow: rowIndex,
|
|
193
|
+
sourceMaxRow: rowIndex,
|
|
194
|
+
sourceMinCol: colIndex,
|
|
195
|
+
sourceMaxCol: colIndex,
|
|
196
|
+
targetRow: rowIndex,
|
|
197
|
+
targetCol: colIndex,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
// Don't `setPointerCapture` - we use `elementFromPoint` during the
|
|
201
|
+
// drag to find the hovered cell, and capture would route the events
|
|
202
|
+
// back to the handle, breaking the lookup. Window-level handlers
|
|
203
|
+
// (`onWindowPointerMove` / `endDragSelection`) keep tracking.
|
|
204
|
+
}
|
|
205
|
+
/** Pointermove during fill-drag. We don't get cell coords from the
|
|
206
|
+
* event directly - find the td under the pointer via elementFromPoint
|
|
207
|
+
* and read its data-svgrid-row / data-svgrid-col attributes. */
|
|
208
|
+
function onFillPointerMove(event) {
|
|
209
|
+
if (!ctx.fillDrag)
|
|
210
|
+
return;
|
|
211
|
+
const el = document.elementFromPoint(event.clientX, event.clientY);
|
|
212
|
+
const cell = el?.closest("td[data-svgrid-row][data-svgrid-col]");
|
|
213
|
+
if (!cell)
|
|
214
|
+
return;
|
|
215
|
+
const r = Number(cell.dataset.svgridRow);
|
|
216
|
+
const c = Number(cell.dataset.svgridCol);
|
|
217
|
+
if (!Number.isFinite(r) || !Number.isFinite(c))
|
|
218
|
+
return;
|
|
219
|
+
if (r === ctx.fillDrag.targetRow && c === ctx.fillDrag.targetCol)
|
|
220
|
+
return;
|
|
221
|
+
ctx.fillDrag = { ...ctx.fillDrag, targetRow: r, targetCol: c };
|
|
222
|
+
}
|
|
223
|
+
function onFillPointerUp() {
|
|
224
|
+
if (!ctx.fillDrag)
|
|
225
|
+
return;
|
|
226
|
+
applyFillPattern();
|
|
227
|
+
}
|
|
228
|
+
function toggleBooleanCell(rowIndex, colIndex) {
|
|
229
|
+
const row = ctx.allRows[rowIndex];
|
|
230
|
+
const column = ctx.allColumns[colIndex];
|
|
231
|
+
if (!row || !column)
|
|
232
|
+
return;
|
|
233
|
+
if (!column.columnDef.field)
|
|
234
|
+
return;
|
|
235
|
+
const baseValue = getColumnBaseValue(row, column);
|
|
236
|
+
const currentValue = Boolean(ctx.getCellDisplayValue(row.id, column.id, baseValue));
|
|
237
|
+
const nextValue = !currentValue;
|
|
238
|
+
row.original[column.columnDef.field] =
|
|
239
|
+
nextValue;
|
|
240
|
+
const key = getCellKey(row.id, column.id);
|
|
241
|
+
ctx.editedCellValues = {
|
|
242
|
+
...ctx.editedCellValues,
|
|
243
|
+
[key]: nextValue,
|
|
244
|
+
};
|
|
245
|
+
ctx.grid.store.setState((prev) => ({ ...prev }));
|
|
246
|
+
}
|
|
247
|
+
function copySelectionToClipboard() {
|
|
248
|
+
const anchor = ctx.selectionRange.anchor;
|
|
249
|
+
const focus = ctx.selectionRange.focus;
|
|
250
|
+
if (!anchor || !focus)
|
|
251
|
+
return;
|
|
252
|
+
const minRow = Math.min(anchor.rowIndex, focus.rowIndex);
|
|
253
|
+
const maxRow = Math.max(anchor.rowIndex, focus.rowIndex);
|
|
254
|
+
const minCol = Math.min(anchor.colIndex, focus.colIndex);
|
|
255
|
+
const maxCol = Math.max(anchor.colIndex, focus.colIndex);
|
|
256
|
+
const lines = [];
|
|
257
|
+
for (let r = minRow; r <= maxRow; r += 1) {
|
|
258
|
+
const row = ctx.allRows[r];
|
|
259
|
+
if (!row || isGroupRow(row))
|
|
260
|
+
continue;
|
|
261
|
+
const cells = [];
|
|
262
|
+
for (let c = minCol; c <= maxCol; c += 1) {
|
|
263
|
+
const column = ctx.allColumns[c];
|
|
264
|
+
if (!column) {
|
|
265
|
+
cells.push("");
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const base = getColumnBaseValue(row, column);
|
|
269
|
+
const display = ctx.getCellDisplayValue(row.id, column.id, base);
|
|
270
|
+
cells.push(String(display ?? ""));
|
|
271
|
+
}
|
|
272
|
+
lines.push(cells.join("\t"));
|
|
273
|
+
}
|
|
274
|
+
const text = lines.join("\n");
|
|
275
|
+
void navigator.clipboard?.writeText(text).catch(() => { });
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Clear every editable cell in the current selection range. Used by
|
|
279
|
+
* Ctrl/Cmd+X (after a copy) and by the Delete / Backspace keys.
|
|
280
|
+
* Returns true if anything was changed - the caller uses that to
|
|
281
|
+
* decide whether to call `preventDefault()` and refresh the store.
|
|
282
|
+
*/
|
|
283
|
+
function clearSelectedCells() {
|
|
284
|
+
const anchor = ctx.selectionRange.anchor ?? ctx.grid.getState().activeCell;
|
|
285
|
+
if (!anchor)
|
|
286
|
+
return false;
|
|
287
|
+
const focus = ctx.selectionRange.focus ?? anchor;
|
|
288
|
+
const startRow = Math.min(anchor.rowIndex, focus.rowIndex);
|
|
289
|
+
const startCol = Math.min(anchor.colIndex, focus.colIndex);
|
|
290
|
+
const endRow = Math.max(anchor.rowIndex, focus.rowIndex);
|
|
291
|
+
const endCol = Math.max(anchor.colIndex, focus.colIndex);
|
|
292
|
+
const next = ctx.internalData.slice();
|
|
293
|
+
let mutated = false;
|
|
294
|
+
for (let r = startRow; r <= endRow; r += 1) {
|
|
295
|
+
const row = ctx.allRows[r];
|
|
296
|
+
if (!row || isGroupRow(row))
|
|
297
|
+
continue;
|
|
298
|
+
const dataIndex = Number(row.id);
|
|
299
|
+
if (!Number.isInteger(dataIndex) ||
|
|
300
|
+
dataIndex < 0 ||
|
|
301
|
+
dataIndex >= next.length)
|
|
302
|
+
continue;
|
|
303
|
+
const originalRow = next[dataIndex];
|
|
304
|
+
if (!originalRow)
|
|
305
|
+
continue;
|
|
306
|
+
const updated = {
|
|
307
|
+
...originalRow,
|
|
308
|
+
};
|
|
309
|
+
let rowChanged = false;
|
|
310
|
+
for (let c = startCol; c <= endCol; c += 1) {
|
|
311
|
+
const column = ctx.allColumns[c];
|
|
312
|
+
if (!column?.columnDef.field)
|
|
313
|
+
continue;
|
|
314
|
+
if (!ctx.isCellEditableAt(r, c))
|
|
315
|
+
continue;
|
|
316
|
+
// Clear means: empty string for text, undefined for everything
|
|
317
|
+
// else. parseEditorValue handles the per-type coercion.
|
|
318
|
+
const editorType = (column.columnDef.editorType ??
|
|
319
|
+
"text");
|
|
320
|
+
updated[column.columnDef.field] = parseEditorValue(editorType, "");
|
|
321
|
+
rowChanged = true;
|
|
322
|
+
}
|
|
323
|
+
if (rowChanged) {
|
|
324
|
+
next[dataIndex] = updated;
|
|
325
|
+
mutated = true;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (mutated) {
|
|
329
|
+
ctx.internalData = next;
|
|
330
|
+
ctx.grid.store.setState((prev) => ({ ...prev }));
|
|
331
|
+
}
|
|
332
|
+
return mutated;
|
|
333
|
+
}
|
|
334
|
+
async function cutSelectionToClipboard() {
|
|
335
|
+
// Cut = copy + clear. Wait for the copy to land on the clipboard so
|
|
336
|
+
// a slow writeText can't race the clear and leave the user with no
|
|
337
|
+
// way to undo via paste.
|
|
338
|
+
copySelectionToClipboard();
|
|
339
|
+
// Best-effort flush; clipboard.writeText is fire-and-forget but we
|
|
340
|
+
// already kicked it off above. The clear is synchronous.
|
|
341
|
+
clearSelectedCells();
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
readCellRaw,
|
|
345
|
+
writeCellRaw,
|
|
346
|
+
applyFillPattern,
|
|
347
|
+
clearSelectedCellValues,
|
|
348
|
+
startFillDrag,
|
|
349
|
+
onFillPointerMove,
|
|
350
|
+
onFillPointerUp,
|
|
351
|
+
toggleBooleanCell,
|
|
352
|
+
copySelectionToClipboard,
|
|
353
|
+
clearSelectedCells,
|
|
354
|
+
cutSelectionToClipboard,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type RowData, type TableFeatures } from "./index";
|
|
2
|
+
import "./sv-grid-scrollbar";
|
|
3
|
+
export declare function createColumns<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(ctx: any): {
|
|
4
|
+
cellPinStyle: (columnId: string) => string;
|
|
5
|
+
isColumnPinned: (columnId: string) => "left" | "right" | null;
|
|
6
|
+
getCurrentColumnOrder: () => string[];
|
|
7
|
+
emitColumnOrder: () => void;
|
|
8
|
+
setColumnOrderInternal: (ids: ReadonlyArray<string>) => void;
|
|
9
|
+
applyColumnDrop: (dragId: string, targetId: string, side: "before" | "after") => void;
|
|
10
|
+
onColumnHeaderDragStart: (e: DragEvent, columnId: string) => void;
|
|
11
|
+
onColumnHeaderDragOver: (e: DragEvent, columnId: string) => void;
|
|
12
|
+
onColumnHeaderDragLeave: (columnId: string) => void;
|
|
13
|
+
onColumnHeaderDrop: (e: DragEvent, columnId: string) => void;
|
|
14
|
+
onColumnHeaderDragEnd: () => void;
|
|
15
|
+
pinColumnLeft: (columnId: string) => void;
|
|
16
|
+
pinColumnRight: (columnId: string) => void;
|
|
17
|
+
unpinColumn: (columnId: string) => void;
|
|
18
|
+
toggleColumnVisibleInPanel: (columnId: string) => void;
|
|
19
|
+
moveColumnInPanel: (columnId: string, dir: -1 | 1) => void;
|
|
20
|
+
toggleGroupInPanel: (columnId: string) => void;
|
|
21
|
+
getColumnBaseWidth: (columnId: string) => any;
|
|
22
|
+
getColumnWidth: (columnId: string) => any;
|
|
23
|
+
startColumnResize: (event: PointerEvent, columnId: string) => void;
|
|
24
|
+
onColumnResizeMove: (event: PointerEvent) => void;
|
|
25
|
+
endColumnResize: () => void;
|
|
26
|
+
measureText: (text: string, font: string) => number;
|
|
27
|
+
autosizeColumn: (columnId: string) => void;
|
|
28
|
+
autosizeAllColumns: () => void;
|
|
29
|
+
resetColumns: () => void;
|
|
30
|
+
};
|
package/dist/columns.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import "./sv-grid-scrollbar";
|
|
2
|
+
export function createColumns(ctx) {
|
|
3
|
+
function cellPinStyle(columnId) {
|
|
4
|
+
// z-index 30 - higher than the active-cell / selection-range stacking
|
|
5
|
+
// context (z=20) so a selected cell in the scrollable middle never
|
|
6
|
+
// bleeds over the pinned columns during horizontal scroll. Still
|
|
7
|
+
// sits below dropdowns (z=900+) and the column menu.
|
|
8
|
+
const leftOffset = ctx.pinnedOffsets.left[columnId];
|
|
9
|
+
if (leftOffset !== undefined) {
|
|
10
|
+
return `position: sticky; left: ${leftOffset}px; z-index: 30;`;
|
|
11
|
+
}
|
|
12
|
+
const rightOffset = ctx.pinnedOffsets.right[columnId];
|
|
13
|
+
if (rightOffset !== undefined) {
|
|
14
|
+
return `position: sticky; right: ${rightOffset}px; z-index: 30;`;
|
|
15
|
+
}
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
function isColumnPinned(columnId) {
|
|
19
|
+
if (ctx.columnPinning.left.includes(columnId))
|
|
20
|
+
return "left";
|
|
21
|
+
if (ctx.columnPinning.right.includes(columnId))
|
|
22
|
+
return "right";
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
/** Compute the current full column order as displayed (pinned-left
|
|
26
|
+
* first, unpinned in the middle, pinned-right last). The order
|
|
27
|
+
* emitted via `onColumnOrderChange` matches what the user sees. */
|
|
28
|
+
function getCurrentColumnOrder() {
|
|
29
|
+
return ctx.allColumns.map((c) => c.id);
|
|
30
|
+
}
|
|
31
|
+
function emitColumnOrder() {
|
|
32
|
+
ctx.props.onColumnOrderChange?.(getCurrentColumnOrder());
|
|
33
|
+
}
|
|
34
|
+
function setColumnOrderInternal(ids) {
|
|
35
|
+
ctx.userColumnOrder = [...ids];
|
|
36
|
+
emitColumnOrder();
|
|
37
|
+
}
|
|
38
|
+
/** Drop `dragId` before / after `targetId` in the user order. We
|
|
39
|
+
* rebuild a clean order out of the currently-displayed columns so
|
|
40
|
+
* hidden columns are unaffected and pin groups stay logically
|
|
41
|
+
* separate (you can reorder freely within left-pinned / unpinned /
|
|
42
|
+
* right-pinned, but a drop across pin zones is allowed - the cell
|
|
43
|
+
* just lands in whichever zone the target belongs to). */
|
|
44
|
+
function applyColumnDrop(dragId, targetId, side) {
|
|
45
|
+
if (dragId === targetId)
|
|
46
|
+
return;
|
|
47
|
+
const current = getCurrentColumnOrder();
|
|
48
|
+
const without = current.filter((id) => id !== dragId);
|
|
49
|
+
let idx = without.indexOf(targetId);
|
|
50
|
+
if (idx < 0)
|
|
51
|
+
return;
|
|
52
|
+
if (side === "after")
|
|
53
|
+
idx++;
|
|
54
|
+
without.splice(idx, 0, dragId);
|
|
55
|
+
setColumnOrderInternal(without);
|
|
56
|
+
}
|
|
57
|
+
function onColumnHeaderDragStart(e, columnId) {
|
|
58
|
+
if (!(ctx.props.enableColumnReorder ?? false))
|
|
59
|
+
return;
|
|
60
|
+
ctx.colDragId = columnId;
|
|
61
|
+
e.dataTransfer?.setData("text/plain", columnId);
|
|
62
|
+
e.dataTransfer.effectAllowed = "move";
|
|
63
|
+
}
|
|
64
|
+
function onColumnHeaderDragOver(e, columnId) {
|
|
65
|
+
if (!ctx.colDragId || ctx.colDragId === columnId)
|
|
66
|
+
return;
|
|
67
|
+
e.preventDefault();
|
|
68
|
+
e.dataTransfer.dropEffect = "move";
|
|
69
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
70
|
+
ctx.colDropSide = e.clientX < rect.left + rect.width / 2 ? "before" : "after";
|
|
71
|
+
ctx.colDropOnId = columnId;
|
|
72
|
+
}
|
|
73
|
+
function onColumnHeaderDragLeave(columnId) {
|
|
74
|
+
if (ctx.colDropOnId === columnId) {
|
|
75
|
+
ctx.colDropOnId = null;
|
|
76
|
+
ctx.colDropSide = null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function onColumnHeaderDrop(e, columnId) {
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
if (ctx.colDragId && ctx.colDropSide)
|
|
82
|
+
applyColumnDrop(ctx.colDragId, columnId, ctx.colDropSide);
|
|
83
|
+
ctx.colDragId = null;
|
|
84
|
+
ctx.colDropOnId = null;
|
|
85
|
+
ctx.colDropSide = null;
|
|
86
|
+
}
|
|
87
|
+
function onColumnHeaderDragEnd() {
|
|
88
|
+
ctx.colDragId = null;
|
|
89
|
+
ctx.colDropOnId = null;
|
|
90
|
+
ctx.colDropSide = null;
|
|
91
|
+
}
|
|
92
|
+
function pinColumnLeft(columnId) {
|
|
93
|
+
const left = ctx.columnPinning.left.filter((id) => id !== columnId);
|
|
94
|
+
const right = ctx.columnPinning.right.filter((id) => id !== columnId);
|
|
95
|
+
ctx.columnPinning = { left: [...left, columnId], right };
|
|
96
|
+
ctx.closeMenus();
|
|
97
|
+
}
|
|
98
|
+
function pinColumnRight(columnId) {
|
|
99
|
+
const left = ctx.columnPinning.left.filter((id) => id !== columnId);
|
|
100
|
+
const right = ctx.columnPinning.right.filter((id) => id !== columnId);
|
|
101
|
+
ctx.columnPinning = { left, right: [columnId, ...right] };
|
|
102
|
+
ctx.closeMenus();
|
|
103
|
+
}
|
|
104
|
+
function unpinColumn(columnId) {
|
|
105
|
+
ctx.columnPinning = {
|
|
106
|
+
left: ctx.columnPinning.left.filter((id) => id !== columnId),
|
|
107
|
+
right: ctx.columnPinning.right.filter((id) => id !== columnId),
|
|
108
|
+
};
|
|
109
|
+
ctx.closeMenus();
|
|
110
|
+
}
|
|
111
|
+
function toggleColumnVisibleInPanel(columnId) {
|
|
112
|
+
if (ctx.hiddenColumns[columnId]) {
|
|
113
|
+
const next = { ...ctx.hiddenColumns };
|
|
114
|
+
delete next[columnId];
|
|
115
|
+
ctx.hiddenColumns = next;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
ctx.hiddenColumns = { ...ctx.hiddenColumns, [columnId]: true };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function moveColumnInPanel(columnId, dir) {
|
|
122
|
+
const current = ctx.toolPanelColumns.map((c) => c.id);
|
|
123
|
+
const i = current.indexOf(columnId);
|
|
124
|
+
const j = i + dir;
|
|
125
|
+
if (i < 0 || j < 0 || j >= current.length)
|
|
126
|
+
return;
|
|
127
|
+
[current[i], current[j]] = [current[j], current[i]];
|
|
128
|
+
ctx.userColumnOrder = current;
|
|
129
|
+
}
|
|
130
|
+
function toggleGroupInPanel(columnId) {
|
|
131
|
+
const g = (ctx.grid.getState().grouping ?? []);
|
|
132
|
+
ctx.grid.setGrouping(g.includes(columnId)
|
|
133
|
+
? g.filter((x) => x !== columnId)
|
|
134
|
+
: [...g, columnId]);
|
|
135
|
+
}
|
|
136
|
+
/** Width before fitColumns scaling - what the columnDef/user actually set. */
|
|
137
|
+
function getColumnBaseWidth(columnId) {
|
|
138
|
+
if (ctx.columnWidths[columnId] !== undefined)
|
|
139
|
+
return ctx.columnWidths[columnId];
|
|
140
|
+
const column = ctx.grid.getAllColumns().find((c) => c.id === columnId);
|
|
141
|
+
if (column?.columnDef.width !== undefined)
|
|
142
|
+
return column.columnDef.width;
|
|
143
|
+
return ctx.props.columnWidth ?? 140;
|
|
144
|
+
}
|
|
145
|
+
function getColumnWidth(columnId) {
|
|
146
|
+
const fitted = ctx.fittedColumnWidths?.[columnId];
|
|
147
|
+
if (fitted !== undefined && ctx.columnWidths[columnId] === undefined)
|
|
148
|
+
return fitted;
|
|
149
|
+
return getColumnBaseWidth(columnId);
|
|
150
|
+
}
|
|
151
|
+
function startColumnResize(event, columnId) {
|
|
152
|
+
event.stopPropagation();
|
|
153
|
+
event.preventDefault();
|
|
154
|
+
ctx.resizingColumnId = columnId;
|
|
155
|
+
ctx.resizeStartX = event.clientX;
|
|
156
|
+
ctx.resizeStartWidth = getColumnWidth(columnId);
|
|
157
|
+
document.addEventListener("pointermove", onColumnResizeMove);
|
|
158
|
+
document.addEventListener("pointerup", endColumnResize);
|
|
159
|
+
document.addEventListener("pointercancel", endColumnResize);
|
|
160
|
+
}
|
|
161
|
+
function onColumnResizeMove(event) {
|
|
162
|
+
if (!ctx.resizingColumnId)
|
|
163
|
+
return;
|
|
164
|
+
// Coalesce updates onto the animation frame: pointermove can fire many
|
|
165
|
+
// times per frame, and each $state mutation triggers a full reactive
|
|
166
|
+
// recompute of the column-layout pipeline. Without rAF coalescing the
|
|
167
|
+
// grid stutters during the drag.
|
|
168
|
+
ctx.resizePendingWidth = Math.max(ctx.MIN_COLUMN_WIDTH, ctx.resizeStartWidth + (event.clientX - ctx.resizeStartX));
|
|
169
|
+
if (ctx.resizeRaf !== null)
|
|
170
|
+
return;
|
|
171
|
+
ctx.resizeRaf = requestAnimationFrame(() => {
|
|
172
|
+
ctx.resizeRaf = null;
|
|
173
|
+
if (!ctx.resizingColumnId)
|
|
174
|
+
return;
|
|
175
|
+
ctx.columnWidths = {
|
|
176
|
+
...ctx.columnWidths,
|
|
177
|
+
[ctx.resizingColumnId]: ctx.resizePendingWidth,
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function endColumnResize() {
|
|
182
|
+
if (ctx.resizeRaf !== null) {
|
|
183
|
+
cancelAnimationFrame(ctx.resizeRaf);
|
|
184
|
+
ctx.resizeRaf = null;
|
|
185
|
+
}
|
|
186
|
+
if (ctx.resizingColumnId && ctx.resizePendingWidth) {
|
|
187
|
+
// Make sure the final width is committed even if the last rAF was
|
|
188
|
+
// canceled mid-flight.
|
|
189
|
+
ctx.columnWidths = {
|
|
190
|
+
...ctx.columnWidths,
|
|
191
|
+
[ctx.resizingColumnId]: ctx.resizePendingWidth,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
ctx.resizingColumnId = null;
|
|
195
|
+
document.removeEventListener("pointermove", onColumnResizeMove);
|
|
196
|
+
document.removeEventListener("pointerup", endColumnResize);
|
|
197
|
+
document.removeEventListener("pointercancel", endColumnResize);
|
|
198
|
+
}
|
|
199
|
+
function measureText(text, font) {
|
|
200
|
+
if (!text)
|
|
201
|
+
return 0;
|
|
202
|
+
if (!ctx.measureCanvas)
|
|
203
|
+
ctx.measureCanvas = document.createElement("canvas");
|
|
204
|
+
const c2d = ctx.measureCanvas.getContext("2d");
|
|
205
|
+
if (!c2d)
|
|
206
|
+
return 0;
|
|
207
|
+
c2d.font = font;
|
|
208
|
+
return c2d.measureText(text).width;
|
|
209
|
+
}
|
|
210
|
+
/** Snap a column to the width of its widest visible cell (header + body). */
|
|
211
|
+
function autosizeColumn(columnId) {
|
|
212
|
+
if (!ctx.gridRootEl)
|
|
213
|
+
return;
|
|
214
|
+
const sampleCell = ctx.gridRootEl.querySelector(`[data-col-id="${CSS.escape(columnId)}"]`);
|
|
215
|
+
if (!sampleCell)
|
|
216
|
+
return;
|
|
217
|
+
const cellFont = getComputedStyle(sampleCell).font;
|
|
218
|
+
let max = ctx.MIN_COLUMN_WIDTH;
|
|
219
|
+
const header = ctx.gridRootEl.querySelector(`[data-svgrid-header-col="${CSS.escape(columnId)}"]`);
|
|
220
|
+
if (header) {
|
|
221
|
+
const labelEl = header.querySelector(".sv-grid-header-label");
|
|
222
|
+
const target = labelEl ?? header;
|
|
223
|
+
const text = target.textContent ?? "";
|
|
224
|
+
// +70 reserves room for sort indicator + funnel + 3-dot menu button
|
|
225
|
+
max = Math.max(max, measureText(text, getComputedStyle(target).font) + 70);
|
|
226
|
+
}
|
|
227
|
+
const cells = ctx.gridRootEl.querySelectorAll(`[data-col-id="${CSS.escape(columnId)}"]`);
|
|
228
|
+
cells.forEach((cell) => {
|
|
229
|
+
const text = cell.textContent ?? "";
|
|
230
|
+
const w = measureText(text, cellFont);
|
|
231
|
+
if (w > max)
|
|
232
|
+
max = w;
|
|
233
|
+
});
|
|
234
|
+
// cell horizontal padding (~16px) + 8px breathing room
|
|
235
|
+
ctx.columnWidths = {
|
|
236
|
+
...ctx.columnWidths,
|
|
237
|
+
[columnId]: Math.max(ctx.MIN_COLUMN_WIDTH, Math.ceil(max) + 24),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function autosizeAllColumns() {
|
|
241
|
+
for (const column of ctx.allColumns)
|
|
242
|
+
autosizeColumn(column.id);
|
|
243
|
+
}
|
|
244
|
+
function resetColumns() {
|
|
245
|
+
ctx.columnWidths = {};
|
|
246
|
+
ctx.hiddenColumns = {};
|
|
247
|
+
ctx.columnPinning = { left: [], right: [] };
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
cellPinStyle,
|
|
251
|
+
isColumnPinned,
|
|
252
|
+
getCurrentColumnOrder,
|
|
253
|
+
emitColumnOrder,
|
|
254
|
+
setColumnOrderInternal,
|
|
255
|
+
applyColumnDrop,
|
|
256
|
+
onColumnHeaderDragStart,
|
|
257
|
+
onColumnHeaderDragOver,
|
|
258
|
+
onColumnHeaderDragLeave,
|
|
259
|
+
onColumnHeaderDrop,
|
|
260
|
+
onColumnHeaderDragEnd,
|
|
261
|
+
pinColumnLeft,
|
|
262
|
+
pinColumnRight,
|
|
263
|
+
unpinColumn,
|
|
264
|
+
toggleColumnVisibleInPanel,
|
|
265
|
+
moveColumnInPanel,
|
|
266
|
+
toggleGroupInPanel,
|
|
267
|
+
getColumnBaseWidth,
|
|
268
|
+
getColumnWidth,
|
|
269
|
+
startColumnResize,
|
|
270
|
+
onColumnResizeMove,
|
|
271
|
+
endColumnResize,
|
|
272
|
+
measureText,
|
|
273
|
+
autosizeColumn,
|
|
274
|
+
autosizeAllColumns,
|
|
275
|
+
resetColumns,
|
|
276
|
+
};
|
|
277
|
+
}
|
package/dist/core.d.ts
CHANGED
|
@@ -110,7 +110,7 @@ export type ColumnDef<TFeatures extends TableFeatures, TData extends RowData> =
|
|
|
110
110
|
footer?: ColumnDefTemplate<HeaderContext<TData>>;
|
|
111
111
|
cell?: ColumnDefTemplate<CellContext<TData>>;
|
|
112
112
|
columns?: Array<ColumnDef<TFeatures, TData>>;
|
|
113
|
-
editorType?: 'text' | 'number' | 'date' | 'datetime' | 'time' | 'password' | 'checkbox' | 'list' | 'chips' | 'select' | 'rich-select' | 'textarea' | 'color' | 'rating';
|
|
113
|
+
editorType?: 'text' | 'number' | 'date' | 'datetime' | 'time' | 'password' | 'checkbox' | 'list' | 'chips' | 'select' | 'rich-select' | 'autocomplete' | 'textarea' | 'color' | 'rating';
|
|
114
114
|
/**
|
|
115
115
|
* Custom in-cell editor. Receives the cell context PLUS a `commit(value)`
|
|
116
116
|
* and `cancel()` helper. Use when none of the built-in `editorType`s fit;
|