@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/src/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;
package/src/SvGrid.svelte CHANGED
@@ -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
@@ -1029,7 +1029,21 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1029
1029
  * work; the shortcut wins only when it is explicitly set.
1030
1030
  */
1031
1031
  sortable?: boolean;
1032
+ /**
1033
+ * Click a header to filter that column. Injects `columnFilteringFeature`,
1034
+ * so you do not import it yourself. Which filter surface appears is a
1035
+ * separate question - see `filterMode` (default `'menu'`).
1036
+ *
1037
+ * <SvGrid {data} {columns} filterable />
1038
+ */
1032
1039
  filterable?: boolean;
1040
+ /**
1041
+ * Inline cell editing. Alias of `enableInlineEditing`, and wins over it when
1042
+ * both are set. A column also needs an `editorType` to be editable; without
1043
+ * one it falls back to a text editor.
1044
+ *
1045
+ * <SvGrid {data} {columns} editable />
1046
+ */
1033
1047
  editable?: boolean;
1034
1048
  /**
1035
1049
  * Cell selection - click a cell to select it, drag or shift-click to extend
@@ -1081,6 +1095,16 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1081
1095
  /** Indent per depth level, in px. Default `12`. */
1082
1096
  indentPx?: number;
1083
1097
  };
1098
+ /**
1099
+ * Show the grouping controls: "Group by this column" in the column menu, and
1100
+ * the group panel when `showGroupPanel` is on. Alias of
1101
+ * `showGroupingControls`, and also injects `columnGroupingFeature`.
1102
+ *
1103
+ * This turns on the UI for grouping. To group without asking the user, set
1104
+ * `groupBy` instead.
1105
+ *
1106
+ * <SvGrid {data} {columns} groupable />
1107
+ */
1084
1108
  groupable?: boolean;
1085
1109
  /**
1086
1110
  * Group the rows by these column ids, outermost first - `['region',
@@ -1158,7 +1182,19 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1158
1182
  autoGroupColumnHeader?: string;
1159
1183
  /** Width (px) of each auto-group column. Default `220`. */
1160
1184
  autoGroupColumnWidth?: number;
1185
+ /**
1186
+ * Show the pagination footer. Alias of `showPagination`, and wins over it
1187
+ * when both are set. Page size starts at `pageSize` (default 10).
1188
+ *
1189
+ * <SvGrid {data} {columns} pageable pageSize={25} />
1190
+ */
1161
1191
  pageable?: boolean;
1192
+ /**
1193
+ * Show the loading state instead of the rows. By default this replaces the
1194
+ * grid body with "Loading..."; set `loadingOverlay` to keep the current rows
1195
+ * visible under a dimmed overlay instead, which is what you usually want for
1196
+ * a server-paged grid.
1197
+ */
1162
1198
  loading?: boolean;
1163
1199
  /**
1164
1200
  * Render `loading` as a non-blocking overlay instead of replacing the
@@ -1170,7 +1206,16 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1170
1206
  loadingOverlay?: boolean;
1171
1207
  /** Skeleton placeholder rows to show on first load. Defaults to 8. */
1172
1208
  loadingSkeletonRows?: number;
1209
+ /**
1210
+ * Render an error message in place of the rows. `null` or omitted means no
1211
+ * error. Takes precedence over `loading` and over the empty state.
1212
+ */
1173
1213
  error?: string | null;
1214
+ /**
1215
+ * Text shown when there are no rows to display - either the data is empty or
1216
+ * a filter matched nothing. Defaults to the localized `noRows` string, so
1217
+ * prefer `localization.text.noRows` when you are translating the whole grid.
1218
+ */
1174
1219
  emptyMessage?: string;
1175
1220
  /**
1176
1221
  * The single place to localize the grid. One object with two fields:
@@ -1190,7 +1235,21 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1190
1235
  * Omitting it (or any field) is a no-op. See {@link GridMessages}.
1191
1236
  */
1192
1237
  localization?: GridLocalization;
