@svgrid/grid 2.6.20 → 2.6.22

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 (110) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +22 -0
  3. package/dist/GridMenus.svelte +17 -12
  4. package/dist/SvGrid.controller.svelte.d.ts +14 -8
  5. package/dist/SvGrid.controller.svelte.js +214 -74
  6. package/dist/SvGrid.css +1 -1
  7. package/dist/SvGrid.svelte +112 -57
  8. package/dist/SvGrid.types.d.ts +191 -1
  9. package/dist/ai.d.ts +28 -0
  10. package/dist/ai.js +6 -0
  11. package/dist/cdn/{GridMenus-B0F9iBrG.js → GridMenus-BuoBPqxx.js} +137 -132
  12. package/dist/cdn/GridMenus-n4llxoOI.js +494 -0
  13. package/dist/cdn/column-resize-DsfNXMom.js +102 -0
  14. package/dist/cdn/row-resize-BRcimkUT.js +95 -0
  15. package/dist/cdn/{src-Cd0tearp.js → src-C9Hihx1W.js} +3497 -3487
  16. package/dist/cdn/{src-B1TdiyS8.js → src-D1lXwq1l.js} +8258 -8248
  17. package/dist/cdn/svgrid.js +10 -8
  18. package/dist/cdn/svgrid.svelte-external.js +10 -8
  19. package/dist/cdn/validate-_CDJzgIo.js +75 -0
  20. package/dist/cell-formatting.d.ts +2 -0
  21. package/dist/cell-formatting.js +2 -0
  22. package/dist/chart-export.d.ts +1 -0
  23. package/dist/chart.d.ts +31 -5
  24. package/dist/chart.js +9 -3
  25. package/dist/column-groups.js +1 -1
  26. package/dist/column-resize.d.ts +46 -0
  27. package/dist/column-resize.js +205 -0
  28. package/dist/columns.d.ts +0 -3
  29. package/dist/columns.js +0 -57
  30. package/dist/core.d.ts +216 -4
  31. package/dist/core.js +532 -119
  32. package/dist/createTree.svelte.d.ts +3 -0
  33. package/dist/createTree.svelte.js +1 -0
  34. package/dist/datetime/date-core.d.ts +2 -0
  35. package/dist/datetime/date-restrict.d.ts +1 -0
  36. package/dist/datetime/timezone.d.ts +1 -0
  37. package/dist/dock-manager-model.d.ts +3 -0
  38. package/dist/dock-manager-model.js +1 -0
  39. package/dist/dock-model.d.ts +6 -0
  40. package/dist/dock-model.js +3 -0
  41. package/dist/editor-contract.d.ts +1 -0
  42. package/dist/filtering/excel-filters.js +28 -0
  43. package/dist/group-display.d.ts +1 -1
  44. package/dist/index.d.ts +2 -1
  45. package/dist/index.js +6 -0
  46. package/dist/list-option.d.ts +1 -0
  47. package/dist/menus.js +1 -1
  48. package/dist/positioning.d.ts +2 -0
  49. package/dist/row-resize.d.ts +11 -0
  50. package/dist/row-resize.js +7 -1
  51. package/dist/scheduler-ical.d.ts +1 -0
  52. package/dist/scheduler-model.d.ts +1 -0
  53. package/dist/selection.js +9 -0
  54. package/dist/spreadsheet.d.ts +1 -1
  55. package/dist/spreadsheet.js +1 -1
  56. package/dist/summaries.js +22 -0
  57. package/dist/svgrid-wrapper.types.d.ts +5 -0
  58. package/dist/toast-store.svelte.d.ts +4 -0
  59. package/dist/validate.d.ts +50 -0
  60. package/dist/validate.js +187 -0
  61. package/package.json +4 -1
  62. package/src/GridMenus.svelte +17 -12
  63. package/src/SvGrid.controller.svelte.ts +223 -76
  64. package/src/SvGrid.css +1 -1
  65. package/src/SvGrid.svelte +112 -57
  66. package/src/SvGrid.types.ts +191 -1
  67. package/src/ai.ts +28 -0
  68. package/src/cell-formatting.ts +2 -0
  69. package/src/chart-export.ts +1 -0
  70. package/src/chart.ts +31 -5
  71. package/src/column-groups.ts +1 -1
  72. package/src/column-resize.test.ts +381 -0
  73. package/src/column-resize.ts +227 -0
  74. package/src/columns.test.ts +0 -103
  75. package/src/columns.ts +0 -58
  76. package/src/core.aggregate.test.ts +134 -0
  77. package/src/core.filter.test.ts +156 -0
  78. package/src/core.grouping.test.ts +146 -0
  79. package/src/core.row-shape.test.ts +119 -0
  80. package/src/core.rowmodel-cache.test.ts +121 -0
  81. package/src/core.sort.test.ts +293 -0
  82. package/src/core.ts +723 -119
  83. package/src/createTree.svelte.ts +3 -0
  84. package/src/datetime/date-core.ts +2 -0
  85. package/src/datetime/date-restrict.ts +1 -0
  86. package/src/datetime/timezone.ts +1 -0
  87. package/src/dock-manager-model.ts +3 -0
  88. package/src/dock-model.ts +6 -0
  89. package/src/editor-contract.ts +1 -0
  90. package/src/filtering/excel-filters.ts +30 -0
  91. package/src/filtering/normalize-fast-path.test.ts +104 -0
  92. package/src/group-display.ts +1 -1
  93. package/src/index.ts +12 -1
  94. package/src/list-option.ts +1 -0
  95. package/src/menus.ts +1 -1
  96. package/src/positioning.ts +2 -0
  97. package/src/resize-props.test.ts +361 -0
  98. package/src/row-resize.test.ts +31 -0
  99. package/src/row-resize.ts +21 -3
  100. package/src/scheduler-ical.ts +1 -0
  101. package/src/scheduler-model.ts +1 -0
  102. package/src/selection.ts +9 -0
  103. package/src/spreadsheet.ts +1 -1
  104. package/src/summaries.ts +21 -0
  105. package/src/svgrid-wrapper.types.ts +5 -0
  106. package/src/svgrid.summaries.test.ts +217 -0
  107. package/src/toast-store.svelte.ts +4 -0
  108. package/src/validate.test.ts +207 -0
  109. package/src/validate.ts +269 -0
  110. package/dist/cdn/GridMenus-IHK_l7m6.js +0 -489
