@1771technologies/lytenyte-pro 1.0.1 → 1.0.3

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 (62) hide show
  1. package/README.md +1 -6
  2. package/dist/+types.d.ts +24 -4
  3. package/dist/cell-selection/cell-selection-driver.js +2 -1
  4. package/dist/cell-selection/cell-style-row.d.ts +2 -2
  5. package/dist/cell-selection/cell-style-row.js +1 -1
  6. package/dist/cell-selection/get-root-cell.js +3 -83
  7. package/dist/cell-selection/index.d.ts +0 -1
  8. package/dist/cell-selection/index.js +0 -1
  9. package/dist/cell-selection/split-cell-selection-rect.d.ts +8 -1
  10. package/dist/cell-selection/split-cell-selection-rect.js +13 -4
  11. package/dist/cell-selection/split-on-pivot.d.ts +3 -0
  12. package/dist/cell-selection/split-on-pivot.js +50 -0
  13. package/dist/cells/cell-editor.js +1 -1
  14. package/dist/cells/cell-spacer.d.ts +3 -0
  15. package/dist/cells/cell-spacer.js +37 -0
  16. package/dist/cells/cell.d.ts +1 -3
  17. package/dist/cells/cell.js +11 -9
  18. package/dist/column-manager/branch.js +1 -1
  19. package/dist/column-manager/leaf.js +1 -1
  20. package/dist/column-manager/move-handle.d.ts +0 -7
  21. package/dist/column-manager/move-handle.js +23 -6
  22. package/dist/filter-tree/leaf.js +3 -1
  23. package/dist/grid-box/+types.d.ts +2 -2
  24. package/dist/grid-box/item.js +3 -3
  25. package/dist/grid-box/use-aggregation-box-items.js +1 -2
  26. package/dist/grid-box/use-column-box-items.d.ts +2 -3
  27. package/dist/grid-box/use-column-box-items.js +3 -3
  28. package/dist/grid-box/use-row-group-box-items.d.ts +3 -3
  29. package/dist/grid-box/use-row-group-box-items.js +41 -5
  30. package/dist/grid.d.ts +1 -1
  31. package/dist/header/resize-handler.js +21 -15
  32. package/dist/license.js +1 -1
  33. package/dist/row-data-source-client/use-client-data-source-paginated.js +154 -164
  34. package/dist/row-data-source-client/use-client-data-source.js +144 -177
  35. package/dist/row-data-source-client/use-client-tree-data-source.js +119 -152
  36. package/dist/row-data-source-server/use-server-data-source.js +102 -120
  37. package/dist/rows/row/row.d.ts +1 -1
  38. package/dist/rows/row/row.js +11 -4
  39. package/dist/rows/rows-sections.js +1 -1
  40. package/dist/sort-manager/+types.d.ts +2 -0
  41. package/dist/sort-manager/hooks/use-sort-row-item.js +6 -6
  42. package/dist/sort-manager/utils/sort-item-to-sort-model.js +5 -0
  43. package/dist/sort-manager/utils/sort-model-to-sort-items.js +2 -1
  44. package/dist/state/+types.d.ts +8 -10
  45. package/dist/state/api/cell-root.d.ts +5 -0
  46. package/dist/state/api/cell-root.js +64 -0
  47. package/dist/state/api/edit-begin.js +5 -9
  48. package/dist/state/api/edit-is-cell-active.d.ts +1 -1
  49. package/dist/state/api/edit-is-cell-active.js +2 -7
  50. package/dist/state/api/focus-cell.js +2 -2
  51. package/dist/state/helpers/column-layout.d.ts +3 -3
  52. package/dist/state/helpers/column-layout.js +9 -15
  53. package/dist/state/helpers/get-full-width-callback.d.ts +1 -1
  54. package/dist/state/helpers/get-full-width-callback.js +2 -0
  55. package/dist/state/helpers/get-span-callback.d.ts +1 -1
  56. package/dist/state/helpers/get-span-callback.js +2 -0
  57. package/dist/state/helpers/row-layout/row-layout.d.ts +5 -4
  58. package/dist/state/helpers/row-layout/row-layout.js +112 -346
  59. package/dist/state/use-lytenyte.js +398 -334
  60. package/dist/viewport/viewport.js +3 -2
  61. package/main.css +27 -3
  62. package/package.json +7 -7
@@ -1,25 +1,23 @@
1
- import { atom, createStore } from "@1771technologies/atom";
2
1
  import { useRef } from "react";
3
2
  import { makeAsyncTree } from "./async-tree/make-async-tree.js";
4
- import { makeGridAtom } from "@1771technologies/lytenyte-shared";
5
3
  import { getNodeDepth } from "./utils/get-node-depth.js";
6
4
  import { getRequestId } from "./utils/get-request-id.js";
