@1771technologies/lytenyte-pro 1.0.2 → 1.0.4

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 (61) hide show
  1. package/dist/+types.d.ts +24 -4
  2. package/dist/cell-selection/cell-selection-driver.js +3 -2
  3. package/dist/cell-selection/cell-style-row.d.ts +2 -2
  4. package/dist/cell-selection/cell-style-row.js +1 -1
  5. package/dist/cell-selection/get-root-cell.js +3 -83
  6. package/dist/cell-selection/index.d.ts +0 -1
  7. package/dist/cell-selection/index.js +0 -1
  8. package/dist/cell-selection/split-cell-selection-rect.d.ts +8 -1
  9. package/dist/cell-selection/split-cell-selection-rect.js +13 -4
  10. package/dist/cell-selection/split-on-pivot.d.ts +3 -0
  11. package/dist/cell-selection/split-on-pivot.js +50 -0
  12. package/dist/cells/cell-editor.js +1 -1
  13. package/dist/cells/cell-spacer.d.ts +3 -0
  14. package/dist/cells/cell-spacer.js +37 -0
  15. package/dist/cells/cell.d.ts +1 -3
  16. package/dist/cells/cell.js +11 -9
  17. package/dist/column-manager/branch.js +1 -1
  18. package/dist/column-manager/leaf.js +1 -1
  19. package/dist/column-manager/move-handle.d.ts +0 -7
  20. package/dist/column-manager/move-handle.js +23 -6
  21. package/dist/filter-tree/leaf.js +3 -1
  22. package/dist/grid-box/+types.d.ts +2 -2
  23. package/dist/grid-box/item.js +3 -3
  24. package/dist/grid-box/use-aggregation-box-items.js +1 -2
  25. package/dist/grid-box/use-column-box-items.d.ts +2 -3
  26. package/dist/grid-box/use-column-box-items.js +3 -3
  27. package/dist/grid-box/use-row-group-box-items.d.ts +3 -3
  28. package/dist/grid-box/use-row-group-box-items.js +41 -5
  29. package/dist/grid.d.ts +1 -1
  30. package/dist/header/resize-handler.js +21 -15
  31. package/dist/license.js +1 -1
  32. package/dist/row-data-source-client/use-client-data-source-paginated.js +154 -164
  33. package/dist/row-data-source-client/use-client-data-source.js +144 -177
  34. package/dist/row-data-source-client/use-client-tree-data-source.js +119 -152
  35. package/dist/row-data-source-server/use-server-data-source.js +102 -120
  36. package/dist/rows/row/row.d.ts +1 -1
  37. package/dist/rows/row/row.js +11 -4
  38. package/dist/rows/rows-sections.js +1 -1
  39. package/dist/sort-manager/+types.d.ts +2 -0
  40. package/dist/sort-manager/hooks/use-sort-row-item.js +6 -6
  41. package/dist/sort-manager/utils/sort-item-to-sort-model.js +5 -0
  42. package/dist/sort-manager/utils/sort-model-to-sort-items.js +2 -1
  43. package/dist/state/+types.d.ts +8 -10
  44. package/dist/state/api/cell-root.d.ts +5 -0
  45. package/dist/state/api/cell-root.js +64 -0
  46. package/dist/state/api/edit-begin.js +5 -9
  47. package/dist/state/api/edit-is-cell-active.d.ts +1 -1
  48. package/dist/state/api/edit-is-cell-active.js +2 -7
  49. package/dist/state/api/focus-cell.js +2 -2
  50. package/dist/state/helpers/column-layout.d.ts +3 -3
  51. package/dist/state/helpers/column-layout.js +9 -15
  52. package/dist/state/helpers/get-full-width-callback.d.ts +1 -1
  53. package/dist/state/helpers/get-full-width-callback.js +2 -0
  54. package/dist/state/helpers/get-span-callback.d.ts +1 -1
  55. package/dist/state/helpers/get-span-callback.js +2 -0
  56. package/dist/state/helpers/row-layout/row-layout.d.ts +5 -4
  57. package/dist/state/helpers/row-layout/row-layout.js +112 -346
  58. package/dist/state/use-lytenyte.js +398 -334
  59. package/dist/viewport/viewport.js +3 -2
  60. package/main.css +27 -3
  61. package/package.json +7 -7