package/dist/SvGrid.css CHANGED
@@ -1573,7 +1573,7 @@ select.sv-grid-fr-editor {
1573
1573
  position: relative;
1574
1574
  }
1575
1575
  /* Declarative cell validation (column `validate` hook). Invalid cells get a
1576
- * soft red wash and a red inset ring - Handsontable's `htInvalid` look. The
1576
+ * soft red wash and a red inset ring - the conventional spreadsheet invalid-cell look. The
1577
1577
  * value keeps rendering as-is; the message (if any) shows as the tooltip. */
1578
1578
  .sv-grid-cell-invalid {
1579
1579
  background-color: var(--sg-invalid-bg, rgba(239, 68, 68, 0.14)) !important;
@@ -15,6 +15,8 @@
15
15
  } from "./index";
16
16
  import "./sv-grid-scrollbar";
17
17
  import "./SvGrid.css";
18
+ import type { RowResizeOptions } from "./row-resize";
19
+ import type { ColumnResizeOptions } from "./column-resize";
18
20
  import {
19
21
  RenderSnippetConfig,
20
22
  RenderComponentConfig,
@@ -167,7 +169,9 @@
167
169
  const hideTooltip = $derived(ctrl.hideTooltip);
168
170
  const findHits = $derived(ctrl.findHits);
169
171
  const headerHeight = $derived(ctrl.headerHeight);
170
- const resizingColumnId = $derived(ctrl.resizingColumnId);
172
+ // Column resizing has always been unconditional; `columnResize={false}` is
173
+ // the opt-out, so the default has to stay on when the prop is absent.
174
+ const columnResizeEnabled = $derived(opt.columnResize === true);
171
175
  const selectionColumnWidth = $derived(ctrl.selectionColumnWidth);
172
176
  const rowNumberColumnWidth = $derived(ctrl.rowNumberColumnWidth);
173
177
  const showRowNumbersEffective = $derived(ctrl.showRowNumbersEffective);
@@ -184,6 +188,7 @@
184
188
  ctrl.showInlineColumnFilterEffective,
185
189
  );
186
190
  const showRowSelectionEffective = $derived(ctrl.showRowSelectionEffective);
191
+ const rowSummariesEnabled = $derived(ctrl.rowSummariesEnabled);
187
192
  const grid = $derived(ctrl.grid);
188
193
  const allColumns = $derived(ctrl.allColumns);
189
194
  const headerGroups = $derived(ctrl.headerGroups);
@@ -263,6 +268,23 @@
263
268
  // Row-grouping display modes: group state lives in synthetic columns instead
