@coreui/data-grid 0.1.0-rc.0 → 0.2.0-rc.0

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 (137) hide show
  1. package/README.md +5 -4
  2. package/dist/css/data-grid.css +149 -31
  3. package/dist/css/data-grid.css.map +1 -1
  4. package/dist/css/data-grid.min.css +2 -2
  5. package/dist/css/data-grid.min.css.map +1 -1
  6. package/dist/js/clipboard.cjs +56 -0
  7. package/dist/js/clipboard.cjs.map +1 -0
  8. package/dist/js/clipboard.mjs +54 -0
  9. package/dist/js/clipboard.mjs.map +1 -0
  10. package/dist/js/csv.cjs +36 -59
  11. package/dist/js/csv.cjs.map +1 -1
  12. package/dist/js/csv.mjs +35 -55
  13. package/dist/js/csv.mjs.map +1 -1
  14. package/dist/js/data-grid.esm.js +14078 -9332
  15. package/dist/js/data-grid.esm.js.map +1 -1
  16. package/dist/js/data-grid.esm.min.js +6 -6
  17. package/dist/js/data-grid.esm.min.js.map +1 -1
  18. package/dist/js/data-grid.js +14377 -9634
  19. package/dist/js/data-grid.js.map +1 -1
  20. package/dist/js/data-grid.lite.esm.js +10476 -0
  21. package/dist/js/data-grid.lite.esm.js.map +1 -0
  22. package/dist/js/data-grid.lite.esm.min.js +8 -0
  23. package/dist/js/data-grid.lite.esm.min.js.map +1 -0
  24. package/dist/js/data-grid.lite.js +10489 -0
  25. package/dist/js/data-grid.lite.js.map +1 -0
  26. package/dist/js/data-grid.lite.min.js +8 -0
  27. package/dist/js/data-grid.lite.min.js.map +1 -0
  28. package/dist/js/data-grid.lite.mjs +10476 -0
  29. package/dist/js/data-grid.lite.mjs.map +1 -0
  30. package/dist/js/data-grid.min.js +6 -6
  31. package/dist/js/data-grid.min.js.map +1 -1
  32. package/dist/js/data-grid.mjs +14078 -9332
  33. package/dist/js/data-grid.mjs.map +1 -1
  34. package/dist/js/drag.cjs +459 -0
  35. package/dist/js/drag.cjs.map +1 -0
  36. package/dist/js/drag.mjs +456 -0
  37. package/dist/js/drag.mjs.map +1 -0
  38. package/dist/js/export-table-CNAKStzj.mjs +26 -0
  39. package/dist/js/export-table-CNAKStzj.mjs.map +1 -0
  40. package/dist/js/export-table-doIwvE5U.cjs +55 -0
  41. package/dist/js/export-table-doIwvE5U.cjs.map +1 -0
  42. package/dist/js/filters.cjs +89 -132
  43. package/dist/js/filters.cjs.map +1 -1
  44. package/dist/js/filters.mjs +88 -128
  45. package/dist/js/filters.mjs.map +1 -1
  46. package/dist/js/labels.cjs +65 -70
  47. package/dist/js/labels.cjs.map +1 -1
  48. package/dist/js/labels.mjs +64 -66
  49. package/dist/js/labels.mjs.map +1 -1
  50. package/dist/js/print.cjs +66 -0
  51. package/dist/js/print.cjs.map +1 -0
  52. package/dist/js/print.mjs +64 -0
  53. package/dist/js/print.mjs.map +1 -0
  54. package/dist/js/validate.cjs +43 -0
  55. package/dist/js/validate.cjs.map +1 -0
  56. package/dist/js/validate.mjs +42 -0
  57. package/dist/js/validate.mjs.map +1 -0
  58. package/dist/js/xlsx.cjs +240 -0
  59. package/dist/js/xlsx.cjs.map +1 -0
  60. package/dist/js/xlsx.mjs +238 -0
  61. package/dist/js/xlsx.mjs.map +1 -0
  62. package/dist/types/base-component.d.ts +28 -18
  63. package/dist/types/data-grid.d.ts +26 -13
  64. package/dist/types/dom/data.d.ts +15 -0
  65. package/dist/types/dom/event-handler.d.ts +21 -10
  66. package/dist/types/dom/manipulator.d.ts +15 -8
  67. package/dist/types/engine/data-source.d.ts +1 -1
  68. package/dist/types/engine/features-lite.d.ts +25 -0
  69. package/dist/types/engine/features.d.ts +35 -0
  70. package/dist/types/engine/table.d.ts +3 -3
  71. package/dist/types/engine/validate.d.mts +1 -0
  72. package/dist/types/engine/validate.d.ts +20 -0
  73. package/dist/types/engine/virtualizer.d.ts +2 -0
  74. package/dist/types/icons.d.ts +6 -4
  75. package/dist/types/index-lite.d.mts +1 -0
  76. package/dist/types/index-lite.d.ts +19 -0
  77. package/dist/types/index.d.ts +11 -2
  78. package/dist/types/types.d.ts +53 -31
  79. package/dist/types/ui/body.d.ts +6 -3
  80. package/dist/types/ui/header.d.ts +3 -2
  81. package/dist/types/ui/loading.d.ts +1 -1
  82. package/dist/types/ui/pinning.d.ts +1 -1
  83. package/dist/types/ui/toolbar.d.ts +10 -2
  84. package/dist/types/util/clipboard.d.mts +1 -0
  85. package/dist/types/util/clipboard.d.ts +29 -0
  86. package/dist/types/util/config.d.ts +27 -10
  87. package/dist/types/util/csv.d.ts +5 -5
  88. package/dist/types/util/drag.d.mts +1 -0
  89. package/dist/types/util/drag.d.ts +48 -0
  90. package/dist/types/util/export-table.d.ts +47 -0
  91. package/dist/types/util/index.d.ts +66 -10
  92. package/dist/types/util/print.d.mts +1 -0
  93. package/dist/types/util/print.d.ts +32 -0
  94. package/dist/types/util/sanitizer.d.ts +15 -11
  95. package/dist/types/util/xlsx.d.mts +1 -0
  96. package/dist/types/util/xlsx.d.ts +17 -0
  97. package/dist/types/util/zip.d.ts +11 -0
  98. package/package.json +88 -10
  99. package/scss/data-grid.scss +204 -16
  100. package/src/{base-component.js → base-component.ts} +21 -17
  101. package/src/data-grid.ts +507 -200
  102. package/src/dom/{data.js → data.ts} +13 -10
  103. package/src/dom/event-handler.ts +380 -0
  104. package/src/dom/{manipulator.js → manipulator.ts} +11 -11
  105. package/src/engine/data-source.ts +7 -3
  106. package/src/engine/features-lite.ts +47 -0
  107. package/src/engine/features.ts +68 -0
  108. package/src/engine/table.ts +80 -47
  109. package/src/engine/validate.ts +64 -0
  110. package/src/engine/virtualizer.ts +17 -1
  111. package/src/icons.ts +11 -5
  112. package/src/index-lite.ts +85 -0
  113. package/src/index.ts +30 -2
  114. package/src/labels.ts +6 -4
  115. package/src/types.ts +87 -32
  116. package/src/ui/body.ts +73 -17
  117. package/src/ui/header.ts +51 -26
  118. package/src/ui/loading.ts +2 -2
  119. package/src/ui/pinning.ts +16 -16
  120. package/src/ui/toolbar.ts +27 -3
  121. package/src/util/clipboard.ts +112 -0
  122. package/src/util/{config.js → config.ts} +25 -11
  123. package/src/util/csv.ts +11 -30
  124. package/src/util/drag.ts +798 -0
  125. package/src/util/export-table.ts +86 -0
  126. package/src/util/{index.js → index.ts} +55 -35
  127. package/src/util/print.ts +125 -0
  128. package/src/util/{sanitizer.js → sanitizer.ts} +17 -13
  129. package/src/util/xlsx.ts +183 -0
  130. package/src/util/zip.ts +170 -0
  131. package/src/base-component.d.ts +0 -19
  132. package/src/dom/event-handler.d.ts +0 -11
  133. package/src/dom/event-handler.js +0 -331
  134. package/src/dom/manipulator.d.ts +0 -9
  135. package/src/util/config.d.ts +0 -11
  136. package/src/util/index.d.ts +0 -10
  137. package/src/util/sanitizer.d.ts +0 -11
package/src/data-grid.ts CHANGED
@@ -5,26 +5,34 @@
5
5
  * --------------------------------------------------------------------------
6
6
  */
7
7
 
8
- import type { Table, TableState } from '@tanstack/table-core'
8
+ import { batch } from '@tanstack/store'
9
9
  import BaseComponent from './base-component.js'
10
+ import type { ComponentConfig } from './util/config.js'
10
11
  import EventHandler from './dom/event-handler.js'
11
12
  import {
12
13
  createActiveCellManager, resolveNavigation, type ActiveCell, type ActiveCellContext, type ActiveCellManager
13
14
  } from './engine/active-cell'
14
15
  import { createDataSource, type GridDataSource } from './engine/data-source'
16
+ import { copyCellSelection, type ClipboardColumn } from './util/clipboard'
17
+ import { printGrid, type PrintColumn } from './util/print'
18
+ import {
19
+ createColumnDragController, createRowDragController, type DragController
20
+ } from './util/drag'
15
21
  import { createScheduler, type Scheduler } from './engine/scheduler'
16
- import { createGridTable } from './engine/table'
22
+ import { createGridTable, subscribeToTableState } from './engine/table'
17
23
  import { createGridVirtualizer, type GridVirtualizer } from './engine/virtualizer'