1238
+ /**
1239
+ * Show the single search box that filters across every column. Explicitly
1240
+ * setting this wins over `filterMode`; leaving it unset means it appears only
1241
+ * when `filterMode` is `'global'`.
1242
+ */
1193
1243
  showGlobalFilter?: boolean;
1244
+ /**
1245
+ * Show the filter section inside each column's menu. Explicitly setting this
1246
+ * wins over `filterMode`; unset, it follows `filterMode` (default `'menu'`,
1247
+ * so this is normally on).
1248
+ *
1249
+ * Setting it `true` also adds the inline "floating filter" input under each
1250
+ * header - that surface requires the explicit opt-in, since it otherwise
1251
+ * duplicates the menu's own filter popover.
1252
+ */
1194
1253
  showColumnFilters?: boolean;
1195
1254
  /**
1196
1255
  * Quick way to pick a single filtering UI. When set it controls which of
@@ -1199,8 +1258,23 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1199
1258
  * Defaults to `'menu'` (only the column menu's filter section is shown).
1200
1259
  */
1201
1260
  filterMode?: "row" | "menu" | "global" | "none";
1261
+ /**
1262
+ * Show the grouping affordances (the column menu's "Group by this column",
1263
+ * and the group panel). The `groupable` shortcut sets this and registers the
1264
+ * grouping feature in one go; prefer that unless you have already registered
1265
+ * `columnGroupingFeature` yourself.
1266
+ */
1202
1267
  showGroupingControls?: boolean;
1268
+ /**
1269
+ * Show the row-selection checkbox column, including the select-all checkbox
1270
+ * in the header. Unset, it follows `selectionMode` (default `'both'`, so
1271
+ * row selection is on).
1272
+ */
1203
1273
  showRowSelection?: boolean;
1274
+ /**
1275
+ * Show the pagination footer. Off by default. `pageable` is the shortcut
1276
+ * alias and wins when both are set.
1277
+ */
1204
1278
  showPagination?: boolean;
1205
1279
  /** Initial page size when pagination is enabled. Defaults to 10. */
1206
1280
  pageSize?: number;
@@ -1230,6 +1304,14 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1230
1304
  * is on. Fetch that page and update `data` / `rowCount` / `pageIndex`.
1231
1305
  */
1232
1306
  onPaginationChange?: (pagination: { pageIndex: number; pageSize: number }) => void;
1307
+ /**
1308
+ * Render only the rows in view instead of all of them. **On by default** -
1309
+ * this is what keeps a 100,000-row grid responsive.
1310
+ *
1311
+ * Turn it off when a row's height cannot be known up front and must not be
1312
+ * clipped, such as a variable-height master-detail panel. Expect the DOM to
1313
+ * hold every row when you do.
1314
+ */
1233
1315
  virtualization?: boolean;
1234
1316
  /** Row height in pixels. Pass a function `(rowIndex) => px` for
1235
1317
  * per-row variable heights (e.g. an interactive row-resize feature).
@@ -1247,6 +1329,28 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1247
1329
  * supplying per-row heights).
1248
1330
  */
1249
1331
  autoRowHeight?: boolean;
1332
+ /**
1333
+ * Let the user drag a row's bottom edge to change its height. **Off by
1334
+ * default**, because a resizable row needs somewhere to grab and most grids
1335
+ * do not want a drag target on every row.
1336
+ *
1337
+ * The grid remembers the heights itself, so this works as a bare boolean -
1338
+ * no `rowHeight` function required. Drag, or focus the grip and use Up/Down
1339
+ * (Shift for 1px steps).
1340
+ *
1341
+ * Turning this on also turns on the **row header column** ({@link
1342
+ * showRowNumbers}), because that is where the grip lives and where a
1343
+ * spreadsheet puts it - a drag target on the edge of a data cell works but
1344
+ * reads as an accident. An explicit `showRowNumbers={false}` still wins; the
1345
+ * grip then falls back to the row's first cell, and a column of your own
1346
+ * carrying `cellClass: 'sv-row-gutter'` is used ahead of either.
1347
+ *
1348
+ * Ignored under `autoRowHeight`, where the content decides the height and a
1349
+ * manual one would immediately be overwritten. For full control of the
1350
+ * heights - persisting them, sharing them between grids - pass a
1351
+ * function-valued {@link rowHeight} and use the `rowResize` action directly.
1352
+ */
1353
+ rowResize?: boolean;
1250
1354
  /**
1251
1355
  * Height (px) of a single column-header level row. With multi-level
1252
1356
  * (grouped) headers the total header height is `levels * headerHeight`,
@@ -1254,6 +1358,11 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1254
1358
  * to their content (the default). Does not affect the filter row.
1255
1359
  */