264
269
  // of a full-width banner row.
265
270
  const groupColumnMode = $derived(ctrl.groupColumnMode);
271
+ /**
272
+ * True when a cell's content needs none of the wrapper snippets.
273
+ *
274
+ * A cell body normally renders through `cellBodyWithFormat` ->
275
+ * `cellBodyFormatted` -> `cellBody`, and with no grouping, no tree data and
276
+ * no conditional formats the first two are pure pass-throughs: three snippet
277
+ * renders and two `{#if}` blocks per cell to reach content that one render
278
+ * produces. Measured by ablation, that chain is 4.2 ms of a 17.4 ms mount at
279
+ * 28 rows x 9 columns - about a quarter of the whole mount, and the largest
280
+ * single per-cell cost.
281
+ *
282
+ * Computed once per render rather than per cell, so the fast path costs one
283
+ * boolean read at each of the ~250 cells instead of two snippet frames.
284
+ */
285
+ const plainCellBody = $derived(
286
+ !groupColumnMode && !treeData && !hasConditionalFormats,
287
+ );
266
288
  const autoGroupCell = $derived(ctrl.autoGroupCell);
267
289
  const isAutoGroupColumn = (id: string): boolean =>
268
290
  id === "__autoGroup" || id.startsWith("__group_");
@@ -279,7 +301,60 @@
279
301
  // The fixed row height, matching what the virtualized path takes from the virtualizer.
280
302
  // The non-virtualized (`virtualization={false}`) body must apply this too, else its rows
281
303
  // fall back to content height and look shorter than a virtualized grid's.
304
+ /**
305
+ * `rowResize` and `columnResize` are both opt-in and both default to OFF, so
306
+ * neither module is imported statically - a grid that leaves them alone must
307
+ * not carry their bytes. This wraps an action so its module is fetched on
308
+ * first enable and never otherwise. The handles appear a microtask after the
309
+ * first paint, which is invisible for a drag affordance.
310
+ *
311
+ * One helper for both: two hand-rolled copies of this bookkeeping would cost
312
+ * more base bundle than the deferral saves.
313
+ */
314
+ type LazyHandle<O> = { update(o: O): void; destroy(): void };
315
+ function lazyAction<O extends { disabled?: boolean }>(
316
+ load: () => Promise<(node: HTMLElement, opts: O) => LazyHandle<O>>,
317
+ ) {
318
+ return (node: HTMLElement, opts: O): LazyHandle<O> => {
319
+ let handle: LazyHandle<O> | null = null;
320
+ let current = opts;
321
+ let destroyed = false;
322
+ const ensure = () => {
323
+ if (handle || destroyed || current.disabled) return;
324
+ void load().then((make) => {
325
+ // The prop can be switched back off, or the grid unmounted, while
326
+ // the chunk is still in flight.
327
+ if (destroyed || current.disabled || handle) return;
328
+ handle = make(node, current);
329
+ });
330
+ };
331
+ ensure();
332
+ return {
333
+ update(next: O) {
334
+ current = next;
335
+ if (handle) handle.update(next);
336
+ else ensure();
337
+ },
338
+ destroy() {
339
+ destroyed = true;
340
+ handle?.destroy();
341
+ },
342
+ };
343
+ };
344
+ }
345
+
346
+ const lazyRowResize = lazyAction<RowResizeOptions>(() =>
347
+ import("./row-resize").then((m) => m.rowResize),
348
+ );
349
+ const lazyColumnResize = lazyAction<ColumnResizeOptions>(() =>
350
+ import("./column-resize").then((m) => m.columnResize),
351
+ );
352
+
282
353
  const rowSizePx = (i: number): number => {
354
+ // A height the user dragged wins over the declared one, so the row stays
355
+ // where they put it across re-renders and virtualization recycling.
356
+ const dragged = ctrl.rowResizeHeightPx(i);
357
+ if (dragged != null) return dragged;
283
358
  const rh = opt.rowHeight;
284
359
  return typeof rh === "function" ? rh(i) : (rh ?? 30);
285
360
  };
@@ -357,26 +432,10 @@
357
432
  return "sv-grid-cell-flash";
358
433
  }
359
434
 
