@svgrid/grid 3.0.4 → 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 (176) hide show
  1. package/README.md +32 -11
  2. package/dist/GridMenus.svelte +34 -4
  3. package/dist/SvGrid.controller.svelte.d.ts +33 -5
  4. package/dist/SvGrid.controller.svelte.js +397 -58
  5. package/dist/SvGrid.css +200 -2
  6. package/dist/SvGrid.svelte +350 -40
  7. package/dist/SvGrid.types.d.ts +433 -7
  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 +92 -37
  15. package/dist/cdn/{GridMenus-BL7ZgQvU.js → GridMenus-C-NtjlrJ.js} +155 -146
  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-DIqb3VZn.js +241 -0
  45. package/dist/cdn/{src-V1uu8iE9.js → src-CgoeSM8k.js} +5339 -4753
  46. package/dist/cdn/{src-BKhZ6eXd.js → src-DfwxB1TH.js} +9817 -9231
  47. package/dist/cdn/svgrid.js +28 -27
  48. package/dist/cdn/svgrid.svelte-external.js +28 -27
  49. package/dist/cdn/validate-AZoD8BoR.js +80 -0
  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 +401 -38
  59. package/dist/editing.js +34 -0
  60. package/dist/gantt-view.svelte.d.ts +24 -0
  61. package/dist/gantt-view.svelte.js +13 -0
  62. package/dist/grid-icons.d.ts +2 -2
  63. package/dist/grid-icons.js +2 -2
  64. package/dist/grid-messages.d.ts +10 -0
  65. package/dist/grid-messages.js +9 -0
  66. package/dist/headless.d.ts +5 -0
  67. package/dist/headless.js +12 -0
  68. package/dist/history.d.ts +21 -0
  69. package/dist/history.js +34 -4
  70. package/dist/index.d.ts +5 -4
  71. package/dist/index.js +3 -3
  72. package/dist/keyboard-handlers.js +24 -1
  73. package/dist/keyboard.js +4 -0
  74. package/dist/row-drag-touch.d.ts +1 -1
  75. package/dist/row-drag.js +35 -1
  76. package/dist/row-model.d.ts +139 -0
  77. package/dist/row-model.js +16 -0
  78. package/dist/row-resize.js +22 -1
  79. package/dist/selection.d.ts +2 -1
  80. package/dist/selection.js +31 -3
  81. package/dist/server-block-cache.d.ts +219 -0
  82. package/dist/server-block-cache.js +539 -0
  83. package/dist/server-data-source.d.ts +274 -8
  84. package/dist/server-data-source.js +229 -20
  85. package/dist/server.d.ts +13 -0
  86. package/dist/server.js +13 -0
  87. package/dist/sparkline.js +7 -5
  88. package/dist/svgrid-wrapper.types.d.ts +33 -0
  89. package/dist/validate.d.ts +4 -0
  90. package/dist/validate.js +29 -3
  91. package/package.json +11 -1
  92. package/src/GridMenus.svelte +34 -4
  93. package/src/SvGrid.controller.svelte.ts +397 -61
  94. package/src/SvGrid.css +200 -2
  95. package/src/SvGrid.svelte +350 -40
  96. package/src/SvGrid.types.ts +453 -7
  97. package/src/SvGridDropdown.svelte +20 -0
  98. package/src/SvModal.svelte +22 -0
  99. package/src/SvModal.test.ts +30 -1
  100. package/src/a11y/dismissable.test.ts +10 -1
  101. package/src/a11y/dismissable.ts +22 -2
  102. package/src/build-api.ts +96 -31
  103. package/src/cell-formatting.test.ts +17 -0
  104. package/src/cell-formatting.ts +18 -1
  105. package/src/cell-render.test.ts +24 -2
  106. package/src/cell-render.ts +24 -8
  107. package/src/clipboard.test.ts +107 -0
  108. package/src/clipboard.ts +62 -23
  109. package/src/columns.test.ts +4 -4
  110. package/src/columns.ts +7 -2
  111. package/src/conditional-formatting.test.ts +8 -0
  112. package/src/conditional-formatting.ts +3 -0
  113. package/src/core.rowmodel-cache.test.ts +51 -0
  114. package/src/core.tick-repair.test.ts +287 -0
  115. package/src/core.ts +407 -38
  116. package/src/editing.test.ts +52 -0
  117. package/src/editing.ts +33 -0
  118. package/src/gantt-stub.test.svelte +38 -0
  119. package/src/gantt-view.svelte.ts +35 -0
  120. package/src/grid-icons.ts +2 -2
  121. package/src/grid-messages.test.ts +7 -0
  122. package/src/grid-messages.ts +22 -0
  123. package/src/headless.ts +24 -0
  124. package/src/history.test.ts +49 -1
  125. package/src/history.ts +48 -2
  126. package/src/icon-seam.test.ts +2 -4
  127. package/src/index.ts +38 -10
  128. package/src/keyboard-handlers.coverage.test.ts +65 -0
  129. package/src/keyboard-handlers.ts +26 -1
  130. package/src/keyboard.ts +3 -0
  131. package/src/row-drag-touch.ts +2 -2
  132. package/src/row-drag.test.ts +51 -0
  133. package/src/row-drag.ts +35 -2
  134. package/src/row-model.ts +152 -0
  135. package/src/row-resize.ts +24 -1
  136. package/src/selection.test.ts +3 -0
  137. package/src/selection.ts +33 -3
  138. package/src/server-block-cache.test.ts +672 -0
  139. package/src/server-block-cache.ts +690 -0
  140. package/src/server-data-source.infinite.test.ts +405 -0
  141. package/src/server-data-source.test.ts +19 -0
  142. package/src/server-data-source.ts +496 -29
  143. package/src/server.ts +49 -0
  144. package/src/sparkline.test.ts +7 -0
  145. package/src/sparkline.ts +6 -4
  146. package/src/svgrid-wrapper.types.ts +32 -0
  147. package/src/svgrid.api.test.ts +21 -0
  148. package/src/svgrid.charting.test.ts +12 -4
  149. package/src/svgrid.context-menu.test.ts +12 -0
  150. package/src/svgrid.detail-rows.svelte.test.ts +187 -0
  151. package/src/svgrid.filter-menu-scroll.test.ts +9 -0
  152. package/src/svgrid.gantt-seam.test.ts +199 -0
  153. package/src/svgrid.live-update-paths.svelte.test.ts +184 -0
  154. package/src/svgrid.menu-scroll-close.test.ts +10 -0
  155. package/src/svgrid.row-model-prop.svelte.test.ts +352 -0
  156. package/src/svgrid.row-model-seam.svelte.test.ts +305 -0
  157. package/src/svgrid.row-pinning.test.ts +15 -1
  158. package/src/svgrid.selection-bar-seam.test.ts +1 -1
  159. package/src/svgrid.sticky-groups.svelte.test.ts +145 -0
  160. package/src/svgrid.upsell-license.test.ts +8 -5
  161. package/src/test-setup.ts +12 -0
  162. package/src/transaction.test.ts +58 -0
  163. package/src/validate.test.ts +29 -0
  164. package/src/validate.ts +34 -3
  165. package/dist/SvGroupCell.svelte +0 -141
  166. package/dist/SvGroupCell.svelte.d.ts +0 -49
  167. package/dist/SvRowGroupPanel.svelte +0 -186
  168. package/dist/SvRowGroupPanel.svelte.d.ts +0 -25
  169. package/dist/cdn/GridMenus-7kbpnnBW.js +0 -635
  170. package/dist/cdn/validate-_CDJzgIo.js +0 -75
  171. package/dist/server-group-model.d.ts +0 -98
  172. package/dist/server-group-model.js +0 -263
  173. package/src/SvGroupCell.svelte +0 -141
  174. package/src/SvRowGroupPanel.svelte +0 -186
  175. package/src/server-group-model.test.ts +0 -294
  176. package/src/server-group-model.ts +0 -370
