@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
@@ -35,8 +35,8 @@ export type GridIconName = 'sort' | 'sort-asc' | 'sort-desc' | 'filter' | 'menu'
35
35
  export type GridIcons = Partial<Record<GridIconName, Snippet>>;
36
36
  /**
37
37
  * Icons whose built-in form is a character rather than an SVG path. Kept as
38
- * data so `<SvGrid>`, its footer and the standalone `SvRowGroupPanel` render
39
- * the same defaults instead of three copies drifting apart.
38
+ * data so `<SvGrid>`, its footer and the row-group panel in @svgrid/enterprise
39
+ * render the same defaults instead of three copies drifting apart.
40
40
  *
41
41
  * Each is the exact character that shipped inline before, so a grid that sets
42
42
  * no `icons` renders byte-for-byte what it always did.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Icons whose built-in form is a character rather than an SVG path. Kept as
3
- * data so `<SvGrid>`, its footer and the standalone `SvRowGroupPanel` render
4
- * the same defaults instead of three copies drifting apart.
3
+ * data so `<SvGrid>`, its footer and the row-group panel in @svgrid/enterprise
4
+ * render the same defaults instead of three copies drifting apart.
5
5
  *
6
6
  * Each is the exact character that shipped inline before, so a grid that sets
7
7
  * no `icons` renders byte-for-byte what it always did.
@@ -74,8 +74,18 @@ export type GridChromeMessages = {
74
74
  bulkEditCancel: string;
75
75
  bulkEditNoFields: string;
76
76
  chartRange: string;
77
+ rowLoadFailed: string;
78
+ rowLoadRetry: string;
79
+ expandGroup: string;
80
+ collapseGroup: string;
81
+ openDetail: string;
82
+ closeDetail: string;
77
83
  pivotUpsellTitle: string;
78
84
  pivotUpsellBody: string;
85
+ ganttUpsellTitle: string;
86
+ ganttUpsellBody: string;
87
+ /** Placeholder in the Gantt view's search box. */
88
+ ganttSearchPlaceholder: string;
79
89
  /** Shared licensing line under every Enterprise upsell note. */
80
90
  upsellLicense: string;
81
91
  upsellLicenseLink: string;
@@ -84,8 +84,17 @@ export const defaultGridMessages = {
84
84
  opBefore: 'Before',
85
85
  opAfter: 'After',
86
86
  chartRange: 'Chart selected range',
87
+ rowLoadFailed: 'Could not load these rows.',
88
+ rowLoadRetry: 'Retry',
89
+ expandGroup: 'Expand group',
90
+ collapseGroup: 'Collapse group',
91
+ openDetail: 'Open details',
92
+ closeDetail: 'Close details',
87
93
  pivotUpsellTitle: 'Pivot mode',
88
94
  pivotUpsellBody: 'Pivot mode is an Enterprise feature. Install @svgrid/enterprise and call enablePivot() to use it.',
95
+ ganttUpsellTitle: 'Gantt view',
96
+ ganttUpsellBody: 'The Gantt view is an Enterprise feature. Install @svgrid/enterprise and call enableGanttView() to render it.',
97
+ ganttSearchPlaceholder: 'Search tasks...',
89
98
  upsellLicense: 'A license key is required for production use. Without one the feature still works, but the grid renders an unlicensed watermark.',
90
99
  upsellLicenseLink: 'View licensing',
91
100
  };