360
- // Keyboard-accessible column resize (#79): focus a resize handle and use the
361
- // arrow keys (Shift = fine 1px step). Complements the pointer-drag resize.
362
- function resizeColumnByKeyboard(e: KeyboardEvent, columnId: string) {
363
- let delta = 0;
364
- const step = e.shiftKey ? 1 : 10;
365
- if (e.key === "ArrowLeft") delta = -step;
366
- else if (e.key === "ArrowRight") delta = step;
367
- else return;
368
- e.preventDefault();
369
- const current = ctrl.getColumnWidth(columnId);
370
- ctrl.columnWidths = {
371
- ...ctrl.columnWidths,
372
- [columnId]: Math.max(40, current + delta),
373
- };
374
- }
375
-
376
435
  // ---- Full-row editing -------------------------------------------------
377
436
  const fullRowEdit = $derived(ctrl.fullRowEdit);
378
437
  // Commit the whole row when the user clicks away from its editors (Excel /
379
- // AG-Grid feel). Clicking within any full-row editor keeps editing.
438
+ // spreadsheet feel). Clicking within any full-row editor keeps editing.
380
439
  // Stays here rather than in SvGridCellEditor: that component is instantiated
381
440
  // once PER editable cell during a full-row edit, so a document listener there
382
441
  // would be attached N times and commit N times.
@@ -428,7 +487,6 @@
428
487
  const setActiveCell = $derived(ctrl.setActiveCell);
429
488
  const scrollActiveCellIntoView = $derived(ctrl.scrollActiveCellIntoView);
430
489
  const getColumnWidth = $derived(ctrl.getColumnWidth);
431
- const startColumnResize = $derived(ctrl.startColumnResize);
432
490
  const getCellRangeEdges = $derived(ctrl.getCellRangeEdges);
433
491
  const fillHandleCell = $derived(ctrl.fillHandleCell);
434
492
  const isInFillPreview = $derived(ctrl.isInFillPreview);
@@ -1293,6 +1351,26 @@
1293
1351
  class="sv-grid-root"
1294
1352
  class:sv-grid-root-fill={opt.containerHeight === "100%"}
1295
1353
  style={chartDockReserveStyle}
1354
+ use:lazyRowResize={{
1355
+ disabled: !ctrl.rowResizeOn,
1356
+ // No gutter column on most grids, so fall back to the first body cell -
1357
+ // otherwise `rowResize` would be a prop that silently does nothing.
1358
+ anchor: "row",
1359
+ onResize: (index, height) => ctrl.setRowResizeHeight(index, height),
1360
+ }}
1361
+ use:lazyColumnResize={{
1362
+ disabled: !columnResizeEnabled,
1363
+ getWidth: (columnId) => ctrl.getColumnWidth(columnId),
1364
+ onResize: (columnId, width) => {
1365
+ ctrl.columnWidths = { ...ctrl.columnWidths, [columnId]: width };
1366
+ },
1367
+ label: (columnId) => {
1368
+ const col = ctrl.findColumnById(columnId);
1369
+ return col ? toolPanelHeaderLabel(col) : columnId;
1370
+ },
1371
+ canResize: (columnId) => ctrl.columnResizable(columnId),
1372
+ onAutosize: (columnId) => ctrl.autosizeColumn(columnId),
1373
+ }}
1296
1374
  >
1297
1375
  {#if showGlobalFilterEffective}
1298
1376
  <label class="sv-grid-global-filter">
@@ -1746,32 +1824,6 @@
1746
1824
  }}
1747
1825
  />
1748
1826
  {/if}
1749
- <div
1750
- class="sv-grid-resize-handle"
1751
- class:is-resizing={resizingColumnId ===
1752
- header.column.id}
1753
- role="separator"
1754
- aria-orientation="vertical"
1755
- aria-label={`Resize ${toolPanelHeaderLabel(header.column)}`}
1756
- tabindex="0"
1757
- {...(() => {
1758
- // A focusable separator is a widget, so ARIA requires
1759
- // aria-valuenow. The value it exposes is the column
1760
- // width the arrow keys change; 40 is the floor
1761
- // enforced in resizeColumnByKeyboard.
1762
- const w = Math.round(ctrl.getColumnWidth(header.column.id));
1763
- return {
1764
- "aria-valuenow": w,
1765
- "aria-valuemin": 40,
1766
- "aria-valuetext": `${w} pixels`,
1767
- };
1768
- })()}
1769
- onpointerdown={(event) =>
1770
- startColumnResize(event, header.column.id)}
1771
- onkeydown={(event) =>
1772
- resizeColumnByKeyboard(event, header.column.id)}
1773
- ondblclick={(event) => event.stopPropagation()}
1774
- ></div>
1775
1827
  {/if}
1776
1828
  </th>
1777
1829
  {/if}