1256
1360
  headerHeight?: number;
1361
+ /**
1362
+ * Extra rows rendered above and below the viewport, so fast scrolling does
1363
+ * not reach empty space before the next batch renders. Defaults to 8.
1364
+ * Raise it for very tall rows, lower it to trim DOM work.
1365
+ */
1257
1366
  overscan?: number;
1258
1367
  /**
1259
1368
  * Height of the grid's scrollable shell. A number is treated as pixels;
@@ -1261,8 +1370,24 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1261
1370
  * make the grid fill its parent. Defaults to 520 px.
1262
1371
  */
1263
1372
  containerHeight?: number | string;
1373
+ /**
1374
+ * Render only the columns in view, the horizontal counterpart of
1375
+ * `virtualization`. **On by default**, which is what makes a 100-column grid
1376
+ * scroll smoothly.
1377
+ *
1378
+ * It recycles column DOM nodes, so it cannot coexist with sticky pinned
1379
+ * columns - turn it off if you need pinning to survive horizontal scrolling.
1380
+ */
1264
1381
  columnVirtualization?: boolean;
1382
+ /**
1383
+ * Extra columns rendered either side of the viewport when
1384
+ * `columnVirtualization` is on. Defaults to 3.
1385
+ */
1265
1386
  columnOverscan?: number;
1387
+ /**
1388
+ * Fallback width in pixels for columns whose `ColumnDef` sets no `width`.
1389
+ * Defaults to 140.
1390
+ */
1266
1391
  columnWidth?: number;
1267
1392
  /**
1268
1393
  * Columns pinned to the left/right edge on mount. Each entry is a
@@ -1284,6 +1409,24 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1284
1409
  * win once they happen.
1285
1410
  */
1286
1411
  fitColumns?: boolean;
1412
+ /**
1413
+ * Let the user drag a column's edge to change its width. **Off by default**,
1414
+ * so `width` means the width you asked for until you say otherwise.
1415
+ *
1416
+ * Turn it on for grids the reader is meant to arrange - a spreadsheet, a
1417
+ * dense report, anything with columns whose content varies in length. Leave
1418
+ * it off for layouts you control, and for columns that must keep their size:
1419
+ * a row-number gutter, a checkbox column, an icon column.
1420
+ *
1421
+ * It is grid-wide rather than per-column: there is no `resizable: false` on a
1422
+ * single column definition. `api.autosizeColumn()`, `fitColumns` and
1423
+ * programmatic width changes work either way - this only governs the drag
1424
+ * handle.
1425
+ *
1426
+ * The handles come from the `columnResize` action, loaded on demand: a grid
1427
+ * that leaves this off never fetches that code.
1428
+ */
1429
+ columnResize?: boolean;
1287
1430
  /**
1288
1431
  * Make the grid usable on narrow screens. When the grid's own width drops
1289
1432
  * below the breakpoint (default `640`px), pinned columns are un-pinned so the
@@ -1293,8 +1436,24 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1293
1436
  * breakpoint; pass `{ breakpoint }` to change it. Off by default.
1294
1437
  */
1295
1438
  responsive?: boolean | { breakpoint?: number };
1439
+ /**
1440
+ * @deprecated Has no effect - nothing in the grid reads this prop. It is kept
1441
+ * only so existing code keeps compiling. The column menu's filter section is
1442
+ * controlled by `showColumnFilters`, or by `filterMode="menu"` (the default).
1443
+ */
1296
1444
  showFilterMenu?: boolean;