18
24
  import {
19
- DEFAULT_COLUMN_MENU_ICON, DEFAULT_FILTER_ICON, DEFAULT_HIDE_COLUMN_ICON, DEFAULT_MOVE_LEFT_ICON, DEFAULT_MOVE_RIGHT_ICON,
20
- DEFAULT_PIN_LEFT_ICON, DEFAULT_PIN_RIGHT_ICON, DEFAULT_SORT_ASCENDING_ICON, DEFAULT_SORT_DESCENDING_ICON,
25
+ DEFAULT_COLUMN_MENU_ICON, DEFAULT_FILTER_ICON, DEFAULT_HIDE_COLUMN_ICON, DEFAULT_MOVE_END_ICON, DEFAULT_MOVE_START_ICON,
26
+ DEFAULT_PIN_END_ICON, DEFAULT_PIN_START_ICON, DEFAULT_ROW_HANDLE_ICON, DEFAULT_SORT_ASCENDING_ICON,
27
+ DEFAULT_SORT_DESCENDING_ICON,
21
28
  DEFAULT_SORT_NEUTRAL_ICON, DEFAULT_TOOLBAR_COLUMNS_ICON, DEFAULT_TOOLBAR_EXPORT_ICON,
22
- DEFAULT_TOOLBAR_REDO_ICON, DEFAULT_TOOLBAR_UNDO_ICON, DEFAULT_UNPIN_ICON
29
+ DEFAULT_TOOLBAR_PRINT_ICON, DEFAULT_TOOLBAR_REDO_ICON, DEFAULT_TOOLBAR_UNDO_ICON, DEFAULT_UNPIN_ICON
23
30
  } from './icons'
24
31
  import { DEFAULT_LABELS, interpolate } from './labels'
25
32
  import type {
26
33
  DataGridColumn, DataGridColumnFilterValue, DataGridEditableOptions, DataGridEditor, DataGridEditorContext,
27
- DataGridItem, DataGridLabels, DataGridMenuAction, DataGridOptions, DataGridSlot, DataGridSlotContext, DataGridState
34
+ DataGridFeatures, DataGridItem, DataGridLabels, DataGridMenuAction, DataGridOptions, DataGridSlot,
35
+ DataGridSlotContext, DataGridState, DataGridTable, DataGridTableState, TableFeatures
28
36
  } from './types'
29
37
  import { createBody, type GridBody } from './ui/body'
30
38
  import { createBuiltInEditor } from './ui/editor'
@@ -41,7 +49,6 @@ import {
41
49
  downloadCsv, exportCsv, type CsvDownloadOptions, type CsvOptions
42
50
  } from './util/csv'
43
51
  import { debounce } from './util/debounce'
44
- import { defineJQueryPlugin } from './util/index.js'
45
52
  import { DefaultAllowlist, sanitizeHtml, SVGAllowlist } from './util/sanitizer.js'
46
53
 
47
54
  /**
@@ -62,7 +69,9 @@ const EVENT_EDIT_COMMIT = `editCommit${EVENT_KEY}`
62
69
  const EVENT_EDIT_START = `editStart${EVENT_KEY}`
63
70
  const EVENT_FILTER_CHANGE = `filterChange${EVENT_KEY}`
64
71
  const EVENT_INPUT = `input${EVENT_KEY}`
72
+ const EVENT_CELL_COPY = `cellCopy${EVENT_KEY}`
65
73
  const EVENT_ORDER_CHANGE = `orderChange${EVENT_KEY}`
74
+ const EVENT_ROW_ORDER_CHANGE = `rowOrderChange${EVENT_KEY}`
66
75
  const EVENT_PAGINATION_CHANGE = `paginationChange${EVENT_KEY}`
67
76
  const EVENT_PINNING_CHANGE = `pinningChange${EVENT_KEY}`
68
77
  const EVENT_SELECTION_CHANGE = `selectionChange${EVENT_KEY}`
@@ -74,27 +83,23 @@ const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
74
83
  const EVENT_FOCUSOUT = `focusout${EVENT_KEY}`
75
84
  const EVENT_KEYDOWN = `keydown${EVENT_KEY}`
76
85
 
77
- const EVENT_DRAGEND = `dragend${EVENT_KEY}`
78
- const EVENT_DRAGLEAVE = `dragleave${EVENT_KEY}`
79
- const EVENT_DRAGOVER = `dragover${EVENT_KEY}`
80
- const EVENT_DRAGSTART = `dragstart${EVENT_KEY}`
81
- const EVENT_DROP = `drop${EVENT_KEY}`
82
86
  const EVENT_MOUSEDOWN = `mousedown${EVENT_KEY}`
87
+ const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`
83
88
  const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`
84
89
  const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`
85
90
 
91
+ const CLASS_NAME_AUTO_ROW_HEIGHT = 'data-grid-auto-row-height'
86
92
  const CLASS_NAME_DATA_GRID = 'data-grid'
87
- const CLASS_NAME_DRAGGING = 'data-grid-dragging'
88
93
  const CLASS_NAME_EDITOR_POPUP = 'data-grid-editor-popup'
89
- const CLASS_NAME_DROP_TARGET = 'data-grid-drop-target'
94
+ const CLASS_NAME_LOADING_MORE = 'data-grid-loading-more'
90
95
  const CLASS_NAME_PAGINATION_TOP = 'data-grid-pagination-top'
91
96
  const CLASS_NAME_PINNED = 'data-grid-pinned'
92
97
  const CLASS_NAME_RESIZABLE = 'data-grid-resizable'
93
98
  const CLASS_NAME_TABLE = 'table'
94
99
  const CLASS_NAME_VIEWPORT = 'data-grid-viewport'
95
100
 
101
+ const SELECTOR_BODY_CELL = 'tbody td[data-coreui-column]'
96
102
  const SELECTOR_COLUMN_FILTER = 'input[data-coreui-column-filter]'
97
- const SELECTOR_DRAGGABLE = 'th[data-coreui-draggable]'
98
103
  const SELECTOR_MENU_BUTTON = 'button[data-coreui-menu]'
99
104
  const SELECTOR_FILTER_BUTTON = 'button[data-coreui-filter]'
100
105
  const SELECTOR_GLOBAL_FILTER = 'input[data-coreui-global-filter]'
@@ -106,6 +111,7 @@ const SELECTOR_SELECT_ALL = 'input[data-coreui-select-all]'
106
111
  const SELECTOR_SORT_BUTTON = '.data-grid-sort-button'
107
112
  const SELECTOR_TOOLBAR_COLUMNS = 'button[data-coreui-toolbar-columns]'
108
113
  const SELECTOR_TOOLBAR_EXPORT = 'button[data-coreui-toolbar-export]'
114
+ const SELECTOR_TOOLBAR_PRINT = 'button[data-coreui-toolbar-print]'
109
115
  const SELECTOR_TOOLBAR_REDO = 'button[data-coreui-toolbar-redo]'
110
116
  const SELECTOR_TOOLBAR_UNDO = 'button[data-coreui-toolbar-undo]'
111
117
 
@@ -128,6 +134,13 @@ const STATE_STORAGE_PREFIX = 'coreui-data-grid:'
128
134
  const STATE_AUTOSAVE_DEBOUNCE_MS = 250
129
135
  const HISTORY_LIMIT = 100
130
136
 
137
+ const CELL_SELECTION_DIRECTIONS: Record<string, 'up' | 'down' | 'left' | 'right' | undefined> = {
138
+ ArrowDown: 'down',
139
+ ArrowLeft: 'left',
140
+ ArrowRight: 'right',
141
+ ArrowUp: 'up'
142
+ }
143
+
131
144
  const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]'
132
145
 
133
146
  const applyTabIndex = (cellElement: HTMLElement, isTabbable: boolean) => {
@@ -138,7 +151,9 @@ const applyTabIndex = (cellElement: HTMLElement, isTabbable: boolean) => {
138
151
  }
139
152
 
140
153
  const Default: DataGridOptions = {
154
+ autoRowHeight: false,
141
155
  cellNavigation: false,
156
+ cellSelection: false,
142
157
  columnFilters: false,
143
158
  columnMenu: false,
144
159
  columnMenuIcon: DEFAULT_COLUMN_MENU_ICON,
@@ -150,20 +165,25 @@ const Default: DataGridOptions = {
150
165
  dataProvider: null,
151
166
  editing: false,
152
167
  empty: 'No items found',
168
+ features: null,
153
169
  filterIcon: DEFAULT_FILTER_ICON,
154
170
  globalFilter: false,
155
171
  hideColumnIcon: DEFAULT_HIDE_COLUMN_ICON,
156
172
  history: false,
173
+ infiniteScroll: false,
157
174
  itemKey: null,
158
175
  items: [],
159
176
  labels: {},
160
- moveLeftIcon: DEFAULT_MOVE_LEFT_ICON,
161
- moveRightIcon: DEFAULT_MOVE_RIGHT_ICON,
177
+ moveEndIcon: DEFAULT_MOVE_END_ICON,
178
+ moveStartIcon: DEFAULT_MOVE_START_ICON,
162
179
  overscan: 10,
163
180
  pagination: false,
164
- pinLeftIcon: DEFAULT_PIN_LEFT_ICON,
165
- pinRightIcon: DEFAULT_PIN_RIGHT_ICON,
181
+ pinEndIcon: DEFAULT_PIN_END_ICON,
182
+ pinStartIcon: DEFAULT_PIN_START_ICON,
183
+ printTitle: null,
184
+ rowHandleIcon: DEFAULT_ROW_HANDLE_ICON,
166
185
  rowHeight: 44,
186
+ rowOrder: false,
167
187
  rowSelection: false,
168
188
  sanitize: true,
169
189
  sanitizeFn: null,
@@ -177,6 +197,7 @@ const Default: DataGridOptions = {
177
197
  toolbar: false,
178
198
  toolbarColumnsIcon: DEFAULT_TOOLBAR_COLUMNS_ICON,
179
199
  toolbarExportIcon: DEFAULT_TOOLBAR_EXPORT_ICON,
200
+ toolbarPrintIcon: DEFAULT_TOOLBAR_PRINT_ICON,
180
201
  toolbarRedoIcon: DEFAULT_TOOLBAR_REDO_ICON,
181
202
  toolbarUndoIcon: DEFAULT_TOOLBAR_UNDO_ICON,
182
203
  unpinIcon: DEFAULT_UNPIN_ICON,
@@ -184,7 +205,9 @@ const Default: DataGridOptions = {
184
205
  }
185
206
 
186
207
  const DefaultType = {
208
+ autoRowHeight: 'boolean',
187
209
  cellNavigation: 'boolean',
210
+ cellSelection: 'boolean',
188
211
  columnFilters: 'boolean',
189
212
  columnMenu: '(boolean|function)',
190
213
  columnMenuIcon: 'string',
@@ -196,20 +219,25 @@ const DefaultType = {
196
219
  dataProvider: '(function|null)',
197
220
  editing: 'boolean',
198
221
  empty: '(string|function)',
222
+ features: '(object|null)',
199
223
  filterIcon: 'string',
200
224
  globalFilter: 'boolean',
201
225
  hideColumnIcon: 'string',
202
226
  history: 'boolean',
227
+ infiniteScroll: '(boolean|object)',
203
228
  itemKey: '(function|null)',
204
229
  items: 'array',
205
230
  labels: 'object',
206
- moveLeftIcon: 'string',
207
- moveRightIcon: 'string',
231
+ moveEndIcon: 'string',
232
+ moveStartIcon: 'string',
208
233
  overscan: 'number',
209
234
  pagination: '(boolean|object)',
210
- pinLeftIcon: 'string',
211
- pinRightIcon: 'string',
235
+ pinEndIcon: 'string',
236
+ pinStartIcon: 'string',
237
+ printTitle: '(string|null)',
238
+ rowHandleIcon: 'string',
212
239
  rowHeight: 'number',
240
+ rowOrder: 'boolean',
213
241
  rowSelection: '(boolean|object)',
214
242
  sanitize: 'boolean',
215
243
  sanitizeFn: '(function|null)',
@@ -223,6 +251,7 @@ const DefaultType = {
223
251
  toolbar: '(boolean|object)',
224
252
  toolbarColumnsIcon: 'string',
225
253
  toolbarExportIcon: 'string',
254
+ toolbarPrintIcon: 'string',
226
255
  toolbarRedoIcon: 'string',
227
256
  toolbarUndoIcon: 'string',
228
257
  unpinIcon: 'string',
@@ -233,9 +262,13 @@ const DefaultType = {
233
262
  * Class definition
234
263
  */
