@svgrid/grid 3.0.5 → 3.0.6

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 (148) hide show
  1. package/README.md +28 -7
  2. package/dist/GridMenus.svelte +34 -4
  3. package/dist/SvGrid.controller.svelte.d.ts +21 -3
  4. package/dist/SvGrid.controller.svelte.js +205 -50
  5. package/dist/SvGrid.css +127 -2
  6. package/dist/SvGrid.svelte +223 -38
  7. package/dist/SvGrid.types.d.ts +77 -4
  8. package/dist/SvGridDropdown.svelte +20 -0
  9. package/dist/SvGridDropdown.svelte.d.ts +12 -0
  10. package/dist/SvModal.svelte +22 -0
  11. package/dist/SvModal.svelte.d.ts +7 -0
  12. package/dist/a11y/dismissable.d.ts +10 -0
  13. package/dist/a11y/dismissable.js +24 -2
  14. package/dist/build-api.js +81 -31
  15. package/dist/cdn/{GridMenus-CID62rlI.js → GridMenus-C-NtjlrJ.js} +150 -141
  16. package/dist/cdn/GridMenus-TssHej3q.js +644 -0
  17. package/dist/cdn/{SvChartMenu-FBSMINA6.js → SvChartMenu-BFSTpvB-.js} +1 -1
  18. package/dist/cdn/{SvChartMenu-Bl6PBbkT.js → SvChartMenu-BZ1Iwv0y.js} +1 -1
  19. package/dist/cdn/{SvDateTimePicker-DQwt4UAs.js → SvDateTimePicker-D9u_cOf8.js} +1 -1
  20. package/dist/cdn/{SvDateTimePicker-vNU6bZ-q.js → SvDateTimePicker-s_6IUpI7.js} +1 -1
  21. package/dist/cdn/{SvGridCellEditor-B1p-vCK5.js → SvGridCellEditor-BlyCSp0q.js} +1 -1
  22. package/dist/cdn/{SvGridCellEditor-D_0q4xAu.js → SvGridCellEditor-ClRRA9lW.js} +1 -1
  23. package/dist/cdn/{SvGridChart-DzLkSwCH.js → SvGridChart-B4EV8U6t.js} +4 -4
  24. package/dist/cdn/{SvGridChart-C3EWAZaM.js → SvGridChart-DsmwTyZF.js} +4 -4
  25. package/dist/cdn/{SvGridChartBuilder-CfII62sZ.js → SvGridChartBuilder-cHloHobN.js} +4 -4
  26. package/dist/cdn/{SvGridChartBuilder-BE2T1ykB.js → SvGridChartBuilder-vOl7C0Za.js} +4 -4
  27. package/dist/cdn/{SvGridChartPanel-xf4sWVTo.js → SvGridChartPanel-AcqF-Ll5.js} +5 -5
  28. package/dist/cdn/{SvGridChartPanel-CCX5_Wgd.js → SvGridChartPanel-biMtSBPA.js} +5 -5
  29. package/dist/cdn/{SvGridChartView-DYwabQWj.js → SvGridChartView-Dx_GmZuL.js} +2 -2
  30. package/dist/cdn/{SvGridChartView-CfuXmY5I.js → SvGridChartView-I3rDHXAq.js} +2 -2
  31. package/dist/cdn/{SvGridDropdown-D0VdjeR8.js → SvGridDropdown-BWeM3lMe.js} +46 -46
  32. package/dist/cdn/{SvGridDropdown-D13MtJ2j.js → SvGridDropdown-CJ6QqTxu.js} +67 -67
  33. package/dist/cdn/{SvModal-CIZWCcad.js → SvModal-ClxGmpAc.js} +187 -186
  34. package/dist/cdn/{SvModal-BAE-pjZX.js → SvModal-DhB_VMFR.js} +148 -147
  35. package/dist/cdn/{cell-formatting-C2Hf5gqd.js → cell-formatting-DVVKOSI9.js} +1 -1
  36. package/dist/cdn/{chart-Dz7SqMXH.js → chart-DEZxwC0i.js} +1 -1
  37. package/dist/cdn/{chart-panel-messages-CUbf2R4i.js → chart-panel-messages-D12XcTZJ.js} +1 -1
  38. package/dist/cdn/{chart-panel-messages-CmNrMdsr.js → chart-panel-messages-DguS7gC5.js} +1 -1
  39. package/dist/cdn/{chart-summary-BJW_tg_X.js → chart-summary-CMAXBGY-.js} +1 -1
  40. package/dist/cdn/{chart-trend-CaN9mDEV.js → chart-trend-BkEp61Gj.js} +1 -1
  41. package/dist/cdn/{dismissable-DAHetSNk.js → dismissable-Brc4EZU1.js} +5 -1
  42. package/dist/cdn/{export-format-CUDLy2yn.js → export-format-YzdwBww2.js} +1 -1
  43. package/dist/cdn/{row-resize-niQCp040.js → row-resize-DtOS1KG6.js} +41 -32
  44. package/dist/cdn/{server-block-cache-CGoWz-87.js → server-block-cache-DIqb3VZn.js} +4 -0
  45. package/dist/cdn/{src-jcFMkBnN.js → src-CgoeSM8k.js} +4697 -4131
  46. package/dist/cdn/{src-Bklofsad.js → src-DfwxB1TH.js} +4727 -4161
  47. package/dist/cdn/svgrid.js +17 -17
  48. package/dist/cdn/svgrid.svelte-external.js +17 -17
  49. package/dist/cdn/{validate-C7Rn_Bns.js → validate-AZoD8BoR.js} +6 -2
  50. package/dist/cell-formatting.js +18 -1
  51. package/dist/cell-render.js +25 -6
  52. package/dist/clipboard.d.ts +2 -2
  53. package/dist/clipboard.js +72 -23
  54. package/dist/columns.js +7 -2
  55. package/dist/conditional-formatting.d.ts +2 -0
  56. package/dist/conditional-formatting.js +2 -0
  57. package/dist/core.d.ts +22 -6
  58. package/dist/core.js +365 -25
  59. package/dist/editing.js +24 -0
  60. package/dist/grid-messages.d.ts +4 -0
  61. package/dist/grid-messages.js +4 -0
  62. package/dist/headless.d.ts +5 -0
  63. package/dist/headless.js +12 -0
  64. package/dist/history.d.ts +21 -0
  65. package/dist/history.js +34 -4
  66. package/dist/index.d.ts +1 -1
  67. package/dist/keyboard-handlers.js +24 -1
  68. package/dist/keyboard.js +4 -0
  69. package/dist/row-drag-touch.d.ts +1 -1
  70. package/dist/row-drag.js +35 -1
  71. package/dist/row-model.d.ts +6 -0
  72. package/dist/row-resize.js +22 -1
  73. package/dist/selection.js +1 -1
  74. package/dist/server-block-cache.d.ts +5 -0
  75. package/dist/server-block-cache.js +8 -0
  76. package/dist/server-data-source.d.ts +35 -3
  77. package/dist/server-data-source.js +11 -2
  78. package/dist/server.d.ts +1 -1
  79. package/dist/sparkline.js +7 -5
  80. package/dist/svgrid-wrapper.types.d.ts +33 -0
  81. package/dist/validate.js +9 -1
  82. package/package.json +6 -1
  83. package/src/GridMenus.svelte +34 -4
  84. package/src/SvGrid.controller.svelte.ts +206 -53
  85. package/src/SvGrid.css +127 -2
  86. package/src/SvGrid.svelte +223 -38
  87. package/src/SvGrid.types.ts +77 -4
  88. package/src/SvGridDropdown.svelte +20 -0
  89. package/src/SvModal.svelte +22 -0
  90. package/src/SvModal.test.ts +30 -1
  91. package/src/a11y/dismissable.test.ts +10 -1
  92. package/src/a11y/dismissable.ts +22 -2
  93. package/src/build-api.ts +85 -27
  94. package/src/cell-formatting.test.ts +17 -0
  95. package/src/cell-formatting.ts +18 -1
  96. package/src/cell-render.test.ts +24 -2
  97. package/src/cell-render.ts +24 -8
  98. package/src/clipboard.test.ts +107 -0
  99. package/src/clipboard.ts +62 -23
  100. package/src/columns.test.ts +4 -4
  101. package/src/columns.ts +7 -2
  102. package/src/conditional-formatting.test.ts +8 -0
  103. package/src/conditional-formatting.ts +3 -0
  104. package/src/core.tick-repair.test.ts +287 -0
  105. package/src/core.ts +374 -26
  106. package/src/editing.test.ts +52 -0
  107. package/src/editing.ts +25 -0
  108. package/src/grid-messages.test.ts +7 -0
  109. package/src/grid-messages.ts +10 -0
  110. package/src/headless.ts +24 -0
  111. package/src/history.test.ts +49 -1
  112. package/src/history.ts +48 -2
  113. package/src/index.ts +2 -0
  114. package/src/keyboard-handlers.coverage.test.ts +65 -0
  115. package/src/keyboard-handlers.ts +26 -1
  116. package/src/keyboard.ts +3 -0
  117. package/src/row-drag-touch.ts +2 -2
  118. package/src/row-drag.test.ts +51 -0
  119. package/src/row-drag.ts +35 -2
  120. package/src/row-model.ts +6 -0
  121. package/src/row-resize.ts +24 -1
  122. package/src/selection.ts +1 -1
  123. package/src/server-block-cache.test.ts +27 -0
  124. package/src/server-block-cache.ts +13 -0
  125. package/src/server-data-source.infinite.test.ts +62 -0
  126. package/src/server-data-source.test.ts +19 -0
  127. package/src/server-data-source.ts +48 -4
  128. package/src/server.ts +2 -0
  129. package/src/sparkline.test.ts +7 -0
  130. package/src/sparkline.ts +6 -4
  131. package/src/svgrid-wrapper.types.ts +32 -0
  132. package/src/svgrid.api.test.ts +21 -0
  133. package/src/svgrid.charting.test.ts +12 -4
  134. package/src/svgrid.context-menu.test.ts +12 -0
  135. package/src/svgrid.detail-rows.svelte.test.ts +187 -0
  136. package/src/svgrid.filter-menu-scroll.test.ts +9 -0
  137. package/src/svgrid.gantt-seam.test.ts +1 -1
  138. package/src/svgrid.live-update-paths.svelte.test.ts +184 -0
  139. package/src/svgrid.menu-scroll-close.test.ts +10 -0
  140. package/src/svgrid.row-model-seam.svelte.test.ts +16 -0
  141. package/src/svgrid.row-pinning.test.ts +15 -1
  142. package/src/svgrid.selection-bar-seam.test.ts +1 -1
  143. package/src/svgrid.sticky-groups.svelte.test.ts +145 -0
  144. package/src/svgrid.upsell-license.test.ts +1 -1
  145. package/src/test-setup.ts +12 -0
  146. package/src/transaction.test.ts +58 -0
  147. package/src/validate.ts +7 -1
  148. package/dist/cdn/GridMenus-DLL-qZeu.js +0 -635