1445
+ /**
1446
+ * Show the always-visible filter row under the header. Explicitly setting
1447
+ * this wins over `filterMode`; unset, it appears only when `filterMode` is
1448
+ * `'row'`.
1449
+ */
1297
1450
  showFilterRow?: boolean;
1451
+ /**
1452
+ * Cell selection - click to select, drag or shift-click to extend to a range,
1453
+ * which is what clipboard copy and the range fill handle operate on. Unset,
1454
+ * it follows `selectionMode` (default `'both'`, so this is on). `selectable`
1455
+ * is the shortcut alias and wins over it.
1456
+ */
1298
1457
  enableCellSelection?: boolean;
1299
1458
  /**
1300
1459
  * Highlight the row under the pointer. Default **false** - the hover tint can
@@ -1320,6 +1479,14 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1320
1479
  rowIndex: number;
1321
1480
  columnId: string;
1322
1481
  }) => unknown;
1482
+ /**
1483
+ * Inline cell editing: F2 or double-click opens an editor in the active cell,
1484
+ * Enter commits, Esc cancels. Off by default.
1485
+ *
1486
+ * A column still needs an `editorType` to pick its editor (text, number,
1487
+ * date, checkbox, list, ...); without one it gets a plain text editor.
1488
+ * `editable` is the shortcut alias and wins over this.
1489
+ */
1323
1490
  enableInlineEditing?: boolean;
1324
1491
  /**
1325
1492
  * Full-row editing. When `true`, starting an edit puts the WHOLE row into
@@ -1329,7 +1496,22 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1329
1496
  * text / number / date / datetime / checkbox / list-select editor types.
1330
1497
  */
1331
1498
  fullRowEditing?: boolean;
1499
+ /**
1500
+ * Append a sticky footer row aggregating every filtered row: the sum of a
1501
+ * numeric column, `Count: N` otherwise. Choose a different aggregate per
1502
+ * column with that column's own `summary` option, or set it to `false` there
1503
+ * to leave the cell blank.
1504
+ *
1505
+ * Off by default. `summary` is the shortcut alias and wins when both are set.
1506
+ *
1507
+ * <SvGrid {data} {columns} summary />
1508
+ */
1332
1509
  enableRowSummaries?: boolean;
1510
+ /**
1511
+ * Shortcut alias for {@link enableRowSummaries}. Wins over it when both are
1512
+ * set, the same precedence `selectable` has over `enableCellSelection`.
1513
+ */
1514
+ summary?: boolean;
1333
1515
  /**
1334
1516
  * Excel-style status bar under the grid showing live aggregates of the
1335
1517
  * selected cell range (count, numeric count, sum, average, min, max).
@@ -1356,7 +1538,7 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1356
1538
  charting?: boolean | ChartingConfig<TData>;
1357
1539
  /**
1358
1540
  * Render the header column menu (⋮) as a tabbed popover - **General**,
1359
- * **Filter**, and **Columns** tabs (the AG-Grid layout). Defaults to `false`,
1541
+ * **Filter**, and **Columns** tabs (the tabbed layout). Defaults to `false`,
1360
1542
  * which keeps the flat menu (actions list + "Choose columns" submenu).
1361
1543
  */
1362
1544
  columnMenuTabs?: boolean;
@@ -1544,6 +1726,14 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
1544
1726
  * filter.
1545
1727
  */
1546
1728
  conditionalStatScope?: "filtered" | "visible" | "all";
1729
+ /**
1730
+ * Fires after an inline edit commits, with the cell's old and new value and
1731
+ * the row it belongs to. This is where you persist the change.
1732
+ *
1733
+ * The grid has already applied the edit to its own state by the time this
1734
+ * runs, so it is a notification, not a veto - reject a value with the
1735
+ * column's `valueParser` or a validation rule instead.
1736
+ */
1547
1737
  onCellValueChange?: (event: {
1548
1738
  rowIndex: number;
1549
1739
  columnId: string;