@@ -16,10 +16,17 @@
16
16
  * follow-up re-fetch of the current page lands.
17
17
  */
18
18
  import type { GridPredicateExpr } from './filtering/predicate-expr.js';
19
+ import { type BlockState } from './server-block-cache.js';
20
+ import { type GridFilterState, type GridRowModel } from './row-model.js';
21
+ /** Sort clauses in priority order; `id` is the column id. */
19
22
  export type ServerSortModel = Array<{
20
23
  id: string;
21
24
  desc: boolean;
22
25
  }>;
26
+ /**
27
+ * What a request carries for filtering: the global search, the per-column
28
+ * operator filters, and the advanced-filter expression.
29
+ */
23
30
  export type ServerFilterModel = {
24
31
  /** Free-text global search. */
25
32
  global?: string;
@@ -53,11 +60,24 @@ export type ServerFilterModel = {
53
60
  */
54
61
  expression?: GridPredicateExpr;
55
62
  };
56
- /** A value column to roll up per group. */
63
+ /** The aggregate functions every backend helper understands. */
64
+ export type ServerAggFn = 'sum' | 'avg' | 'min' | 'max' | 'count';
65
+ /**
66
+ * One value column to roll up per group. `fn` is one of the five built-ins
67
+ * or any name your backend knows (`median`, `countDistinct`, a domain
68
+ * aggregate): the request carries it untouched. The SvelteKit planner emits
69
+ * only the built-ins plus the names it was told to allow, since `fn` ends
70
+ * up in SQL.
71
+ */
57
72
  export type ServerAggregation = {
58
73
  col: string;
59
- fn: 'sum' | 'avg' | 'min' | 'max' | 'count';
74
+ fn: ServerAggFn | (string & {});
60
75
  };
76
+ /**
77
+ * One range of rows as the grid asks for it. A flat request carries the
78
+ * range, the sort and the filter; a grouped request adds `groupBy`,
79
+ * `groupKeys` and `aggregations`; a pivoted one `pivotBy` and `pivotMode`.
80
+ */
61
81
  export type ServerRequest = {
62
82
  /** Zero-based index of the first row wanted (inclusive). */
63
83
  startRow: number;
@@ -82,6 +102,43 @@ export type ServerRequest = {
82
102
  groupKeys?: string[];
83
103
  /** Value columns to aggregate per group. */
84
104
  aggregations?: ServerAggregation[];
105
+ /**
106
+ * Server-side pivot: the columns whose distinct values become columns.
107
+ * With `pivotMode` on, a group row carries one value per (pivot key x
108
+ * aggregation) under a field named `<key>_<col>` (the separator is the
109
+ * row model's `pivotFieldSeparator`), and the response lists those
110
+ * fields in `pivotResultFields`. Only the Enterprise row model sets it.
111
+ */
112
+ pivotBy?: string[];
113
+ pivotMode?: boolean;
114
+ /**
115
+ * True on a top-level request when the grid wants a grand-total row and
116
+ * does not have one cached. Answer with `ServerResult.grandTotal`. Only
117
+ * the Enterprise server row model sets it.
118
+ */
119
+ needsGrandTotal?: boolean;
120
+ /**
121
+ * The group (or tree node) row being expanded, when this request is for
122
+ * its children. Handy for backends that key children off something on
123
+ * the parent rather than off `groupKeys`. Absent at the top level.
124
+ */
125
+ parentRow?: unknown;
126
+ /**
127
+ * Whatever the app passed as `context` to its controller, forwarded
128
+ * untouched on every request. Keep it JSON-serialisable: the SvelteKit
129
+ * transport posts the whole request to your endpoint.
130
+ */
131
+ context?: unknown;
132
+ /**
133
+ * Aborted when the grid no longer wants the answer: the block was purged
134
+ * or evicted, the sort or filter changed, a group was collapsed, the
135
+ * controller was disposed. Hand it to `fetch` and a query the user has
136
+ * scrolled past is cancelled at the server instead of completing for
137
+ * nothing; a rejection carrying the abort is ignored by the grid. Not
138
+ * serialisable - the SvelteKit transport reads it and leaves it out of
139
+ * the body.
140
+ */
141
+ signal?: AbortSignal;
85
142
  };
86
143
  /**
87
144
  * A group row in the server-side group/tree model - one distinct key at a
@@ -104,13 +161,28 @@ export type ServerGroupRow<TData> = {
104
161
  loading: boolean;
105
162
  /** Aggregate values keyed by column id, read from the group's response row. */
106
163
  aggregates: Record<string, unknown>;
164
+ /**
165
+ * How many rows this group holds, when the backend said (see the row
166
+ * model's `childCount` option). Drawn next to the key by `SvGroupCell`,
167
+ * and used to size the group's scrollbar before its first block lands.
168
+ */
169
+ childCount?: number;
170
+ /**
171
+ * `false` when nothing can open beneath this row: the innermost group
172
+ * level under a server-side pivot, whose rows are the result itself.
173
+ * The group cell then draws no expander.
174
+ */
175
+ expandable?: boolean;
107
176
  /** The raw response row for this group (key + aggregates), for cell rendering. */
108
177
  data: TData;
109
178
  };
179
+ /** A data row in the display list. */
110
180
  export type ServerLeafRow<TData> = {
111
181
  kind: 'leaf';
112
182
  id: string;
113
183
  level: number;
184
+ /** The group path this leaf sits under. Set by the block-cached row model. */
185
+ route?: string[];
114
186
  data: TData;
115
187
  };
116
188
  /**
@@ -150,11 +222,64 @@ export type ServerSkeletonRow = {
150
222
  id: string;
151
223
  level: number;
152
224
  };
153
- /** A row in the flattened server-side group/tree display list. */
154
- export type ServerDisplayRow<TData> = ServerGroupRow<TData> | ServerLeafRow<TData> | ServerMoreRow | ServerFooterRow<TData> | ServerSkeletonRow;
225
+ /**
226
+ * A grand-total row across the whole result. One per grid, at the top or
227
+ * the bottom, with the fixed id `sv-grand-total` so a transaction can
228
+ * address it.
229
+ */
230
+ export type ServerGrandTotalRow<TData> = {
231
+ kind: 'grandTotal';
232
+ id: 'sv-grand-total';
233
+ level: 0;
234
+ aggregates: Record<string, unknown>;
235
+ data: TData;
236
+ };
237
+ /**
238
+ * A row whose data has not arrived: `loading` while its block is in
239
+ * flight, `failed` when the fetch rejected. Shared, frozen objects - one
240
+ * per state, not one per row - so a million unloaded rows cost nothing to
241
+ * represent. They also carry the grid's placeholder mark, so
242
+ * `rowPlaceholderState()` recognises them and the grid draws them itself.
243
+ */
244
+ export type ServerPlaceholderRow = {
245
+ readonly kind: 'placeholder';
246
+ readonly state: 'loading' | 'failed';
247
+ };
248
+ /**
249
+ * The detail panel under a leaf whose detail is open: master-detail on a
250
+ * server-side row model. The grid draws it through `renderDetailRow`
251
+ * (mark it with `isDetailRow`); `master` is the leaf it belongs to.
252
+ */
253
+ export type ServerDetailRow<TData> = {
254
+ kind: 'detail';
255
+ id: string;
256
+ level: number;
257
+ route?: string[];
258
+ /** The leaf's id, as `getRowId` names it. */
259
+ masterId: string;
260
+ master: TData;
261
+ };
262
+ /**
263
+ * Every row a server row model can put on screen. Each carries an `id` and
264
+ * a `level`. The block-cached model adds {@link ServerPlaceholderRow} for
265
+ * rows not yet loaded - see its own `ServerRowModelDisplayRow`.
266
+ */
267
+ export type ServerDisplayRow<TData> = ServerGroupRow<TData> | ServerLeafRow<TData> | ServerDetailRow<TData> | ServerMoreRow | ServerFooterRow<TData> | ServerSkeletonRow | ServerGrandTotalRow<TData>;
268
+ /**
269
+ * What `getRows` answers with: the rows for the requested range and the
270
+ * count after filtering, plus the grand total and the pivot fields when
271
+ * asked for.
272
+ */
155
273
  export type ServerResult<TData> = {
156
274
  rows: ReadonlyArray<TData>;
157
- /** Total row count after filtering (for the pager). */
275
+ /**
276
+ * Total row count after filtering, for the pager and the scrollbar.
277
+ *
278
+ * Paging needs it. Infinite scrolling does not: send `-1` (or, from a
279
+ * source typed loosely, omit it) when counting is expensive, and the grid
280
+ * discovers the end from the first short block instead. See
281
+ * `mode: 'infinite'` on {@link ServerControllerOptions}.
282
+ */
158
283
  rowCount: number;
159
284
  /**
160
285
  * Set `true` ONLY when `filterModel.expression` was applied in full. Leave it
@@ -162,7 +287,53 @@ export type ServerResult<TData> = {
162
287
  * pretending the filter ran. See the contract on `ServerFilterModel.expression`.
163
288
  */
164
289
  appliedExpression?: boolean;
290
+ /**
291
+ * The grand-total row, in reply to `ServerRequest.needsGrandTotal`: an
292
+ * object sets it, `null` removes it, and leaving it out keeps whatever the
293
+ * grid already had. Shaped like a group row: the aggregate values live
294
+ * under their column ids.
295
+ */
296
+ grandTotal?: TData | null;
297
+ /**
298
+ * Pivot mode: the fields the group rows carry for the pivoted values,
299
+ * e.g. `["2024_amount", "2025_amount"]`, from which the grid builds one
300
+ * column per field under a header group per pivot key. Send the full
301
+ * list on every pivoted response; the grid keeps the union. Every group
302
+ * row carries every listed field, `null` where no rows fall in that
303
+ * cell.
304
+ */
305
+ pivotResultFields?: string[];
306
+ /**
307
+ * Pivot mode, the long way: full column definitions instead of field
308
+ * names, for a backend that wants to name and format them itself. Wins
309
+ * over `pivotResultFields` when both are present.
310
+ */
311
+ pivotResultColumns?: ReadonlyArray<unknown>;
312
+ };
313
+ /**
314
+ * A selection expressed as a rule rather than a list, for `updateWhere`.
315
+ * The flat shape is "these ids" or "everything except these"; the nested
316
+ * shape is the same idea per group, keyed by group key or leaf id, as the
317
+ * Enterprise row model keeps it under `groupSelects: 'descendants'`.
318
+ */
319
+ export type ServerSelectionRule = {
320
+ selectAll: boolean;
321
+ toggled: string[];
322
+ } | {
323
+ selectAllChildren: boolean;
324
+ toggled: Record<string, {
325
+ selectAllChildren: boolean;
326
+ toggled: Record<string, unknown>;
327
+ group?: boolean;
328
+ }>;
329
+ group?: boolean;
330
+ /** The group columns the tree's levels are keyed by, outer to inner. */
331
+ groupBy?: string[];
165
332
  };
333
+ /**
334
+ * The contract a backend implements: `getRows`, and optionally the write
335
+ * methods, a bulk edit by rule and `destroy`.
336
+ */
166
337
  export type ServerDataSource<TData> = {
167
338
  getRows(request: ServerRequest): Promise<ServerResult<TData>>;
168
339
  /**
@@ -174,7 +345,28 @@ export type ServerDataSource<TData> = {
174
345
  createRow?(input: Partial<TData>): Promise<TData>;
175
346
  updateRow?(id: string, patch: Partial<TData>): Promise<TData>;
176
347
  deleteRow?(id: string): Promise<void>;
348
+ /**
349
+ * Apply one patch to every row a selection RULE names, server-side - the
350
+ * write behind a bulk edit of rows the grid never loaded. `filterModel`
351
+ * scopes the rows exactly as `getRows` does; `selection` is the rule:
352
+ * either "these ids" (`selectAll: false`) or "everything but these"
353
+ * (`selectAll: true`), or the per-group tree the Enterprise row model
354
+ * keeps under `groupSelects: 'descendants'`. Resolve with how many rows
355
+ * changed. Optional: without it, a bulk edit under select-all is refused
356
+ * rather than silently applied to the loaded rows only.
357
+ */
358
+ updateWhere?(filterModel: ServerFilterModel, patch: Partial<TData>, selection: ServerSelectionRule): Promise<number>;
359
+ /**
360
+ * Called once, from the controller's `dispose()`, for a source with
361
+ * something to close: a socket, a subscription, a worker.
362
+ */
363
+ destroy?(): void;
177
364
  };
365
+ /**
366
+ * What `createServerDataSource` emits on every change: the rows on hand,
367
+ * the counts, the loading and saving flags, the last error, and the
368
+ * current sort and filter.
369
+ */
178
370
  export type ServerState<TData> = {
179
371
  rows: ReadonlyArray<TData>;
180
372
  total: number;
@@ -196,12 +388,50 @@ export type ServerState<TData> = {
196
388
  * compiling; the controller always sets it.
197
389
  */
198
390
  expressionUnapplied?: boolean;
391
+ /**
392
+ * Rows after filtering, or `null` when the backend has not said and the
393
+ * end has not been found yet. Only ever null in `infinite` mode; `total`
394
+ * carries the best current guess either way.
395
+ */
396
+ rowCount?: number | null;
397
+ /** False while the end of an infinite list is still being discovered. */
398
+ lastRowKnown?: boolean;
399
+ /** Blocks whose fetch failed, in `infinite` mode. Empty when all is well. */
400
+ failedBlocks?: number[];
199
401
  };
200
- export type ServerController<TData> = {
402
+ /**
403
+ * Everything a controller can do, plus the {@link GridRowModel} surface, so
404
+ * one object can be driven by hand OR handed to `<SvGrid rowModel>` and wire
405
+ * itself up.
406
+ */
407
+ export type ServerController<TData> = GridRowModel<TData> & {
201
408
  /** Re-fetch the current page (e.g. after a mutation). */
202
409
  refresh(): void;
410
+ /**
411
+ * The rows on screen, so `infinite` mode knows which blocks to fetch and
412
+ * which to spare from eviction. Wire it to the grid's
413
+ * `onVisibleRangeChange` - or pass the controller as `rowModel` and the
414
+ * grid wires it for you. No-op in `page` mode.
415
+ */
416
+ setViewport(startIndex: number, endIndex: number): void;
417
+ /** Re-fetch the blocks that failed. No-op in `page` mode. */
418
+ retryLoads(): void;
419
+ /**
420
+ * Throw away every cached block and reload from the current viewport.
421
+ * `refresh()` is the gentler option: it keeps the row count and the scroll
422
+ * position. No-op in `page` mode, where there is only ever one page held.
423
+ */
424
+ purge(): void;
425
+ /** Cached blocks and their state, for logging and tests. Empty in `page` mode. */
426
+ getCacheState(): BlockState[];
203
427
  setSort(sortModel: ServerSortModel): void;
204
- setFilter(filterModel: ServerFilterModel): void;
428
+ /**
429
+ * Replace the filter. Takes the `ServerFilterModel` a request carries, or
430
+ * the payload the grid's own `onFiltersChange` hands you - which is a
431
+ * list of columns rather than a map, and is converted here so that every
432
+ * app does not write the same `Object.fromEntries` by hand.
433
+ */
434
+ setFilter(filterModel: ServerFilterModel | GridFilterState): void;
205
435
  setPage(pageIndex: number): void;
206
436
  setPageSize(pageSize: number): void;
207
437
  /**
@@ -225,10 +455,14 @@ export type ServerController<TData> = {
225
455
  /** Stop accepting in-flight responses (call on unmount). */
226
456
  dispose(): void;
227
457
  };
458
+ /**
459
+ * Options for `createServerDataSource`: the page size, or the block
460
+ * settings in `infinite` mode, optimistic writes and the change callback.
461
+ */
228
462
  export type ServerControllerOptions<TData> = {
229
463
  pageSize?: number;
230
464
  /** Called whenever any of `rows` / `total` / `loading` / page changes. */
231
- onChange: (state: ServerState<TData>) => void;
465
+ onChange?: (state: ServerState<TData>) => void;
232
466
  /**
233
467
  * Apply `updateRow` / `deleteRow` to the local rows immediately (before the
234
468
  * server confirms) and roll back on error - so edits feel instant and no
@@ -238,5 +472,37 @@ export type ServerControllerOptions<TData> = {
238
472
  optimistic?: boolean;
239
473
  /** Resolve a row's stable id, so optimistic update/delete can find it in `rows`. */
240
474
  getRowId?: (row: TData) => string;
475
+ /**
476
+ * How rows reach the grid.
477
+ *
478
+ * - `page` (default): one page at a time. `state.rows` is that page, and
479
+ * `setPage` moves between them.
480
+ * - `infinite`: one long scrollable list. `state.rows` spans the whole
481
+ * result, with placeholder rows standing in for blocks nobody has
482
+ * scrolled to yet; blocks load as the viewport reaches them.
483
+ */
484
+ mode?: 'page' | 'infinite';
485
+ /** `infinite` mode: rows per request. Default 100. */
486
+ blockSize?: number;
487
+ /**
488
+ * `infinite` mode: keep at most this many loaded blocks, evicting the
489
+ * least recently seen. Unlimited by default.
490
+ */
491
+ maxBlocksInCache?: number;
492
+ /** `infinite` mode: requests open at once. Default 2. */
493
+ maxConcurrentRequests?: number;
494
+ /** `infinite` mode: wait for the scroll to settle this long before fetching. */
495
+ blockLoadDebounceMs?: number;
496
+ /**
497
+ * `infinite` mode: rows to claim before anything has loaded, so there is a
498
+ * scrollbar on first paint. Default 1.
499
+ */
500
+ initialRowCount?: number;
241
501
  };
502
+ /**
503
+ * The free server row model over a `ServerDataSource`: one page at a time,
504
+ * or one block-cached list in `infinite` mode, with sort, filter, race
505
+ * safety and writes. The result is a `GridRowModel`, so
506
+ * `<SvGrid rowModel={ctl} />` wires every seam.
507
+ */
242
508
  export declare function createServerDataSource<TData>(source: ServerDataSource<TData>, options: ServerControllerOptions<TData>): ServerController<TData>;