package/dist/clipboard.js CHANGED
@@ -86,9 +86,9 @@ export function createClipboard(ctx) {
86
86
  if (before !== value)
87
87
  steps.push({ rowId: row.id, columnId, field, before, after: value });
88
88
  }
89
- function applyFillPattern() {
89
+ function applyFillPattern(toggled = false) {
90
90
  const steps = [];
91
- runHistoryGroup(ctx, () => applyFillCells(steps));
91
+ runHistoryGroup(ctx, () => applyFillCells(steps, toggled));
92
92
  if (steps.length)
93
93
  pushHistory(ctx, steps, nextGroupId());
94
94
  }
@@ -98,11 +98,14 @@ export function createClipboard(ctx) {
98
98
  * `sourceStart` is the row (or column) of the first source value and
99
99
  * `targetStart` that of the first target; `step` is -1 filling upward.
100
100
  */
101
- function filledValue(sources, pattern, i, sourceStart, targetStart, step, axis, rowIndex, columnId) {
101
+ function filledValue(sources, pattern, i, sourceStart, at, step, axis, rowIndex, columnId) {
102
102
  const hook = ctx.props.processCellForFill;
103
103
  if (hook && sources.length) {
104
104
  const k = i % sources.length;
105
- const distance = (targetStart + step * i) - (sourceStart + step * k);
105
+ // The real distance to the cell being filled, which is not i when a
106
+ // row the fill skips lies between: a formula moves by the rows it
107
+ // actually travelled.
108
+ const distance = at - (sourceStart + step * k);
106
109
  const delta = axis === "rows" ? { rows: distance, cols: 0 } : { rows: 0, cols: distance };
107
110
  const decided = hook({ value: sources[k], delta, rowIndex, columnId });
108
111
  if (decided !== undefined)
@@ -149,7 +152,17 @@ export function createClipboard(ctx) {
149
152
  };
150
153
  applyFillPattern();
151
154
  }
152
- function applyFillCells(steps) {
155
+ /** The fill's values the other way round from the pattern's default. */
156
+ function toggledPattern(sources, count) {
157
+ if (sources.length === 1 && typeof sources[0] === 'number' && Number.isFinite(sources[0])) {
158
+ return Array.from({ length: count }, (_, i) => sources[0] + i + 1);
159
+ }
160
+ return Array.from({ length: count }, (_, i) => sources[i % sources.length]);
161
+ }
162
+ function applyFillCells(steps, toggled = false) {
163
+ const pattern = (sources, count) => (toggled ? toggledPattern(sources, count) : buildFillPattern(sources, count));
164
+ const includeCollapsed = ctx.props.includeCollapsedRows;
165
+ const skipsRow = (r) => ctx.isRowCollapsed?.(r) === true && !(includeCollapsed?.(r) ?? false);
153
166
  const d = ctx.fillDrag;
154
167
  if (!d)
155
168
  return;
@@ -176,25 +189,32 @@ export function createClipboard(ctx) {
176
189
  for (let r = d.sourceMinRow; r <= d.sourceMaxRow; r += 1) {
177
190
  sourceColValues.push(readCellRaw(r, column.id));
178
191
  }
192
+ // A collapsed row the consumer does not count (a filtered row in a
193
+ // spreadsheet) is neither written nor a step of the series: the
194
+ // pattern runs over the rows that are there, as Excel's does.
179
195
  if (newMaxRow > d.sourceMaxRow) {
180
- const targetRows = newMaxRow - d.sourceMaxRow;
181
- const fills = buildFillPattern(sourceColValues, targetRows);
182
- for (let i = 0; i < targetRows; i += 1) {
183
- const targetRow = d.sourceMaxRow + 1 + i;
196
+ const targets = [];
197
+ for (let r = d.sourceMaxRow + 1; r <= newMaxRow; r += 1)
198
+ if (!skipsRow(r))
199
+ targets.push(r);
200
+ const fills = pattern(sourceColValues, targets.length);
201
+ targets.forEach((targetRow, i) => {
184
202
  if (ctx.isCellEditableAt(targetRow, c))
185
- writeFilled(steps, targetRow, column.id, filledValue(sourceColValues, fills, i, d.sourceMinRow, d.sourceMaxRow + 1, 1, "rows", targetRow, column.id));
186
- }
203
+ writeFilled(steps, targetRow, column.id, filledValue(sourceColValues, fills, i, d.sourceMinRow, targetRow, 1, "rows", targetRow, column.id));
204
+ });
187
205
  }
188
206
  if (newMinRow < d.sourceMinRow) {
189
207
  // Filling upward - reverse-extrapolate.
190
208
  const reversed = sourceColValues.slice().reverse();
191
- const targetRows = d.sourceMinRow - newMinRow;
192
- const fills = buildFillPattern(reversed, targetRows);
193
- for (let i = 0; i < targetRows; i += 1) {
194
- const targetRow = d.sourceMinRow - 1 - i;
209
+ const targets = [];
210
+ for (let r = d.sourceMinRow - 1; r >= newMinRow; r -= 1)
211
+ if (!skipsRow(r))
212
+ targets.push(r);
213
+ const fills = pattern(reversed, targets.length);
214
+ targets.forEach((targetRow, i) => {
195
215
  if (ctx.isCellEditableAt(targetRow, c))
196
- writeFilled(steps, targetRow, column.id, filledValue(reversed, fills, i, d.sourceMaxRow, d.sourceMinRow - 1, -1, "rows", targetRow, column.id));
197
- }
216
+ writeFilled(steps, targetRow, column.id, filledValue(reversed, fills, i, d.sourceMaxRow, targetRow, -1, "rows", targetRow, column.id));
217
+ });
198
218
  }
199
219
  }
200
220
  }
@@ -211,23 +231,23 @@ export function createClipboard(ctx) {
211
231
  }
212
232
  if (newMaxCol > d.sourceMaxCol) {
213
233
  const targetCols = newMaxCol - d.sourceMaxCol;
214
- const fills = buildFillPattern(sourceRowValues, targetCols);
234
+ const fills = pattern(sourceRowValues, targetCols);
215
235
  for (let i = 0; i < targetCols; i += 1) {
216
236
  const targetCol = d.sourceMaxCol + 1 + i;
217
237
  const col = ctx.allColumns[targetCol];
218
238
  if (col && ctx.isCellEditableAt(r, targetCol))
219
- writeFilled(steps, r, col.id, filledValue(sourceRowValues, fills, i, d.sourceMinCol, d.sourceMaxCol + 1, 1, "cols", r, col.id));
239
+ writeFilled(steps, r, col.id, filledValue(sourceRowValues, fills, i, d.sourceMinCol, targetCol, 1, "cols", r, col.id));
220
240
  }
221
241
  }
222
242
  if (newMinCol < d.sourceMinCol) {
223
243
  const reversed = sourceRowValues.slice().reverse();
224
244
  const targetCols = d.sourceMinCol - newMinCol;
225
- const fills = buildFillPattern(reversed, targetCols);
245
+ const fills = pattern(reversed, targetCols);
226
246
  for (let i = 0; i < targetCols; i += 1) {
227
247
  const targetCol = d.sourceMinCol - 1 - i;
228
248
  const col = ctx.allColumns[targetCol];
229
249
  if (col && ctx.isCellEditableAt(r, targetCol))
230
- writeFilled(steps, r, col.id, filledValue(reversed, fills, i, d.sourceMaxCol, d.sourceMinCol - 1, -1, "cols", r, col.id));
250
+ writeFilled(steps, r, col.id, filledValue(reversed, fills, i, d.sourceMaxCol, targetCol, -1, "cols", r, col.id));
231
251
  }
232
252
  }
233
253
  }
@@ -252,8 +272,12 @@ export function createClipboard(ctx) {
252
272
  const minCol = Math.min(anchor.colIndex, focus.colIndex);
253
273
  const maxCol = Math.max(anchor.colIndex, focus.colIndex);
254
274
  for (let r = minRow; r <= maxRow; r += 1) {
275
+ if (ctx.isRowCollapsed?.(r))
276
+ continue;
255
277
  for (let c = minCol; c <= maxCol; c += 1) {
256
278
  const col = ctx.allColumns[c];
279
+ if (col && ctx.collapsedColumns?.[col.id])
280
+ continue;
257
281
  if (col?.columnDef.field && ctx.isCellEditableAt(r, c)) {
258
282
  writeCellRaw(r, col.id, null);
259
283
  }
@@ -418,10 +442,16 @@ export function createClipboard(ctx) {
418
442
  return;
419
443
  ctx.fillDrag = { ...ctx.fillDrag, targetRow: hit.row, targetCol: hit.col };
420
444
  }
421
- function onFillPointerUp() {
445
+ /**
446
+ * The release. Excel's Ctrl turns the fill the other way: a series
447
+ * becomes a copy of the block, and one number, which copies on its own,
448
+ * becomes a series stepping by one. The modifier is read here, at the
449
+ * release, so holding Ctrl only at the end still counts, as in Excel.
450
+ */
451
+ function onFillPointerUp(event) {
422
452
  if (!ctx.fillDrag)
423
453
  return;
424
- applyFillPattern();
454
+ applyFillPattern(!!(event && (event.ctrlKey || event.metaKey)));
425
455
  }
426
456
  // ---- Range move / copy (drag the selection border) --------------------
427
457
  /** How thick the draggable strip on a range border is, in CSS pixels.
@@ -772,6 +802,7 @@ export function createClipboard(ctx) {
772
802
  // each value through a consumer hook before it hits the clipboard.
773
803
  const withHeaders = ctx.props.copyHeadersToClipboard === true;
774
804
  const processCell = ctx.props.processCellForClipboard;
805
+ const copyCollapsed = ctx.props.includeCollapsedRows;
775
806
  const blocks = [];
776
807
  for (const rect of rects) {
777
808
  const lines = [];
@@ -779,6 +810,8 @@ export function createClipboard(ctx) {
779
810
  const header = [];
780
811
  for (let c = rect.minCol; c <= rect.maxCol; c += 1) {
781
812
  const column = ctx.allColumns[c];
813
+ if (column && ctx.collapsedColumns?.[column.id])
814
+ continue;
782
815
  header.push(column ? toolPanelHeaderLabel(column) : "");
783
816
  }
784
817
  lines.push(header.join("\t"));
@@ -787,6 +820,14 @@ export function createClipboard(ctx) {
787
820
  const row = ctx.allRows[r];
788
821
  if (!row || isGroupRow(row))
789
822
  continue;
823
+ // A collapsed row is folded to nothing: the user cannot see it and
824
+ // the keyboard walks past it, so a copy leaves it out too. That is
825
+ // what a spreadsheet does with a filtered row, and it is what makes
826
+ // "filter, copy, paste" carry the rows that matched. A consumer that
827
+ // tells hidden from filtered answers per row (`includeCollapsedRows`):
828
+ // Excel copies a row hidden by hand.
829
+ if (ctx.isRowCollapsed?.(r) && !copyCollapsed?.(r))
830
+ continue;
790
831
  const cells = [];
791
832
  for (let c = rect.minCol; c <= rect.maxCol; c += 1) {
792
833
  const column = ctx.allColumns[c];
@@ -794,6 +835,8 @@ export function createClipboard(ctx) {
794
835
  cells.push("");
795
836
  continue;
796
837
  }
838
+ if (ctx.collapsedColumns?.[column.id])
839
+ continue;
797
840
  const base = getColumnBaseValue(row, column);
798
841
  let value = ctx.getCellDisplayValue(row.id, column.id, base);
799
842
  if (processCell) {
@@ -846,6 +889,10 @@ export function createClipboard(ctx) {
846
889
  const row = ctx.allRows[r];
847
890
  if (!row || isGroupRow(row))
848
891
  continue;
892
+ // A collapsed row is not there as far as the user is concerned, and a
893
+ // Delete over a filtered block must not wipe what the filter hid.
894
+ if (ctx.isRowCollapsed?.(r))
895
+ continue;
849
896
  // By identity, not `Number(row.id)` - that is the array index only under
850
897
  // the default getRowId, so a custom one cleared the wrong row.
851
898
  const dataIndex = dataIndexOf(row);
@@ -862,6 +909,8 @@ export function createClipboard(ctx) {
862
909
  const column = ctx.allColumns[c];
863
910
  if (!column?.columnDef.field)
864
911
  continue;
912
+ if (ctx.collapsedColumns?.[column.id])
913
+ continue;
865
914
  if (!ctx.isCellEditableAt(r, c))
866
915
  continue;
867
916
  // Clear means: empty string for text, undefined for everything
package/dist/columns.js CHANGED
@@ -5,13 +5,18 @@ export function createColumns(ctx) {
5
5
  // context (z=20) so a selected cell in the scrollable middle never
6
6
  // bleeds over the pinned columns during horizontal scroll. Still
7
7
  // sits below dropdowns (z=900+) and the column menu.
8
+ // Logical insets, not `left` / `right`: the offsets are measured from the
9
+ // pinned side in READING order, so under `dir="rtl"` the left-pinned
10
+ // columns have to stick to the right edge. `inset-inline-start` is that
11
+ // edge in either direction; with `left` a right-to-left grid scrolls its
12
+ // pinned columns off the screen.
8
13
  const leftOffset = ctx.pinnedOffsets.left[columnId];
9
14
  if (leftOffset !== undefined) {
10
- return `position: sticky; left: ${leftOffset}px; z-index: 30;`;
15
+ return `position: sticky; inset-inline-start: ${leftOffset}px; z-index: 30;`;
11
16
  }
12
17
  const rightOffset = ctx.pinnedOffsets.right[columnId];
13
18
  if (rightOffset !== undefined) {
14
- return `position: sticky; right: ${rightOffset}px; z-index: 30;`;
19
+ return `position: sticky; inset-inline-end: ${rightOffset}px; z-index: 30;`;
15
20
  }
16
21
  return "";
17
22
  }
@@ -101,6 +101,8 @@ export type RuleFormat<TData = unknown> = {
101
101
  background?: string;
102
102
  color?: string;
103
103
  fontWeight?: string | number;
104
+ /** A short glyph drawn before the value while the rule matches. */
105
+ icon?: string;
104
106
  };
105
107
  export type ConditionalFormatSpec<TData = unknown> = ColorScaleFormat | DataBarFormat | IconSetFormat | RuleFormat<TData>;
106
108
  /** A format scoped to specific columns (omit `columns` to apply to all). */
@@ -198,6 +198,8 @@ export function resolveCellFormat(value, row, columnId, formats, stat) {
198
198
  out.color = fmt.color;
199
199
  if (fmt.fontWeight != null)
200
200
  out.fontWeight = fmt.fontWeight;
201
+ if (fmt.icon)
202
+ out.icon = fmt.icon;
201
203
  }
202
204
  continue;
203
205
  }
package/dist/core.d.ts CHANGED
@@ -274,8 +274,9 @@ export type ColumnDef<TFeatures extends TableFeatures, TData extends RowData> =
274
274
  * - `false` → invalid, no message
275
275
  * - a non-empty `string` → invalid, string is the tooltip
276
276
  *
277
- * The value keeps rendering as-is (the grid does NOT roll it back); pair
278
- * with `onCellValueChange` if you also want to reject the commit.
277
+ * On its own `validate` flags: the value keeps rendering as-is and an
278
+ * edit that fails it still lands. Set `rejectInvalid` to refuse such an
279
+ * edit instead.
279
280
  */
280
281
  validate?: (params: {
281
282
  value: unknown;
@@ -283,6 +284,16 @@ export type ColumnDef<TFeatures extends TableFeatures, TData extends RowData> =
283
284
  rowIndex: number;
284
285
  column: Column<TData>;
285
286
  }) => string | boolean | null | undefined;
287
+ /**
288
+ * Refuse an edit that `validate` flags. When true, a committed value that
289
+ * makes `validate` return `false` or a message is not written: the cell
290
+ * keeps its old value, no history step is recorded and
291
+ * `onCellValueChange` does not fire. The value is checked after
292
+ * `valueParser` has run, so the rule sees what would be stored. Applies to
293
+ * the inline editor, a commit to a selection and a full-row edit; paste
294
+ * does not go through the editor and is not checked.
295
+ */
296
+ rejectInvalid?: boolean;
286
297
  /**
287
298
  * Gate editing per column or per cell.
288
299
  *
@@ -689,10 +700,15 @@ export declare function flattenTreeData<T extends RowData>(data: ReadonlyArray<T
689
700
  * master-detail alike - all three are the same expand/collapse mechanism.
690
701
  */
691
702
  export declare function createExpandedRowModel<TData extends RowData>(): RowModelFactory<TData>;
692
- /**
693
- * Orders rows by the active {@link SortingState}. Pass your own comparators to
694
- * override the built-in {@link sortFns} - useful for locale-aware or
695
- * domain-specific ordering.
703
+ /** The rows `getRowModel` replaced in the rebuild this pipeline run follows, or null. */
704
+ export declare function replacedRowsOf(table: SvGrid<any>): ReadonlyMap<Row<any>, Row<any>> | null;
705
+ /**
706
+ * The sorting stage of the row pipeline: orders the rows by the grid's
707
+ * `sorting` state with the built-in comparators (or the `localSortFns` map
708
+ * handed in), stable, equal keys keeping their data order. A tick that
709
+ * replaces a few rows out of many is repaired incrementally rather than
710
+ * re-sorted (see the note inside). Registered by `rowSortingFeature`; an app
711
+ * only calls this to install its own comparator set.
696
712
  */
697
713
  export declare function createSortedRowModel<TData extends RowData>(localSortFns?: typeof sortFns): RowModelFactory<TData>;
698
714
  /**