@svgrid/grid 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/dist/GridMenus.svelte +205 -127
  2. package/dist/SvGrid.controller.svelte.d.ts +44 -1
  3. package/dist/SvGrid.controller.svelte.js +223 -38
  4. package/dist/SvGrid.css +2012 -1709
  5. package/dist/SvGrid.helpers.test.d.ts +1 -0
  6. package/dist/SvGrid.helpers.test.js +298 -0
  7. package/dist/SvGrid.svelte +2346 -2043
  8. package/dist/SvGrid.types.d.ts +91 -4
  9. package/dist/aligned-grids.d.ts +6 -0
  10. package/dist/aligned-grids.js +84 -0
  11. package/dist/aligned-grids.test.d.ts +1 -0
  12. package/dist/aligned-grids.test.js +75 -0
  13. package/dist/build-api.coverage.test.d.ts +20 -0
  14. package/dist/build-api.coverage.test.js +505 -0
  15. package/dist/build-api.js +59 -29
  16. package/dist/cell-render.test.d.ts +1 -0
  17. package/dist/cell-render.test.js +338 -0
  18. package/dist/chart-export.test.d.ts +1 -0
  19. package/dist/chart-export.test.js +302 -0
  20. package/dist/chart.coverage.test.d.ts +1 -0
  21. package/dist/chart.coverage.test.js +748 -0
  22. package/dist/clipboard.js +88 -24
  23. package/dist/clipboard.test.d.ts +1 -0
  24. package/dist/clipboard.test.js +700 -0
  25. package/dist/collaboration.coverage.test.d.ts +1 -0
  26. package/dist/collaboration.coverage.test.js +200 -0
  27. package/dist/column-groups.d.ts +19 -0
  28. package/dist/column-groups.js +62 -0
  29. package/dist/column-groups.test.d.ts +1 -0
  30. package/dist/column-groups.test.js +56 -0
  31. package/dist/column-types.d.ts +10 -0
  32. package/dist/column-types.js +63 -0
  33. package/dist/column-types.test.d.ts +1 -0
  34. package/dist/column-types.test.js +62 -0
  35. package/dist/columns.test.d.ts +1 -0
  36. package/dist/columns.test.js +625 -0
  37. package/dist/core.d.ts +85 -0
  38. package/dist/editing.d.ts +7 -0
  39. package/dist/editing.js +191 -5
  40. package/dist/editing.test.d.ts +1 -0
  41. package/dist/editing.test.js +732 -0
  42. package/dist/editors/cell-editors.coverage.test.d.ts +1 -0
  43. package/dist/editors/cell-editors.coverage.test.js +139 -0
  44. package/dist/facet-buckets.test.d.ts +1 -0
  45. package/dist/facet-buckets.test.js +296 -0
  46. package/dist/filter-operators.test.d.ts +1 -0
  47. package/dist/filter-operators.test.js +135 -0
  48. package/dist/hyperformula-adapter.test.d.ts +1 -0
  49. package/dist/hyperformula-adapter.test.js +205 -0
  50. package/dist/index.d.ts +5 -2
  51. package/dist/index.js +4 -1
  52. package/dist/keyboard-handlers.coverage.test.d.ts +1 -0
  53. package/dist/keyboard-handlers.coverage.test.js +495 -0
  54. package/dist/keyboard-handlers.js +7 -2
  55. package/dist/menus.js +1 -0
  56. package/dist/menus.test.d.ts +1 -0
  57. package/dist/menus.test.js +560 -0
  58. package/dist/named-views.coverage.test.d.ts +1 -0
  59. package/dist/named-views.coverage.test.js +180 -0
  60. package/dist/row-drag.d.ts +49 -0
  61. package/dist/row-drag.js +221 -0
  62. package/dist/row-drag.test.d.ts +1 -0
  63. package/dist/row-drag.test.js +142 -0
  64. package/dist/row-resize.test.d.ts +1 -0
  65. package/dist/row-resize.test.js +329 -0
  66. package/dist/scroll-sync.js +3 -0
  67. package/dist/scroll-sync.test.d.ts +1 -0
  68. package/dist/scroll-sync.test.js +290 -0
  69. package/dist/selection.d.ts +7 -1
  70. package/dist/selection.js +76 -36
  71. package/dist/selection.multi-range.test.d.ts +1 -0
  72. package/dist/selection.multi-range.test.js +55 -0
  73. package/dist/selection.test.d.ts +1 -0
  74. package/dist/selection.test.js +647 -0
  75. package/dist/server-data-source.coverage.test.d.ts +1 -0
  76. package/dist/server-data-source.coverage.test.js +154 -0
  77. package/dist/spreadsheet.d.ts +30 -0
  78. package/dist/spreadsheet.js +48 -0
  79. package/dist/spreadsheet.test.d.ts +1 -0
  80. package/dist/spreadsheet.test.js +446 -0
  81. package/dist/sv-grid-scrollbar.js +13 -1
  82. package/dist/svgrid-wrapper.types.d.ts +19 -0
  83. package/dist/svgrid.behavior.test.js +20 -0
  84. package/dist/svgrid.interaction.test.js +31 -0
  85. package/dist/svgrid.new-features.wrapper.test.js +34 -2
  86. package/dist/test-setup.js +9 -3
  87. package/dist/virtualization/scroll-scaling.d.ts +17 -0
  88. package/dist/virtualization/scroll-scaling.js +35 -0
  89. package/dist/virtualization/scroll-scaling.test.js +42 -1
  90. package/package.json +2 -1
  91. package/src/GridMenus.svelte +205 -127
  92. package/src/SvGrid.controller.svelte.ts +2352 -2195
  93. package/src/SvGrid.css +2012 -1747
  94. package/src/SvGrid.svelte +2346 -2047
  95. package/src/SvGrid.types.ts +537 -456
  96. package/src/aligned-grids.test.ts +80 -0
  97. package/src/aligned-grids.ts +87 -0
  98. package/src/build-api.ts +683 -663
  99. package/src/clipboard.test.ts +49 -0
  100. package/src/clipboard.ts +51 -23
  101. package/src/column-groups.test.ts +59 -0
  102. package/src/column-groups.ts +80 -0
  103. package/src/column-types.test.ts +68 -0
  104. package/src/column-types.ts +82 -0
  105. package/src/core.ts +78 -0
  106. package/src/editing.ts +669 -513
  107. package/src/index.ts +12 -0
  108. package/src/menus.ts +1 -0
  109. package/src/row-drag.test.ts +168 -0
  110. package/src/row-drag.ts +255 -0
  111. package/src/scroll-sync.ts +2 -0
  112. package/src/selection.multi-range.test.ts +61 -0
  113. package/src/selection.ts +71 -37
  114. package/src/spreadsheet.test.ts +489 -445
  115. package/src/spreadsheet.ts +304 -246
  116. package/src/svgrid-wrapper.types.ts +19 -0
  117. package/src/svgrid.new-features.wrapper.test.ts +2 -2