@@ -27,3 +27,8 @@ export { columnFilteringFeature, columnGroupingFeature, createCoreRowModel, crea
27
27
  export { createGrid, createSvGrid, type SvelteGrid } from './createGrid.svelte.js';
28
28
  export { createGridState, createSvGridState } from './createGridState.svelte.js';
29
29
  export { subscribeGrid, subscribeSvGrid } from './subscribe.js';
30
+ export { createVirtualizer } from './virtualization/virtualizer.js';
31
+ export { createSvelteVirtualizer } from './virtualization/svelte-virtualizer.svelte.js';
32
+ export { createColumnVirtualizer } from './virtualization/column-virtualizer.js';
33
+ export type { VirtualItem, VirtualizerOptions, VirtualizerState } from './virtualization/types.js';
34
+ export { getGridCellDomId, getGridCellA11yProps, getGridHeaderA11yProps, getGridRootA11yProps, getGridRowA11yProps, type GridCellA11yInput, type GridColumnA11yInput, type GridSortDirection, } from './a11y.js';
package/dist/headless.js CHANGED
@@ -27,3 +27,15 @@ export { columnFilteringFeature, columnGroupingFeature, createCoreRowModel, crea
27
27
  export { createGrid, createSvGrid } from './createGrid.svelte.js';
28
28
  export { createGridState, createSvGridState } from './createGridState.svelte.js';
29
29
  export { subscribeGrid, subscribeSvGrid } from './subscribe.js';
30
+ // The virtualizers are pure window arithmetic (scroll offset in, visible
31
+ // range out) with no DOM of their own, and a custom renderer over 50k rows
32
+ // needs one. They were only on the barrel, so the Headless demos imported
33
+ // the barrel to reach them and paid for the whole thing.
34
+ export { createVirtualizer } from './virtualization/virtualizer.js';
35
+ export { createSvelteVirtualizer } from './virtualization/svelte-virtualizer.svelte.js';
36
+ export { createColumnVirtualizer } from './virtualization/column-virtualizer.js';
37
+ // The WAI-ARIA attribute factories: plain objects to spread onto your own
38
+ // markup (`role`, `aria-sort`, `aria-rowindex`, ...). No DOM is touched here
39
+ // either; a custom renderer that wants keyboard navigation reads
40
+ // `activeCell` from the store and spreads these.
41
+ export { getGridCellDomId, getGridCellA11yProps, getGridHeaderA11yProps, getGridRootA11yProps, getGridRowA11yProps, } from './a11y.js';
package/dist/history.d.ts CHANGED
@@ -38,6 +38,15 @@ export type HistoryStep = {
38
38
  undo: () => void;
39
39
  redo: () => void;
40
40
  };
41
+ /**
42
+ * The consumer's own mark on the step, copied from `api.setHistoryTag` at
43
+ * the moment it is recorded. The grid never reads it: it is there for a
44
+ * consumer that shows one of several data sets through the grid and has
45
+ * to know which one a step belongs to before it lets Ctrl+Z apply it (a
46
+ * workbook with several sheets, say). Kept as given, so an object tag
47
+ * compares by identity. Not serialised.
48
+ */
49
+ tag?: unknown;
41
50
  };
42
51
  /** Ctx surface these helpers touch. The controller satisfies it structurally. */
43
52
  type HistoryCtx = {
@@ -49,8 +58,20 @@ type HistoryCtx = {
49
58
  * inside it joins that group, so a command does not have to thread a group
50
59
  * id down through the writers it calls. */
51
60
  historyGroupId: string | undefined;
61
+ /** Stamped on every step recorded while it is set; see `HistoryStep.tag`. */
62
+ historyTag?: unknown;
52
63
  applyHistoryStep(step: HistoryStep, direction: 'undo' | 'redo'): void;
53
64
  };
65
+ /** What the next undo would apply: the tag of the step Ctrl+Z takes next
66
+ * (a group carries one tag, so its last step's is the group's). Null when
67
+ * there is nothing to undo. */
68
+ export declare function peekUndoHistory(ctx: HistoryCtx): {
69
+ tag: unknown;
70
+ } | null;
71
+ /** The redo counterpart of `peekUndoHistory`. */
72
+ export declare function peekRedoHistory(ctx: HistoryCtx): {
73
+ tag: unknown;
74
+ } | null;
54
75
  /** Undo one action. Returns false when there is nothing left to undo. */
55
76
  export declare function undoHistory(ctx: HistoryCtx): boolean;
56
77
  /** Redo one action. Returns false when there is nothing left to redo. */
package/dist/history.js CHANGED
@@ -41,6 +41,34 @@ function groupEnd(history, start) {
41
41
  i += 1;
42
42
  return i;
43
43
  }
44
+ /**
45
+ * The last `limit` ACTIONS of a history, whole groups kept. The cap used
46
+ * to count steps, and a sort of 5,000 rows is 20,000 steps in one group:
47
+ * it cut the group to its last 200 cells, so Ctrl+Z put a fifth of a
48
+ * column back and left the rest sorted. An action is one press of Ctrl+Z,
49
+ * so that is what the buffer counts; the steps inside are the cost of it.
50
+ */
51
+ function lastActions(history, limit) {
52
+ let i = history.length;
53
+ let actions = 0;
54
+ while (i > 0 && actions < limit) {
55
+ i = groupStart(history, i - 1);
56
+ actions += 1;
57
+ }
58
+ return i === 0 ? history : history.slice(i);
59
+ }
60
+ /** What the next undo would apply: the tag of the step Ctrl+Z takes next
61
+ * (a group carries one tag, so its last step's is the group's). Null when
62
+ * there is nothing to undo. */
63
+ export function peekUndoHistory(ctx) {
64
+ const step = ctx.historyPtr >= 0 ? ctx.history[ctx.historyPtr] : undefined;
65
+ return step ? { tag: step.tag } : null;
66
+ }
67
+ /** The redo counterpart of `peekUndoHistory`. */
68
+ export function peekRedoHistory(ctx) {
69
+ const step = ctx.historyPtr < ctx.history.length - 1 ? ctx.history[ctx.historyPtr + 1] : undefined;
70
+ return step ? { tag: step.tag } : null;
71
+ }
44
72
  /** Undo one action. Returns false when there is nothing left to undo. */
45
73
  export function undoHistory(ctx) {
46
74
  if (ctx.historyPtr < 0)
@@ -94,11 +122,13 @@ export function pushHistory(ctx, steps, groupId) {
94
122
  // Outside one, a group of one is just a step. Tagging it would make undo do
95
123
  // the same work through a slower path and would show up in serialized state.
96
124
  const id = ctx.historyGroupId ?? (groupId && steps.length > 1 ? groupId : undefined);
125
+ const tag = ctx.historyTag;
97
126
  let next = ctx.history.slice(0, ctx.historyPtr + 1);
98
- for (const step of steps)
99
- next.push(id ? { ...step, groupId: id } : step);
100
- if (next.length > ctx.UNDO_LIMIT)
101
- next = next.slice(next.length - ctx.UNDO_LIMIT);
127
+ for (const step of steps) {
128
+ const stamped = tag === undefined ? step : { ...step, tag };
129
+ next.push(id ? { ...stamped, groupId: id } : stamped);
130
+ }
131
+ next = lastActions(next, ctx.UNDO_LIMIT);
102
132
  ctx.history = next;
103
133
  ctx.historyPtr = ctx.history.length - 1;
104
134
  ctx.historyVersion += 1;
package/dist/index.d.ts CHANGED
@@ -12,6 +12,8 @@ export * from './ai.js';
12
12
  export { registerExportProvider, getExportProvider, type GridExportProvider, type GridExportRunOptions, } from './export-provider.js';
13
13
  export type { SchedulerConfig, SchedulerDrawerConfig, SchedulerEventMoveEvent, SchedulerEventResizeEvent, SchedulerEventCommitEvent, SchedulerRangeSelection, SchedulerView, SchedulerResource, SchedulerCollisionMode, SchedulerException, SchedulerEditScope, SchedulerOccurrenceChangeEvent, } from './SvGrid.types.js';
14
14
  export { registerSchedulerView, getSchedulerView, hasSchedulerView } from './scheduler-view.svelte.js';
15
+ export type { GanttConfig, GanttDrawerConfig, GanttTaskMoveEvent, GanttTaskResizeEvent, GanttProgressChangeEvent, GanttTaskCommitEvent, GanttDependency, GanttDependencyType, GanttZoom, } from './SvGrid.types.js';
16
+ export { registerGanttView, getGanttView, hasGanttView } from './gantt-view.svelte.js';
15
17
  export { registerSelectionBarView, getSelectionBarView, hasSelectionBarView } from './selection-bar-view.svelte.js';
16
18
  export type { ChartViewConfig } from './SvGrid.types.js';
17
19
  export { registerChartView, getChartView, hasChartView } from './chart-view.svelte.js';
@@ -211,10 +213,9 @@ export { resolveColumnTypes, inferCellDataType, type CellDataType } from './colu
211
213
  export { computeColumnGroupMeta, hiddenLeavesForCollapse, type ColumnGroupMeta, type ColumnGroupShow, } from './column-groups.js';
212
214
  export { createHyperFormulaSheet, type HyperFormulaSheet, type HyperFormulaSheetConfig, type HyperFormulaInstance, } from './hyperformula-adapter.js';
213
215
  export { createCollaboration, broadcastChannelTransport, type CollabUser, type CollabCell, type CollabPresence, type CollabMessage, type CollabTransport, type Collaboration, } from './collaboration.js';
214
- export { createServerDataSource, type ServerDataSource, type ServerRequest, type ServerResult, type ServerController, type ServerState, type ServerSortModel, type ServerFilterModel, type ServerAggregation, type ServerGroupRow, type ServerLeafRow, type ServerMoreRow, type ServerFooterRow, type ServerSkeletonRow, type ServerDisplayRow, } from './server-data-source.js';
215
- export { createServerGroupModel, serverGroupRows, serverGroupNav, type ServerGroupController, type ServerGroupControllerOptions, type ServerGroupState, type ServerGroupGridRow, } from './server-group-model.js';
216
- export { default as SvGroupCell } from './SvGroupCell.svelte';
217
- export { default as SvRowGroupPanel } from './SvRowGroupPanel.svelte';
216
+ export { createServerDataSource, type ServerDataSource, type ServerSelectionRule, type ServerRequest, type ServerResult, type ServerController, type ServerControllerOptions, type ServerState, type ServerSortModel, type ServerFilterModel, type ServerAggFn, type ServerAggregation, type ServerGroupRow, type ServerLeafRow, type ServerMoreRow, type ServerFooterRow, type ServerSkeletonRow, type ServerGrandTotalRow, type ServerPlaceholderRow, type ServerDisplayRow, type ServerDetailRow, } from './server-data-source.js';
217
+ export { createBlockCache, createRowPlaceholder, rowPlaceholderState, type BlockCache, type BlockCacheOptions, type BlockCacheState, type BlockFetchResult, type BlockState, } from './server-block-cache.js';
218
+ export { toServerFilterColumns, type GridRowModel, type GridFilterState, type GridRowModelSort, } from './row-model.js';
218
219
  export { createNamedViews, memoryViews, localStorageViews, attachAutoSavedView, type SavedView, type ViewStorage, type NamedViews, type AutoSavedViewOptions, } from './named-views.js';
219
220
  export { resolveCellFormat, computeColumnStat, lerpColor, rgba, contrastText, formatNeedsStats, formatsNeedingStats, type ConditionalFormat, type ConditionalFormatSpec, type ColorScaleFormat, type ColorScaleStop, type ScaleBounds, type DataBarFormat, type IconSetFormat, type RuleFormat, type ResolvedCellFormat, } from './conditional-formatting.js';
220
221
  export { defaultGridMessages, resolveGridMessages, type GridMessages, type GridChromeMessages, } from './grid-messages.js';
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ export { registerBoardView, getBoardView, hasBoardView } from './board-view.svel
15
15
  export * from './ai.js';
16
16
  export { registerExportProvider, getExportProvider, } from './export-provider.js';
17
17
  export { registerSchedulerView, getSchedulerView, hasSchedulerView } from './scheduler-view.svelte.js';
18
+ export { registerGanttView, getGanttView, hasGanttView } from './gantt-view.svelte.js';
18
19
  // Bulk-action bar over the row selection. Prop + types free, renderer Pro.
19
20
  export { registerSelectionBarView, getSelectionBarView, hasSelectionBarView } from './selection-bar-view.svelte.js';
20
21
  export { registerChartView, getChartView, hasChartView } from './chart-view.svelte.js';
@@ -253,9 +254,8 @@ export { computeColumnGroupMeta, hiddenLeavesForCollapse, } from './column-group
253
254
  export { createHyperFormulaSheet, } from './hyperformula-adapter.js';
254
255
  export { createCollaboration, broadcastChannelTransport, } from './collaboration.js';
255
256
  export { createServerDataSource, } from './server-data-source.js';
256
- export { createServerGroupModel, serverGroupRows, serverGroupNav, } from './server-group-model.js';
257
- export { default as SvGroupCell } from './SvGroupCell.svelte';
258
- export { default as SvRowGroupPanel } from './SvRowGroupPanel.svelte';
257
+ export { createBlockCache, createRowPlaceholder, rowPlaceholderState, } from './server-block-cache.js';
258
+ export { toServerFilterColumns, } from './row-model.js';
259
259
  export { createNamedViews, memoryViews, localStorageViews, attachAutoSavedView, } from './named-views.js';
260
260
  export { resolveCellFormat, computeColumnStat, lerpColor, rgba, contrastText, formatNeedsStats, formatsNeedingStats, } from './conditional-formatting.js';
261
261
  export { defaultGridMessages, resolveGridMessages, } from './grid-messages.js';
@@ -166,6 +166,28 @@ export function createKeyboard(ctx) {
166
166
  row.toggleExpanded?.();
167
167
  return;
168
168
  }
169
+ // The same key on a server-side tree: a group opens or closes, a leaf
170
+ // opens or closes its detail panel when the grid draws one.
171
+ const sg = ctx.props.serverGroup;
172
+ if (event.ctrlKey && sg && row) {
173
+ const data = row.original;
174
+ if (sg.isGroup(data)) {
175
+ sg.onToggle(data);
176
+ return;
177
+ }
178
+ if (sg.toggleDetail && ctx.props.renderDetailRow && (sg.hasDetail?.(data) ?? true)) {
179
+ sg.toggleDetail(data);
180
+ return;
181
+ }
182
+ }
183
+ // ...and on a client-side master-detail: the app's own toggle.
184
+ if (event.ctrlKey && row && ctx.props.onDetailToggle && ctx.props.renderDetailRow) {
185
+ const data = row.original;
186
+ if (!ctx.props.isDetailRow?.(data, current.rowIndex) && (ctx.props.hasDetail?.(data) ?? true)) {
187
+ ctx.props.onDetailToggle(data, current.rowIndex);
188
+ return;
189
+ }
190
+ }
169
191
  if (column?.columnDef.editorType === "checkbox") {
170
192
  ctx.toggleBooleanCell(current.rowIndex, current.colIndex);
171
193
  return;
@@ -257,7 +279,8 @@ export function createKeyboard(ctx) {
257
279
  ctx.setSelection(next.rowIndex, next.colIndex);
258
280
  }
259
281
  function onWindowKeydown(event) {
260
- if (event.key === "Escape" && (ctx.columnMenuFor || ctx.operatorMenuFor)) {
282
+ if (event.key === "Escape" &&
283
+ (ctx.columnMenuFor || ctx.operatorMenuFor || ctx.filterMenuFor || ctx.inSuggestFor || ctx.chooseColumnsPos)) {
261
284
  ctx.closeMenus();
262
285
  }
263
286
  }
package/dist/keyboard.js CHANGED
@@ -37,6 +37,10 @@ export function getKeyboardIntent(event) {
37
37
  // Tab → move right (Shift+Tab → left), wraps at row boundaries
38
38
  // Delete → clear contents of the selected cells
39
39
  // F2 / Space → start editing the active cell
40
+ // Ctrl+Enter acts on the row rather than moving: a group opens or closes,
41
+ // a row with a detail panel shows or hides it (see the activate branch).
42
+ if (event.key === 'Enter' && (event.ctrlKey || event.metaKey))
43
+ return 'activate';
40
44
  if (event.key === 'Enter')
41
45
  return event.shiftKey ? 'moveUp' : 'moveDown';
42
46
  if (event.key === 'Tab')
@@ -3,7 +3,7 @@ export type TouchDragDeps = {
3
3
  ctx: any;
4
4
  managed: () => boolean;
5
5
  originalAt: (rowIndex: number) => unknown;
6
- commitDropOnRow: (rowIndex: number, side: "before" | "after") => void;
6
+ commitDropOnRow: (rowIndex: number, side: "before" | "after" | "into") => void;
7
7
  clearIndicators: () => void;
8
8
  cancelPendingLeave: () => void;
9
9
  /** Publish the dragged row on the shared cross-grid bus. */
package/dist/row-drag.js CHANGED
@@ -98,7 +98,27 @@ export function createRowDrag(ctx) {
98
98
  e.dataTransfer.dropEffect = "move";
99
99
  const rect = e.currentTarget.getBoundingClientRect();
100
100
  ctx.rowDropIndex = rowIndex;
101
- ctx.rowDropSide = e.clientY < rect.top + rect.height / 2 ? "before" : "after";
101
+ ctx.rowDropSide = sideAt(rowIndex, rect, e.clientY);
102
+ }
103
+ /**
104
+ * Which edge the pointer is on. A custom drop handler also gets the middle
105
+ * of a group or tree row as "into" (the row becomes its child); the
106
+ * managed reorder only knows before and after.
107
+ */
108
+ function sideAt(rowIndex, rect, y) {
109
+ const rel = (y - rect.top) / Math.max(rect.height, 1);
110
+ if (ctx.props.onRowDrop && rel >= 0.25 && rel <= 0.75 && canNest(rowIndex))
111
+ return "into";
112
+ return rel < 0.5 ? "before" : "after";
113
+ }
114
+ function canNest(rowIndex) {
115
+ const row = ctx.allRows[rowIndex];
116
+ if (!row)
117
+ return false;
118
+ const sg = ctx.props.serverGroup;
119
+ if (sg)
120
+ return !!sg.isGroup(row.original);
121
+ return typeof row.getCanExpand === "function" && row.getCanExpand();
102
122
  }
103
123
  function onRowDragLeave(rowIndex) {
104
124
  // A leave from a row that is not the current target is already stale.
@@ -137,6 +157,15 @@ export function createRowDrag(ctx) {
137
157
  const sourceGridId = bus.gridId;
138
158
  const sameGrid = sourceGridId === gridId;
139
159
  clearIndicators();
160
+ // A custom handler owns the drop: the grid reports it and leaves its
161
+ // data alone (a row model's rows are not the grid's to splice).
162
+ if (sameGrid && ctx.props.onRowDrop) {
163
+ bus = null;
164
+ ctx.props.onRowDrop({ row: dragged, target, targetIndex: rowIndex, side });
165
+ return;
166
+ }
167
+ if (side === "into")
168
+ side = "after";
140
169
  const data = ctx.internalData.slice();
141
170
  if (sameGrid) {
142
171
  const from = data.indexOf(dragged);
@@ -183,6 +212,11 @@ export function createRowDrag(ctx) {
183
212
  const sourceGridId = bus.gridId;
184
213
  const sameGrid = sourceGridId === gridId;
185
214
  clearIndicators();
215
+ if (sameGrid && ctx.props.onRowDrop) {
216
+ bus = null;
217
+ ctx.props.onRowDrop({ row: dragged, target: null, targetIndex: null, side: "after" });
218
+ return;
219
+ }
186
220
  const data = ctx.internalData.slice();
187
221
  if (sameGrid) {
188
222
  const from = data.indexOf(dragged);
@@ -0,0 +1,139 @@
1
+ /**
2
+ * `GridRowModel` - one prop instead of eleven.
3
+ *
4
+ * A grid backed by a server needs the same wiring every time: hand it the
5
+ * rows, tell it not to sort or filter locally, forward the sort and the filter
6
+ * to the backend, report which rows are on screen, say which rows have not
7
+ * loaded, and delegate selection. Written out by hand that is a dozen props
8
+ * and a filter-shape conversion that every app gets slightly differently:
9
+ *
10
+ * ```svelte
11
+ * <SvGrid data={s.rows} externalSort externalFilter loading={s.loading}
12
+ * onSortingChange={(x) => ctl.setSort(x)}
13
+ * onFiltersChange={(f) => ctl.setFilter({ global: f.global,
14
+ * columns: Object.fromEntries(f.columns.map((c) => [c.id, { ... }])) })}
15
+ * onVisibleRangeChange={(r) => ctl.setViewport(r.startIndex, r.endIndex)}
16
+ * ... />
17
+ * ```
18
+ *
19
+ * An object that implements this interface carries all of it, so the same grid
20
+ * becomes:
21
+ *
22
+ * ```svelte
23
+ * <SvGrid rowModel={ctl} {columns} />
24
+ * ```
25
+ *
26
+ * `createServerDataSource` returns one, and so does the Enterprise server row
27
+ * model - which is the point of the interface rather than a concrete type: the
28
+ * grid depends on the SHAPE, never on either implementation, and an app with
29
+ * its own fetching can satisfy it too.
30
+ *
31
+ * Every member except `subscribe` / `getRows` / `isLoading` is optional, and a
32
+ * prop written explicitly on `<SvGrid>` always wins over the model's answer -
33
+ * so adopting this is never all-or-nothing.
34
+ */
35
+ import type { FilterOperator } from './SvGrid.types.js';
36
+ /** The filter state as the grid reports it, straight from `onFiltersChange`. */
37
+ export type GridFilterState = {
38
+ global: string;
39
+ columns: Array<{
40
+ id: string;
41
+ operator: FilterOperator;
42
+ value: string;
43
+ valueTo?: string;
44
+ selectedValues?: Array<string>;
45
+ }>;
46
+ };
47
+ /** The sort the grid hands a row model: column id and direction, in priority order. */
48
+ export type GridRowModelSort = Array<{
49
+ id: string;
50
+ desc: boolean;
51
+ }>;
52
+ /**
53
+ * What `<SvGrid rowModel>` consumes: rows, a loading flag, a change
54
+ * subscription, and whichever optional parts the model implements - sort,
55
+ * filter, viewport, placeholders, group accessors, selection, filter
56
+ * values, paging, pinned rows and pivot columns. `createServerDataSource`
57
+ * and the Enterprise `createServerRowModel` both satisfy it.
58
+ */
59
+ export type GridRowModel<TData> = {
60
+ /**
61
+ * Register a callback for "something changed, re-read me". Returns an
62
+ * unsubscribe function, which the grid calls on unmount.
63
+ */
64
+ subscribe(onChange: () => void): () => void;
65
+ /** The rows to render, including any placeholders for unloaded ones. */
66
+ getRows(): ReadonlyArray<TData>;
67
+ /** True while a fetch is in flight, for the loading overlay. */
68
+ isLoading(): boolean;
69
+ /** Stable row id. Required once selection or editing is involved. */
70
+ getRowId?(row: TData, index: number): string;
71
+ /** Sort on the server. Present means "do not sort locally". */
72
+ setSort?(sort: GridRowModelSort): void;
73
+ /** Filter on the server. Present means "do not filter locally". */
74
+ setFilter?(filters: GridFilterState): void;
75
+ /** Which rows are on screen, so a block-loading model knows what to fetch. */
76
+ setViewport?(startIndex: number, endIndex: number): void;
77
+ /** Why a row has no data yet, or null when it does. */
78
+ rowPlaceholder?(row: TData, rowIndex: number): 'loading' | 'failed' | null;
79
+ /** Retry the failed block a placeholder row belongs to. */
80
+ retryRow?(row: TData, rowIndex: number): void;
81
+ /** Group / tree accessors, for the grid's treegrid keyboard and ARIA. */
82
+ group?: {
83
+ isGroup: (row: TData) => boolean;
84
+ level: (row: TData) => number;
85
+ expanded?: (row: TData) => boolean;
86
+ onToggle: (row: TData) => void;
87
+ /** Open or close the detail panel under a leaf. Ctrl+Enter on a row calls it when `renderDetailRow` is set, and so does the `showDetailToggle` chevron. */
88
+ toggleDetail?: (row: TData) => void;
89
+ /** Whether the detail under a leaf is open: the chevron's direction. */
90
+ detailOpen?: (row: TData) => boolean;
91
+ /** Whether a row can open a detail; the chevron is left out where this is false. */
92
+ hasDetail?: (row: TData) => boolean;
93
+ };
94
+ /** Selection the grid does not own - see the `rowSelectionModel` prop. */
95
+ selection?: {
96
+ isSelected: (rowId: string, row: TData) => boolean;
97
+ headerState: () => 'none' | 'some' | 'all';
98
+ toggle: (rowId: string, row: TData, next: boolean) => void;
99
+ toggleAll: (next: boolean) => void;
100
+ selectedCount?: () => number | null;
101
+ bulkUpdate?: (patch: Record<string, unknown>) => Promise<number>;
102
+ };
103
+ /** Distinct values for a column's set filter, fetched from the server. */
104
+ filterValues?(columnId: string): Promise<Array<string>>;
105
+ /** Server-side paging. Omit it for infinite scrolling. */
106
+ pagination?: {
107
+ pageIndex: number;
108
+ pageSize: number;
109
+ rowCount: number;
110
+ setPage(pageIndex: number): void;
111
+ setPageSize(pageSize: number): void;
112
+ /** Choices for the footer's page-size selector. */
113
+ pageSizes?: number[];
114
+ /**
115
+ * Ask the grid for as many rows as its body fits: it measures and calls
116
+ * `setPageSize` whenever the fit changes.
117
+ */
118
+ autoPageSize?: boolean;
119
+ };
120
+ /** Rows to pin above / below the scrolling body - a grand total, say. */
121
+ readonly pinnedTopRows?: ReadonlyArray<TData>;
122
+ readonly pinnedBottomRows?: ReadonlyArray<TData>;
123
+ /**
124
+ * Columns that replace the grid's `columns` while the model is in pivot
125
+ * mode, or null. Read after every change notification.
126
+ */
127
+ readonly pivotResultColumns?: ReadonlyArray<unknown> | null;
128
+ };
129
+ /**
130
+ * Turn the grid's filter payload into the column-keyed map a `ServerRequest`
131
+ * carries. Exported because a hand-written `GridRowModel` needs exactly this
132
+ * conversion, and copying it is how the two shapes drift apart.
133
+ */
134
+ export declare function toServerFilterColumns(filters: GridFilterState): Record<string, {
135
+ operator: string;
136
+ value: string;
137
+ valueTo?: string;
138
+ selectedValues?: Array<string>;
139
+ }>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Turn the grid's filter payload into the column-keyed map a `ServerRequest`
3
+ * carries. Exported because a hand-written `GridRowModel` needs exactly this
4
+ * conversion, and copying it is how the two shapes drift apart.
5
+ */
6
+ export function toServerFilterColumns(filters) {
7
+ return Object.fromEntries(filters.columns.map((c) => [
8
+ c.id,
9
+ {
10
+ operator: c.operator,
11
+ value: c.value,
12
+ ...(c.valueTo !== undefined ? { valueTo: c.valueTo } : {}),
13
+ ...(c.selectedValues !== undefined ? { selectedValues: c.selectedValues } : {}),
14
+ },
15
+ ]));
16
+ }
@@ -31,6 +31,19 @@ export function rowResize(node, opts) {
31
31
  let drag = null;
32
32
  /** The last press on a strip, for telling a double-click from two drags. */
33
33
  let lastPress = null;
34
+ /**
35
+ * A focusable `role="separator"` is a splitter, and a splitter carries its
36
+ * position: axe's `aria-required-attr` fails one without `aria-valuenow`,
37
+ * and a screen reader reading the strip says nothing useful without it. The
38
+ * value is the row's height in pixels, between the action's min and max.
39
+ */
40
+ function setStripValue(strip, height) {
41
+ const min = current.min ?? 20;
42
+ const max = current.max ?? 320;
43
+ strip.setAttribute('aria-valuemin', String(min));
44
+ strip.setAttribute('aria-valuemax', String(max));
45
+ strip.setAttribute('aria-valuenow', String(Math.round(Math.max(min, Math.min(max, height || min)))));
46
+ }
34
47
  function rowIndexOf(tr) {
35
48
  const dataRow = tr.querySelector('[data-svgrid-row]');
36
49
  const val = dataRow?.dataset.svgridRow;
@@ -43,6 +56,7 @@ export function rowResize(node, opts) {
43
56
  const max = current.max ?? 320;
44
57
  const next = Math.max(min, Math.min(max, drag.startHeight + (e.clientY - drag.startY)));
45
58
  drag.trEl.style.height = `${Math.round(next)}px`;
59
+ setStripValue(drag.strip, next);
46
60
  current.onResizeMove?.(drag.rowIndex, Math.round(next));
47
61
  }
48
62
  function onPointerUp(e) {
@@ -94,6 +108,7 @@ export function rowResize(node, opts) {
94
108
  const max = current.max ?? 320;
95
109
  const next = Math.round(Math.max(min, Math.min(max, tr.getBoundingClientRect().height + delta)));
96
110
  tr.style.height = `${next}px`;
111
+ setStripValue(t, next);
97
112
  current.onResizeMove?.(rowIndex, next);
98
113
  current.onResize(rowIndex, next);
99
114
  }
@@ -164,8 +179,13 @@ export function rowResize(node, opts) {
164
179
  : null);
165
180
  if (!gutter)
166
181
  continue;
167
- if (gutter.querySelector(`:scope > .${STRIP_CLASS}`))
182
+ const already = gutter.querySelector(`:scope > .${STRIP_CLASS}`);
183
+ if (already) {
184
+ // The row may have been resized from outside the action (a saved
185
+ // height, a double-click autofit); keep the separator's value honest.
186
+ setStripValue(already, tr.getBoundingClientRect().height);
168
187
  continue;
188
+ }
169
189
  // Anchor the strip to the gutter cell + allow it to overflow
170
190
  // downward into the row gap so the hit-area straddles the
171
191
  // row boundary the way Excel does.
@@ -180,6 +200,7 @@ export function rowResize(node, opts) {
180
200
  // A separator used as an interactive splitter has to be focusable so
181
201
  // keyboard-only users can reach it and drive `onKeyDown` (#79).
182
202
  strip.tabIndex = 0;
203
+ setStripValue(strip, tr.getBoundingClientRect().height);
183
204
  // Inline the geometry + pointer-events so the strip works even
184
205
  // before SvGrid.css is parsed; the hover tint still comes from
185
206
  // the stylesheet. We keep the strip fully inside the gutter
@@ -1,9 +1,10 @@
1
1
  import { type RowData, type TableFeatures } from "./index.js";
2
2
  import "./sv-grid-scrollbar.js";
3
3
  export declare function createSelection<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(ctx: any): {
4
- isRowSelected: (rowId: string) => boolean;
4
+ isRowSelected: (rowId: string) => any;
5
5
  toggleRowSelectionById: (rowId: string) => void;
6
6
  toggleSelectAllRows: () => void;
7
+ setSelectAllRows: (select: boolean) => void;
7
8
  setActiveCell: (rowIndex: number, colIndex: number) => void;
8
9
  scrollActiveCellIntoView: (rowIndex: number, colIndex: number) => void;
9
10
  setSelection: (rowIndex: number, colIndex: number, additive?: boolean) => void;
package/dist/selection.js CHANGED
@@ -7,14 +7,41 @@ import { getColumnBaseValue, isGroupRow, } from "./cell-values.js";
7
7
  import { expandRectToMerges, originOf, endOf } from "./merges.js";
8
8
  export function createSelection(ctx) {
9
9
  function isRowSelected(rowId) {
10
+ const model = ctx.props.rowSelectionModel;
11
+ if (model) {
12
+ const row = ctx.allRows.find((r) => r.id === rowId);
13
+ return row ? model.isSelected(rowId, row.original) : false;
14
+ }
10
15
  return Boolean(ctx.rowSelectionState[rowId]);
11
16
  }
12
17
  function toggleRowSelectionById(rowId) {
18
+ const model = ctx.props.rowSelectionModel;
19
+ if (model) {
20
+ const row = ctx.allRows.find((r) => r.id === rowId);
21
+ if (!row)
22
+ return;
23
+ model.toggle(rowId, row.original, !model.isSelected(rowId, row.original));
24
+ return;
25
+ }
13
26
  ctx.grid.setRowSelection((prev) => ({ ...prev, [rowId]: !prev[rowId] }));
14
27
  }
15
28
  function toggleSelectAllRows() {
16
- const selectable = ctx.allRows.filter((row) => !isGroupRow(row));
17
- const select = ctx.headerSelectionState !== "all";
29
+ setSelectAllRows(ctx.headerSelectionState !== "all");
30
+ }
31
+ /**
32
+ * Select or clear every row, for the header checkbox and for
33
+ * `api.selectAllRows()`.
34
+ */
35
+ function setSelectAllRows(select) {
36
+ // An external model decides what "all" means - possibly a million rows
37
+ // the grid has never seen - so it gets the intent, not a row list.
38
+ if (ctx.props.rowSelectionModel) {
39
+ ctx.props.rowSelectionModel.toggleAll(select);
40
+ return;
41
+ }
42
+ // Placeholder rows are excluded: there is no row there to select yet,
43
+ // and ticking one would leave a selected id that never resolves.
44
+ const selectable = ctx.allRows.filter((row) => !isGroupRow(row) && !ctx.placeholderStateOf(row));
18
45
  ctx.grid.setRowSelection((prev) => {
19
46
  const next = { ...prev };
20
47
  for (const row of selectable) {
@@ -495,7 +522,7 @@ export function createSelection(ctx) {
495
522
  // Also commit a fill-handle drag if one was in progress - the user
496
523
  // released the mouse, time to apply the pattern.
497
524
  if (ctx.fillDrag)
498
- ctx.onFillPointerUp();
525
+ ctx.onFillPointerUp(event);
499
526
  if (ctx.moveDrag)
500
527
  ctx.onMovePointerUp(event);
501
528
  }
@@ -646,6 +673,7 @@ export function createSelection(ctx) {
646
673
  isRowSelected,
647
674
  toggleRowSelectionById,
648
675
  toggleSelectAllRows,
676
+ setSelectAllRows,
649
677
  setActiveCell,
650
678
  scrollActiveCellIntoView,
651
679
  setSelection,