@@ -2176,12 +2228,11 @@
2176
2228
  rendered.column.columnDef.cellFlash,
2177
2229
  ),
2178
2230
  }}
2179
- {...getGridCellA11yProps({
2180
- id: getGridCellDomId(ctrl.gridDomId, rowIndex, colIndex),
2181
- rowIndex: rowIndex + 1,
2182
- colIndex: colIndex + 1,
2183
- selected: isRowSelected(row.id),
2184
- })}
2231
+ role="gridcell"
2232
+ id={getGridCellDomId(ctrl.gridDomId, rowIndex, colIndex)}
2233
+ aria-colindex={colIndex + 1}
2234
+ aria-rowindex={rowIndex + 1}
2235
+ aria-selected={isRowSelected(row.id)}
2185
2236
  >
2186
2237
  {#if inRowEdit || isEditing}
2187
2238
  <!-- The editing cell stays empty until the lazy
@@ -2193,11 +2244,15 @@
2193
2244
  <CellEditor {ctrl} column={rendered.column} {row} fullRow={inRowEdit} />
2194
2245
  {/if}
2195
2246
  {:else}
2196
- {@render cellBodyWithFormat(
2197
- row,
2198
- rendered.column,
2199
- cellValue,
2200
- )}
2247
+ {#if plainCellBody}
2248
+ {@render cellBody(row, rendered.column, cellValue)}
2249
+ {:else}
2250
+ {@render cellBodyWithFormat(
2251
+ row,
2252
+ rendered.column,
2253
+ cellValue,
2254
+ )}
2255
+ {/if}
2201
2256
  {/if}
2202
2257
  {#if !isEditing && fillHandleCell && fillHandleCell.rowIndex === rowIndex && fillHandleCell.colIndex === colIndex}
2203
2258
  <!-- Excel-style fill handle: drag down/right to
@@ -2519,7 +2574,7 @@
2519
2574
  {/each}
2520
2575
  </tbody>
2521
2576
  {/if}
2522
- {#if opt.enableRowSummaries ?? true}
2577
+ {#if rowSummariesEnabled}
2523
2578
  <!-- svelte-ignore a11y_no_redundant_roles -->
2524
2579
  <tfoot class="sv-grid-foot" role="rowgroup">
2525
2580
  <tr
@@ -993,7 +993,21 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
993
993
  * work; the shortcut wins only when it is explicitly set.
994
994
  */
995
995
  sortable?: boolean;
996
+ /**
997
+ * Click a header to filter that column. Injects `columnFilteringFeature`,
998
+ * so you do not import it yourself. Which filter surface appears is a
999
+ * separate question - see `filterMode` (default `'menu'`).
1000
+ *
1001
+ * <SvGrid {data} {columns} filterable />
1002
+ */
996
1003
  filterable?: boolean;
1004
+ /**
1005
+ * Inline cell editing. Alias of `enableInlineEditing`, and wins over it when
1006
+ * both are set. A column also needs an `editorType` to be editable; without
1007
+ * one it falls back to a text editor.
1008
+ *
1009
+ * <SvGrid {data} {columns} editable />
1010
+ */
997
1011
  editable?: boolean;
998
1012
  /**
999
1013
  * Cell selection - click a cell to select it, drag or shift-click to extend
@@ -1045,6 +1059,16 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1045
1059
  /** Indent per depth level, in px. Default `12`. */
1046
1060
  indentPx?: number;
1047
1061
  };
1062
+ /**
1063
+ * Show the grouping controls: "Group by this column" in the column menu, and
1064
+ * the group panel when `showGroupPanel` is on. Alias of
1065
+ * `showGroupingControls`, and also injects `columnGroupingFeature`.
1066
+ *
1067
+ * This turns on the UI for grouping. To group without asking the user, set
1068
+ * `groupBy` instead.
1069
+ *
1070
+ * <SvGrid {data} {columns} groupable />
1071
+ */
1048
1072
  groupable?: boolean;
1049
1073
  /**
1050
1074
  * Group the rows by these column ids, outermost first - `['region',
@@ -1122,7 +1146,19 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1122
1146
  autoGroupColumnHeader?: string;
1123
1147
  /** Width (px) of each auto-group column. Default `220`. */
1124
1148
  autoGroupColumnWidth?: number;
1149
+ /**
1150
+ * Show the pagination footer. Alias of `showPagination`, and wins over it
1151
+ * when both are set. Page size starts at `pageSize` (default 10).
1152
+ *
1153
+ * <SvGrid {data} {columns} pageable pageSize={25} />
1154
+ */
1125
1155
  pageable?: boolean;
1156
+ /**
1157
+ * Show the loading state instead of the rows. By default this replaces the
1158
+ * grid body with "Loading..."; set `loadingOverlay` to keep the current rows
1159
+ * visible under a dimmed overlay instead, which is what you usually want for
1160
+ * a server-paged grid.
1161
+ */
1126
1162
  loading?: boolean;
1127
1163
  /**
1128
1164
  * Render `loading` as a non-blocking overlay instead of replacing the
@@ -1134,7 +1170,16 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1134
1170
  loadingOverlay?: boolean;
1135
1171
  /** Skeleton placeholder rows to show on first load. Defaults to 8. */
1136
1172
  loadingSkeletonRows?: number;
1173
+ /**
1174
+ * Render an error message in place of the rows. `null` or omitted means no
1175
+ * error. Takes precedence over `loading` and over the empty state.
1176
+ */
1137
1177
  error?: string | null;
1178
+ /**
1179
+ * Text shown when there are no rows to display - either the data is empty or
1180
+ * a filter matched nothing. Defaults to the localized `noRows` string, so
1181
+ * prefer `localization.text.noRows` when you are translating the whole grid.
1182
+ */
1138
1183
  emptyMessage?: string;
1139
1184
  /**
1140
1185
  * The single place to localize the grid. One object with two fields:
@@ -1154,7 +1199,21 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1154
1199
  * Omitting it (or any field) is a no-op. See {@link GridMessages}.
1155
1200
  */
1156
1201
  localization?: GridLocalization;
1202
+ /**
1203
+ * Show the single search box that filters across every column. Explicitly
1204
+ * setting this wins over `filterMode`; leaving it unset means it appears only
1205
+ * when `filterMode` is `'global'`.
1206
+ */
1157
1207
  showGlobalFilter?: boolean;
1208
+ /**
1209
+ * Show the filter section inside each column's menu. Explicitly setting this
1210
+ * wins over `filterMode`; unset, it follows `filterMode` (default `'menu'`,
1211
+ * so this is normally on).
1212
+ *
1213
+ * Setting it `true` also adds the inline "floating filter" input under each
1214
+ * header - that surface requires the explicit opt-in, since it otherwise
1215
+ * duplicates the menu's own filter popover.
1216
+ */
1158
1217
  showColumnFilters?: boolean;
1159
1218
  /**
1160
1219
  * Quick way to pick a single filtering UI. When set it controls which of
@@ -1163,8 +1222,23 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1163
1222
  * Defaults to `'menu'` (only the column menu's filter section is shown).
1164
1223
  */
1165
1224
  filterMode?: "row" | "menu" | "global" | "none";
1225
+ /**
1226
+ * Show the grouping affordances (the column menu's "Group by this column",
1227
+ * and the group panel). The `groupable` shortcut sets this and registers the
1228
+ * grouping feature in one go; prefer that unless you have already registered
1229
+ * `columnGroupingFeature` yourself.
1230
+ */
1166
1231
  showGroupingControls?: boolean;
1232
+ /**
1233
+ * Show the row-selection checkbox column, including the select-all checkbox
1234
+ * in the header. Unset, it follows `selectionMode` (default `'both'`, so
1235
+ * row selection is on).
1236
+ */
1167
1237
  showRowSelection?: boolean;
1238
+ /**
1239
+ * Show the pagination footer. Off by default. `pageable` is the shortcut
1240
+ * alias and wins when both are set.
1241
+ */
1168
1242
  showPagination?: boolean;
1169
1243
  /** Initial page size when pagination is enabled. Defaults to 10. */
1170
1244
  pageSize?: number;
@@ -1197,6 +1271,14 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1197
1271
  pageIndex: number;
1198
1272
  pageSize: number;
1199
1273
  }) => void;
1274
+ /**
1275
+ * Render only the rows in view instead of all of them. **On by default** -
1276
+ * this is what keeps a 100,000-row grid responsive.
1277
+ *
1278
+ * Turn it off when a row's height cannot be known up front and must not be
1279
+ * clipped, such as a variable-height master-detail panel. Expect the DOM to
1280
+ * hold every row when you do.
1281
+ */
1200
1282
  virtualization?: boolean;
1201
1283
  /** Row height in pixels. Pass a function `(rowIndex) => px` for
1202
1284
  * per-row variable heights (e.g. an interactive row-resize feature).
@@ -1214,6 +1296,28 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1214
1296
  * supplying per-row heights).
1215
1297
  */
1216
1298
  autoRowHeight?: boolean;
1299
+ /**
1300
+ * Let the user drag a row's bottom edge to change its height. **Off by
1301
+ * default**, because a resizable row needs somewhere to grab and most grids
1302
+ * do not want a drag target on every row.
1303
+ *
1304
+ * The grid remembers the heights itself, so this works as a bare boolean -
1305
+ * no `rowHeight` function required. Drag, or focus the grip and use Up/Down
1306
+ * (Shift for 1px steps).
1307
+ *
1308
+ * Turning this on also turns on the **row header column** ({@link
1309
+ * showRowNumbers}), because that is where the grip lives and where a
1310
+ * spreadsheet puts it - a drag target on the edge of a data cell works but
1311
+ * reads as an accident. An explicit `showRowNumbers={false}` still wins; the
1312
+ * grip then falls back to the row's first cell, and a column of your own
1313
+ * carrying `cellClass: 'sv-row-gutter'` is used ahead of either.
1314
+ *
1315
+ * Ignored under `autoRowHeight`, where the content decides the height and a
1316
+ * manual one would immediately be overwritten. For full control of the
1317
+ * heights - persisting them, sharing them between grids - pass a
1318
+ * function-valued {@link rowHeight} and use the `rowResize` action directly.
1319
+ */
1320
+ rowResize?: boolean;
1217
1321
  /**
1218
1322
  * Height (px) of a single column-header level row. With multi-level
1219
1323
  * (grouped) headers the total header height is `levels * headerHeight`,
@@ -1221,6 +1325,11 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1221
1325
  * to their content (the default). Does not affect the filter row.
1222
1326
  */
1223
1327
  headerHeight?: number;
1328
+ /**
1329
+ * Extra rows rendered above and below the viewport, so fast scrolling does
1330
+ * not reach empty space before the next batch renders. Defaults to 8.
1331
+ * Raise it for very tall rows, lower it to trim DOM work.
1332
+ */
1224
1333
  overscan?: number;
1225
1334
  /**
1226
1335
  * Height of the grid's scrollable shell. A number is treated as pixels;
@@ -1228,8 +1337,24 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1228
1337
  * make the grid fill its parent. Defaults to 520 px.
1229
1338
  */
1230
1339
  containerHeight?: number | string;
1340
+ /**
1341
+ * Render only the columns in view, the horizontal counterpart of
1342
+ * `virtualization`. **On by default**, which is what makes a 100-column grid
1343
+ * scroll smoothly.
1344
+ *
1345
+ * It recycles column DOM nodes, so it cannot coexist with sticky pinned
1346
+ * columns - turn it off if you need pinning to survive horizontal scrolling.
1347
+ */
1231
1348
  columnVirtualization?: boolean;
1349
+ /**
1350
+ * Extra columns rendered either side of the viewport when
1351
+ * `columnVirtualization` is on. Defaults to 3.
1352
+ */
1232
1353
  columnOverscan?: number;
1354
+ /**
1355
+ * Fallback width in pixels for columns whose `ColumnDef` sets no `width`.
1356
+ * Defaults to 140.
1357
+ */
1233
1358
  columnWidth?: number;
1234
1359
  /**
1235
1360
  * Columns pinned to the left/right edge on mount. Each entry is a
@@ -1251,6 +1376,24 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1251
1376
  * win once they happen.
1252
1377
  */
1253
1378
  fitColumns?: boolean;
1379
+ /**
1380
+ * Let the user drag a column's edge to change its width. **Off by default**,
1381
+ * so `width` means the width you asked for until you say otherwise.
1382
+ *
1383
+ * Turn it on for grids the reader is meant to arrange - a spreadsheet, a
1384
+ * dense report, anything with columns whose content varies in length. Leave
1385
+ * it off for layouts you control, and for columns that must keep their size:
1386
+ * a row-number gutter, a checkbox column, an icon column.
1387
+ *
1388
+ * It is grid-wide rather than per-column: there is no `resizable: false` on a
1389
+ * single column definition. `api.autosizeColumn()`, `fitColumns` and
1390
+ * programmatic width changes work either way - this only governs the drag
1391
+ * handle.
1392
+ *
1393
+ * The handles come from the `columnResize` action, loaded on demand: a grid
1394
+ * that leaves this off never fetches that code.
1395
+ */
1396
+ columnResize?: boolean;
1254
1397
  /**
1255
1398
  * Make the grid usable on narrow screens. When the grid's own width drops
1256
1399
  * below the breakpoint (default `640`px), pinned columns are un-pinned so the
@@ -1262,8 +1405,24 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1262
1405
  responsive?: boolean | {
1263
1406
  breakpoint?: number;
1264
1407
  };
1408
+ /**
1409
+ * @deprecated Has no effect - nothing in the grid reads this prop. It is kept
1410
+ * only so existing code keeps compiling. The column menu's filter section is
1411
+ * controlled by `showColumnFilters`, or by `filterMode="menu"` (the default).
1412
+ */
1265
1413
  showFilterMenu?: boolean;
1414
+ /**
1415
+ * Show the always-visible filter row under the header. Explicitly setting
1416
+ * this wins over `filterMode`; unset, it appears only when `filterMode` is
1417
+ * `'row'`.
1418
+ */
1266
1419
  showFilterRow?: boolean;
1420
+ /**
1421
+ * Cell selection - click to select, drag or shift-click to extend to a range,
1422
+ * which is what clipboard copy and the range fill handle operate on. Unset,
1423
+ * it follows `selectionMode` (default `'both'`, so this is on). `selectable`
1424
+ * is the shortcut alias and wins over it.
1425
+ */
1267
1426
  enableCellSelection?: boolean;
1268
1427
  /**
1269
1428
  * Highlight the row under the pointer. Default **false** - the hover tint can
@@ -1289,6 +1448,14 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1289
1448
  rowIndex: number;
1290
1449
  columnId: string;
1291
1450
  }) => unknown;
1451
+ /**
1452
+ * Inline cell editing: F2 or double-click opens an editor in the active cell,
1453
+ * Enter commits, Esc cancels. Off by default.
1454
+ *
1455
+ * A column still needs an `editorType` to pick its editor (text, number,
1456
+ * date, checkbox, list, ...); without one it gets a plain text editor.
1457
+ * `editable` is the shortcut alias and wins over this.
1458
+ */
1292
1459
  enableInlineEditing?: boolean;
1293
1460
  /**
1294
1461
  * Full-row editing. When `true`, starting an edit puts the WHOLE row into
@@ -1298,7 +1465,22 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1298
1465
  * text / number / date / datetime / checkbox / list-select editor types.
1299
1466
  */
1300
1467
  fullRowEditing?: boolean;
1468
+ /**
1469
+ * Append a sticky footer row aggregating every filtered row: the sum of a
1470
+ * numeric column, `Count: N` otherwise. Choose a different aggregate per
1471
+ * column with that column's own `summary` option, or set it to `false` there
1472
+ * to leave the cell blank.
1473
+ *
1474
+ * Off by default. `summary` is the shortcut alias and wins when both are set.
1475
+ *
1476
+ * <SvGrid {data} {columns} summary />
1477
+ */
1301
1478
  enableRowSummaries?: boolean;
1479
+ /**
1480
+ * Shortcut alias for {@link enableRowSummaries}. Wins over it when both are
1481
+ * set, the same precedence `selectable` has over `enableCellSelection`.
1482
+ */
1483
+ summary?: boolean;
1302
1484
  /**
1303
1485
  * Excel-style status bar under the grid showing live aggregates of the
1304
1486
  * selected cell range (count, numeric count, sum, average, min, max).
@@ -1321,7 +1503,7 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1321
1503
  charting?: boolean | ChartingConfig<TData>;
1322
1504
  /**
1323
1505
  * Render the header column menu (⋮) as a tabbed popover - **General**,
1324
- * **Filter**, and **Columns** tabs (the AG-Grid layout). Defaults to `false`,
1506
+ * **Filter**, and **Columns** tabs (the tabbed layout). Defaults to `false`,
1325
1507
  * which keeps the flat menu (actions list + "Choose columns" submenu).
1326
1508
  */
1327
1509
  columnMenuTabs?: boolean;
@@ -1514,6 +1696,14 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1514
1696
  * filter.
1515
1697
  */
1516
1698
  conditionalStatScope?: "filtered" | "visible" | "all";
1699
+ /**
1700
+ * Fires after an inline edit commits, with the cell's old and new value and
1701
+ * the row it belongs to. This is where you persist the change.
1702
+ *
1703
+ * The grid has already applied the edit to its own state by the time this
1704
+ * runs, so it is a notification, not a veto - reject a value with the
1705
+ * column's `valueParser` or a validation rule instead.
1706
+ */
1517
1707
  onCellValueChange?: (event: {
1518
1708
  rowIndex: number;
1519
1709
  columnId: string;