package/dist/core.d.ts CHANGED
@@ -37,6 +37,30 @@ export type CellContext<TData extends RowData> = {
37
37
  table: SvGrid<TData>;
38
38
  getValue: () => unknown;
39
39
  };
40
+ /** Params passed to a column's `colSpan(...)` / `rowSpan(...)` callbacks. */
41
+ export type CellSpanParams<TData extends RowData = RowData> = {
42
+ /** The row's underlying data object. */
43
+ data: TData;
44
+ /** Display-row index in the current (filtered/sorted) row set. */
45
+ rowIndex: number;
46
+ /** The column's id. */
47
+ columnId: string;
48
+ /** The cell's base value for this column. */
49
+ value: unknown;
50
+ };
51
+ /** Params passed to a column's `valueParser(...)` on edit commit. */
52
+ export type ValueParserParams<TData extends RowData = RowData> = {
53
+ /** The value after built-in per-`editorType` coercion. */
54
+ newValue: unknown;
55
+ /** The cell's previous value. */
56
+ oldValue: unknown;
57
+ /** The raw string the editor produced (pre-coercion). */
58
+ rawInput: string;
59
+ /** The row's underlying data object. */
60
+ data: TData;
61
+ /** The column's id. */
62
+ columnId: string;
63
+ };
40
64
  /**
41
65
  * Context passed to a custom `cellEditor` snippet/component. Three write
42
66
  * helpers cover the lifecycle:
@@ -110,6 +134,45 @@ export type ColumnDef<TFeatures extends TableFeatures, TData extends RowData> =
110
134
  footer?: ColumnDefTemplate<HeaderContext<TData>>;
111
135
  cell?: ColumnDefTemplate<CellContext<TData>>;
112
136
  columns?: Array<ColumnDef<TFeatures, TData>>;
137
+ /**
138
+ * Declarative cell spanning (merged cells). Return how many COLUMNS this
139
+ * cell spans to the right (1 = no span). Value-driven, AG-Grid-style. Feed
140
+ * `spansToMerges(rows, columns)` into `spreadsheetLayout` to apply - it uses
141
+ * the same real `colspan`/`rowspan` merge engine (no separate code path).
142
+ */
143
+ colSpan?: (params: CellSpanParams<TData>) => number;
144
+ /**
145
+ * Declarative cell spanning (merged cells). Return how many ROWS this cell
146
+ * spans downward (1 = no span). See `colSpan` for how to apply.
147
+ */
148
+ rowSpan?: (params: CellSpanParams<TData>) => number;
149
+ /**
150
+ * High-level data type for the column. A convenience that resolves to the
151
+ * right `editorType`, alignment, date `format`, and filter operators without
152
+ * setting each by hand:
153
+ * 'text' → text editor, left-aligned
154
+ * 'number' → number editor, right-aligned, numeric filter operators
155
+ * 'boolean' → checkbox editor, centered
156
+ * 'date' → date editor (Date values), right-aligned, `{ type: 'date' }` format
157
+ * 'dateString' → date editor for ISO date STRINGS (e.g. '2026-06-27')
158
+ * Anything you set explicitly (`editorType`, `align`, `format`) still wins -
159
+ * `cellDataType` only fills the gaps. Grid-level `inferColumnTypes` infers
160
+ * this from the first data row for columns that declare neither.
161
+ */
162
+ cellDataType?: 'text' | 'number' | 'boolean' | 'date' | 'dateString';
163
+ /**
164
+ * For a column INSIDE a collapsible column group: `'open'` shows this column
165
+ * only while the group is expanded, `'closed'` only while collapsed. Omit to
166
+ * always show it. Setting it on any direct child gives the parent group a
167
+ * collapse toggle. Pair with `openByDefault` on the group.
168
+ */
169
+ columnGroupShow?: 'open' | 'closed';
170
+ /**
171
+ * For a GROUP column (one with `columns: [...]`): start the group expanded.
172
+ * Defaults to `false` (collapsed), matching AG Grid - so only the always-on
173
+ * and `columnGroupShow: 'closed'` children show until the user expands it.
174
+ */
175
+ openByDefault?: boolean;
113
176
  editorType?: 'text' | 'number' | 'date' | 'datetime' | 'time' | 'password' | 'checkbox' | 'list' | 'chips' | 'select' | 'rich-select' | 'autocomplete' | 'textarea' | 'color' | 'rating';