package/dist/+types.d.ts CHANGED
@@ -81,7 +81,7 @@ export interface UseLyteNyteProps<T> {
81
81
  /**
82
82
  * The function predicate used to determine if a row should be rendered as full width.
83
83
  */
84
- readonly rowFullWidthPredicate?: RowFullWidthPredicate<T>;
84
+ readonly rowFullWidthPredicate?: RowFullWidthPredicate<T> | null;
85
85
  /**
86
86
  * The renderer used to render the content of a full width row.
87
87
  */
@@ -402,7 +402,7 @@ export interface GridState<T> {
402
402
  * full-width row. Full-width rows span across all columns and bypass standard cell layout.
403
403
  */
404
404
  readonly rowFullWidthPredicate: GridAtom<{
405
- fn: RowFullWidthPredicate<T>;
405
+ fn: RowFullWidthPredicate<T> | null;
406
406
  }>;
407
407
  /**
408
408
  * The component function that renders full-width rows in the grid. This renderer is called
@@ -983,6 +983,14 @@ export interface RowCellLayout<T> {
983
983
  * Number of rows this cell spans across.
984
984
  */
985
985
  readonly rowSpan: number;
986
+ /**
987
+ * Indicates if this cell is row spanned over and will not be rendered
988
+ */
989
+ readonly isDeadRow: boolean;
990
+ /**
991
+ * Indicates if this cell is column spanned over and will not be rendered
992
+ */
993
+ readonly isDeadCol: boolean;
986
994
  /**
987
995
  * A unique identifier that can be used for rendering keys or tracking elements.
988
996
  */
@@ -2701,7 +2709,7 @@ export type FieldRowGroup<T> = number | string | FieldPath | FieldRowGroupFn<T>;
2701
2709
  */
2702
2710
  export type Field<T> = number | string | FieldPath | FieldFn<T>;
2703
2711
  /**
2704
- * A function that returns a {@link ReactNode} representing the rendered content of a cell.
2712
+ * A function that returns a ReactNode representing the rendered content of a cell.
2705
2713
  *
2706
2714
  * This function is called once per cell for the associated column. Cell renderers should be
2707
2715
  * optimized for performance, as slow renderers may degrade the overall responsiveness of the grid.
@@ -2984,6 +2992,18 @@ export interface GridApi<T> {
2984
2992
  * This operation respects column group visibility and layout rules.
2985
2993
  */
2986
2994
  readonly columnMove: (params: ColumnMoveParams<T>) => void;
2995
+ /**
2996
+ * Returns the root cell for the provided row and column index. This may be:
2997
+ *
2998
+ * - A cell that is not covered by the row or column span of another cell, in this case the root cell
2999
+ * is the cell itself
3000
+ * - A cell that is covered by the row or column span of another cell, in this case the root cell is the
3001
+ * spanning cell
3002
+ * - A full width row, in this case the root cell is the row itself. Note that full width rows cannot be
3003
+ * spanned over, so it is not possible for a spanning cell to continue past a full width row, even if the
3004
+ * span amount would allow it
3005
+ */
3006
+ readonly cellRoot: (row: number, column: number) => PositionGridCell | PositionFullWidthRow | null;
2987
3007
  /**
2988
3008
  * Toggles the expansion state of one or more column groups.
2989
3009
  * You can also pass a boolean to directly set the expansion state.
@@ -4976,7 +4996,7 @@ export type DragPlaceholderFn<T> = (
4976
4996
  /**
4977
4997
  * Parameters for rendering the placeholder.
4978
4998
  */
4979
- params: DragPlaceholderParams<T>) => ReactNode;
4999
+ params: DragPlaceholderParams<T>) => HTMLElement;
4980
5000
  /**
4981
5001
  * Parameters passed when rendering the drag placeholder content.
4982
5002
  *
@@ -171,7 +171,7 @@ export function CellSelectionDriver() {
171
171
  event.preventDefault();
172
172
  }
173
173
  if (!isDeselect && grid.state.cellSelections.get().length <= 1)
174
- grid.internal.cellSelectionPivot.set(startSelection);
174
+ grid.internal.cellSelectionPivot.set({ ...startSelection, isUnit: true });
175
175
  grid.internal.cellSelectionIsDeselect.set(isDeselect);
176
176
  if (isAdditive) {
177
177
  updateAdditiveCellSelection(grid, startSelection);
@@ -180,7 +180,7 @@ export function CellSelectionDriver() {
180
180
  grid.state.cellSelections.set([startSelection]);
181
181
  }
182
182
  lastRect = startSelection;
183
- document.addEventListener("pointermove", pointerMove);
183
+ document.addEventListener("mousemove", pointerMove);
184
184
  document.addEventListener("contextmenu", pointerUp);
185
185
  document.addEventListener("pointerup", pointerUp);
186
186
  };
@@ -267,6 +267,7 @@ export function CellSelectionDriver() {
267
267
  rowEnd: focus.rowIndex + 1,
268
268
  columnStart: focus.colIndex,
269
269
  columnEnd: focus.colIndex + 1,
270
+ isUnit: true,
270
271
  });
271
272
  }
272
273
  });
@@ -1,6 +1,6 @@
1
- import type { DataRect } from "../+types";
1
+ import type { DataRectSplit } from "./split-cell-selection-rect";
2
2
  export declare function CellStyleRow({ rect, isRowPinnedTop, isDeselect, isRowPinnedBottom, isPivot, }: {
3
- rect: DataRect;
3
+ rect: DataRectSplit;
4
4
  isRowPinnedTop?: boolean;
5
5
  isDeselect?: boolean;
6
6
  isRowPinnedBottom?: boolean;
@@ -80,5 +80,5 @@ export function CellStyleRow({ rect, isRowPinnedTop, isDeselect, isRowPinnedBott
80
80
  xPositions,
81
81
  yPositions,
82
82
  ]);
83
- return (_jsx("div", { style: style, "data-ln-cell-selection-rect": true, "data-ln-cell-selection-is-deselect": isDeselect, "data-ln-cell-selection-is-pivot": isPivot }));
83
+ return (_jsx("div", { style: style, "data-ln-cell-selection-rect": true, "data-ln-cell-selection-is-deselect": isDeselect, "data-ln-cell-selection-is-pivot": isPivot, "data-ln-cell-selection-is-unit": rect.isUnit, "data-ln-cell-selection-border-top": rect.borderTop, "data-ln-cell-selection-border-bottom": rect.borderBottom, "data-ln-cell-selection-border-start": rect.borderStart, "data-ln-cell-selection-border-end": rect.borderEnd }));
84
84
  }
@@ -1,86 +1,6 @@
1
- import { getSpanFn } from "../state/helpers/get-span-callback.js";
2
- import { getFullWidthCallback } from "../state/helpers/get-full-width-callback.js";
3
- import { applyLayoutUpdate } from "@1771technologies/lytenyte-shared";
4
1
  export const getRootCell = (grid, rowIndex, columnIndex) => {
5
- const rds = grid.state.rowDataSource.get();
6
- const meta = grid.state.columnMeta.get();
7
- const columns = meta.columnsVisible;
8
- const rowScan = grid.state.rowScanDistance.get();
9
- const colScan = grid.state.colScanDistance.get();
10
- const fullWidth = grid.state.rowFullWidthPredicate.get().fn;
11
- const layoutMap = new Map();
12
- const topCount = grid.state.rowDataStore.rowTopCount.get();
13
- const botCount = grid.state.rowDataStore.rowBottomCount.get();
14
- const rowCenterCount = grid.state.rowDataStore.rowCenterCount.get();
15
- const isTop = rowIndex < topCount;
16
- const isBot = rowIndex >= topCount + rowCenterCount;
17
- const isStart = columns[columnIndex].pin === "start";
18
- const isEnd = columns[columnIndex].pin === "end";
19
- applyLayoutUpdate({
20
- computeColSpan: getSpanFn(rds, grid, columns, "col"),
21
- computeRowSpan: getSpanFn(rds, grid, columns, "row"),
22
- colScanDistance: colScan,
23
- rowScanDistance: rowScan,
24
- invalidated: true,
25
- isFullWidth: getFullWidthCallback(rds, fullWidth, grid),
26
- isRowCutoff: (r) => {
27
- const row = rds.rowByIndex(r);
28
- return !row || row.kind === "branch";
29
- },
30
- layoutMap,
31
- nextLayout: {
32
- rowTopStart: 0,
33
- rowTopEnd: topCount,
34
- rowBotStart: topCount + rowCenterCount,
35
- rowBotEnd: topCount + rowCenterCount + botCount,
36
- rowCenterStart: isTop || isBot ? 0 : rowIndex,
37
- rowCenterEnd: isTop || isBot ? 0 : rowIndex + 1,
38
- rowCenterLast: topCount + rowCenterCount,
39
- colStartStart: 0,
40
- colStartEnd: meta.columnVisibleStartCount,
41
- colEndStart: meta.columnVisibleStartCount + meta.columnVisibleCenterCount,
42
- colEndEnd: columns.length,
43
- colCenterStart: isStart || isEnd ? 0 : columnIndex,
44
- colCenterEnd: isStart || isEnd ? 0 : columnIndex + 1,
45
- colCenterLast: meta.columnVisibleStartCount + meta.columnVisibleCenterCount,
46
- },
47
- prevLayout: {
48
- colCenterEnd: -1,
49
- colCenterLast: -1,
50
- colCenterStart: -1,
51
- colEndEnd: -1,
52
- colEndStart: -1,
53
- colStartEnd: -1,
54
- colStartStart: -1,
55
- rowBotEnd: -1,
56
- rowBotStart: -1,
57
- rowCenterEnd: -1,
58
- rowCenterLast: -1,
59
- rowCenterStart: -1,
60
- rowTopEnd: -1,
61
- rowTopStart: -1,
62
- },
63
- });
64
- const row = layoutMap.get(rowIndex);
65
- const cell = row?.get(columnIndex);
66
- if (!cell)
2
+ const c = grid.api.cellRoot(rowIndex, columnIndex);
3
+ if (!c || c.kind === "full-width")
67
4
  return null;
68
- if (cell?.length === 2)
69
- return {
70
- colIndex: columnIndex,
71
- colSpan: 1,
72
- rowIndex: rowIndex,
73
- rowSpan: 1,
74
- };
75
- // Otherwise this is a spanning cell hence we need to find the spans layout.
76
- const root = layoutMap.get(cell[1]);
77
- const rootCell = root?.get(cell[2]);
78
- if (!rootCell)
79
- return null;
80
- return {
81
- colIndex: cell[2],
82
- rowIndex: cell[1],
83
- rowSpan: rootCell[0],
84
- colSpan: rootCell[1],
85
- };
5
+ return c.root;
86
6
  };
@@ -4,7 +4,6 @@ export { boundSelectionRect } from "./bound-selection-rect.js";
4
4
  export { fullWidthStartEndIndex } from "./full-width-start-end-index.js";
5
5
  export { areRectsEqual } from "./are-rects-equal.js";
6
6
  export { deselectRectRange } from "./deselect-rect-range.js";
7
- export { isOverlappingRect } from "./is-overlapping-rect.js";
8
7
  export { adjustRectForRowAndCellSpan } from "./adjust-rect-for-row-and-cell-span.js";
9
8
  export { updateAdditiveCellSelection } from "./update-additive-cell-selection.js";
10
9
  export { expandCellSelectionDown } from "./expand-cell-selection-down.js";
@@ -4,7 +4,6 @@ export { boundSelectionRect } from "./bound-selection-rect.js";
4
4
  export { fullWidthStartEndIndex } from "./full-width-start-end-index.js";
5
5
  export { areRectsEqual } from "./are-rects-equal.js";
6
6
  export { deselectRectRange } from "./deselect-rect-range.js";
7
- export { isOverlappingRect } from "./is-overlapping-rect.js";
8
7
  export { adjustRectForRowAndCellSpan } from "./adjust-rect-for-row-and-cell-span.js";
9
8
  export { updateAdditiveCellSelection } from "./update-additive-cell-selection.js";
10
9
  export { expandCellSelectionDown } from "./expand-cell-selection-down.js";
@@ -6,6 +6,13 @@ interface SplitCellSelectionRectArgs {
6
6
  readonly rowTopCount: number;
7
7
  readonly rowCenterCount: number;
8
8
  }
9
+ export interface DataRectSplit extends DataRect {
10
+ readonly isUnit: boolean;
11
+ readonly borderTop?: boolean;
12
+ readonly borderBottom?: boolean;
13
+ readonly borderStart?: boolean;
14
+ readonly borderEnd?: boolean;
15
+ }
9
16
  /**
10
17
  * Splits a cell selection rectangle into multiple rectangles when it crosses specified boundary regions.
11
18
  * This is useful for handling selections that span across different grid sections (e.g., fixed columns/rows,
@@ -35,5 +42,5 @@ interface SplitCellSelectionRectArgs {
35
42
  * @param rowCenterCount - Number of rows in the center (usually scrollable) section
36
43
  * @returns An array of split rectangles. If no splits were necessary, returns an array with just the original rectangle
37
44
  */
