@1771technologies/lytenyte-pro 1.0.0-beta.9 → 1.0.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 (102) hide show
  1. package/dist/+types.d.ts +577 -61
  2. package/dist/cell-selection/update-additive-cell-selection.js +0 -2
  3. package/dist/cells/cell-editor.js +11 -4
  4. package/dist/cells/cell.js +1 -1
  5. package/dist/column-manager/branch.d.ts +9 -3
  6. package/dist/column-manager/branch.js +20 -4
  7. package/dist/column-manager/column-manager.d.ts +3 -5
  8. package/dist/column-manager/column-manager.js +6 -8
  9. package/dist/column-manager/context.d.ts +2 -2
  10. package/dist/column-manager/label.d.ts +1 -1
  11. package/dist/column-manager/label.js +5 -5
  12. package/dist/column-manager/leaf.d.ts +2 -2
  13. package/dist/column-manager/leaf.js +22 -4
  14. package/dist/column-manager/move-handle.d.ts +3 -3
  15. package/dist/column-manager/move-handle.js +3 -5
  16. package/dist/column-manager/panel.d.ts +1 -0
  17. package/dist/column-manager/panel.js +2 -0
  18. package/dist/column-manager/root.d.ts +6 -7
  19. package/dist/column-manager/root.js +2 -15
  20. package/dist/column-manager/use-column-manager.d.ts +9 -18
  21. package/dist/column-manager/use-column-manager.js +22 -22
  22. package/dist/column-manager/use-columns-from-context.d.ts +2 -2
  23. package/dist/column-manager/use-columns-from-context.js +2 -2
  24. package/dist/column-manager/visibility-checkbox.d.ts +1 -1
  25. package/dist/column-manager/visibility-checkbox.js +2 -2
  26. package/dist/filter-tree/branch.d.ts +4 -1
  27. package/dist/filter-tree/branch.js +1 -1
  28. package/dist/filter-tree/inclusion-checkbox.d.ts +1 -1
  29. package/dist/filter-tree/inclusion-checkbox.js +2 -2
  30. package/dist/filter-tree/label.d.ts +1 -1
  31. package/dist/filter-tree/label.js +2 -2
  32. package/dist/filter-tree/root.d.ts +3 -3
  33. package/dist/filter-tree/root.js +4 -4
  34. package/dist/grid-box/+types.d.ts +4 -2
  35. package/dist/grid-box/item.d.ts +4 -1
  36. package/dist/grid-box/item.js +39 -9
  37. package/dist/grid-box/use-aggregation-box-items.js +3 -1
  38. package/dist/grid-box/use-column-box-items.d.ts +6 -2
  39. package/dist/grid-box/use-column-box-items.js +11 -14
  40. package/dist/grid-box/use-row-group-box-items.d.ts +2 -2
  41. package/dist/grid-box/use-row-group-box-items.js +14 -15
  42. package/dist/grid.d.ts +0 -12
  43. package/dist/grid.js +0 -12
  44. package/dist/header/header-cell.d.ts +1 -1
  45. package/dist/header/header-cell.js +2 -2
  46. package/dist/header/header-group-cell.js +3 -1
  47. package/dist/header/resize-handler.d.ts +2 -2
  48. package/dist/header/resize-handler.js +7 -3
  49. package/dist/header/use-drag-move.js +9 -2
  50. package/dist/header/use-header-cell-renderer.js +4 -4
  51. package/dist/index.d.ts +6 -0
  52. package/dist/index.js +6 -0
  53. package/dist/license.js +1 -1
  54. package/dist/listbox/item.js +1 -1
  55. package/dist/row-data-source-client/filter/compute-filtered-rows.js +1 -1
  56. package/dist/row-data-source-client/use-client-data-source-paginated.d.ts +3 -3
  57. package/dist/row-data-source-client/use-client-data-source-paginated.js +62 -19
  58. package/dist/row-data-source-client/use-client-data-source.js +46 -15
  59. package/dist/row-data-source-client/use-client-tree-data-source.js +45 -15
  60. package/dist/row-data-source-server/use-server-data-source.js +26 -0
  61. package/dist/sort-manager/sort-add.d.ts +1 -1
  62. package/dist/sort-manager/sort-add.js +3 -3
  63. package/dist/sort-manager/sort-apply.d.ts +1 -1
  64. package/dist/sort-manager/sort-apply.js +3 -3
  65. package/dist/sort-manager/sort-cancel.d.ts +1 -1
  66. package/dist/sort-manager/sort-cancel.js +3 -3
  67. package/dist/sort-manager/sort-clear.d.ts +1 -1
  68. package/dist/sort-manager/sort-clear.js +3 -3
  69. package/dist/sort-manager/sort-column-select.d.ts +1 -1
  70. package/dist/sort-manager/sort-column-select.js +2 -2
  71. package/dist/sort-manager/sort-direction-select.d.ts +1 -1
  72. package/dist/sort-manager/sort-direction-select.js +2 -2
  73. package/dist/sort-manager/sort-remove.d.ts +1 -1
  74. package/dist/sort-manager/sort-remove.js +3 -3
  75. package/dist/sort-manager/sort-value-select.d.ts +1 -1
  76. package/dist/sort-manager/sort-value-select.js +2 -2
  77. package/dist/state/+types.d.ts +2 -1
  78. package/dist/state/api/column-autosize.js +1 -1
  79. package/dist/state/api/column-from-index.d.ts +1 -1
  80. package/dist/state/api/column-from-index.js +1 -1
  81. package/dist/state/api/column-update.d.ts +4 -1
  82. package/dist/state/api/column-update.js +13 -0
  83. package/dist/state/api/edit-end.js +1 -1
  84. package/dist/state/api/export-data-rect.js +1 -1
  85. package/dist/state/helpers/column-add-row-group.d.ts +2 -1
  86. package/dist/state/helpers/column-add-row-group.js +9 -1
  87. package/dist/state/helpers/column-marker.js +1 -1
  88. package/dist/state/helpers/edit-on-change.js +1 -0
  89. package/dist/state/helpers/empty-row-data-source.js +1 -0
  90. package/dist/state/helpers/resolve-column.d.ts +1 -1
  91. package/dist/state/helpers/resolve-column.js +7 -0
  92. package/dist/state/use-lytenyte.js +16 -4
  93. package/dist/tree-view/branch/branch.d.ts +4 -1
  94. package/dist/tree-view/branch/branch.js +4 -2
  95. package/dist/tree-view/hooks/use-tree-view-paths.d.ts +1 -1
  96. package/dist/tree-view/hooks/use-tree-view-paths.js +3 -3
  97. package/dist/tree-view/leaf.js +1 -0
  98. package/dist/viewport/begin-editing.js +1 -1
  99. package/main.css +8 -4
  100. package/package.json +7 -7
  101. package/dist/column-manager/passive-scroll.d.ts +0 -2
  102. package/dist/column-manager/passive-scroll.js +0 -2