114
177
  /**
115
178
  * Custom in-cell editor. Receives the cell context PLUS a `commit(value)`
@@ -143,6 +206,21 @@ export type ColumnDef<TFeatures extends TableFeatures, TData extends RowData> =
143
206
  * `false`.
144
207
  */
145
208
  editable?: boolean | ((context: CellContext<TData>) => boolean);
209
+ /**
210
+ * Transform the committed edit value before it is written to the row.
211
+ * Runs after the built-in per-`editorType` coercion, so `newValue` is
212
+ * already type-parsed; return the final value to store (e.g. round a
213
+ * number, uppercase a code, look up an id). AG-Grid-style `valueParser`.
214
+ */
215
+ valueParser?: (params: ValueParserParams<TData>) => unknown;
216
+ /**
217
+ * Briefly flash / highlight this column's cell when its value changes
218
+ * (streaming feeds, edits, server pushes). `true` uses the default flash;
219
+ * pass `{ className }` to apply your own animation class instead.
220
+ */
221
+ cellFlash?: boolean | {
222
+ className?: string;
223
+ };
146
224
  /**
147
225
  * When `false`, this column never shows a sort indicator and clicking
148
226
  * its header is a no-op - `api.setSort(thisColumn, ...)` is also
@@ -203,6 +281,13 @@ export type ColumnDef<TFeatures extends TableFeatures, TData extends RowData> =
203
281
  sparkline?: SparklineConfig;
204
282
  /** Initial column width in pixels. Falls back to the grid's `columnWidth` prop. */
205
283
  width?: number;