38
- export declare function splitCellSelectionRect({ rect, colStartCount, colCenterCount, rowTopCount, rowCenterCount, }: SplitCellSelectionRectArgs): DataRect[];
45
+ export declare function splitCellSelectionRect({ rect, colStartCount, colCenterCount, rowTopCount, rowCenterCount, }: SplitCellSelectionRectArgs): DataRectSplit[];
39
46
  export {};
@@ -31,6 +31,7 @@ export function splitCellSelectionRect({ rect, colStartCount, colCenterCount, ro
31
31
  // Calculate the boundary positions for columns
32
32
  const colStartBound = colStartCount;
33
33
  const colEndBound = colStartCount + colCenterCount;
34
+ const isUnit = rect.rowEnd - rect.rowStart === 1 && rect.columnEnd - rect.columnStart === 1;
34
35
  const colSplits = [];
35
36
  // Handle column splits first
36
37
  // Case 1: Selection starts before the fixed columns and extends into the scrollable area
@@ -38,6 +39,7 @@ export function splitCellSelectionRect({ rect, colStartCount, colCenterCount, ro
38
39
  const startSplit = {
39
40
  ...rect,
40
41
  columnEnd: colStartBound,
42
+ isUnit,
41
43
  };
42
44
  colSplits.push(startSplit);
43
45
  rect = { ...rect, columnStart: colStartBound };
@@ -47,12 +49,13 @@ export function splitCellSelectionRect({ rect, colStartCount, colCenterCount, ro
47
49
  const endSplit = {
48
50
  ...rect,
49
51
  columnStart: colEndBound,
52
+ isUnit,
50
53
  };
51
54
  rect = { ...rect, columnEnd: colEndBound };
52
55
  colSplits.push(endSplit);
53
56
  }
54
57
  // Add the remaining rectangle after column splits
55
- colSplits.push(rect);
58
+ colSplits.push({ ...rect, isUnit });
56
59
  // Calculate the boundary positions for rows
57
60
  const topBound = rowTopCount;
58
61
  const bottomBound = rowTopCount + rowCenterCount;
@@ -61,19 +64,25 @@ export function splitCellSelectionRect({ rect, colStartCount, colCenterCount, ro
61
64
  for (let split of colSplits) {
62
65
  // Case 1: Selection spans from top section into center section
63
66
  if (split.rowStart < topBound && split.rowEnd > topBound) {
64
- const topSplit = { ...split, rowEnd: topBound };
67
+ const topSplit = { ...split, rowEnd: topBound, isUnit };
65
68
  split = { ...split, rowStart: topBound };
66
69
  rowSplits.push(topSplit);
67
70
  }
68
71
  // Case 2: Selection spans from center section into bottom section
69
72
  if (split.rowStart < bottomBound && split.rowEnd > bottomBound) {
70
- const bottomSplit = { ...split, rowStart: bottomBound };
73
+ const bottomSplit = {
74
+ ...split,
75
+ rowStart: bottomBound,
76
+ isUnit,
77
+ };
71
78
  split = { ...split, rowEnd: bottomBound };
72
79
  rowSplits.push(bottomSplit);
73
80
  }
74
81
  rowSplits.push(split);
75
82
  }
76
- return rowSplits.sort((l, r) => {
83
+ return rowSplits
84
+ .map((c) => ({ ...c, borderTop: true, borderBottom: true, borderEnd: true, borderStart: true }))
85
+ .sort((l, r) => {
77
86
  return l.rowStart - r.rowStart || l.columnStart - r.columnStart;
78
87
  });
79
88
  }
@@ -0,0 +1,3 @@
1
+ import type { DataRect } from "../+types";
2
+ import type { DataRectSplit } from "./split-cell-selection-rect";
3
+ export declare function splitOnPivot(rect: DataRectSplit, pivot: DataRect): DataRectSplit[] | null;
@@ -0,0 +1,50 @@
1
+ import { areRectsEqual } from "./are-rects-equal";
2
+ export function splitOnPivot(rect, pivot) {
3
+ if (rect.isUnit || areRectsEqual(rect, pivot))
4
+ return null;
5
+ const splits = [];
6
+ const isAfter = pivot.columnStart > rect.columnStart;
7
+ const isSame = pivot.columnStart === rect.columnStart && pivot.columnEnd === rect.columnEnd;
8
+ // The pivot is on the right side of the rect. So we split by end
9
+ if (isAfter) {
10
+ const split = { ...rect, columnEnd: rect.columnEnd - 1, borderEnd: false };
11
+ if (split.columnStart !== split.columnEnd)
12
+ splits.push(split);
13
+ }
14
+ else {
15
+ const split = {
16
+ ...rect,
17
+ columnStart: rect.columnStart + 1,
18
+ borderStart: false,
19
+ };
20
+ if (split.columnStart !== split.columnEnd)
21
+ splits.push(split);
22
+ }
23
+ if (pivot.rowStart > rect.rowStart) {
24
+ const split = {
25
+ ...rect,
26
+ columnStart: pivot.columnStart,
27
+ columnEnd: pivot.columnEnd,
28
+ rowEnd: rect.rowEnd - 1,
29
+ borderBottom: false,
30
+ borderStart: !isAfter,
31
+ borderEnd: isSame || isAfter,
32
+ };
33
+ if (split.rowStart !== split.rowEnd)
34
+ splits.push(split);
35
+ }
36
+ else {
37
+ const split = {
38
+ ...rect,
39
+ columnStart: pivot.columnStart,
40
+ columnEnd: pivot.columnEnd,
41
+ rowStart: rect.rowStart + 1,
42
+ borderTop: false,
43
+ borderStart: !isAfter,
44
+ borderEnd: isSame || isAfter,
45
+ };
46
+ if (split.rowStart !== split.rowEnd)
47
+ splits.push(split);
48
+ }
49
+ return splits;
50
+ }
@@ -55,7 +55,7 @@ export function CellEditor({ cell }) {
55
55
  columnCount: grid.state.columnMeta.get().columnsVisible.length,
56
56
  focusActive: grid.internal.focusActive,
57
57
  id: grid.state.gridId.get(),
58
- layout: grid.internal.layout.get(),
58
+ getRootCell: grid.api.cellRoot,
59
59
  rtl: grid.state.rtl.get(),
60
60
  scrollIntoView: grid.api.scrollIntoView,
61
61
  });
@@ -0,0 +1,3 @@
1
+ export declare function CellSpacePinStart(): import("react/jsx-runtime").JSX.Element | null;
2
+ export declare function CellSpacerPinEnd(): import("react/jsx-runtime").JSX.Element | null;
3
+ export declare function CellSpacerNoPin(): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useGridRoot } from "../context";
3
+ export function CellSpacePinStart() {
4
+ const ctx = useGridRoot().grid;
5
+ const xPos = ctx.state.xPositions.useValue();
6
+ const bounds = ctx.state.viewBounds.useValue();
7
+ const offset = xPos[bounds.colCenterStart] - xPos[bounds.colStartEnd];
8
+ const meta = ctx.state.columnMeta.useValue();
9
+ if (meta.columnVisibleStartCount === 0)
10
+ return null;
11
+ return _jsx("div", { style: { display: "inline-block", width: offset, height: 0 } });
12
+ }
13
+ export function CellSpacerPinEnd() {
14
+ const ctx = useGridRoot().grid;
15
+ const xPos = ctx.state.xPositions.useValue();
16
+ const bounds = ctx.state.viewBounds.useValue();
17
+ const startOffset = xPos[bounds.colCenterEnd];
18
+ let offset = xPos[bounds.colEndStart] - startOffset;
19
+ const viewWidth = ctx.state.viewportWidthInner.useValue();
20
+ if (xPos.at(-1) < viewWidth) {
21
+ offset = viewWidth - xPos.at(-1);
22
+ }
23
+ const meta = ctx.state.columnMeta.useValue();
24
+ if (meta.columnVisibleEndCount === 0)
25
+ return null;
26
+ return _jsx("div", { style: { display: "inline-block", width: offset, height: 0 } });
27
+ }
28
+ export function CellSpacerNoPin() {
29
+ const ctx = useGridRoot().grid;
30
+ const xPos = ctx.state.xPositions.useValue();
31
+ const bounds = ctx.state.viewBounds.useValue();
32
+ const offset = xPos[bounds.colCenterStart - bounds.colStartEnd];
33
+ const meta = ctx.state.columnMeta.useValue();
34
+ if (meta.columnVisibleStartCount > 0)
35
+ return null;
36
+ return _jsx("div", { style: { display: "inline-block", width: offset, height: 0 } });
37
+ }
@@ -1,7 +1,5 @@
1
- import { type ReactNode } from "react";
2
- import type { CellRendererFn, RowCellLayout } from "../+types";
1
+ import type { RowCellLayout } from "../+types";
3
2
  export interface CellProps {
4
3
  readonly cell: RowCellLayout<any>;
5
- readonly children?: ReactNode | CellRendererFn<any>;
6
4
  }
7
5
  export declare const Cell: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "children"> & CellProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
@@ -1,19 +1,18 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { forwardRef, useEffect, useState } from "react";
3
- import { fastDeepMemo } from "@1771technologies/lytenyte-react-hooks";
4
3
  import { useGridRoot } from "../context";
5
- import { CellReact } from "@1771technologies/lytenyte-shared";
4
+ import { CellReact, sizeFromCoord } from "@1771technologies/lytenyte-shared";
6
5
  import { CellDefault } from "./cell-default";
7
6
  import { CellEditor } from "./cell-editor";
8
7
  import { useRowMeta } from "../rows/row/context";
9
- const CellImpl = forwardRef(function Cell({ cell, children, ...props }, forwarded) {
8
+ import { CellSpacePinStart, CellSpacerPinEnd } from "./cell-spacer";
9
+ export const Cell = forwardRef(function Cell({ cell, ...props }, forwarded) {
10
10
  const grid = useGridRoot().grid;
11
11
  const cx = grid.state;
12
- grid.internal.refreshKey.useValue();
13
12
  const base = grid.state.columnBase.useValue();
14
13
  const row = cell.row.useValue();
15
14
  const renderers = cx.cellRenderers.useValue();
16
- const providedRenderer = children ?? cell.column.cellRenderer ?? base.cellRenderer;
15
+ const providedRenderer = cell.column.cellRenderer ?? base.cellRenderer;
17
16
  const Renderer = providedRenderer
18
17
  ? typeof providedRenderer === "string"
19
18
  ? (renderers[providedRenderer] ?? CellDefault)
@@ -30,9 +29,12 @@ const CellImpl = forwardRef(function Cell({ cell, children, ...props }, forwarde
30
29
  pos.rowIndex < cell.rowIndex + cell.rowSpan);
31
30
  });
32
31
  }, [cell.column, cell.rowIndex, cell.rowSpan, grid.internal.editActivePos]);
32
+ const xPositions = cx.xPositions.useValue();
33
+ const yPositions = cx.yPositions.useValue();
33
34
  const rowMeta = useRowMeta();
34
- if (!row)
35
+ if (cell.isDeadRow)
36
+ return _jsx("div", { style: { width: sizeFromCoord(cell.colIndex, xPositions) } });
37
+ if (!row || cell.isDeadCol)
35
38
  return null;
36
- return (_jsxs(CellReact, { ...props, ref: forwarded, cell: cell, isEditing: isEditing, viewportWidth: cx.viewportWidthInner.useValue(), detailHeight: grid.api.rowDetailRenderedHeight(row ?? ""), rtl: cx.rtl.useValue(), xPosition: cx.xPositions.useValue(), yPosition: cx.yPositions.useValue(), children: [isEditing && _jsx(CellEditor, { cell: cell }), !isEditing && (_jsx(_Fragment, { children: typeof Renderer === "function" ? (_jsx(Renderer, { column: cell.column, rowSelected: rowMeta.selected, rowIndeterminate: rowMeta.indeterminate, row: row, grid: grid, rowIndex: cell.rowIndex, colIndex: cell.colIndex, rowPin: cell.rowPin })) : (Renderer) }))] }));
39
+ return (_jsxs(_Fragment, { children: [cell.colFirstEndPin && _jsx(CellSpacerPinEnd, {}), _jsxs(CellReact, { ...props, ref: forwarded, cell: cell, isEditing: isEditing, detailHeight: grid.api.rowDetailRenderedHeight(row ?? ""), rtl: cx.rtl.useValue(), xPosition: xPositions, yPosition: yPositions, children: [isEditing && _jsx(CellEditor, { cell: cell }), !isEditing && (_jsx(Renderer, { column: cell.column, rowSelected: rowMeta.selected, rowIndeterminate: rowMeta.indeterminate, row: row, grid: grid, rowIndex: cell.rowIndex, colIndex: cell.colIndex, rowPin: cell.rowPin }))] }), cell.colLastStartPin && _jsx(CellSpacePinStart, {})] }));
37
40
  });
38
- export const Cell = fastDeepMemo(CellImpl);
@@ -8,7 +8,7 @@ import { useColumnsFromContext } from "./use-columns-from-context";
8
8
  export const Branch = forwardRef(function Branch({ item, label, labelWrapClassName, labelWrapStyle, ...props }, forwarded) {
9
9
  const grid = useGrid();
10
10
  const id = grid.state.gridId.useValue();
11
- const accepted = `${id}/columns`;
11
+ const accepted = `${id}-columns`;
12
12
  const base = grid.state.columnBase.useValue();
13
13
  const columns = useColumnsFromContext(item);
14
14
  const isVisible = useMemo(() => {
@@ -11,7 +11,7 @@ export const Leaf = forwardRef(function ColumnManagerLeaf({ item, ...props }, fo
11
11
  }, [item]);
12
12
  const grid = useGrid();
13
13
  const id = grid.state.gridId.useValue();
14
- const accepted = `${id}/columns`;
14
+ const accepted = `${id}-columns`;
15
15
  const base = grid.state.columnBase.useValue();
16
16
  const columns = useColumnsFromContext(item);
17
17
  const isVisible = useMemo(() => {
@@ -1,12 +1,5 @@
1
1
  import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
2
- import { type ReactNode } from "react";
3
- import type { Column } from "../+types";
4
- import type { PathBranch, PathLeaf } from "@1771technologies/lytenyte-shared";
5
2
  export interface MoveHandleProps {
6
3
  readonly as?: SlotComponent;
7
- readonly placeholder?: (p: {
8
- columns: Column<any>[];
9
- item: PathBranch<Column<any>> | PathLeaf<Column<any>>;
10
- }) => ReactNode;
11
4
  }
12
5
  export declare const MoveHandle: import("react").ForwardRefExoticComponent<Omit<import("react").ClassAttributes<HTMLDivElement> & import("react").HTMLAttributes<HTMLDivElement> & MoveHandleProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
@@ -5,7 +5,7 @@ import { forwardRef, useMemo } from "react";
5
5
  import { useColumnItemContext } from "./context";
6
6
  import { useColumnsFromContext } from "./use-columns-from-context";
7
7
  import { useGrid } from "../grid-provider/use-grid";
8
- export const MoveHandle = forwardRef(function MoveHandle({ as, placeholder: Placeholder, ...props }, forwarded) {
8
+ export const MoveHandle = forwardRef(function MoveHandle({ as, ...props }, forwarded) {
9
9
  const item = useColumnItemContext().item;
10
10
  const grid = useGrid();
11
11
  const columns = useColumnsFromContext(item);
@@ -15,9 +15,19 @@ export const MoveHandle = forwardRef(function MoveHandle({ as, placeholder: Plac
15
15
  }, [base.uiHints?.movable, columns]);
16
16
  const { dragProps: { ref, ...otherProps }, } = useDraggable({
17
17
  getItems: () => {
18
+ const gridId = grid.state.gridId.get();
19
+ const isGroupable = columns.length === 1 && (columns[0].uiHints?.rowGroupable ?? base.uiHints?.rowGroupable);
20
+ if (isGroupable) {
21
+ return {
22
+ siteLocalData: {
23
+ [`${gridId}-columns`]: columns,
24
+ [`${gridId}-group`]: columns[0].id,
25
+ },
26
+ };
27
+ }
18
28
  return {
19
29
  siteLocalData: {
20
- [`${grid.state.gridId.get()}/columns`]: columns,
30
+ [`${gridId}-columns`]: columns,
21
31
  },
22
32
  };
23
33
  },
@@ -39,10 +49,17 @@ export const MoveHandle = forwardRef(function MoveHandle({ as, placeholder: Plac
39
49
  before: isBefore,
40
50
  });
41
51
  },
42
- placeholder: () => {
43
- if (Placeholder)
44
- return _jsx(Placeholder, { columns: columns, item: item });
45
- return (_jsx("div", { children: item.kind === "branch" ? item.data.joinPath.at(-1) : (item.data.name ?? item.data.id) }));
52
+ placeholder: (_, el) => {
53
+ let current = el;
54
+ while (current &&
55
+ !current.getAttribute("data-ln-column-manager-leaf") &&
56
+ !current.getAttribute("data-ln-tree-branch")) {
57
+ current = current.parentElement;
58
+ }
59
+ if (current)
60
+ return current;
61
+ else
62
+ return el;
46
63
  },
47
64
  });
48
65
  const combined = useCombinedRefs(ref, forwarded);
@@ -6,7 +6,9 @@ import { useTreeItem } from "./hooks/use-tree-item";
6
6
  export const Leaf = forwardRef(function Leaf({ item, ...props }, forwarded) {
7
7
  const value = useTreeItem(item);
8
8
  return (_jsx(FilterTreeItemContext.Provider, { value: value, children: _jsx(TreeLeaf, { ...props, itemId: item.leaf.data.id, ref: forwarded, ...item.attrs, style: { ...props.style, ...item.attrs.style }, onClick: () => value.onCheckChange(), onKeyDown: (ev) => {
9
- if (ev.key === " ")
9
+ if (ev.key === " ") {
10
+ ev.preventDefault();
10
11
  value.onCheckChange();
12
+ }
11
13
  } }) }));
12
14
  });
@@ -1,4 +1,3 @@
1
- import type { ReactNode } from "react";
2
1
  import type { DropEventParams } from "../+types.js";
3
2
  export interface GridBoxItem<T = any> {
4
3
  readonly id: string;
@@ -6,10 +5,11 @@ export interface GridBoxItem<T = any> {
6
5
  readonly data: T;
7
6
  readonly dragData: Record<string, any>;
8
7
  readonly draggable: boolean;
9
- readonly dragPlaceholder?: () => ReactNode;
8
+ readonly dragPlaceholder?: (el: HTMLElement) => HTMLElement;
10
9
  readonly onDrop: (p: DropEventParams) => void;
11
10
  readonly onAction: (el: HTMLElement) => void;
12
11
  readonly onDelete: (el: HTMLElement) => void;
13
12
  readonly index: number;
14
13
  readonly source: string;
14
+ readonly active?: boolean;
15
15
  }
@@ -12,7 +12,7 @@ export const BoxItem = forwardRef(function BoxItem({ item, itemAs, itemClassName
12
12
  siteLocalData: item.dragData,
13
13
  };
14
14
  },
15
- placeholder: item.dragPlaceholder,
15
+ placeholder: item.dragPlaceholder ? (_, el) => item.dragPlaceholder(el) : undefined,
16
16
  });
17
17
  const ref = useCombinedRefs(forwarded, dragProps.ref);
18
18
  const extraProps = item.draggable ? { ...dragProps, ref } : { ref: forwarded };
@@ -31,7 +31,7 @@ export const BoxItem = forwardRef(function BoxItem({ item, itemAs, itemClassName
31
31
  ],
32
32
  slot: itemAs ?? _jsx("div", {}),
33
33
  });
34
- return (_jsx(DropWrap, { ...props, onEnter: (e) => {
34
+ return (_jsx(DropWrap, { ...props, active: item.active, onEnter: (e) => {
35
35
  const data = dragState.active.get();
36
36
  const thisSource = e.getAttribute("data-ln-source");
37
37
  const dragSource = data?.getAttribute("data-ln-source");
@@ -54,7 +54,7 @@ export const BoxItem = forwardRef(function BoxItem({ item, itemAs, itemClassName
54
54
  }, onLeave: (el) => {
55
55
  el.removeAttribute("data-ln-is-before");
56
56
  el.removeAttribute("data-ln-is-after");
57
- }, "data-ln-source": item.source, "data-ln-index": item.index, accepted: accepted, onDrop: (e) => {
57
+ }, "data-ln-source": item.source, "data-ln-index": item.index, accepted: item.active === false ? [] : accepted, onDrop: (e) => {
58
58
  const el = e.dropElement;
59
59
  el.removeAttribute("data-ln-is-before");
60
60
  el.removeAttribute("data-ln-is-after");
@@ -7,7 +7,6 @@ export function useAggregationBoxItems({ grid, orientation }) {
7
7
  const items = Object.entries(model).map(([id, agg], i) => {
8
8
  const column = grid.api.columnById(id);
9
9
  const name = column?.name ?? column?.id ?? id;
10
- const fn = typeof agg.fn === "string" ? agg.fn : "Fn(x)";
11
10
  return {
12
11
  draggable: false,
13
12
  id,
@@ -15,7 +14,7 @@ export function useAggregationBoxItems({ grid, orientation }) {
15
14
  source: "aggregation",
16
15
  data: { id, agg },
17
16
  dragData: {},
18
- label: `${name} ${fn}`,
17
+ label: name,
19
18
  onAction: () => { },
20
19
  onDelete: () => {
21
20
  grid.state.aggModel.set((prev) => {