235
264
 
236
- class DataGrid extends BaseComponent {
265
+ class DataGrid<TFeatures extends TableFeatures = DataGridFeatures> extends BaseComponent {
237
266
  declare _config: DataGridOptions
238
- private _table!: Table<DataGridItem>
267
+ // Typed on the full set even when the runtime set is smaller - internals
268
+ // capability-guard every optional-feature call, and the public `table`
269
+ // getter narrows back to the instance's TFeatures.
270
+ private _table!: DataGridTable
271
+ private _unsubscribeState: (() => void) | null = null
239
272
  private _scheduler!: Scheduler
240
273
  private _virtualizer: GridVirtualizer | null = null
241
274
  private _header!: GridHeader
@@ -245,7 +278,13 @@ class DataGrid extends BaseComponent {
245
278
  private _emptySlot: DataGridSlot | null = null
246
279
  private _dataSource: GridDataSource | null = null
247
280
  private _loading: GridLoading | null = null
281
+ private _loadingMore: GridLoading | null = null
248
282
  private _loadFailed = false
283
+ // Infinite scroll accumulates every loaded page here; the table's data is
284
+ // this buffer, not the last response.
285
+ private _loadedItems: DataGridItem[] = []
286
+ private _loadMorePending = false
287
+ private _pageResetPending = false
249
288
  private _dataVersion = 0
250
289
  private _viewportElement!: HTMLDivElement
251
290
  private _tableElement!: HTMLTableElement
@@ -272,14 +311,15 @@ private _undoStack: DataGridEditCommitEntry[] = []
272
311
  private _editorErrorElement: HTMLElement | null = null
273
312
  private _editorFocusPending = false
274
313
  private _columnsByKey = new Map<string, DataGridColumn>()
275
- private _dragColumn: string | null = null
314
+ private _columnDrag: DragController | null = null
315
+ private _rowDrag: DragController | null = null
276
316
  private _menu: GridMenu | null = null
277
317
  private _tooltip: GridTooltip | null = null
278
318
  private _filterMenu: GridFilterMenu | null = null
279
319
  private _columnChooser: GridColumnChooser | null = null
280
320
  private _toolbarConfig: ResolvedToolbar | null = null
281
321
 
282
- constructor(element: Element | string, config?: Partial<DataGridOptions>) {
322
+ constructor(element: Element | string, config?: Partial<DataGridOptions<TFeatures>>) {
283
323
  super(element, config)
284
324
 
285
325
  if (!this._element) {
@@ -305,8 +345,10 @@ private _undoStack: DataGridEditCommitEntry[] = []
305
345
  }
306
346
 
307
347
  // Getters
308
- get table(): Table<DataGridItem> {
309
- return this._table
348
+ get table(): DataGridTable<TFeatures> {
349
+ // TFeatures is invariant, so the internal full-set alias needs the double
350
+ // cast back to the instance's actual set.
351
+ return this._table as unknown as DataGridTable<TFeatures>
310
352
  }
311
353
 
312
354
  static get Default(): DataGridOptions {
@@ -321,19 +363,22 @@ private _undoStack: DataGridEditCommitEntry[] = []
321
363
  return NAME
322
364
  }
323
365
 
324
- static getInstance(element: Element | string | null): DataGrid | null {
325
- return super.getInstance(element) as DataGrid | null
326
- }
327
-
328
- static getOrCreateInstance(element: Element | string, config?: Partial<DataGridOptions>): DataGrid {
329
- return super.getOrCreateInstance(element, config) as DataGrid
330
- }
331
-
332
366
  // Public
333
367
  getSelectedItems(): DataGridItem[] {
368
+ if (typeof this._table.getSelectedRowModel !== 'function') {
369
+ return []
370
+ }
371
+
334
372
  return this._table.getSelectedRowModel().rows.map(row => row.original)
335
373
  }
336
374
 
375
+ // Prints every sorted and filtered row, not the virtual window or the
376
+ // current page: the grid renders a plain complete table, prints it, and
377
+ // throws it away.
378
+ print(): void {
379
+ printGrid(this._table, this._printColumns(), { title: this._config.printTitle ?? undefined })
380
+ }
381
+
337
382
  getCsv(options?: CsvOptions): string {
338
383
  return exportCsv(this._table, options)
339
384
  }
@@ -345,22 +390,66 @@ private _undoStack: DataGridEditCommitEntry[] = []
345
390
  // A serializable snapshot of every user-adjustable state slice. Feed it
346
391
  // back through restoreState() - scroll position and edit drafts excluded.
347
392
  getState(): DataGridState {
348
- const state = this._table.getState()
393
+ // A reduced feature set has no atom for its absent slices - the snapshot
394
+ // keeps its full shape with neutral values so persisted state stays
395
+ // portable between feature sets.
396
+ const { state } = this._table.store
349
397
  return {
350
- columnFilters: state.columnFilters,
351
- columnOrder: state.columnOrder,
352
- columnPinning: state.columnPinning,
353
- columnSizing: state.columnSizing,
354
- columnVisibility: state.columnVisibility,
398
+ columnFilters: state.columnFilters ?? [],
399
+ columnOrder: state.columnOrder ?? [],
400
+ columnPinning: state.columnPinning ?? { start: [], end: [] },
401
+ columnSizing: state.columnSizing ?? {},
402
+ columnVisibility: state.columnVisibility ?? {},
355
403
  globalFilter: (state.globalFilter as string | undefined) ?? '',
356
- pagination: state.pagination,
357
- rowSelection: state.rowSelection,
358
- sorting: state.sorting
404
+ pagination: state.pagination ?? { pageIndex: 0, pageSize: Number.MAX_SAFE_INTEGER },
405
+ rowSelection: state.rowSelection ?? {},
406
+ sorting: state.sorting ?? []
359
407
  }
360
408
  }
361
409
 
362
410
  restoreState(state: Partial<DataGridState>): void {
363
- this._table.setState(previous => ({ ...previous, ...state }))
411
+ // v9 owns one atom per slice and has no bulk state setter; batching keeps
412
+ // the writes to a single store emission, so the change events still fire
413
+ // once for the whole restore.
414
+ // The setter-presence checks let a snapshot taken on one feature set
415
+ // restore into a grid running a smaller one - absent slices are skipped.
416
+ batch(() => {
417
+ if (state.columnFilters !== undefined && typeof this._table.setColumnFilters === 'function') {
418
+ this._table.setColumnFilters(state.columnFilters)
419
+ }
420
+
421
+ if (state.columnOrder !== undefined && typeof this._table.setColumnOrder === 'function') {
422
+ this._table.setColumnOrder(state.columnOrder)
423
+ }
424
+
425
+ if (state.columnPinning !== undefined && typeof this._table.setColumnPinning === 'function') {
426
+ this._table.setColumnPinning(state.columnPinning)
427
+ }
428
+
429
+ if (state.columnSizing !== undefined && typeof this._table.setColumnSizing === 'function') {
430
+ this._table.setColumnSizing(state.columnSizing)
431
+ }
432
+
433
+ if (state.columnVisibility !== undefined && typeof this._table.setColumnVisibility === 'function') {
434
+ this._table.setColumnVisibility(state.columnVisibility)
435
+ }
436
+
437
+ if (state.globalFilter !== undefined && typeof this._table.setGlobalFilter === 'function') {
438
+ this._table.setGlobalFilter(state.globalFilter)
439
+ }
440
+
441
+ if (state.pagination !== undefined && typeof this._table.setPagination === 'function') {
442
+ this._table.setPagination(state.pagination)
443
+ }
444
+
445
+ if (state.rowSelection !== undefined && typeof this._table.setRowSelection === 'function') {
446
+ this._table.setRowSelection(state.rowSelection)
447
+ }
448
+
449
+ if (state.sorting !== undefined && typeof this._table.setSorting === 'function') {
450
+ this._table.setSorting(state.sorting)
451
+ }
452
+ })
364
453
 
365
454
  // The built-in search input is uncontrolled - sync it to the restored
366
455
  // filter so the UI matches the state.
@@ -424,19 +513,23 @@ private _undoStack: DataGridEditCommitEntry[] = []
424
513
  this._stopEditing({ commit: false })
425
514
  this._config.items = items
426
515
  this._dataVersion++
516
+ this._virtualizer?.remeasure()
427
517
  this._table.setOptions(previous => ({ ...previous, data: items }))
428
518
  this._scheduler.schedule()
429
519
  }
430
520
 
431
521
  // Full rebuild: recreates the table, wiping sorting/filters/selection/scroll.
432
522
  // Use setItems() to swap data while keeping user state.
433
- update(config: Partial<DataGridOptions>): void {
434
- this._config = this._getConfig({ ...this._config, ...config })
523
+ update(config: Partial<DataGridOptions<TFeatures>>): void {
524
+ this._config = this._getConfig({ ...this._config, ...config }) as DataGridOptions
435
525
  this._labels = { ...DEFAULT_LABELS, ...this._config.labels }
436
526
 
437
527
  this._teardownUi()
438
528
  this._selectionAnchorIndex = null
439
529
  this._loadFailed = false
530
+ this._pageResetPending = false
531
+ this._loadedItems = []
532
+ this._loadMorePending = false
440
533
  this._dataVersion++
441
534
  this._table = this._createTable()
442
535
  this._render()
@@ -445,6 +538,8 @@ private _undoStack: DataGridEditCommitEntry[] = []
445
538
 
446
539
  dispose(): void {
447
540
  this._teardownUi()
541
+ this._unsubscribeState?.()
542
+ this._unsubscribeState = null
448
543
  this._scheduler.dispose()
449
544
  this._tooltip?.dispose()
450
545
  this._tooltip = null
@@ -460,19 +555,25 @@ private _undoStack: DataGridEditCommitEntry[] = []
460
555
 
461
556
  // Private
462
557
  // Editing needs the active-cell substrate (Enter/F2 target the active cell).
463
- _configAfterMerge(config: DataGridOptions): DataGridOptions {
464
- if (config.editing) {
558
+ _configAfterMerge(config: ComponentConfig): ComponentConfig {
559
+ // Both need the active-cell substrate: editing targets it with Enter/F2,
560
+ // cell selection anchors ranges on it.
561
+ if (config.editing || config.cellSelection) {
465
562
  config.cellNavigation = true
466
563
  }
467
564
 
468
565
  return config
469
566
  }
470
567
 
471
- private _createTable(): Table<DataGridItem> {
472
- return createGridTable(this._config, (previous, next) => {
568
+ private _createTable(): DataGridTable {
569
+ this._unsubscribeState?.()
570
+ const table = createGridTable(this._config)
571
+ this._unsubscribeState = subscribeToTableState(table, (previous, next) => {
473
572
  this._notifyStateChange(previous, next)
474
573
  this._scheduler.schedule()
475
574
  })
575
+
576
+ return table
476
577
  }
477
578
 
478
579
  private _teardownUi(): void {
@@ -505,6 +606,21 @@ private _undoStack: DataGridEditCommitEntry[] = []
505
606
  this._loading = null
506
607
  }
507
608
 
609
+ if (this._loadingMore) {
610
+ this._loadingMore.element.remove()
611
+ this._loadingMore = null
612
+ }
613
+
614
+ if (this._columnDrag) {
615
+ this._columnDrag.dispose()
616
+ this._columnDrag = null
617
+ }
618
+
619
+ if (this._rowDrag) {
620
+ this._rowDrag.dispose()
621
+ this._rowDrag = null
622
+ }
623
+
508
624
  if (this._virtualizer) {
509
625
  this._virtualizer.destroy()
510
626
  this._virtualizer = null
@@ -581,7 +697,10 @@ private _undoStack: DataGridEditCommitEntry[] = []
581
697
  return
582
698
  }
583
699
 
584
- if (!toolbarConfig.columns && !toolbarConfig.export && !toolbarConfig.search && !toolbarConfig.history) {
700
+ if (
701
+ !toolbarConfig.columns && !toolbarConfig.export && !toolbarConfig.print &&
702
+ !toolbarConfig.search && !toolbarConfig.history
703
+ ) {
585
704
  return
586
705
  }
587
706
 
@@ -591,11 +710,13 @@ private _undoStack: DataGridEditCommitEntry[] = []
591
710
  icons: {
592
711
  columns: this._sanitizeIcon(this._config.toolbarColumnsIcon),
593
712
  export: this._sanitizeIcon(this._config.toolbarExportIcon),
713
+ print: this._sanitizeIcon(this._config.toolbarPrintIcon),
594
714
  redo: this._sanitizeIcon(this._config.toolbarRedoIcon),
595
715
  undo: this._sanitizeIcon(this._config.toolbarUndoIcon)
596
716
  },
597
717
  history: toolbarConfig.history,
598
718
  labels: this._labels,
719
+ print: toolbarConfig.print,
599
720
  search: toolbarConfig.search
600
721
  })
601
722
  this._element.append(this._toolbar.element)
@@ -620,6 +741,7 @@ private _undoStack: DataGridEditCommitEntry[] = []
620
741
  createActiveCellManager(() => this._scheduler.schedule()) :
621
742
  null
622
743
  this._element.classList.add(CLASS_NAME_DATA_GRID)
744
+ this._element.classList.toggle(CLASS_NAME_AUTO_ROW_HEIGHT, Boolean(this._config.autoRowHeight))
623
745
  this._element.classList.toggle(CLASS_NAME_RESIZABLE, Boolean(this._config.columnSizing))
624
746
  this._element.classList.toggle(CLASS_NAME_PINNED, Boolean(this._config.columnPinning))
625
747
  if (this._config.sorterVisibility) {
@@ -637,9 +759,11 @@ private _undoStack: DataGridEditCommitEntry[] = []
637
759
 
638
760
  const selectionEnabled = Boolean(this._config.rowSelection)
639
761
  const selectionOptions = typeof this._config.rowSelection === 'object' ? this._config.rowSelection : {}
640
- // Server-side mode implies pagination — virtualized infinite scroll over a
641
- // dataProvider is out of scope until 0.3.0.
642
- const paginationEnabled = Boolean(this._config.pagination) || Boolean(this._config.dataProvider)
762
+ // Server-side mode implies pagination unless it scrolls infinitely, where
763
+ // the pages accumulate behind the virtualizer instead of replacing.
764
+ const paginationEnabled =
765
+ Boolean(this._config.pagination) ||
766
+ (Boolean(this._config.dataProvider) && !this._config.infiniteScroll)
643
767
  const paginationOptions = typeof this._config.pagination === 'object' ? this._config.pagination : {}
644
768
 
645
769
  if (this._config.columnMenu) {
@@ -654,8 +778,15 @@ private _undoStack: DataGridEditCommitEntry[] = []
654
778
  root: this._element as HTMLElement,
655
779
  labels: this._labels,
656
780
  getColumn: columnKey => this._columnsByKey.get(columnKey) ?? null,
657
- getFacetedValues: columnKey =>
658
- [...(this._table.getColumn(columnKey)?.getFacetedUniqueValues().keys() ?? [])],
781
+ getFacetedValues: columnKey => {
782
+ const column = this._table.getColumn(columnKey)
783
+ // Only filterType 'select' menus ask for values, and the coverage
784
+ // assertion ties that filter type to the faceting features - this
785
+ // guard covers select columns added later through update().
786
+ return typeof column?.getFacetedUniqueValues === 'function' ?
787
+ [...column.getFacetedUniqueValues().keys()] :
788
+ []
789
+ },
659
790
  getFilterValue: columnKey =>
660
791
  this._table.getColumn(columnKey)?.getFilterValue() as DataGridColumnFilterValue | undefined,
661
792
  applyFilter: (columnKey, value) => {
@@ -686,26 +817,22 @@ private _undoStack: DataGridEditCommitEntry[] = []
686
817
  isSortable: column => this._isColumnSortable(column),
687
818
  labels: this._labels,
688
819
  resizable: Boolean(this._config.columnSizing),
820
+ rowOrder: this._config.rowOrder,
689
821
  selection: selectionEnabled,
690
822
  selectAll: selectionEnabled && selectionOptions.selectAll !== false,
691
823
  table: this._table
692
824
  })
693
825
  this._body = createBody({
826
+ autoRowHeight: this._config.autoRowHeight && this._config.virtualization,
694
827
  cellNavigation: this._config.cellNavigation,
828
+ cellSelection: this._config.cellSelection,
695
829
  getDataVersion: () => this._dataVersion,
696
830
  getEditingCell: () =>
697
831
  (this._editingCell ? { rowId: this._editingCell.rowId, columnId: this._editingCell.columnId } : null),
698
832
  // Popup editors overlay the cell; its content stays in place.
699
833
  getEditorElement: () => (this._editor && !this._editor.popup ? this._editor.element : null),
700
834
  getPinning: () => (this._config.columnPinning ? this._getPinning() : null),
701
- getRowIndexOffset: () => {
702
- if (!this._config.pagination && !this._config.dataProvider) {
703
- return 0
704
- }
705
-
706
- const { pageIndex, pageSize } = this._table.getState().pagination
707
- return pageIndex * pageSize
708
- },
835
+ getRowIndexOffset: () => this._rowIndexOffset(),
709
836
  getRows: () => this._table.getRowModel().rows,
710
837
  getVisibleColumns: () => this._visibleColumns(),
711
838
  getVirtualizer: () => this._virtualizer?.instance ?? null,
@@ -722,6 +849,8 @@ private _undoStack: DataGridEditCommitEntry[] = []
722
849
 
723
850
  return typeof this._config.empty === 'function' ? this._config.empty() : this._config.empty
724
851
  },
852
+ rowHandleIcon: this._sanitizeIcon(this._config.rowHandleIcon),
853
+ rowOrder: this._config.rowOrder,
725
854
  sanitizeContent: html =>
726
855
  (this._config.sanitize ? sanitizeHtml(html, DefaultAllowlist, this._config.sanitizeFn) : html),
727
856
  selection: selectionEnabled
@@ -750,6 +879,13 @@ private _undoStack: DataGridEditCommitEntry[] = []
750
879
  this._viewportElement.append(this._loading.element)
751
880
  }
752
881
 
882
+ if (this._config.infiniteScroll) {
883
+ // A second indicator: the overlay covers the grid, which is wrong once
884
+ // rows are already on screen and only the next page is arriving.
885
+ this._loadingMore = createLoading(this._labels, CLASS_NAME_LOADING_MORE)
886
+ this._viewportElement.append(this._loadingMore.element)
887
+ }
888
+
753
889
  this._element.append(this._viewportElement)
754
890
 
755
891
  if (paginationEnabled) {
@@ -788,6 +924,7 @@ private _undoStack: DataGridEditCommitEntry[] = []
788
924
  }
789
925
  } else if (this._config.virtualization) {
790
926
  this._virtualizer = createGridVirtualizer({
927
+ autoRowHeight: this._config.autoRowHeight,
791
928
  count: this._table.getRowModel().rows.length,
792
929
  getScrollElement: () => this._viewportElement,
793
930
  onChange: () => this._scheduler.schedule(),
@@ -796,6 +933,8 @@ private _undoStack: DataGridEditCommitEntry[] = []
796
933
  })
797
934
  }
798
935
 
936
+ this._initColumnDrag()
937
+ this._initRowDrag()
799
938
  this._update()
800
939
  }
801
940
 
@@ -818,6 +957,18 @@ private _undoStack: DataGridEditCommitEntry[] = []
818
957
  }
819
958
  })
820
959
 
960
+ // Drag-select: table-core owns the session (it attaches its own document
961
+ // mouseup), so the grid only routes the two events at the right cell.
962
+ EventHandler.on(this._element, EVENT_MOUSEDOWN, SELECTOR_BODY_CELL, event => {
963
+ const cell = this._tableCellFromTarget(event)
964
+ cell?.getSelectionStartHandler()(event)
965
+ })
966
+
967
+ EventHandler.on(this._element, EVENT_MOUSEENTER, SELECTOR_BODY_CELL, event => {
968
+ const cell = this._tableCellFromTarget(event)
969
+ cell?.getSelectionExtendHandler()(event)
970
+ })
971
+
821
972
  EventHandler.on(this._element, EVENT_DBLCLICK, event => {
822
973
  if (!this._config.editing) {
823
974
  return
@@ -872,7 +1023,12 @@ private _undoStack: DataGridEditCommitEntry[] = []
872
1023
  })
873
1024
 
874
1025
  EventHandler.on(this._element, EVENT_CLICK, SELECTOR_TOOLBAR_EXPORT, () => {
875
- this.downloadCsv({ scope: 'filtered', ...this._toolbarConfig?.exportOptions })
1026
+ const { exporter, ...exportOptions } = this._toolbarConfig?.exportOptions ?? {};
1027
+ (exporter ?? downloadCsv)(this._table, { scope: 'filtered', ...exportOptions })
1028
+ })
1029
+
1030
+ EventHandler.on(this._element, EVENT_CLICK, SELECTOR_TOOLBAR_PRINT, () => {
1031
+ this.print()
876
1032
  })
877
1033
 
878
1034
  EventHandler.on(this._element, EVENT_CLICK, SELECTOR_TOOLBAR_UNDO, () => {
@@ -883,42 +1039,6 @@ private _undoStack: DataGridEditCommitEntry[] = []
883
1039
  this.redo()
884
1040
  })
885
1041
 
886
- EventHandler.on(this._element, EVENT_DRAGSTART, SELECTOR_DRAGGABLE, event => {
887
- this._onColumnDragStart(event)
888
- })
889
-
890
- EventHandler.on(this._element, EVENT_DRAGOVER, SELECTOR_DRAGGABLE, event => {
891
- if (!this._dragColumn) {
892
- return
893
- }
894
-
895
- const target = (event.delegateTarget ?? event.target) as HTMLElement
896
- const targetKey = target.dataset.coreuiColumn
897
- // A drop is only valid within the drag source's pinned region; leaving
898
- // other targets un-prevented shows the browser's no-drop cursor there.
899
- const source = this._table.getColumn(this._dragColumn)
900
- const targetColumn = targetKey ? this._table.getColumn(targetKey) : undefined
901
- if (!source || !targetColumn || targetKey === this._dragColumn || source.getIsPinned() !== targetColumn.getIsPinned()) {
902
- return
903
- }
904
-
905
- event.preventDefault()
906
- target.classList.add(CLASS_NAME_DROP_TARGET)
907
- })
908
-
909
- EventHandler.on(this._element, EVENT_DRAGLEAVE, SELECTOR_DRAGGABLE, event => {
910
- const target = (event.delegateTarget ?? event.target) as HTMLElement
911
- target.classList.remove(CLASS_NAME_DROP_TARGET)
912
- })
913
-
914
- EventHandler.on(this._element, EVENT_DROP, SELECTOR_DRAGGABLE, event => {
915
- this._onColumnDrop(event)
916
- })
917
-
918
- EventHandler.on(this._element, EVENT_DRAGEND, SELECTOR_DRAGGABLE, () => {
919
- this._endColumnDrag()
920
- })
921
-
922
1042
  EventHandler.on(this._element, EVENT_MOUSEDOWN, SELECTOR_RESIZER, event => {
923
1043
  this._startColumnResize(event)
924
1044
  })
@@ -1147,6 +1267,22 @@ private _undoStack: DataGridEditCommitEntry[] = []
1147
1267
  return
1148
1268
  }
1149
1269
 
1270
+ if (this._config.cellSelection && (event.ctrlKey || event.metaKey) && found.cell.rowIndex >= 0) {
1271
+ const key = event.key.toLowerCase()
1272
+ if (key === 'a') {
1273
+ event.preventDefault()
1274
+ this._table.selectAllCells()
1275
+ this._scheduler.schedule()
1276
+ return
1277
+ }
1278
+
1279
+ if (key === 'c') {
1280
+ event.preventDefault()
1281
+ this._copyCellSelection()
1282
+ return
1283
+ }
1284
+ }
1285
+
1150
1286
  const result = resolveNavigation(event.key, event.ctrlKey || event.metaKey, found.cell, this._activeCellContext())
1151
1287
  if (!result) {
1152
1288
  return
@@ -1154,6 +1290,17 @@ private _undoStack: DataGridEditCommitEntry[] = []
1154
1290
 
1155
1291
  event.preventDefault()
1156
1292
 
1293
+ // Shift+arrow grows the range from its anchor and leaves focus put; a
1294
+ // plain arrow moves focus and collapses the range to the new cell.
1295
+ if (this._config.cellSelection && found.cell.rowIndex >= 0 && result.cell.rowIndex >= 0) {
1296
+ const direction = CELL_SELECTION_DIRECTIONS[event.key]
1297
+ if (event.shiftKey && direction) {
1298
+ this._table.extendCellSelection(direction)
1299
+ this._scheduler.schedule()
1300
+ return
1301
+ }
1302
+ }
1303
+
1157
1304
  if (result.pageDelta === 1 && this._table.getCanNextPage()) {
1158
1305
  this._table.nextPage()
1159
1306
  } else if (result.pageDelta === -1 && this._table.getCanPreviousPage()) {
@@ -1163,6 +1310,24 @@ private _undoStack: DataGridEditCommitEntry[] = []
1163
1310
  this._setActiveCell(result.cell)
1164
1311
  }
1165
1312
 
1313
+ // The table-core Cell behind a DOM cell, or null when cell selection is off
1314
+ // or the target is not a data cell.
1315
+ private _tableCellFromTarget(event: Event & Record<string, unknown>) {
1316
+ if (!this._config.cellSelection) {
1317
+ return null
1318
+ }
1319
+
1320
+ const element = (event.delegateTarget ?? event.target) as HTMLElement
1321
+ const columnId = element.dataset.coreuiColumn
1322
+ const rowIndex = Number(element.closest<HTMLElement>('tr')?.dataset.coreuiIndex ?? -1)
1323
+ if (!columnId || rowIndex < 0) {
1324
+ return null
1325
+ }
1326
+
1327
+ const row = this._table.getRowModel().rows[rowIndex]
1328
+ return row?.getAllCells().find(cell => cell.column.id === columnId) ?? null
1329
+ }
1330
+
1166
1331
  private _descendIntoCell(cellElement: HTMLElement): void {
1167
1332
  cellElement.querySelector<HTMLElement>(FOCUSABLE_SELECTOR)?.focus({ preventScroll: true })
1168
1333
  }
@@ -1429,6 +1594,15 @@ private _undoStack: DataGridEditCommitEntry[] = []
1429
1594
 
1430
1595
  private _setActiveCell(cell: ActiveCell): void {
1431
1596
  this._activeCell?.set(cell, { focus: true })
1597
+ // The active cell is the grid's single focus owner; cell selection follows
1598
+ // it rather than keeping a second anchor of its own.
1599
+ if (this._config.cellSelection && cell.rowIndex >= 0) {
1600
+ const row = this._table.getRowModel().rows[cell.rowIndex]
1601
+ if (row) {
1602
+ this._table.setFocusedCell(row.id, cell.columnId)
1603
+ }
1604
+ }
1605
+
1432
1606
  if (this._virtualizer && cell.rowIndex >= 0) {
1433
1607
  // No-op when the row is already in view (align: auto); otherwise the
1434
1608
  // focus request stays pending until the row renders on the next flush.
@@ -1436,6 +1610,28 @@ private _undoStack: DataGridEditCommitEntry[] = []
1436
1610
  }
1437
1611
  }
1438
1612
 
1613
+ // The columns the selection's column indexes address, with the formatter
1614
+ // each cell displays through — a copied date pastes as the date on screen.
1615
+ private _printColumns(): PrintColumn[] {
1616
+ return this._visibleColumns().map(column => ({
1617
+ id: column.key,
1618
+ label: column.label ?? column.key,
1619
+ formatter: column.formatter
1620
+ }))
1621
+ }
1622
+
1623
+ private _clipboardColumns(): ClipboardColumn[] {
1624
+ return this._visibleColumns().map(column => ({ id: column.key, formatter: column.formatter }))
1625
+ }
1626
+
1627
+ private _copyCellSelection(): void {
1628
+ copyCellSelection(this._table, this._clipboardColumns()).then(text => {
1629
+ if (text !== '') {
1630
+ EventHandler.trigger(this._element, EVENT_CELL_COPY, { text })
1631
+ }
1632
+ }, () => {})
1633
+ }
1634
+
1439
1635
  private _activeCellContext(): ActiveCellContext {
1440
1636
  const rowCount = this._table.getRowModel().rows.length
1441
1637
  const paginated = Boolean(this._config.pagination) || Boolean(this._config.dataProvider)
@@ -1445,7 +1641,7 @@ private _undoStack: DataGridEditCommitEntry[] = []
1445
1641
  columnIds: this._visibleLeafColumns().map(column => column.id),
1446
1642
  rowCount,
1447
1643
  pageStep: paginated ?
1448
- this._table.getState().pagination.pageSize :
1644
+ this._table.store.state.pagination.pageSize :
1449
1645
  Math.max(1, viewportRows || rowCount),
1450
1646
  paginated
1451
1647
  }
@@ -1563,23 +1759,23 @@ private _undoStack: DataGridEditCommitEntry[] = []
1563
1759
 
1564
1760
  if (this._config.columnPinning) {
1565
1761
  const pinned = column.getIsPinned()
1566
- if (pinned !== 'left') {
1762
+ if (pinned !== 'start') {
1567
1763
  actions.push({
1568
- key: 'pin-left',
1569
- label: this._labels.pinLeft,
1764
+ key: 'pin-start',
1765
+ label: this._labels.pinStart,
1570
1766
  group: 'pinning',
1571
- icon: this._sanitizeIcon(this._config.pinLeftIcon),
1572
- run: () => column.pin('left')
1767
+ icon: this._sanitizeIcon(this._config.pinStartIcon),
1768
+ run: () => column.pin('start')
1573
1769
  })
1574
1770
  }
1575
1771
 
1576
- if (pinned !== 'right') {
1772
+ if (pinned !== 'end') {
1577
1773
  actions.push({
1578
- key: 'pin-right',
1579
- label: this._labels.pinRight,
1774
+ key: 'pin-end',
1775
+ label: this._labels.pinEnd,
1580
1776
  group: 'pinning',
1581
- icon: this._sanitizeIcon(this._config.pinRightIcon),
1582
- run: () => column.pin('right')
1777
+ icon: this._sanitizeIcon(this._config.pinEndIcon),
1778
+ run: () => column.pin('end')
1583
1779
  })
1584
1780
  }
1585
1781
 
@@ -1595,23 +1791,23 @@ private _undoStack: DataGridEditCommitEntry[] = []
1595
1791
  }
1596
1792
 
1597
1793
  if (this._config.columnOrder && config.movable !== false) {
1598
- const region = this._visibleLeafColumns().filter(item => item.getIsPinned() === column.getIsPinned())
1794
+ const region = this._visibleLeafColumns().filter(item => this._pinnedRegion(item) === this._pinnedRegion(column))
1599
1795
  const index = region.findIndex(item => item.id === columnKey)
1600
1796
  actions.push(
1601
1797
  {
1602
- key: 'move-left',
1603
- label: this._labels.moveLeft,
1798
+ key: 'move-start',
1799
+ label: this._labels.moveStart,
1604
1800
  disabled: index <= 0,
1605
1801
  group: 'ordering',
1606
- icon: this._sanitizeIcon(this._config.moveLeftIcon),
1802
+ icon: this._sanitizeIcon(this._config.moveStartIcon),
1607
1803
  run: () => this._moveColumn(columnKey, -1)
1608
1804
  },
1609
1805
  {
1610
- key: 'move-right',
1611
- label: this._labels.moveRight,
1806
+ key: 'move-end',
1807
+ label: this._labels.moveEnd,
1612
1808
  disabled: index === region.length - 1,
1613
1809
  group: 'ordering',
1614
- icon: this._sanitizeIcon(this._config.moveRightIcon),
1810
+ icon: this._sanitizeIcon(this._config.moveEndIcon),
1615
1811
  run: () => this._moveColumn(columnKey, 1)
1616
1812
  }
1617
1813
  )
@@ -1644,7 +1840,7 @@ private _undoStack: DataGridEditCommitEntry[] = []
1644
1840
  // missing ids at the end when they are shown again.
1645
1841
  private _orderedLeafIds(): string[] {
1646
1842
  const allIds = this._table.getAllLeafColumns().map(column => column.id)
1647
- const order = this._table.getState().columnOrder
1843
+ const order = this._table.store.state.columnOrder ?? []
1648
1844
  if (order.length === 0) {
1649
1845
  return allIds
1650
1846
  }
@@ -1661,10 +1857,10 @@ private _undoStack: DataGridEditCommitEntry[] = []
1661
1857
  return
1662
1858
  }
1663
1859
 
1664
- const region = column.getIsPinned()
1860
+ const region = this._pinnedRegion(column)
1665
1861
  const ids = this._orderedLeafIds()
1666
1862
  const regionIds = this._visibleLeafColumns()
1667
- .filter(item => item.getIsPinned() === region)
1863
+ .filter(item => this._pinnedRegion(item) === region)
1668
1864
  .map(item => item.id)
1669
1865
  const neighbor = regionIds[regionIds.indexOf(columnKey) + direction]
1670
1866
  if (!neighbor) {
@@ -1678,64 +1874,92 @@ private _undoStack: DataGridEditCommitEntry[] = []
1678
1874
  this._table.setColumnOrder(ids)
1679
1875
  }
1680
1876
 
1681
- private _onColumnDragStart(event: Event & Record<string, unknown>): void {
1682
- // A drag started from the resize handle is a resize, not a reorder. The
1683
- // handle's mousedown is preventDefault'd so the browser never starts a drag
1684
- // there; this ancestry check is a secondary guard.
1685
- if ((event.target as HTMLElement).closest?.(SELECTOR_RESIZER)) {
1686
- event.preventDefault()
1877
+ // Pointer-based, not HTML5 drag events: the controller owns the ghost, the
1878
+ // drop indicator and the edge auto-scroll, and behaves the same on touch.
1879
+ private _initColumnDrag(): void {
1880
+ if (!this._config.columnOrder) {
1687
1881
  return
1688
1882
  }
1689
1883
 
1690
- const target = (event.delegateTarget ?? event.target) as HTMLElement
1691
- this._dragColumn = target.dataset.coreuiColumn ?? null
1692
- target.classList.add(CLASS_NAME_DRAGGING)
1884
+ this._columnDrag = createColumnDragController({
1885
+ root: this._element as HTMLElement,
1886
+ getScrollElement: () => this._viewportElement,
1887
+ canDrop: (sourceKey, targetKey) => {
1888
+ const source = this._table.getColumn(sourceKey)
1889
+ const target = this._table.getColumn(targetKey)
1890
+ return Boolean(source && target) &&
1891
+ sourceKey !== targetKey &&
1892
+ this._pinnedRegion(source!) === this._pinnedRegion(target!)
1893
+ },
1894
+ onReorder: (sourceKey, targetKey, after) => this._moveColumnTo(sourceKey, targetKey, after)
1895
+ })
1896
+ }
1693
1897
 
1694
- const { dataTransfer } = event as unknown as DragEvent
1695
- if (dataTransfer) {
1696
- dataTransfer.effectAllowed = 'move'
1697
- dataTransfer.setData('text/plain', this._dragColumn ?? '')
1898
+ // Rows are indexed within the current row model; the offset turns that into
1899
+ // a position in `items`.
1900
+ private _rowIndexOffset(): number {
1901
+ // The infinite buffer always starts at the first row, so its indices are
1902
+ // already absolute.
1903
+ if (this._config.infiniteScroll || (!this._config.pagination && !this._config.dataProvider)) {
1904
+ return 0
1698
1905
  }
1699
- }
1700
1906
 
1701
- private _onColumnDrop(event: Event & Record<string, unknown>): void {
1702
- event.preventDefault()
1703
- const target = (event.delegateTarget ?? event.target) as HTMLElement
1704
- const targetKey = target.dataset.coreuiColumn
1705
- const sourceKey = this._dragColumn
1706
- this._endColumnDrag()
1907
+ const { pageIndex, pageSize } = this._table.store.state.pagination
1908
+ return pageIndex * pageSize
1909
+ }
1707
1910
 
1708
- if (!sourceKey || !targetKey || sourceKey === targetKey) {
1911
+ private _initRowDrag(): void {
1912
+ if (!this._config.rowOrder) {
1709
1913
  return
1710
1914
  }
1711
1915
 
1712
- const source = this._table.getColumn(sourceKey)
1713
- const targetColumn = this._table.getColumn(targetKey)
1714
- // Reordering never crosses a pinning boundary — pin membership is state,
1715
- // not position.
1716
- if (!source || !targetColumn || source.getIsPinned() !== targetColumn.getIsPinned()) {
1916
+ this._rowDrag = createRowDragController({
1917
+ root: this._element as HTMLElement,
1918
+ getScrollElement: () => this._viewportElement,
1919
+ onReorder: (sourceIndex, targetIndex, after) => this._moveRowTo(sourceIndex, targetIndex, after)
1920
+ })
1921
+ }
1922
+
1923
+ // The grid never mutates `items` — it hands the reordered array to the app
1924
+ // through rowOrderChange, the same contract inline editing uses.
1925
+ private _moveRowTo(sourceIndex: number, targetIndex: number, after: boolean): void {
1926
+ const offset = this._rowIndexOffset()
1927
+ const items = [...this._config.items]
1928
+ const from = offset + sourceIndex
1929
+ const [item] = items.splice(from, 1)
1930
+ if (item === undefined) {
1717
1931
  return
1718
1932
  }
1719
1933
 
1934
+ // Resolved AFTER the removal, so the index still points at the target
1935
+ // whichever direction the row travelled.
1936
+ const target = offset + targetIndex
1937
+ const to = target > from ? target - 1 : target
1938
+ const newIndex = after ? to + 1 : to
1939
+ items.splice(newIndex, 0, item)
1940
+
1941
+ EventHandler.trigger(this._element, EVENT_ROW_ORDER_CHANGE, {
1942
+ items, item, oldIndex: from, newIndex
1943
+ })
1944
+ }
1945
+
1946
+ private _moveColumnTo(sourceKey: string, targetKey: string, after: boolean): void {
1720
1947
  const ids = this._orderedLeafIds()
1721
1948
  const from = ids.indexOf(sourceKey)
1722
- const to = ids.indexOf(targetKey)
1723
- if (from === -1 || to === -1) {
1949
+ if (from === -1) {
1724
1950
  return
1725
1951
  }
1726
1952
 
1727
- // Removing the source first makes inserting at the target's original index
1728
- // land after it when dragging right and before it when dragging left.
1729
1953
  ids.splice(from, 1)
1730
- ids.splice(to, 0, sourceKey)
1731
- this._table.setColumnOrder(ids)
1732
- }
1733
-
1734
- private _endColumnDrag(): void {
1735
- this._dragColumn = null
1736
- for (const cell of this._element.querySelectorAll(`.${CLASS_NAME_DRAGGING}, .${CLASS_NAME_DROP_TARGET}`)) {
1737
- cell.classList.remove(CLASS_NAME_DRAGGING, CLASS_NAME_DROP_TARGET)
1954
+ // Resolved AFTER the removal, so the index still points at the target
1955
+ // whichever direction the column travelled.
1956
+ const to = ids.indexOf(targetKey)
1957
+ if (to === -1) {
1958
+ return
1738
1959
  }
1960
+
1961
+ ids.splice(after ? to + 1 : to, 0, sourceKey)
1962
+ this._table.setColumnOrder(ids)
1739
1963
  }
1740
1964
 
1741
1965
  private _startColumnResize(event: Event & Record<string, unknown>): void {
@@ -1797,7 +2021,7 @@ private _undoStack: DataGridEditCommitEntry[] = []
1797
2021
  this._dataSource = createDataSource({
1798
2022
  provider: request => dataProvider(request),
1799
2023
  getRequest: () => {
1800
- const state = this._table.getState()
2024
+ const { state } = this._table.store
1801
2025
  return {
1802
2026
  columnFilters: state.columnFilters,
1803
2027
  globalFilter: (state.globalFilter as string | undefined) ?? '',
@@ -1805,13 +2029,29 @@ private _undoStack: DataGridEditCommitEntry[] = []
1805
2029
  sorting: state.sorting
1806
2030
  }
1807
2031
  },
1808
- onLoad: response => {
2032
+ onLoad: (response, request) => {
1809
2033
  this._stopEditing({ commit: false })
1810
2034
  this._loadFailed = false
2035
+ this._loadMorePending = false
1811
2036
  this._dataVersion++
2037
+
2038
+ let { items } = response
2039
+ if (this._config.infiniteScroll) {
2040
+ const firstPage = request.pagination.pageIndex === 0
2041
+ items = firstPage ? response.items : [...this._loadedItems, ...response.items]
2042
+ this._loadedItems = items
2043
+ // Appended rows land at fresh indices; a first page puts different
2044
+ // data at indices the virtualizer has already measured — and shrinks
2045
+ // the buffer back under a viewport that may be scrolled far past it.
2046
+ if (firstPage) {
2047
+ this._viewportElement.scrollTop = 0
2048
+ this._virtualizer?.remeasure()
2049
+ }
2050
+ }
2051
+
1812
2052
  this._table.setOptions(previous => ({
1813
2053
  ...previous,
1814
- data: response.items,
2054
+ data: items,
1815
2055
  rowCount: response.totalRows
1816
2056
  }))
1817
2057
  EventHandler.trigger(this._element, EVENT_DATA_LOAD, {
@@ -1824,16 +2064,17 @@ private _undoStack: DataGridEditCommitEntry[] = []
1824
2064
  onError: error => {
1825
2065
  this._stopEditing({ commit: false })
1826
2066
  this._loadFailed = true
2067
+ this._loadMorePending = false
2068
+ this._loadedItems = []
1827
2069
  this._dataVersion++
1828
2070
  this._table.setOptions(previous => ({ ...previous, data: [], rowCount: 0 }))
1829
2071
  EventHandler.trigger(this._element, EVENT_DATA_ERROR, { error })
1830
2072
  this._scheduler.schedule()
1831
2073
  },
1832
2074
  onLoadingChange: loading => {
1833
- if (this._loading) {
1834
- this._loading.setVisible(loading)
1835
- }
1836
-
2075
+ const appending = Boolean(this._config.infiniteScroll) && this._loadedItems.length > 0
2076
+ this._loading?.setVisible(loading && !appending)
2077
+ this._loadingMore?.setVisible(loading && appending)
1837
2078
  this._viewportElement.setAttribute('aria-busy', String(loading))
1838
2079
  }
1839
2080
  })
@@ -1841,14 +2082,55 @@ private _undoStack: DataGridEditCommitEntry[] = []
1841
2082
  this._dataSource.load()
1842
2083
  }
1843
2084
 
2085
+ // The trigger is the last RENDERED row index, not a scroll ratio: measured
2086
+ // row heights make the ratio meaningless (the total size keeps moving as
2087
+ // rows are measured, so a ratio either fires early or never).
2088
+ private _maybeLoadMore(): void {
2089
+ if (!this._config.infiniteScroll || !this._dataSource || !this._virtualizer || this._loadMorePending) {
2090
+ return
2091
+ }
2092
+
2093
+ const loaded = this._table.getRowModel().rows.length
2094
+ if (loaded === 0 || loaded >= this._getTotalRows()) {
2095
+ return
2096
+ }
2097
+
2098
+ const options = typeof this._config.infiniteScroll === 'object' ? this._config.infiniteScroll : {}
2099
+ const threshold = options.threshold ?? this._config.overscan
2100
+ const rendered = this._virtualizer.instance.getVirtualItems()
2101
+ const last = rendered[rendered.length - 1]
2102
+ if (!last || last.index < loaded - 1 - threshold) {
2103
+ return
2104
+ }
2105
+
2106
+ this._loadMorePending = true
2107
+ this._table.setPageIndex(this._table.store.state.pagination.pageIndex + 1)
2108
+ }
2109
+
1844
2110
  // Visible leaf columns in VISUAL order: left-pinned, center (columnOrder),
1845
2111
  // right-pinned — getVisibleLeafColumns() alone does not regroup pinning.
2112
+ // Without the pinning feature there are no regions to regroup, and without
2113
+ // visibility every leaf column is visible.
1846
2114
  private _visibleLeafColumns() {
1847
- return [
1848
- ...this._table.getLeftVisibleLeafColumns(),
1849
- ...this._table.getCenterVisibleLeafColumns(),
1850
- ...this._table.getRightVisibleLeafColumns()
1851
- ]
2115
+ if (typeof this._table.getCenterVisibleLeafColumns === 'function') {
2116
+ return [
2117
+ ...this._table.getStartVisibleLeafColumns(),
2118
+ ...this._table.getCenterVisibleLeafColumns(),
2119
+ ...this._table.getEndVisibleLeafColumns()
2120
+ ]
2121
+ }
2122
+
2123
+ if (typeof this._table.getVisibleLeafColumns === 'function') {
2124
+ return this._table.getVisibleLeafColumns()
2125
+ }
2126
+
2127
+ return this._table.getAllLeafColumns()
2128
+ }
2129
+
2130
+ // Ordering paths compare pinned regions even on grids that never enabled
2131
+ // pinning - without the feature every column sits in the unpinned region.
2132
+ private _pinnedRegion(column: { getIsPinned?: () => 'start' | 'end' | false }): 'start' | 'end' | false {
2133
+ return typeof column.getIsPinned === 'function' ? column.getIsPinned() : false
1852
2134
  }
1853
2135
 
1854
2136
  private _chooserColumns(): ColumnChooserColumn[] {
@@ -1893,14 +2175,14 @@ private _undoStack: DataGridEditCommitEntry[] = []
1893
2175
  }
1894
2176
 
1895
2177
  private _getFilteredColumns(): string[] {
1896
- return this._table.getState().columnFilters.map(filter => filter.id)
2178
+ return this._table.store.state.columnFilters.map(filter => filter.id)
1897
2179
  }
1898
2180
 
1899
2181
  private _getPinning(): GridPinning {
1900
- // Visible columns only - getLeftLeafColumns/getPinnedIndex include hidden
2182
+ // Visible columns only - getStartLeafColumns/getPinnedIndex include hidden
1901
2183
  // columns, which would leave the edge class on a column nobody sees.
1902
- const leftColumns = this._table.getLeftLeafColumns().filter(column => column.getIsVisible())
1903
- const rightColumns = this._table.getRightLeafColumns().filter(column => column.getIsVisible())
2184
+ const leftColumns = this._table.getStartLeafColumns().filter(column => column.getIsVisible())
2185
+ const rightColumns = this._table.getEndLeafColumns().filter(column => column.getIsVisible())
1904
2186
  // The selection cell is not a TanStack column; anchor it to the left as
1905
2187
  // soon as any data column is pinned there so the checkbox travels with them.
1906
2188
  const selectPinned = Boolean(this._config.rowSelection) && leftColumns.length > 0
@@ -1908,8 +2190,8 @@ private _undoStack: DataGridEditCommitEntry[] = []
1908
2190
 
1909
2191
  for (const [index, column] of leftColumns.entries()) {
1910
2192
  columns[column.id] = {
1911
- side: 'left',
1912
- offset: column.getStart('left'),
2193
+ side: 'start',
2194
+ offset: column.getStart('start'),
1913
2195
  edge: index === leftColumns.length - 1,
1914
2196
  afterSelect: selectPinned
1915
2197
  }
@@ -1917,8 +2199,8 @@ private _undoStack: DataGridEditCommitEntry[] = []
1917
2199
 
1918
2200
  for (const [index, column] of rightColumns.entries()) {
1919
2201
  columns[column.id] = {
1920
- side: 'right',
1921
- offset: column.getAfter('right'),
2202
+ side: 'end',
2203
+ offset: column.getAfter('end'),
1922
2204
  edge: index === 0,
1923
2205
  afterSelect: false
1924
2206
  }
@@ -1928,7 +2210,7 @@ private _undoStack: DataGridEditCommitEntry[] = []
1928
2210
  columns,
1929
2211
  select: selectPinned ?
1930
2212
  {
1931
- side: 'left', offset: 0, edge: false, afterSelect: false
2213
+ side: 'start', offset: 0, edge: false, afterSelect: false
1932
2214
  } :
1933
2215
  null
1934
2216
  }
@@ -1986,10 +2268,14 @@ null
1986
2268
  return this._table.options.rowCount ?? 0
1987
2269
  }
1988
2270
 
2271
+ if (typeof this._table.getFilteredRowModel !== 'function') {
2272
+ return this._table.getCoreRowModel().rows.length
2273
+ }
2274
+
1989
2275
  return this._table.getFilteredRowModel().rows.length
1990
2276
  }
1991
2277
 
1992
- private _notifyStateChange(previous: TableState, next: TableState): void {
2278
+ private _notifyStateChange(previous: DataGridTableState, next: DataGridTableState): void {
1993
2279
  // TanStack's resize handler keeps document-level listeners until mouseup;
1994
2280
  // a dispose mid-drag would re-enter here against a torn-down instance.
1995
2281
  if (!this._element) {
@@ -2025,16 +2311,22 @@ null
2025
2311
  // auto-reset the page index, which replaces the state object without
2026
2312
  // changing it - identity alone would kill an edit right after its
2027
2313
  // editCommit handler applied the change.
2314
+ // Infinite scroll is the exception: its page bumps only append, so every
2315
+ // row already on screen keeps its index, its measurement and its focus.
2028
2316
  if (
2029
2317
  previous.sorting !== next.sorting ||
2030
2318
  previous.columnFilters !== next.columnFilters ||
2031
2319
  previous.globalFilter !== next.globalFilter ||
2032
- previous.pagination.pageIndex !== next.pagination.pageIndex ||
2033
- previous.pagination.pageSize !== next.pagination.pageSize
2320
+ (!this._config.infiniteScroll &&
2321
+ (previous.pagination?.pageIndex !== next.pagination?.pageIndex ||
2322
+ previous.pagination?.pageSize !== next.pagination?.pageSize))
2034
2323
  ) {
2035
2324
  this._stopEditing({ commit: true, force: true })
2036
2325
  this._selectionAnchorIndex = null
2037
2326
  this._activeCell?.reset()
2327
+ // Row measurements are cached by index, so the same index now holding a
2328
+ // different row makes them stale.
2329
+ this._virtualizer?.remeasure()
2038
2330
  }
2039
2331
 
2040
2332
  if (previous.sorting !== next.sorting) {
@@ -2064,7 +2356,9 @@ null
2064
2356
  })
2065
2357
  }
2066
2358
 
2067
- if (previous.pagination !== next.pagination) {
2359
+ // No paginationChange under infinite scroll — pagination is internal
2360
+ // there (no widget, not user-adjustable); dataLoad is the page signal.
2361
+ if (previous.pagination !== next.pagination && !this._config.infiniteScroll) {
2068
2362
  EventHandler.trigger(this._element, EVENT_PAGINATION_CHANGE, {
2069
2363
  pagination: next.pagination
2070
2364
  })
@@ -2097,15 +2391,26 @@ null
2097
2391
  if (this._dataSource) {
2098
2392
  const refetchNeeded = filtersChanged || previous.sorting !== next.sorting
2099
2393
 
2100
- if (refetchNeeded && next.pagination.pageIndex !== 0) {
2101
- // Back to page one first; the resulting pagination change re-enters
2102
- // this handler and triggers the (debounced) fetch exactly once.
2103
- this._table.setPageIndex(0)
2394
+ if (refetchNeeded) {
2395
+ if (next.pagination.pageIndex !== 0) {
2396
+ // Back to page one. The write lands synchronously, so the request the
2397
+ // debounced fetch reads already carries index 0 - but it also echoes
2398
+ // back here as a pagination change, which must not fetch again.
2399
+ this._pageResetPending = true
2400
+ this._table.setPageIndex(0)
2401
+ }
2402
+
2403
+ this._dataSource.load()
2104
2404
  return
2105
2405
  }
2106
2406
 
2107
- if (refetchNeeded || previous.pagination !== next.pagination) {
2108
- this._dataSource.load()
2407
+ if (previous.pagination !== next.pagination) {
2408
+ const echoedPageReset = this._pageResetPending && next.pagination.pageIndex === 0
2409
+ this._pageResetPending = false
2410
+
2411
+ if (!echoedPageReset) {
2412
+ this._dataSource.load()
2413
+ }
2109
2414
  }
2110
2415
  }
2111
2416
  }
@@ -2136,14 +2441,16 @@ null
2136
2441
  order: this._visibleLeafColumns().map(column => column.id),
2137
2442
  pinning: this._config.columnPinning ? this._getPinning() : null,
2138
2443
  resizingColumn: this._config.columnSizing ?
2139
- this._table.getState().columnSizingInfo.isResizingColumn :
2444
+ this._table.store.state.columnResizing.isResizingColumn :
2140
2445
  false,
2141
2446
  sizes: (this._config.columnSizing || this._config.columnPinning) ? this._getColumnSizes() : null,
2142
- sorting: this._table.getState().sorting,
2447
+ sorting: this._table.store.state.sorting ?? [],
2143
2448
  selectAll: this._config.rowSelection ?
2144
2449
  {
2145
2450
  checked: this._table.getIsAllRowsSelected(),
2146
- indeterminate: this._table.getIsSomeRowsSelected()
2451
+ // getIsSomeRowsSelected() means "at least one" - the all-selected
2452
+ // case has to be excluded for the tri-state checkbox.
2453
+ indeterminate: this._table.getIsSomeRowsSelected() && !this._table.getIsAllRowsSelected()
2147
2454
  } :
2148
2455
  null
2149
2456
  })
@@ -2169,10 +2476,12 @@ null
2169
2476
  for (const instance of this._paginations) {
2170
2477
  instance.refresh()
2171
2478
  }
2479
+
2480
+ this._maybeLoadMore()
2172
2481
  }
2173
2482
 
2174
2483
  private _paginationState() {
2175
- const { pagination } = this._table.getState()
2484
+ const { pagination } = this._table.store.state
2176
2485
  return {
2177
2486
  pageCount: this._table.getPageCount(),
2178
2487
  pageIndex: pagination.pageIndex,
@@ -2203,6 +2512,4 @@ null
2203
2512
  }
2204
2513
  }
2205
2514
 
2206
- defineJQueryPlugin(DataGrid)
2207
-
2208
2515
  export default DataGrid