7
5
  import { RangeTree } from "./range-tree/range-tree.js";
8
6
  import { getNodePath } from "./utils/get-node-path.js";
9
7
  import { equal } from "@1771technologies/lytenyte-js-utils";
8
+ import { computed, effect, makeAtom, peek, signal } from "@1771technologies/lytenyte-shared";
10
9
  export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, dataInFilterItemFetcher, cellUpdateHandler, cellUpdateOptimistically = true, blockSize = 200, }) {
11
10
  let grid = null;
12
- const snapshot$ = atom(Date.now());
13
- const rdsStore = createStore();
14
- const tree$ = atom(makeAsyncTree());
15
- const tree = makeGridAtom(tree$, rdsStore);
16
- const isLoading$ = atom(false);
17
- const isLoading = makeGridAtom(isLoading$, rdsStore);
18
- const error$ = atom();
19
- const loadError = makeGridAtom(error$, rdsStore);
20
- const nodesWithError = atom(new Map());
21
- const initialized = atom(false);
22
- const model$ = atom({
11
+ const snapshot$ = signal(Date.now());
12
+ const tree$ = signal(makeAsyncTree());
13
+ const tree = makeAtom(tree$);
14
+ const isLoading$ = signal(false);
15
+ const isLoading = makeAtom(isLoading$);
16
+ const error$ = signal(null);
17
+ const loadError = makeAtom(error$);
18
+ const nodesWithError = signal(new Map());
19
+ const initialized = signal(false);
20
+ const model$ = signal({
23
21
  sorts: [],
24
22
  filters: {},
25
23
  filtersIn: {},
@@ -38,12 +36,12 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
38
36
  values: [],
39
37
  },
40
38
  });
41
- const model = makeGridAtom(model$, rdsStore);
42
- const pivotGroupExpansions = atom((g) => g(model$).pivotGroupExpansions);
43
- const rowGroupExpansions = atom((g) => g(model$).groupExpansions);
44
- const pivotMode = atom((g) => g(model$).pivotMode);
45
- const topData = atom([]);
46
- const botData = atom([]);
39
+ const model = makeAtom(model$);
40
+ const pivotGroupExpansions = computed(() => model$().pivotGroupExpansions);
41
+ const rowGroupExpansions = computed(() => model$().groupExpansions);
42
+ const pivotMode = computed(() => model$().pivotMode);
43
+ const topData = signal([]);
44
+ const botData = signal([]);
47
45
  const seenRequests = new Set();
48
46
  const dataResponseHandler = (res) => {
49
47
  const t = tree.get();
@@ -56,10 +54,10 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
56
54
  });
57
55
  pinResponses.forEach((p) => {
58
56
  if (p.kind === "top") {
59
- rdsStore.set(topData, p.data);
57
+ topData.set(p.data);
60
58
  }
61
59
  else {
62
- rdsStore.set(botData, p.data);
60
+ botData.set(p.data);
63
61
  }
64
62
  });
65
63
  dataResponses.forEach((r) => {
@@ -96,7 +94,7 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
96
94
  onSuccess?.();
97
95
  return;
98
96
  }
99
- rdsStore.set(nodesWithError, (prev) => {
97
+ nodesWithError.set((prev) => {
100
98
  const next = new Map(prev);
101
99
  p.forEach((r) => {
102
100
  for (let i = r.rowStartIndex; i < r.rowEndIndex; i++) {
@@ -122,7 +120,7 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
122
120
  console.error(e);
123
121
  }
124
122
  finally {
125
- rdsStore.set(snapshot$, Date.now());
123
+ snapshot$.set(Date.now());
126
124
  grid.state.rowDataStore.rowClearCache();
127
125
  }
128
126
  };
@@ -177,7 +175,7 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
177
175
  });
178
176
  }
179
177
  dataRequestHandler(requests, false, () => { }, (e) => {
180
- rdsStore.set(nodesWithError, (prev) => {
178
+ nodesWithError.set((prev) => {
181
179
  const next = new Map(prev);
182
180
  requests.forEach((r) => {
183
181
  for (let i = r.rowStartIndex; i < r.rowEndIndex; i++) {
@@ -191,7 +189,7 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
191
189
  const resetRequest = async () => {
192
190
  seenRequests.clear();
193
191
  tree.set(makeAsyncTree());
194
- rdsStore.set(nodesWithError, new Map());
192
+ nodesWithError.set(new Map());
195
193
  // Initialize the grid.
196
194
  const initialDataRequest = {
197
195
  path: [],
@@ -208,11 +206,11 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
208
206
  });
209
207
  isLoading.set(false);
210
208
  };
211
- const flat$ = atom((g) => {
212
- g(snapshot$);
213
- const mode = rdsStore.get(pivotMode);
214
- const expansions = mode ? g(pivotGroupExpansions) : g(rowGroupExpansions);
215
- const t = g(tree$);
209
+ const flat$ = computed(() => {
210
+ snapshot$();
211
+ const mode = pivotMode();
212
+ const expansions = mode ? pivotGroupExpansions() : rowGroupExpansions();
213
+ const t = tree$();
216
214
  const rowIdToRow = new Map();
217
215
  const rowIndexToRow = new Map();
218
216
  const rowIdToRowIndex = new Map();
@@ -244,7 +242,10 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
244
242
  rangeTree,
245
243
  };
246
244
  });
247
- const flat = makeGridAtom(flat$, rdsStore);
245
+ const flat = makeAtom(flat$);
246
+ const topLength = computed(() => topData().length);
247
+ const botLength = computed(() => botData().length);
248
+ const flatLength = computed(() => flat.$().size);
248
249
  const cleanup = [];
249
250
  const init = (g) => {
250
251
  grid = g;
@@ -258,7 +259,7 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
258
259
  const pivotMode = g.state.columnPivotMode.get();
259
260
  const pivotModel = g.state.columnPivotModel.get();
260
261
  const pivotGroupExpansions = g.state.columnPivotRowGroupExpansions.get();
261
- rdsStore.set(model$, {
262
+ model$.set({
262
263
  sorts,
263
264
  filters,
264
265
  filtersIn,
@@ -270,25 +271,24 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
270
271
  pivotModel,
271
272
  pivotGroupExpansions,
272
273
  });
273
- rdsStore.set(initialized, true);
274
+ initialized.set(true);
274
275
  // Handle row count changes
275
276
  const f = flat.get();
276
277
  g.state.rowDataStore.rowCenterCount.set(f.size);
277
- g.state.rowDataStore.rowBottomCount.set(rdsStore.get(botData).length);
278
- g.state.rowDataStore.rowTopCount.set(rdsStore.get(topData).length);
279
- rdsStore.sub(flat$, () => {
280
- const f = flat.get();
281
- g.state.rowDataStore.rowCenterCount.set(f.size);
278
+ g.state.rowDataStore.rowBottomCount.set(peek(botData).length);
279
+ g.state.rowDataStore.rowTopCount.set(peek(topData).length);
280
+ cleanup.push(effect(() => {
281
+ g.state.rowDataStore.rowCenterCount.set(flatLength());
282
282
  viewChange();
283
- });
284
- rdsStore.sub(topData, () => {
285
- g.state.rowDataStore.rowTopCount.set(rdsStore.get(topData).length);
283
+ }));
284
+ cleanup.push(effect(() => {
285
+ g.state.rowDataStore.rowTopCount.set(topLength());
286
286
  g.state.rowDataStore.rowClearCache();
287
- });
288
- rdsStore.sub(botData, () => {
289
- g.state.rowDataStore.rowBottomCount.set(rdsStore.get(botData).length);
287
+ }));
288
+ cleanup.push(effect(() => {
289
+ g.state.rowDataStore.rowBottomCount.set(botLength);
290
290
  g.state.rowDataStore.rowClearCache();
291
- });
291
+ }));
292
292
  resetRequest();
293
293
  // Watch the view bound changes.
294
294
  g.state.viewBounds.watch(() => {
@@ -314,78 +314,60 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
314
314
  };
315
315
  if (pivotMode)
316
316
  updatePivotColumns(pivotModel);
317
- // Make these deep equality checks
318
- cleanup.push(g.state.columnPivotMode.watch(() => {
319
- const model = g.state.columnPivotModel.get();
320
- updatePivotColumns(model, true);
321
- rdsStore.set(model$, (prev) => ({ ...prev, pivotMode: g.state.columnPivotMode.get() }));
322
- g.state.rowDataStore.rowClearCache();
323
- }));
324
- cleanup.push(g.state.columnPivotModel.watch(() => {
325
- const model = g.state.columnPivotModel.get();
317
+ let prevModel = peek(model$);
318
+ effect(() => {
319
+ // @ts-expect-error this is fine
320
+ const rowGroupModel = g.state.rowGroupModel.$();
321
+ // @ts-expect-error this is fine
322
+ const rowGroupExpansions = g.state.rowGroupExpansions.$();
323
+ // @ts-expect-error this is fine
324
+ const aggModel = g.state.aggModel.$();
325
+ // @ts-expect-error this is fine
326
+ const filterModelIn = g.state.filterInModel.$();
327
+ // @ts-expect-error this is fine
328
+ const quickSearch = g.state.quickSearch.$();
329
+ // @ts-expect-error this is fine
330
+ const filterModel = g.state.filterModel.$();
331
+ // @ts-expect-error this is fine
332
+ const sortModel = g.state.sortModel.$();
333
+ // @ts-expect-error this is fine
334
+ const columnPivotExpansions = g.state.columnPivotColumnGroupExpansions.$();
335
+ // @ts-expect-error this is fine
336
+ const model = g.state.columnPivotModel.$();
337
+ // @ts-expect-error this is fine
338
+ const mode = g.state.columnPivotMode.$();
326
339
  updatePivotColumns(model);
327
- rdsStore.set(model$, (prev) => ({
328
- ...prev,
340
+ const newModel = {
341
+ aggregations: aggModel,
342
+ filters: filterModel,
343
+ filtersIn: filterModelIn,
344
+ group: rowGroupModel,
345
+ groupExpansions: rowGroupExpansions,
346
+ quickSearch,
347
+ pivotGroupExpansions: columnPivotExpansions,
348
+ pivotMode: mode,
329
349
  pivotModel: model,
330
- }));
331
- g.state.rowDataStore.rowClearCache();
332
- }));
333
- g.state.columnPivotRowGroupExpansions.watch(() => {
334
- rdsStore.set(model$, (prev) => ({
335
- ...prev,
336
- columnPivotGroupExpansions: g.state.columnPivotRowGroupExpansions.get(),
337
- }));
338
- grid?.state.rowDataStore.rowClearCache();
339
- });
340
- // Sort model monitoring
341
- cleanup.push(g.state.sortModel.watch(() => {
342
- rdsStore.set(model$, (prev) => ({ ...prev, sorts: g.state.sortModel.get() }));
343
- resetRequest();
344
- }));
345
- // Filter model monitoring
346
- cleanup.push(g.state.filterModel.watch(() => {
347
- rdsStore.set(model$, (prev) => ({ ...prev, filters: g.state.filterModel.get() }));
348
- resetRequest();
349
- }));
350
- cleanup.push(g.state.quickSearch.watch(() => {
351
- rdsStore.set(model$, (prev) => ({ ...prev, quickSearch: g.state.quickSearch.get() }));
352
- resetRequest();
353
- }));
354
- cleanup.push(g.state.filterInModel.watch(() => {
355
- rdsStore.set(model$, (prev) => ({ ...prev, filtersIn: g.state.filterInModel.get() }));
356
- resetRequest();
357
- }));
358
- // Row group model monitoring
359
- cleanup.push(g.state.rowGroupModel.watch(() => {
360
- rdsStore.set(model$, (prev) => ({ ...prev, group: g.state.rowGroupModel.get() }));
361
- resetRequest();
362
- }));
363
- // Row group expansions monitoring
364
- cleanup.push(g.state.rowGroupExpansions.watch(() => {
365
- rdsStore.set(model$, (prev) => ({
366
- ...prev,
367
- groupExpansions: g.state.rowGroupExpansions.get(),
368
- }));
369
- grid?.state.rowDataStore.rowClearCache();
370
- }));
371
- // Agg model monitoring
372
- cleanup.push(g.state.aggModel.watch(() => {
373
- rdsStore.set(model$, (prev) => ({ ...prev, agg: g.state.aggModel.get() }));
350
+ sorts: sortModel,
351
+ };
352
+ if (equal(newModel, prevModel))
353
+ return;
354
+ prevModel = newModel;
355
+ model$.set(newModel);
374
356
  resetRequest();
375
- }));
357
+ });
376
358
  };
377
359
  const rowById = (id) => {
378
360
  const f = flat.get();
379
361
  const node = f.rowIdToRow.get(id);
380
362
  if (!node) {
381
363
  {
382
- const top = rdsStore.get(topData);
364
+ const top = peek(topData);
383
365
  const node = top.find((c) => c.id === id);
384
366
  if (node)
385
367
  return { kind: "leaf", data: node.data, id: node.id };
386
368
  }
387
369
  {
388
- const bot = rdsStore.get(topData);
370
+ const bot = peek(topData);
389
371
  const node = bot.find((c) => c.id === id);
390
372
  if (node)
391
373
  return { kind: "leaf", data: node.data, id: node.id };
@@ -428,9 +410,9 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
428
410
  };
429
411
  const rowByIndex = (ri) => {
430
412
  const f = flat.get();
431
- const top = rdsStore.get(topData);
432
- const bot = rdsStore.get(botData);
433
- const errors = rdsStore.get(nodesWithError);
413
+ const top = peek(topData);
414
+ const bot = peek(botData);
415
+ const errors = peek(nodesWithError);
434
416
  const error = errors.get(ri);
435
417
  if (ri == null || ri < 0 || ri >= f.size + top.length + bot.length)
436
418
  return null;
@@ -453,7 +435,7 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
453
435
  return { kind: "leaf", data: null, id: `error-${ri}`, loading: false, error };
454
436
  if (!node)
455
437
  return { kind: "leaf", data: null, id: `loading-${ri}`, loading: true, error: null };
456
- const isLoading = rdsStore.get(loadingGroups$);
438
+ const isLoading = peek(loadingGroups$);
457
439
  if (node.kind === "parent") {
458
440
  return {
459
441
  kind: "branch",
@@ -472,10 +454,10 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
472
454
  error,
473
455
  };
474
456
  };
475
- const loadingGroups$ = atom(new Set());
457
+ const loadingGroups$ = signal(new Set());
476
458
  const rowExpand = (p) => {
477
459
  const f = flat.get();
478
- const loadingRows = new Set(rdsStore.get(loadingGroups$));
460
+ const loadingRows = new Set(peek(loadingGroups$));
479
461
  const rowsForThis = new Set();
480
462
  const rowIndices = [];
481
463
  const requests = Object.entries(p)
@@ -503,39 +485,39 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
503
485
  };
504
486
  })
505
487
  .filter((c) => !!c);
506
- const mode = rdsStore.get(pivotMode);
488
+ const mode = peek(pivotMode);
507
489
  // Remove the errors before requesting.
508
- const errorRows = rdsStore.get(nodesWithError);
490
+ const errorRows = peek(nodesWithError);
509
491
  if (rowIndices.some((c) => errorRows.has(c))) {
510
- rdsStore.set(nodesWithError, (prev) => {
492
+ nodesWithError.set((prev) => {
511
493
  const n = new Map(prev);
512
494
  rowIndices.forEach((c) => n.delete(c));
513
495
  return prev;
514
496
  });
515
497
  }
516
498
  // Mark these groups as loading
517
- rdsStore.set(loadingGroups$, loadingRows);
499
+ loadingGroups$.set(loadingRows);
518
500
  grid?.state.rowDataStore.rowClearCache();
519
501
  dataRequestHandler(requests, false, () => {
520
502
  if (mode)
521
503
  grid?.state.columnPivotColumnGroupExpansions.set((prev) => ({ ...prev, ...p }));
522
504
  else
523
505
  grid?.state.rowGroupExpansions.set((prev) => ({ ...prev, ...p }));
524
- const next = new Set(rdsStore.get(loadingGroups$));
506
+ const next = new Set(peek(loadingGroups$));
525
507
  rowsForThis.forEach((c) => next.delete(c));
526
- rdsStore.set(loadingGroups$, next);
508
+ loadingGroups$.set(next);
527
509
  setTimeout(() => {
528
510
  grid?.state.rowDataStore.rowClearCache();
529
511
  });
530
512
  }, (error) => {
531
- rdsStore.set(nodesWithError, (prev) => {
513
+ nodesWithError.set((prev) => {
532
514
  const n = new Map(prev);
533
515
  rowIndices.forEach((c) => n.set(c, error));
534
516
  return prev;
535
517
  });
536
- const next = new Set(rdsStore.get(loadingGroups$));
518
+ const next = new Set(peek(loadingGroups$));
537
519
  rowsForThis.forEach((c) => next.delete(c));
538
- rdsStore.set(loadingGroups$, next);
520
+ loadingGroups$.set(next);
539
521
  setTimeout(() => {
540
522
  grid?.state.rowDataStore.rowClearCache();
541
523
  });
@@ -618,8 +600,8 @@ export function makeServerDataSource({ dataFetcher, dataColumnPivotFetcher, data
618
600
  };
619
601
  const rowUpdate = (updates) => {
620
602
  const f = flat.get();
621
- const top = rdsStore.get(topData);
622
- const bot = rdsStore.get(botData);
603
+ const top = peek(topData);
604
+ const bot = peek(botData);
623
605
  const firstBot = f.size + top.length;
624
606
  const idMap = new Map([...updates.entries()]
625
607
  .map(([key, data]) => {
@@ -4,4 +4,4 @@ export interface RowProps extends Omit<DropWrapProps, "accepted"> {
4
4
  readonly row: RowNormalRowLayout<any>;
5
5
  readonly accepted?: string[];
6
6
  }
7
- export declare const Row: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "onDrag"> & RowProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
7
+ export declare const Row: import("react").NamedExoticComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "onDrag"> & RowProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
@@ -1,16 +1,23 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { forwardRef } from "react";
3
- import { fastDeepMemo } from "@1771technologies/lytenyte-react-hooks";
2
+ import { forwardRef, memo } from "react";
4
3
  import { useGridRoot } from "../../context";
5
4
  import { RowDetailRow } from "../row-detail-row";
6
5
  import { RowReact } from "@1771technologies/lytenyte-shared";
7
6
  import { useRowContextValue } from "./use-row-context-value";
8
7
  import { RowContext } from "./context";
8
+ import { equal } from "@1771technologies/lytenyte-js-utils";
9
+ import { CellSpacerNoPin } from "../../cells/cell-spacer";
9
10
  const empty = [];
10
11
  const RowImpl = forwardRef(function Rows({ row, ...props }, forwarded) {
11
12
  const ctx = useGridRoot().grid;
12
13
  const rowMeta = useRowContextValue(ctx, row.row);
13
14
  const accepted = props.accepted ?? empty;
14
- return (_jsx(RowContext.Provider, { value: rowMeta, children: _jsxs(RowReact, { ...props, ref: forwarded, accepted: accepted, gridId: ctx.state.gridId.useValue(), rowIndex: row.rowIndex, rowFirstPinBottom: row.rowFirstPinBottom, rowLastPinTop: row.rowLastPinTop, rowIsFocusRow: row.rowIsFocusRow ?? false, yPositions: ctx.state.yPositions.useValue(), "data-ln-row-selected": rowMeta.selected, children: [props.children, _jsx(RowDetailRow, { layout: row })] }) }));
15
+ return (_jsx(RowContext.Provider, { value: rowMeta, children: _jsxs(RowReact, { ...props, ref: forwarded, accepted: accepted, gridId: ctx.state.gridId.useValue(), rowIndex: row.rowIndex, rowFirstPinBottom: row.rowFirstPinBottom, rowLastPinTop: row.rowLastPinTop, rowIsFocusRow: row.rowIsFocusRow ?? false, yPositions: ctx.state.yPositions.useValue(), "data-ln-row-selected": rowMeta.selected, children: [_jsx(CellSpacerNoPin, {}), props.children, _jsx(RowDetailRow, { layout: row })] }) }));
16
+ });
17
+ export const Row = memo(RowImpl, (prev, next) => {
18
+ const { row: rowP, ...propsP } = prev;
19
+ const { row: rowN, ...propsN } = next;
20
+ const { cells: _, ...rowPropsP } = rowP;
21
+ const { cells: __, ...rowPropsN } = rowN;
22
+ return equal(rowPropsN, rowPropsP) && equal(propsP, propsN);
15
23
  });
16
- export const Row = fastDeepMemo(RowImpl);
@@ -15,7 +15,7 @@ export const RowsCenter = fastDeepMemo(forwardRef(function RowsCenter({ children
15
15
  const cx = useGridRoot().grid;
16
16
  const view = cx.view.useValue().rows;
17
17
  const rowCenterCount = cx.state.rowDataStore.rowCenterCount.useValue();
18
- return (_jsx(RowsCenterReact, { ...props, ref: forwarded, rowFirst: cx.state.rowDataStore.rowTopCount.useValue(), rowLast: rowCenterCount + cx.state.rowDataStore.rowTopCount.useValue(), height: view.rowCenterTotalHeight, children: _jsxs(NativeScroller, { children: [_jsx(CellSelectionCenter, {}), children] }) }));
18
+ return (_jsx(RowsCenterReact, { ...props, ref: forwarded, rowFirst: cx.state.rowDataStore.rowTopCount.useValue(), rowLast: rowCenterCount + cx.state.rowDataStore.rowTopCount.useValue(), height: view.rowCenterTotalHeight, pinSectionHeights: view.rowBottomTotalHeight + view.rowTopTotalHeight, children: _jsxs(NativeScroller, { children: [_jsx(CellSelectionCenter, {}), children] }) }));
19
19
  }));
20
20
  export const RowsBottom = fastDeepMemo(forwardRef(function RowsBottom(props, forwarded) {
21
21
  const cx = useGridRoot().grid;
@@ -1,9 +1,11 @@
1
+ import type { SortModelItem } from "../+types";
1
2
  export interface SortItem {
2
3
  readonly isCustom: boolean;
3
4
  readonly columnId?: string;
4
5
  readonly label?: string;
5
6
  readonly sortOn?: "values" | "values_absolute" | "values_accented" | "values_nulls_first" | "values_absolute_nulls_first" | "values_accented_nulls_first" | "values_absolute_accented_nulls_first";
6
7
  readonly sortDirection: "ascending" | "descending";
8
+ readonly originalSort?: SortModelItem<any>;
7
9
  }
8
10
  export interface Option {
9
11
  readonly label: string;
@@ -118,11 +118,11 @@ const sortValuesForDateAndDateTime = [
118
118
  const sortValuesString = [
119
119
  { label: "Values", value: "values" },
120
120
  { label: "Insensitive", value: "values_insensitive" },
121
- { label: "Insensitive, Ignore Punctuation", value: "value_insensitive_ignore" },
122
- { label: "Insensitive, Trim", value: "value_insensitive_trim" },
123
- { label: "Insensitive, Ignore Punctuation, Trim", value: "value_insensitive_ignore_trim" },
124
- { label: "Ignore Punctuation", value: "values_ignore_punctuation" },
125
- { label: "Ignore Punctuation, Trim", value: "values_ignore_punctuation_trim" },
121
+ { label: "Insensitive, Ignore Punctuation", value: "values_insensitive_ignore" },
122
+ { label: "Insensitive, Trim", value: "values_insensitive_trim" },
123
+ { label: "Insensitive, Ignore Punctuation, Trim", value: "values_insensitive_ignore_trim" },
124
+ { label: "Ignore Punctuation", value: "values_ignore" },
125
+ { label: "Ignore Punctuation, Trim", value: "values_ignore_trim" },
126
126
  { label: "Trim Whitespace", value: "values_trim" },
127
127
  { label: "Nulls First", value: "values_nulls_first" },
128
128
  { label: "Nulls First, Insensitive", value: "values_nulls_first_insensitive" },
@@ -131,7 +131,7 @@ const sortValuesString = [
131
131
  { label: "Nulls First, Insensitive, Trim", value: "values_nulls_first_insensitive_trim" },
132
132
  {
133
133
  label: "Nulls First, Insensitive, Ignore Punctuation",
134
- value: "values_nulls_insensitive_first_ignore",
134
+ value: "values_nulls_first_insensitive_ignore",
135
135
  },
136
136
  {
137
137
  label: "Nulls First, Insensitive, Ignore Punctuation, Trim",
@@ -1,6 +1,8 @@
1
1
  export function sortItemsToSortModel(sortItems, lookup) {
2
2
  return sortItems
3
3
  .filter((c) => {
4
+ if (c.isCustom)
5
+ return true;
4
6
  if (!c.columnId)
5
7
  return false;
6
8
  if (!c.sortOn)
@@ -11,6 +13,9 @@ export function sortItemsToSortModel(sortItems, lookup) {
11
13
  })
12
14
  .map((c) => {
13
15
  const col = lookup.get(c.columnId);
16
+ if (c.isCustom) {
17
+ return c.originalSort;
18
+ }
14
19
  if (col.type === "number") {
15
20
  return {
16
21
  columnId: col.id,
@@ -8,6 +8,7 @@ export function sortModelToSortItems(items, lookup) {
8
8
  isCustom: true,
9
9
  sortDirection,
10
10
  columnId: c.columnId ?? undefined,
11
+ originalSort: c,
11
12
  };
12
13
  }
13
14
  const column = lookup.get(columnId);
@@ -23,7 +24,7 @@ export function sortModelToSortItems(items, lookup) {
23
24
  if (opts?.ignorePunctuation)
24
25
  value += "_ignore";
25
26
  if (opts?.trimWhitespace)
26
- value += "trim";
27
+ value += "_trim";
27
28
  }
28
29
  if (c.sort.kind === "number") {
29
30
  const opts = c.sort.options;
@@ -1,14 +1,13 @@
1
- import type { LayoutMap } from "@1771technologies/lytenyte-shared";
2
- import type { Column, DataRect, EditActivePosition, GridAtom, GridAtomReadonly, HeaderGroupCellLayout, PositionUnion, VirtualTarget } from "../+types";
3
- import type { Atom, createStore } from "@1771technologies/atom";
1
+ import type { LayoutState, WriteSignal } from "@1771technologies/lytenyte-shared";
2
+ import type { Column, EditActivePosition, GridAtom, GridAtomReadonly, HeaderGroupCellLayout, PositionUnion, VirtualTarget } from "../+types";
3
+ import type { DataRectSplit } from "../cell-selection/split-cell-selection-rect";
4
4
  export interface InternalAtoms {
5
5
  readonly headerRows: GridAtomReadonly<number>;
6
6
  readonly headerCols: GridAtomReadonly<number>;
7
7
  readonly headerHeightTotal: GridAtomReadonly<number>;
8
8
  readonly xScroll: GridAtom<number>;
9
9
  readonly yScroll: GridAtom<number>;
10
- readonly refreshKey: GridAtom<number>;
11
- readonly layout: GridAtomReadonly<LayoutMap>;
10
+ readonly layout: LayoutState;
12
11
  readonly focusActive: GridAtom<PositionUnion | null>;
13
12
  readonly focusPrevColIndex: GridAtom<number | null>;
14
13
  readonly focusPrevRowIndex: GridAtom<number | null>;
@@ -17,7 +16,7 @@ export interface InternalAtoms {
17
16
  readonly editValidation: GridAtom<Record<string, any> | boolean>;
18
17
  readonly rowAutoHeightCache: GridAtom<Record<number, number>>;
19
18
  readonly rowDetailAutoHeightCache: GridAtom<Record<number, number>>;
20
- readonly rowSelectedIds: Atom<Set<string>>;
19
+ readonly rowSelectedIds: WriteSignal<Set<string>>;
21
20
  readonly rowSelectionPivot: GridAtom<string | null>;
22
21
  readonly rowSelectionLastWasDeselect: GridAtom<boolean>;
23
22
  readonly rowGroupColumnState: GridAtom<Record<string, Partial<Column<any>>>>;
@@ -27,9 +26,8 @@ export interface InternalAtoms {
27
26
  target: HTMLElement | VirtualTarget;
28
27
  context: any;
29
28
  }>>;
30
- readonly cellSelectionPivot: GridAtom<DataRect | null>;
31
- readonly cellSelectionAdditiveRects: GridAtom<DataRect[] | null>;
29
+ readonly cellSelectionPivot: GridAtom<DataRectSplit | null>;
30
+ readonly cellSelectionAdditiveRects: GridAtom<DataRectSplit[] | null>;
32
31
  readonly cellSelectionIsDeselect: GridAtom<boolean>;
33
- readonly cellSelectionSplits: GridAtomReadonly<DataRect[]>;
34
- readonly store: ReturnType<typeof createStore>;
32
+ readonly cellSelectionSplits: GridAtomReadonly<DataRectSplit[]>;
35
33
  }
@@ -0,0 +1,5 @@
1
+ import type { InternalAtoms } from "../+types";
2
+ import type { Grid, GridApi } from "../../+types";
3
+ export declare const makeCellRoot: (grid: Grid<any> & {
4
+ internal: InternalAtoms;
5
+ }) => GridApi<any>["cellRoot"];
@@ -0,0 +1,64 @@
1
+ import { CONTAINS_DEAD_CELLS, FULL_WIDTH, updateLayout } from "@1771technologies/lytenyte-shared";
2
+ import { getSpanFn } from "../helpers/get-span-callback";
3
+ import { getFullWidthCallback } from "../helpers/get-full-width-callback";
4
+ export const makeCellRoot = (grid) => {
5
+ return (row, column) => {
6
+ const l = grid.internal.layout;
7
+ const meta = grid.state.columnMeta.get();
8
+ const ds = grid.state.rowDataStore;
9
+ // Is this a valid position.
10
+ if (row < 0 || row >= ds.rowCount.get())
11
+ return null;
12
+ if (column < 0 || column >= meta.columnsVisible.length)
13
+ return null;
14
+ const rds = grid.state.rowDataSource.get();
15
+ const columns = meta.columnsVisible;
16
+ const rowFullWidthPredicate = grid.state.rowFullWidthPredicate.get();
17
+ if (!l.computed[row]) {
18
+ updateLayout({
19
+ base: l.base,
20
+ computed: l.computed,
21
+ lookup: l.lookup,
22
+ special: l.special,
23
+ botCount: ds.rowBottomCount.get(),
24
+ topCount: ds.rowTopCount.get(),
25
+ startCount: meta.columnVisibleStartCount,
26
+ centerCount: meta.columnVisibleCenterCount,
27
+ endCount: meta.columnVisibleEndCount,
28
+ computeColSpan: getSpanFn(rds, grid, columns, "col"),
29
+ computeRowSpan: getSpanFn(rds, grid, columns, "row"),
30
+ isFullWidth: getFullWidthCallback(rds, rowFullWidthPredicate.fn, grid),
31
+ isRowCutoff: (r) => {
32
+ const row = rds.rowByIndex(r);
33
+ return !row || row.kind === "branch";
34
+ },
35
+ rowStart: row,
36
+ rowEnd: row + 1,
37
+ rowMax: ds.rowCenterCount.get() + ds.rowTopCount.get(),
38
+ rowScanDistance: grid.state.rowScanDistance.get(),
39
+ });
40
+ }
41
+ const status = l.special[row];
42
+ if (status === FULL_WIDTH) {
43
+ return { kind: "full-width", rowIndex: row, colIndex: 0 };
44
+ }
45
+ if (status === CONTAINS_DEAD_CELLS) {
46
+ const spec = l.lookup.get(row);
47
+ // This cell is not covered
48
+ if (!spec || spec[column * 4] !== 0) {
49
+ return { kind: "cell", rowIndex: row, colIndex: column, root: null };
50
+ }
51
+ const rowSpan = spec[column * 4];
52
+ const colSpan = spec[column * 4 + 1];
53
+ const rowIndex = spec[column * 4 + 2];
54
+ const colIndex = spec[column * 4 + 3];
55
+ return {
56
+ kind: "cell",
57
+ rowIndex: row,
58
+ colIndex: column,
59
+ root: { colIndex, colSpan, rowIndex, rowSpan },
60
+ };
61
+ }
62
+ return { kind: "cell", rowIndex: row, colIndex: column, root: null };
63
+ };
64
+ };