284
+ /**
285
+ * Initial visibility. Set `false` to start the column hidden while still
286
+ * listing it in the Choose Columns UI for the user to re-enable. Applied
287
+ * once at mount; after that `api.setColumnVisible` / user toggles win.
288
+ * On a group column, `false` hides the whole group's leaf columns.
289
+ */
290
+ visible?: boolean;
206
291
  /**
207
292
  * Horizontal alignment for header and body cells. When omitted, the
208
293
  * default is inferred from `editorType`:
package/dist/editing.d.ts CHANGED
@@ -13,6 +13,12 @@ export declare function createEditing<TFeatures extends TableFeatures = TableFea
13
13
  getRowColumnValue: (row: Row<TData>, columnId: string) => unknown;
14
14
  getCellDisplayValue: (rowId: string, columnId: string, baseValue: unknown) => any;
15
15
  startEditingWithChar: (rowIndex: number, colIndex: number, char: string) => boolean;
16
+ startEditing: (rowIndex: number, columnId: string) => boolean;
17
+ stopEditing: (cancel?: boolean) => boolean;
18
+ startFullRowEdit: (rowIndex: number) => boolean;
19
+ setFullRowDraft: (columnId: string, value: unknown) => void;
20
+ commitFullRowEdit: () => void;
21
+ cancelFullRowEdit: () => void;
16
22
  saveEditingCell: () => void;
17
23
  applyHistoryStep: (step: HistoryStep, direction: "undo" | "redo") => void;
18
24
  updateEditingCellValue: (value: string) => void;
@@ -20,5 +26,6 @@ export declare function createEditing<TFeatures extends TableFeatures = TableFea
20
26
  focusOnMount: (node: HTMLInputElement | HTMLTextAreaElement) => void;
21
27
  onCellDoubleClick: (rowIndex: number, colIndex: number) => void;
22
28
  pasteFromClipboard: () => Promise<void>;
29
+ onGridPaste: (event: ClipboardEvent) => void;
23
30
  };
24
31
  export {};
package/dist/editing.js CHANGED
@@ -110,27 +110,39 @@ export function createEditing(ctx) {
110
110
  multiple: column?.columnDef.editorMultiple === true,
111
111
  });
112
112
  let oldValue = undefined;
113
+ let finalValue = parsedValue;
113
114
  if (row?.original && column?.columnDef.field) {
114
115
  oldValue = row.original[column.columnDef.field];
116
+ // Per-column valueParser refines the type-coerced value before storing.
117
+ const parser = column.columnDef.valueParser;
118
+ if (parser) {
119
+ finalValue = parser({
120
+ newValue: parsedValue,
121
+ oldValue,
122
+ rawInput: ctx.editingCell.value,
123
+ data: row.original,
124
+ columnId: ctx.editingCell.columnId,
125
+ });
126
+ }
115
127
  row.original[column.columnDef.field] =
116
- parsedValue;
128
+ finalValue;
117
129
  }
118
130
  const key = getCellKey(ctx.editingCell.rowId, ctx.editingCell.columnId);
119
131
  ctx.editedCellValues = {
120
132
  ...ctx.editedCellValues,
121
- [key]: parsedValue,
133
+ [key]: finalValue,
122
134
  };
123
135
  ctx.grid.store.setState((prev) => ({ ...prev }));
124
136
  // Record into the history at the current pointer. Any forward
125
137
  // history (steps the user could have redone) is truncated - this
126
138
  // is the standard "edit invalidates redo" rule.
127
- if (oldValue !== parsedValue && row?.original && column?.columnDef.field) {
139
+ if (oldValue !== finalValue && row?.original && column?.columnDef.field) {
128
140
  const step = {
129
141
  rowId: ctx.editingCell.rowId,
130
142
  columnId: ctx.editingCell.columnId,
131
143
  field: column.columnDef.field,
132
144
  before: oldValue,
133
- after: parsedValue,
145
+ after: finalValue,
134
146
  };
135
147
  const truncated = ctx.history.slice(0, ctx.historyPtr + 1);
136
148
  truncated.push(step);
@@ -156,7 +168,7 @@ export function createEditing(ctx) {
156
168
  rowIndex,
157
169
  columnId: column.id,
158
170
  oldValue,
159
- newValue: parsedValue,
171
+ newValue: finalValue,
160
172
  row: row.original,
161
173
  });
162
174
  }
@@ -228,6 +240,13 @@ export function createEditing(ctx) {
228
240
  return;
229
241
  if (isGroupRow(row))
230
242
  return;
243
+ // Full-row editing: put the whole row into edit instead of one cell.
244
+ if (ctx.props.fullRowEditing) {
245
+ if (ctx.fullRowEdit?.rowId === row.id)
246
+ return;
247
+ startFullRowEdit(rowIndex);
248
+ return;
249
+ }
231
250
  if (!isCellEditable(column, row))
232
251
  return;
233
252
  if (ctx.editingCell?.rowId === row.id && ctx.editingCell?.columnId === column.id)
@@ -255,6 +274,12 @@ export function createEditing(ctx) {
255
274
  ctx.setSelection(rowIndex, colIndex);
256
275
  }
257
276
  async function pasteFromClipboard() {
277
+ // Preferred path: the async Clipboard API. Requires a secure context
278
+ // (HTTPS or localhost) AND read permission; it also works on Firefox,
279
+ // where the native `paste` event does NOT fire on a non-editable element.
280
+ // On plain HTTP (a XAMPP/Apache LAN host) `navigator.clipboard` is
281
+ // undefined - there the Ctrl+V keydown handler skips preventDefault and
282
+ // lets the browser deliver a native `paste` event to `onGridPaste`.
258
283
  if (!navigator.clipboard?.readText)
259
284
  return;
260
285
  let text;
@@ -264,6 +289,28 @@ export function createEditing(ctx) {
264
289
  catch {
265
290
  return;
266
291
  }
292
+ applyPastedText(text);
293
+ }
294
+ /**
295
+ * Native `paste` ClipboardEvent fallback (insecure-context path). A real
296
+ * Ctrl/Cmd+V on the focused grid root fires this with `clipboardData`
297
+ * readable even over plain HTTP and with no permission prompt. Wired on the
298
+ * grid root in SvGrid.svelte; the keydown handler lets the gesture through
299
+ * (no preventDefault) whenever the async API is unavailable.
300
+ */
301
+ function onGridPaste(event) {
302
+ // When the async API is available the keydown handler already pasted via
303
+ // pasteFromClipboard(); ignore the (suppressed) native event so we don't
304
+ // paste twice.
305
+ if (typeof navigator.clipboard?.readText === "function")
306
+ return;
307
+ const text = event.clipboardData?.getData("text/plain") ?? "";
308
+ if (!text)
309
+ return;
310
+ event.preventDefault();
311
+ applyPastedText(text);
312
+ }
313
+ function applyPastedText(text) {
267
314
  const anchor = ctx.selectionRange.anchor ?? ctx.grid.getState().activeCell;
268
315
  if (!anchor)
269
316
  return;
@@ -326,12 +373,150 @@ export function createEditing(ctx) {
326
373
  ctx.internalData = next;
327
374
  ctx.grid.store.setState((prev) => ({ ...prev }));
328
375
  }
376
+ /** Programmatically begin editing a cell (mirrors a double-click). */
377
+ function startEditing(rowIndex, columnId) {
378
+ if (!ctx.editingEnabled)
379
+ return false;
380
+ const row = ctx.allRows[rowIndex];
381
+ if (!row || isGroupRow(row))
382
+ return false;
383
+ const colIndex = ctx.allColumns.findIndex((c) => c.id === columnId);
384
+ if (colIndex < 0)
385
+ return false;
386
+ const column = ctx.allColumns[colIndex];
387
+ if (!isCellEditable(column, row))
388
+ return false;
389
+ if (ctx.editingCell?.rowId === row.id &&
390
+ ctx.editingCell?.columnId === columnId)
391
+ return true;
392
+ onCellDoubleClick(rowIndex, colIndex);
393
+ return (ctx.editingCell?.rowId === row.id &&
394
+ ctx.editingCell?.columnId === columnId);
395
+ }
396
+ /** Commit (default) or cancel the active edit, if any. */
397
+ function stopEditing(cancel = false) {
398
+ if (!ctx.editingCell)
399
+ return false;
400
+ if (cancel) {
401
+ ctx.editingCell = null;
402
+ }
403
+ else {
404
+ saveEditingCell();
405
+ }
406
+ return true;
407
+ }
408
+ // ---- Full-row editing -------------------------------------------------
409
+ /** Put the whole row into edit mode, seeding a draft per editable column. */
410
+ function startFullRowEdit(rowIndex) {
411
+ if (!ctx.editingEnabled || !ctx.props.fullRowEditing)
412
+ return false;
413
+ const row = ctx.allRows[rowIndex];
414
+ if (!row || isGroupRow(row))
415
+ return false;
416
+ if (ctx.fullRowEdit && ctx.fullRowEdit.rowId !== row.id)
417
+ commitFullRowEdit();
418
+ ctx.editingCell = null; // never both at once
419
+ const draft = {};
420
+ for (const column of ctx.allColumns) {
421
+ if (!column.columnDef.field)
422
+ continue;
423
+ if (!isCellEditable(column, row))
424
+ continue;
425
+ draft[column.id] = getCellDisplayValue(row.id, column.id, row.getCellValueByColumnId(column.id));
426
+ }
427
+ ctx.fullRowEdit = { rowId: row.id, draft };
428
+ ctx.setActiveCell(rowIndex, Math.max(0, ctx.allColumns.findIndex((c) => c.id in draft)));
429
+ return true;
430
+ }
431
+ /** Stage one column's draft value during full-row editing. */
432
+ function setFullRowDraft(columnId, value) {
433
+ const fr = ctx.fullRowEdit;
434
+ if (!fr)
435
+ return;
436
+ ctx.fullRowEdit = { rowId: fr.rowId, draft: { ...fr.draft, [columnId]: value } };
437
+ }
438
+ /** Commit every drafted column of the full-row edit in one data update. */
439
+ function commitFullRowEdit() {
440
+ const fr = ctx.fullRowEdit;
441
+ if (!fr)
442
+ return;
443
+ const row = ctx.allRows.find((r) => r.id === fr.rowId);
444
+ if (!row?.original) {
445
+ ctx.fullRowEdit = null;
446
+ return;
447
+ }
448
+ const changed = [];
449
+ for (const column of ctx.allColumns) {
450
+ if (!(column.id in fr.draft))
451
+ continue;
452
+ const field = column.columnDef.field;
453
+ if (!field)
454
+ continue;
455
+ const editorType = (column.columnDef.editorType ?? "text");
456
+ const parsed = parseEditorValue(editorType, fr.draft[column.id], {
457
+ multiple: column.columnDef.editorMultiple === true,
458
+ });
459
+ const oldValue = row.original[field];
460
+ const parser = column.columnDef.valueParser;
461
+ const finalValue = parser
462
+ ? parser({
463
+ newValue: parsed,
464
+ oldValue,
465
+ rawInput: String(fr.draft[column.id] ?? ""),
466
+ data: row.original,
467
+ columnId: column.id,
468
+ })
469
+ : parsed;
470
+ if (oldValue !== finalValue) {
471
+ row.original[field] = finalValue;
472
+ const key = getCellKey(fr.rowId, column.id);
473
+ ctx.editedCellValues = { ...ctx.editedCellValues, [key]: finalValue };
474
+ changed.push({ columnId: column.id, field, before: oldValue, after: finalValue });
475
+ }
476
+ }
477
+ // Record the whole-row change as consecutive history steps.
478
+ if (changed.length) {
479
+ let hist = ctx.history.slice(0, ctx.historyPtr + 1);
480
+ for (const c of changed) {
481
+ hist.push({ rowId: fr.rowId, columnId: c.columnId, field: c.field, before: c.before, after: c.after });
482
+ }
483
+ if (hist.length > ctx.UNDO_LIMIT)
484
+ hist = hist.slice(hist.length - ctx.UNDO_LIMIT);
485
+ ctx.history = hist;
486
+ ctx.historyPtr = ctx.history.length - 1;
487
+ ctx.historyVersion += 1;
488
+ }
489
+ ctx.grid.store.setState((prev) => ({ ...prev }));
490
+ if (ctx.props.onCellValueChange && changed.length) {
491
+ const rowIndex = ctx.internalData.indexOf(row.original);
492
+ for (const c of changed) {
493
+ ctx.props.onCellValueChange({
494
+ rowIndex,
495
+ columnId: c.columnId,
496
+ oldValue: c.before,
497
+ newValue: c.after,
498
+ row: row.original,
499
+ });
500
+ }
501
+ }
502
+ ctx.fullRowEdit = null;
503
+ }
504
+ /** Discard the full-row edit. */
505
+ function cancelFullRowEdit() {
506
+ ctx.fullRowEdit = null;
507
+ }
329
508
  return {
330
509
  isCellEditable,
331
510
  isCellEditableAt,
332
511
  getRowColumnValue,
333
512
  getCellDisplayValue,
334
513
  startEditingWithChar,
514
+ startEditing,
515
+ stopEditing,
516
+ startFullRowEdit,
517
+ setFullRowDraft,
518
+ commitFullRowEdit,
519
+ cancelFullRowEdit,
335
520
  saveEditingCell,
336
521
  applyHistoryStep,
337
522
  updateEditingCellValue,
@@ -339,5 +524,6 @@ export function createEditing(ctx) {
339
524
  focusOnMount,
340
525
  onCellDoubleClick,
341
526
  pasteFromClipboard,
527
+ onGridPaste,
342
528
  };
343
529
  }
@@ -0,0 +1 @@
1
+ export {};