@@ -10,7 +10,7 @@ import { builtIns } from "./built-ins/built-ins.js";
10
10
  export function makeClientDataSourcePaginated(p) {
11
11
  const rdsStore = createStore();
12
12
  const pageInternal = atom(0);
13
- const rowsPerPage = atom(50);
13
+ const rowsPerPage = atom(p.rowsPerPage ?? 50);
14
14
  const pageCount = atom((g) => Math.max(Math.ceil(g(flatLength) / g(rowsPerPage)), 1));
15
15
  const page = atom((g) => clamp(0, g(pageInternal), g(pageCount) - 1), (g, s, n) => {
16
16
  const res = typeof n === "function" ? n(g(pageInternal)) : n;
@@ -19,6 +19,9 @@ export function makeClientDataSourcePaginated(p) {
19
19
  const data = atom(p.data);
20
20
  const topData = atom(p.topData ?? []);
21
21
  const bottomData = atom(p.bottomData ?? []);
22
+ const dataToSrc$ = atom((g) => {
23
+ return new Map(g(data).map((c, i) => [c, i]));
24
+ });
22
25
  const cache = new Map();
23
26
  const centerNodes = atom((g) => {
24
27
  const nodes = [];
@@ -149,6 +152,13 @@ export function makeClientDataSourcePaginated(p) {
149
152
  };
150
153
  return comparator;
151
154
  });
155
+ const idToNode = atom((g) => {
156
+ const map = new Map();
157
+ traverse(g(tree).root, (node) => {
158
+ map.set(node.id, node);
159
+ });
160
+ return map;
161
+ });
152
162
  const initialized = atom(false);
153
163
  const flat = atom((g) => {
154
164
  if (!g(initialized))
@@ -200,14 +210,27 @@ export function makeClientDataSourcePaginated(p) {
200
210
  const currentPage = rdsStore.get(pageInternal);
201
211
  const center = clamp(0, rowCount - currentPage * perPage, perPage);
202
212
  store.rowCenterCount.set(center);
203
- cleanup.push(rdsStore.sub(flatLength, () => {
204
- grid.state.rowDataStore.rowClearCache();
213
+ const updateCounts = () => {
205
214
  const rowCount = rdsStore.get(flatLength);
206
215
  const perPage = rdsStore.get(rowsPerPage);
207
216
  const currentPage = rdsStore.get(pageInternal);
208
217
  const center = clamp(0, rowCount - currentPage * perPage, perPage);
218
+ // Move to the last page if we are past the boundary
219
+ if (center === 0 && currentPage !== 0) {
220
+ const currentPage = rdsStore.get(pageCount) - 1;
221
+ rdsStore.set(page, currentPage);
222
+ rdsStore.set(snapshot, (prev) => prev + 1);
223
+ const center = clamp(0, rowCount - currentPage * perPage, perPage);
224
+ store.rowCenterCount.set(center);
225
+ grid.state.rowDataStore.rowClearCache();
226
+ return;
227
+ }
209
228
  store.rowCenterCount.set(center);
210
- }));
229
+ grid.state.rowDataStore.rowClearCache();
230
+ };
231
+ cleanup.push(rdsStore.sub(flatLength, updateCounts));
232
+ cleanup.push(rdsStore.sub(page, updateCounts));
233
+ cleanup.push(rdsStore.sub(rowsPerPage, updateCounts));
211
234
  cleanup.push(rdsStore.sub(pageInternal, () => {
212
235
  grid.state.rowDataStore.rowClearCache();
213
236
  }));
@@ -299,30 +322,32 @@ export function makeClientDataSourcePaginated(p) {
299
322
  };
300
323
  const rowUpdate = (updates) => {
301
324
  const grid = rdsStore.get(grid$);
302
- const t = rdsStore.get(tree);
303
325
  const d = rdsStore.get(data);
304
- for (const [key, data] of updates.entries()) {
305
- const rowIndex = typeof key === "number" ? key : rowToIndex(key);
306
- const row = rowByIndex(rowIndex);
307
- if (!row || !grid) {
308
- console.error(`Failed to find the row at index ${rowIndex} which is being updated.`);
326
+ const idMap = rdsStore.get(idToNode);
327
+ const dataToSrc = rdsStore.get(dataToSrc$);
328
+ for (const [key, next] of updates.entries()) {
329
+ const row = typeof key === "string" ? rowById(key) : rowByIndex(key);
330
+ const treeNode = typeof key === "string" ? idMap.get(key) : null;
331
+ if ((!row && !treeNode) || !grid) {
332
+ console.error(`Failed to find the row with identifier ${key} which is being updated.`);
309
333
  continue;
310
334
  }
311
- if (row.kind === "branch") {
312
- row.data = data;
335
+ if (row?.kind === "branch") {
336
+ row.data = next;
313
337
  }
314
338
  else {
315
- const source = t.idToSourceIndex.get(row.id);
339
+ const data = row?.kind === "leaf" ? row.data : treeNode?.data.data;
340
+ const source = dataToSrc.get(data);
316
341
  if (source == null) {
317
- console.error(`Failed to find the row at index ${rowIndex} which is being updated.`);
342
+ console.error(`Failed to find the row with identifier ${key} which is being updated.`);
318
343
  continue;
319
344
  }
320
- d[source] = data;
345
+ d[source] = next;
321
346
  }
322
- grid.state.rowDataStore.rowInvalidateIndex(rowIndex);
323
347
  }
324
348
  rdsStore.set(data, [...d]);
325
349
  rdsStore.set(snapshot, (prev) => prev + 1);
350
+ grid.state.rowDataStore.rowClearCache();
326
351
  };
327
352
  const rowToIndex = (rowId) => {
328
353
  const f = rdsStore.get(flat);
@@ -435,11 +460,29 @@ export function makeClientDataSourcePaginated(p) {
435
460
  const grid = rdsStore.get(grid$);
436
461
  grid?.state.rowDataStore.rowClearCache();
437
462
  },
463
+ rowSetCenterData: (d) => {
464
+ rdsStore.set(data, d);
465
+ const grid = rdsStore.get(grid$);
466
+ grid?.state.rowDataStore.rowClearCache();
467
+ },
438
468
  rowSetTopData: (data) => {
439
469
  rdsStore.set(topData, data);
440
470
  const grid = rdsStore.get(grid$);
441
471
  grid?.state.rowDataStore.rowClearCache();
442
472
  },
473
+ rowData: (section) => {
474
+ const d = [];
475
+ if (section === "top" || section === "flat") {
476
+ d.push(...rdsStore.get(topData));
477
+ }
478
+ if (section === "center" || section === "flat") {
479
+ d.push(...rdsStore.get(data));
480
+ }
481
+ if (section === "bottom" || section === "flat") {
482
+ d.push(...rdsStore.get(bottomData));
483
+ }
484
+ return d;
485
+ },
443
486
  rowExpand: (expansions) => {
444
487
  const grid = rdsStore.get(grid$);
445
488
  if (!grid)
@@ -526,12 +569,12 @@ export function useClientRowDataSourcePaginated(p) {
526
569
  if (p.reflectData) {
527
570
  // Need to queue the microtask since it we cannot update state during render.
528
571
  if (p.data !== da.center.get())
529
- queueMicrotask(() => da.center.set(p.data));
572
+ queueMicrotask(() => ds.current.rowSetCenterData(p.data));
530
573
  if (!equal(p.topData ?? [], da.top.get())) {
531
- queueMicrotask(() => da.top.set(p.topData ?? []));
574
+ queueMicrotask(() => ds.current.rowSetTopData(p.topData ?? []));
532
575
  }
533
576
  if (!equal(p.bottomData ?? [], da.bottom.get()))
534
- queueMicrotask(() => da.bottom.set(p.bottomData ?? []));
577
+ queueMicrotask(() => ds.current.rowSetBotData(p.bottomData ?? []));
535
578
  }
536
579
  return ds.current;
537
580
  }
@@ -14,6 +14,9 @@ export function makeClientDataSource(p) {
14
14
  const data = atom(p.data);
15
15
  const topData = atom(p.topData ?? []);
16
16
  const bottomData = atom(p.bottomData ?? []);
17
+ const dataToSrc$ = atom((g) => {
18
+ return new Map(g(data).map((c, i) => [c, i]));
19
+ });
17
20
  const cache = new Map();
18
21
  const centerNodes = atom((g) => {
19
22
  const nodes = [];
@@ -199,6 +202,13 @@ export function makeClientDataSource(p) {
199
202
  };
200
203
  return comparator;
201
204
  });
205
+ const idToNode = atom((g) => {
206
+ const map = new Map();
207
+ traverse(g(tree).root, (node) => {
208
+ map.set(node.id, node);
209
+ });
210
+ return map;
211
+ });
202
212
  const tree = atom((g) => (g(columnPivotMode) ? g(pivotTree) : g(normalTree)));
203
213
  const initialized = atom(false);
204
214
  const flatPivot = atom((g) => {
@@ -318,6 +328,7 @@ export function makeClientDataSource(p) {
318
328
  let prevPivotColumnValues = pivotModel.values;
319
329
  const updatePivotColumns = (model, ignoreEqualCheck = false) => {
320
330
  if (!ignoreEqualCheck &&
331
+ rdsStore.get(initialized) &&
321
332
  equal(prevPivotColumnModel, model.columns) &&
322
333
  equal(prevPivotColumnValues, model.values))
323
334
  return;
@@ -429,30 +440,32 @@ export function makeClientDataSource(p) {
429
440
  };
430
441
  const rowUpdate = (updates) => {
431
442
  const grid = rdsStore.get(grid$);
432
- const t = rdsStore.get(normalTree);
433
443
  const d = rdsStore.get(data);
434
- for (const [key, data] of updates.entries()) {
435
- const rowIndex = typeof key === "number" ? key : rowToIndex(key);
436
- const row = rowByIndex(rowIndex);
437
- if (!row || !grid) {
438
- console.error(`Failed to find the row at index ${rowIndex} which is being updated.`);
444
+ const idMap = rdsStore.get(idToNode);
445
+ const dataToSrc = rdsStore.get(dataToSrc$);
446
+ for (const [key, next] of updates.entries()) {
447
+ const row = typeof key === "string" ? rowById(key) : rowByIndex(key);
448
+ const treeNode = typeof key === "string" ? idMap.get(key) : null;
449
+ if ((!row && !treeNode) || !grid) {
450
+ console.error(`Failed to find the row with identifier ${key} which is being updated.`);
439
451
  continue;
440
452
  }
441
- if (row.kind === "branch") {
442
- row.data = data;
453
+ if (row?.kind === "branch") {
454
+ row.data = next;
443
455
  }
444
456
  else {
445
- const source = t.idToSourceIndex.get(row.id);
457
+ const data = row?.kind === "leaf" ? row.data : treeNode?.data.data;
458
+ const source = dataToSrc.get(data);
446
459
  if (source == null) {
447
- console.error(`Failed to find the row at index ${rowIndex} which is being updated.`);
460
+ console.error(`Failed to find the row with identifier ${key} which is being updated.`);
448
461
  continue;
449
462
  }
450
- d[source] = data;
463
+ d[source] = next;
451
464
  }
452
- grid.state.rowDataStore.rowInvalidateIndex(rowIndex);
453
465
  }
454
466
  rdsStore.set(data, [...d]);
455
467
  rdsStore.set(snapshot, (prev) => prev + 1);
468
+ grid.state.rowDataStore.rowClearCache();
456
469
  };
457
470
  const rowToIndex = (rowId) => {
458
471
  const f = rdsStore.get(flat);
@@ -545,11 +558,29 @@ export function makeClientDataSource(p) {
545
558
  const grid = rdsStore.get(grid$);
546
559
  grid?.state.rowDataStore.rowClearCache();
547
560
  },
561
+ rowSetCenterData: (d) => {
562
+ rdsStore.set(data, d);
563
+ const grid = rdsStore.get(grid$);
564
+ grid?.state.rowDataStore.rowClearCache();
565
+ },
548
566
  rowSetTopData: (data) => {
549
567
  rdsStore.set(topData, data);
550
568
  const grid = rdsStore.get(grid$);
551
569
  grid?.state.rowDataStore.rowClearCache();
552
570
  },
571
+ rowData: (section) => {
572
+ const d = [];
573
+ if (section === "top" || section === "flat") {
574
+ d.push(...rdsStore.get(topData));
575
+ }
576
+ if (section === "center" || section === "flat") {
577
+ d.push(...rdsStore.get(data));
578
+ }
579
+ if (section === "bottom" || section === "flat") {
580
+ d.push(...rdsStore.get(bottomData));
581
+ }
582
+ return d;
583
+ },
553
584
  rowExpand: (expansions) => {
554
585
  const grid = rdsStore.get(grid$);
555
586
  if (!grid)
@@ -655,12 +686,12 @@ export function useClientRowDataSource(p) {
655
686
  if (p.reflectData) {
656
687
  // Need to queue the microtask since it we cannot update state during render.
657
688
  if (p.data !== da.center.get())
658
- queueMicrotask(() => da.center.set(p.data));
689
+ queueMicrotask(() => ds.current.rowSetCenterData(p.data));
659
690
  if (!equal(p.topData ?? [], da.top.get())) {
660
- queueMicrotask(() => da.top.set(p.topData ?? []));
691
+ queueMicrotask(() => ds.current.rowSetTopData(p.topData ?? []));
661
692
  }
662
693
  if (!equal(p.bottomData ?? [], da.bottom.get()))
663
- queueMicrotask(() => da.bottom.set(p.bottomData ?? []));
694
+ queueMicrotask(() => ds.current.rowSetBotData(p.bottomData ?? []));
664
695
  }
665
696
  return ds.current;
666
697
  }
@@ -12,6 +12,9 @@ export function makeClientTreeDataSource(p) {
12
12
  const data = atom(p.data);
13
13
  const topData = atom(p.topData ?? []);
14
14
  const bottomData = atom(p.bottomData ?? []);
15
+ const dataToSrc$ = atom((g) => {
16
+ return new Map(g(data).map((c, i) => [c, i]));
17
+ });
15
18
  const cache = new Map();
16
19
  const centerNodes = atom((g) => {
17
20
  const nodes = [];
@@ -130,6 +133,13 @@ export function makeClientTreeDataSource(p) {
130
133
  };
131
134
  return comparator;
132
135
  });
136
+ const idToNode = atom((g) => {
137
+ const map = new Map();
138
+ traverse(g(tree).root, (node) => {
139
+ map.set(node.id, node);
140
+ });
141
+ return map;
142
+ });
133
143
  const initialized = atom(false);
134
144
  const flat = atom((g) => {
135
145
  if (!g(initialized))
@@ -275,30 +285,32 @@ export function makeClientTreeDataSource(p) {
275
285
  };
276
286
  const rowUpdate = (updates) => {
277
287
  const grid = rdsStore.get(grid$);
278
- const t = rdsStore.get(tree);
279
288
  const d = rdsStore.get(data);
280
- for (const [key, data] of updates.entries()) {
281
- const rowIndex = typeof key === "number" ? key : rowToIndex(key);
282
- const row = rowByIndex(rowIndex);
283
- if (!row || !grid) {
284
- console.error(`Failed to find the row at index ${rowIndex} which is being updated.`);
289
+ const idMap = rdsStore.get(idToNode);
290
+ const dataToSrc = rdsStore.get(dataToSrc$);
291
+ for (const [key, next] of updates.entries()) {
292
+ const row = typeof key === "string" ? rowById(key) : rowByIndex(key);
293
+ const treeNode = typeof key === "string" ? idMap.get(key) : null;
294
+ if ((!row && !treeNode) || !grid) {
295
+ console.error(`Failed to find the row with identifier ${key} which is being updated.`);
285
296
  continue;
286
297
  }
287
- if (row.kind === "branch") {
288
- row.data = data;
298
+ if (row?.kind === "branch") {
299
+ row.data = next;
289
300
  }
290
301
  else {
291
- const source = t.idToSourceIndex.get(row.id);
302
+ const data = row?.kind === "leaf" ? row.data : treeNode?.data.data;
303
+ const source = dataToSrc.get(data);
292
304
  if (source == null) {
293
- console.error(`Failed to find the row at index ${rowIndex} which is being updated.`);
305
+ console.error(`Failed to find the row with identifier ${key} which is being updated.`);
294
306
  continue;
295
307
  }
296
- d[source] = data;
308
+ d[source] = next;
297
309
  }
298
- grid.state.rowDataStore.rowInvalidateIndex(rowIndex);
299
310
  }
300
311
  rdsStore.set(data, [...d]);
301
312
  rdsStore.set(snapshot, (prev) => prev + 1);
313
+ grid.state.rowDataStore.rowClearCache();
302
314
  };
303
315
  const rowToIndex = (rowId) => {
304
316
  const f = rdsStore.get(flat);
@@ -391,6 +403,11 @@ export function makeClientTreeDataSource(p) {
391
403
  const grid = rdsStore.get(grid$);
392
404
  grid?.state.rowDataStore.rowClearCache();
393
405
  },
406
+ rowSetCenterData: (d) => {
407
+ rdsStore.set(data, d);
408
+ const grid = rdsStore.get(grid$);
409
+ grid?.state.rowDataStore.rowClearCache();
410
+ },
394
411
  rowSetTopData: (data) => {
395
412
  rdsStore.set(topData, data);
396
413
  const grid = rdsStore.get(grid$);
@@ -469,6 +486,19 @@ export function makeClientTreeDataSource(p) {
469
486
  const t = rdsStore.get(tree);
470
487
  grid.state.rowSelectedIds.set(new Set(t.idsAll));
471
488
  },
489
+ rowData: (section) => {
490
+ const d = [];
491
+ if (section === "top" || section === "flat") {
492
+ d.push(...rdsStore.get(topData));
493
+ }
494
+ if (section === "center" || section === "flat") {
495
+ d.push(...rdsStore.get(data));
496
+ }
497
+ if (section === "bottom" || section === "flat") {
498
+ d.push(...rdsStore.get(bottomData));
499
+ }
500
+ return d;
501
+ },
472
502
  rowAreAllSelected: (rowId) => {
473
503
  const g = rdsStore.get(grid$);
474
504
  if (!g)
@@ -501,12 +531,12 @@ export function useClientTreeDataSource(p) {
501
531
  if (p.reflectData) {
502
532
  // Need to queue the microtask since it we cannot update state during render.
503
533
  if (p.data !== da.center.get())
504
- queueMicrotask(() => da.center.set(p.data));
534
+ queueMicrotask(() => ds.current.rowSetCenterData(p.data));
505
535
  if (!equal(p.topData ?? [], da.top.get())) {
506
- queueMicrotask(() => da.top.set(p.topData ?? []));
536
+ queueMicrotask(() => ds.current.rowSetTopData(p.topData ?? []));
507
537
  }
508
538
  if (!equal(p.bottomData ?? [], da.bottom.get()))
509
- queueMicrotask(() => da.bottom.set(p.bottomData ?? []));
539
+ queueMicrotask(() => ds.current.rowSetBotData(p.bottomData ?? []));
510
540
  }
511
541
  return ds.current;
512
542
  }
@@ -453,6 +453,7 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
453
453
  return { kind: "leaf", data: null, id: `error-${ri}`, loading: false, error };
454
454
  if (!node)
455
455
  return { kind: "leaf", data: null, id: `loading-${ri}`, loading: true, error: null };
456
+ const isLoading = rdsStore.get(loadingGroups$);
456
457
  if (node.kind === "parent") {
457
458
  return {
458
459
  kind: "branch",
@@ -461,6 +462,7 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
461
462
  key: node.path,
462
463
  depth: getNodeDepth(node),
463
464
  error,
465
+ loading: isLoading.has(node.data.id),
464
466
  };
465
467
  }
466
468
  return {
@@ -470,13 +472,19 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
470
472
  error,
471
473
  };
472
474
  };
475
+ const loadingGroups$ = atom(new Set());
473
476
  const rowExpand = (p) => {
474
477
  const f = flat.get();
478
+ const loadingRows = new Set(rdsStore.get(loadingGroups$));
479
+ const rowsForThis = new Set();
475
480
  const rowIndices = [];
476
481
  const requests = Object.entries(p)
477
482
  .map(([rowId, state]) => {
478
483
  if (!state)
479
484
  return null;
485
+ // Mark as loading
486
+ loadingRows.add(rowId);
487
+ rowsForThis.add(rowId);
480
488
  const rowIndex = rowToIndex(rowId);
481
489
  if (rowIndex == null)
482
490
  return null;
@@ -505,17 +513,32 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
505
513
  return prev;
506
514
  });
507
515
  }
516
+ // Mark these groups as loading
517
+ rdsStore.set(loadingGroups$, loadingRows);
518
+ grid?.state.rowDataStore.rowClearCache();
508
519
  dataRequestHandler(requests, false, () => {
509
520
  if (mode)
510
521
  grid?.state.columnPivotColumnGroupExpansions.set((prev) => ({ ...prev, ...p }));
511
522
  else
512
523
  grid?.state.rowGroupExpansions.set((prev) => ({ ...prev, ...p }));
524
+ const next = new Set(rdsStore.get(loadingGroups$));
525
+ rowsForThis.forEach((c) => next.delete(c));
526
+ rdsStore.set(loadingGroups$, next);
527
+ setTimeout(() => {
528
+ grid?.state.rowDataStore.rowClearCache();
529
+ });
513
530
  }, (error) => {
514
531
  rdsStore.set(nodesWithError, (prev) => {
515
532
  const n = new Map(prev);
516
533
  rowIndices.forEach((c) => n.set(c, error));
517
534
  return prev;
518
535
  });
536
+ const next = new Set(rdsStore.get(loadingGroups$));
537
+ rowsForThis.forEach((c) => next.delete(c));
538
+ rdsStore.set(loadingGroups$, next);
539
+ setTimeout(() => {
540
+ grid?.state.rowDataStore.rowClearCache();
541
+ });
519
542
  });
520
543
  };
521
544
  const rowToIndex = (rowId) => {
@@ -651,6 +674,9 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
651
674
  rowSelect,
652
675
  rowSelectAll,
653
676
  rowSetBotData,
677
+ rowSetCenterData: () => {
678
+ throw new Error("Server side data source does not support full row updates");
679
+ },
654
680
  rowSetTopData,
655
681
  rowToIndex,
656
682
  rowUpdate,
@@ -1,6 +1,6 @@
1
1
  import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
2
2
  export interface SortAddProps {
3
- readonly slot?: SlotComponent<{
3
+ readonly as?: SlotComponent<{
4
4
  onAdd: () => void;
5
5
  disabled: boolean;
6
6
  }>;
@@ -2,12 +2,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useSlot } from "@1771technologies/lytenyte-react-hooks";
3
3
  import { forwardRef } from "react";
4
4
  import { useSortRowCtx } from "./context";
5
- export const SortAdd = forwardRef(function SortAdd({ slot, ...props }, forwarded) {
5
+ export const SortAdd = forwardRef(function SortAdd({ as: as, ...props }, forwarded) {
6
6
  const row = useSortRowCtx();
7
7
  const renderer = useSlot({
8
- props: [props],
8
+ props: [typeof as !== "function" ? { onClick: row.onAdd, disabled: !row.canAdd } : {}, props],
9
9
  ref: forwarded,
10
- slot: slot ?? (_jsx("button", { onClick: row.onAdd, disabled: !row.canAdd, children: "+" })),
10
+ slot: as ?? _jsx("button", { children: "+" }),
11
11
  state: { onAdd: row.onAdd, disabled: !row.canAdd },
12
12
  });
13
13
  return renderer;
@@ -1,6 +1,6 @@
1
1
  import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
2
2
  export interface SortApplyProps {
3
- readonly slot?: SlotComponent<{
3
+ readonly as?: SlotComponent<{
4
4
  onApply: () => void;
5
5
  }>;
6
6
  }
@@ -4,7 +4,7 @@ import { forwardRef } from "react";
4
4
  import { useSortManagerCtx } from "./context";
5
5
  import { itemsWithIdToMap } from "@1771technologies/lytenyte-js-utils";
6
6
  import { sortItemsToSortModel } from "./utils/sort-item-to-sort-model";
7
- export const SortApply = forwardRef(function SortApply({ slot, ...props }, forwarded) {
7
+ export const SortApply = forwardRef(function SortApply({ as, ...props }, forwarded) {
8
8
  const ctx = useSortManagerCtx();
9
9
  const onApply = useEvent(() => {
10
10
  const lookup = itemsWithIdToMap(ctx.mode ? ctx.grid.state.columnPivotColumns.get() : ctx.grid.state.columns.get());
@@ -15,9 +15,9 @@ export const SortApply = forwardRef(function SortApply({ slot, ...props }, forwa
15
15
  ctx.grid.state.sortModel.set(model);
16
16
  });
17
17
  const renderer = useSlot({
18
- props: [props],
18
+ props: [typeof as !== "function" ? { onClick: onApply } : {}, props],
19
19
  ref: forwarded,
20
- slot: slot ?? _jsx("button", { onClick: onApply }),
20
+ slot: as ?? _jsx("button", {}),
21
21
  state: { onApply },
22
22
  });
23
23
  return renderer;
@@ -1,6 +1,6 @@
1
1
  import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
2
2
  export interface SortCancelProps {
3
- readonly slot?: SlotComponent<{
3
+ readonly as?: SlotComponent<{
4
4
  onCancel: () => void;
5
5
  }>;
6
6
  }
@@ -4,7 +4,7 @@ import { forwardRef } from "react";
4
4
  import { useSortManagerCtx } from "./context";
5
5
  import { sortModelToSortItems } from "./utils/sort-model-to-sort-items";
6
6
  import { itemsWithIdToMap } from "@1771technologies/lytenyte-js-utils";
7
- export const SortCancel = forwardRef(function SortCancel({ slot, ...props }, forwarded) {
7
+ export const SortCancel = forwardRef(function SortCancel({ as, ...props }, forwarded) {
8
8
  const ctx = useSortManagerCtx();
9
9
  const onCancel = useEvent(() => {
10
10
  const model = ctx.mode
@@ -18,9 +18,9 @@ export const SortCancel = forwardRef(function SortCancel({ slot, ...props }, for
18
18
  ctx.setSortItems(state);
19
19
  });
20
20
  const renderer = useSlot({
21
- props: [props],
21
+ props: [typeof as !== "function" ? { onClick: onCancel } : {}, props],
22
22
  ref: forwarded,
23
- slot: slot ?? _jsx("button", { onClick: onCancel }),
23
+ slot: as ?? _jsx("button", {}),
24
24
  state: { onCancel },
25
25
  });
26
26
  return renderer;
@@ -1,6 +1,6 @@
1
1
  import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
2
2
  export interface SortClearProps {
3
- readonly slot?: SlotComponent<{
3
+ readonly as?: SlotComponent<{
4
4
  onClear: () => void;
5
5
  }>;
6
6
  }
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEvent, useSlot } from "@1771technologies/lytenyte-react-hooks";
3
3
  import { forwardRef } from "react";
4
4
  import { useSortManagerCtx } from "./context";
5
- export const SortClear = forwardRef(function SortClear({ slot, ...props }, forwarded) {
5
+ export const SortClear = forwardRef(function SortClear({ as, ...props }, forwarded) {
6
6
  const ctx = useSortManagerCtx();
7
7
  const onClear = useEvent(() => {
8
8
  if (ctx.mode) {
@@ -13,9 +13,9 @@ export const SortClear = forwardRef(function SortClear({ slot, ...props }, forwa
13
13
  }
14
14
  });
15
15
  const renderer = useSlot({
16
- props: [props],
16
+ props: [typeof as !== "function" ? { onClick: onClear } : {}, props],
17
17
  ref: forwarded,
18
- slot: slot ?? _jsx("button", { onClick: onClear }),
18
+ slot: as ?? _jsx("button", {}),
19
19
  state: { onClear },
20
20
  });
21
21
  return renderer;
@@ -1,7 +1,7 @@
1
1
  import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
2
2
  import type { Option } from "./+types";
3
3
  export interface SortColumnSelectProps {
4
- readonly slot?: SlotComponent<{
4
+ readonly as?: SlotComponent<{
5
5
  options: Option[];
6
6
  onSelect: (v: Option | null) => void;
7
7
  value: Option | null;
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useSlot } from "@1771technologies/lytenyte-react-hooks";
3
3
  import { forwardRef } from "react";
4
4
  import { useSortRowCtx } from "./context";
5
- export const SortColumnSelect = forwardRef(function SortColumnSelect({ slot, ...props }, forwarded) {
5
+ export const SortColumnSelect = forwardRef(function SortColumnSelect({ as, ...props }, forwarded) {
6
6
  const row = useSortRowCtx();
7
7
  const el = (_jsxs("select", { "aria-label": "Select column to sort", value: row.columnItem?.value ?? "", onChange: (e) => {
8
8
  const item = row.columnOptions.find((c) => c.value === e.target.value);
@@ -13,7 +13,7 @@ export const SortColumnSelect = forwardRef(function SortColumnSelect({ slot, ...
13
13
  const renderer = useSlot({
14
14
  props: [props],
15
15
  ref: forwarded,
16
- slot: slot ?? el,
16
+ slot: as ?? el,
17
17
  state: { options: row.columnOptions, onSelect: row.columnOnSelect, value: row.columnSelected },
18
18
  });
19
19
  return renderer;
@@ -1,7 +1,7 @@
1
1
  import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
2
2
  import type { Option } from "./+types";
3
3
  export interface SortDirectionSelectProps {
4
- readonly slot?: SlotComponent<{
4
+ readonly as?: SlotComponent<{
5
5
  options: Option[];
6
6
  onSelect: (v: Option | null) => void;
7
7
  value: Option | null;
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useSlot } from "@1771technologies/lytenyte-react-hooks";
3
3
  import { forwardRef } from "react";
4
4
  import { useSortRowCtx } from "./context";
5
- export const SortDirectionSelect = forwardRef(function SortDirectionSelect({ slot, ...props }, forwarded) {
5
+ export const SortDirectionSelect = forwardRef(function SortDirectionSelect({ as, ...props }, forwarded) {
6
6
  const row = useSortRowCtx();
7
7
  const el = (_jsx("select", { "aria-label": "Select sort direction", value: row.sortDirectionSelected?.value ?? "", onChange: (e) => {
8
8
  const item = row.sortDirectionOptions.find((c) => c.value === e.target.value);
@@ -13,7 +13,7 @@ export const SortDirectionSelect = forwardRef(function SortDirectionSelect({ slo
13
13
  const renderer = useSlot({
14
14
  props: [props],
15
15
  ref: forwarded,
16
- slot: slot ?? el,
16
+ slot: as ?? el,
17
17
  state: {
18
18
  options: row.sortDirectionOptions,
19
19
  onSelect: row.sortDirectionOnSelect,
@@ -1,6 +1,6 @@
1
1
  import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
2
2
  export interface SortRemoveProps {
3
- readonly slot?: SlotComponent<{
3
+ readonly as?: SlotComponent<{
4
4
  onRemove: () => void;
5
5
  }>;
6
6
  }