@ai-matrx/design-system 0.22.0 → 0.25.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 (93) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/dist/data-table/cell-undo.cjs +98 -0
  3. package/dist/data-table/cell-undo.cjs.map +1 -0
  4. package/dist/data-table/cell-undo.d.cts +85 -0
  5. package/dist/data-table/cell-undo.d.ts +85 -0
  6. package/dist/data-table/cell-undo.js +78 -0
  7. package/dist/data-table/cell-undo.js.map +1 -0
  8. package/dist/data-table/copy-helpers.d.cts +6 -2
  9. package/dist/data-table/copy-helpers.d.ts +6 -2
  10. package/dist/data-table/coverage.cjs +116 -0
  11. package/dist/data-table/coverage.cjs.map +1 -0
  12. package/dist/data-table/coverage.d.cts +65 -0
  13. package/dist/data-table/coverage.d.ts +65 -0
  14. package/dist/data-table/coverage.js +96 -0
  15. package/dist/data-table/coverage.js.map +1 -0
  16. package/dist/data-table/fill.cjs +299 -0
  17. package/dist/data-table/fill.cjs.map +1 -0
  18. package/dist/data-table/fill.d.cts +129 -0
  19. package/dist/data-table/fill.d.ts +129 -0
  20. package/dist/data-table/fill.js +277 -0
  21. package/dist/data-table/fill.js.map +1 -0
  22. package/dist/data-table/filter-engine.d.cts +6 -2
  23. package/dist/data-table/filter-engine.d.ts +6 -2
  24. package/dist/data-table/grid-clipboard.cjs +165 -0
  25. package/dist/data-table/grid-clipboard.cjs.map +1 -0
  26. package/dist/data-table/grid-clipboard.d.cts +85 -0
  27. package/dist/data-table/grid-clipboard.d.ts +85 -0
  28. package/dist/data-table/grid-clipboard.js +145 -0
  29. package/dist/data-table/grid-clipboard.js.map +1 -0
  30. package/dist/data-table/grid-selection.cjs +258 -0
  31. package/dist/data-table/grid-selection.cjs.map +1 -0
  32. package/dist/data-table/grid-selection.d.cts +166 -0
  33. package/dist/data-table/grid-selection.d.ts +166 -0
  34. package/dist/data-table/grid-selection.js +238 -0
  35. package/dist/data-table/grid-selection.js.map +1 -0
  36. package/dist/data-table/grouping.cjs +302 -0
  37. package/dist/data-table/grouping.cjs.map +1 -0
  38. package/dist/data-table/grouping.d.cts +119 -0
  39. package/dist/data-table/grouping.d.ts +119 -0
  40. package/dist/data-table/grouping.js +282 -0
  41. package/dist/data-table/grouping.js.map +1 -0
  42. package/dist/data-table/host.d.cts +6 -2
  43. package/dist/data-table/host.d.ts +6 -2
  44. package/dist/data-table/index.cjs +2433 -246
  45. package/dist/data-table/index.cjs.map +1 -1
  46. package/dist/data-table/index.d.cts +11 -3
  47. package/dist/data-table/index.d.ts +11 -3
  48. package/dist/data-table/index.js +2425 -238
  49. package/dist/data-table/index.js.map +1 -1
  50. package/dist/data-table/infer-filter.d.cts +6 -2
  51. package/dist/data-table/infer-filter.d.ts +6 -2
  52. package/dist/data-table/layered-filters.d.cts +6 -2
  53. package/dist/data-table/layered-filters.d.ts +6 -2
  54. package/dist/data-table/query-control.d.cts +6 -2
  55. package/dist/data-table/query-control.d.ts +6 -2
  56. package/dist/data-table/spreadsheet.cjs +1014 -0
  57. package/dist/data-table/spreadsheet.cjs.map +1 -0
  58. package/dist/data-table/spreadsheet.d.cts +118 -0
  59. package/dist/data-table/spreadsheet.d.ts +118 -0
  60. package/dist/data-table/spreadsheet.js +994 -0
  61. package/dist/data-table/spreadsheet.js.map +1 -0
  62. package/dist/data-table/types.cjs.map +1 -1
  63. package/dist/data-table/types.d.cts +6 -2
  64. package/dist/data-table/types.d.ts +6 -2
  65. package/dist/data-table/url-state.d.cts +6 -2
  66. package/dist/data-table/url-state.d.ts +6 -2
  67. package/dist/data-table/validation.cjs +229 -0
  68. package/dist/data-table/validation.cjs.map +1 -0
  69. package/dist/data-table/validation.d.cts +125 -0
  70. package/dist/data-table/validation.d.ts +125 -0
  71. package/dist/data-table/validation.js +209 -0
  72. package/dist/data-table/validation.js.map +1 -0
  73. package/dist/data-table/virtual-window.cjs +203 -0
  74. package/dist/data-table/virtual-window.cjs.map +1 -0
  75. package/dist/data-table/virtual-window.d.cts +84 -0
  76. package/dist/data-table/virtual-window.d.ts +84 -0
  77. package/dist/data-table/virtual-window.js +183 -0
  78. package/dist/data-table/virtual-window.js.map +1 -0
  79. package/dist/data-table/xlsx.d.cts +6 -2
  80. package/dist/data-table/xlsx.d.ts +6 -2
  81. package/dist/field-formats/index.d.cts +2 -2
  82. package/dist/field-formats/index.d.ts +2 -2
  83. package/dist/formulas/index.cjs +1041 -0
  84. package/dist/formulas/index.cjs.map +1 -0
  85. package/dist/formulas/index.d.cts +389 -0
  86. package/dist/formulas/index.d.ts +389 -0
  87. package/dist/formulas/index.js +1019 -0
  88. package/dist/formulas/index.js.map +1 -0
  89. package/dist/{types-BdbvlF9-.d.cts → types-CJWU1Gae.d.cts} +1 -1
  90. package/dist/{types-BdbvlF9-.d.ts → types-CJWU1Gae.d.ts} +1 -1
  91. package/dist/{types-Sn249eoy.d.cts → types-CmQrOz-T.d.cts} +154 -2
  92. package/dist/{types-D-flTpK0.d.ts → types-nlLCMiqd.d.ts} +154 -2
  93. package/package.json +109 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,156 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.25.0 — 2026-09-20
4
+
5
+ **Five defects a real browser found that jsdom could not, and the table's own
6
+ stress page so the next one is found the same way.**
7
+
8
+ Every clause in the component suite was green while all five of these were
9
+ live. They are claims about SCROLLING, about a POINTER, and about what a person
10
+ READS — none of which jsdom has. `demo/` is now where a real browser does that
11
+ work: a hundred thousand rows with grouping, the spreadsheet gestures, the
12
+ coverage sentence and the horizontal window on at once.
13
+
14
+ - **The fill handle dragged and filled nothing.** Two `mouseup` listeners on
15
+ `window`; the one that only cleared the drag flag was registered first, so by
16
+ the time the one that commits the fill ran, there was no drag in progress.
17
+ One handler now reads the flag and then clears it. Proven by a real pointer:
18
+ four cells filled, `"Filled 4 cells down 1 column."`
19
+ - **The scroll re-rendered the whole table on every event.** The window was
20
+ derived from a scroll offset held in state, so a four-thousand-line component
21
+ ran on every scroll whether or not one different row would be drawn: 38ms a
22
+ frame while scrolling EIGHT PIXELS, against the 16.7ms floor the same browser
23
+ hits on a static forty-row table. The scroll handler computes the window off
24
+ the DOM and sets state only when the rendered range actually moves.
25
+ - **The first paint drew every row**, because the window settled in an effect
26
+ and an effect runs after the first render. Render now derives a window when
27
+ state has none, and when a stale one no longer fits the row count.
28
+ - **`bodyEntries` built the whole list before windowing it**, allocating a
29
+ hundred thousand objects per scroll to render forty rows. It slices first.
30
+ - **`cellProps` used `indexOf` per cell** — O(rows) per cell, twenty-four
31
+ million comparisons a frame at 100,000 rows. Index maps.
32
+ - **The sticky header sat UNDER the frozen column.** A frozen body cell is
33
+ `z-20` so it can slide under the columns to its right; the header was `z-10`,
34
+ so the frozen column's cells scrolled over the header they belong to and the
35
+ top data row printed through the column names. Only a table long enough to
36
+ scroll shows it.
37
+ - **`rowHeight` did nothing unless virtualization was engaged** — so a view that
38
+ remembered a row height was ignored on every table short enough to read. It
39
+ applies on its own now, with a clause that pins it.
40
+ - **A group header said its subtotals twice** — once in the label line and again
41
+ in each column's cell — and the cell version was left-aligned under a
42
+ right-aligned money column. The label carries the count; the columns carry
43
+ the subtotals, each aligned with the numbers it totals.
44
+
45
+ Measured on the production demo build, 1440x900 headless Chromium, 100,000 rows:
46
+ **19 of the 40 rendered rows in the document, a 3.3-million-pixel scroll height,
47
+ 18.6ms median frame and 23.6ms at the 95th percentile**, zero console errors.
48
+
49
+ ## 0.24.0 — 2026-09-20
50
+
51
+ **The window goes sideways too.**
52
+
53
+ 0.23.0 windowed the rows. A table can also be forty rows and three hundred
54
+ columns, and that one put every column in the document. `virtualize.columns`
55
+ closes it: the frozen leading run is ALWAYS drawn — a frozen identity column
56
+ that scrolled out of the DOM would leave the table blank exactly when somebody
57
+ scrolled far enough to need it — and a spacer cell on either side of the window
58
+ carries the width of what was left out, in the header, every body row, every
59
+ group header and the footer, so the table is as wide as it says it is.
60
+
61
+ - It engages only past **30** non-frozen columns and only when the consumer
62
+ asks for it, so nothing in the product changes shape today.
63
+ - A windowed column takes a FIXED width, and that is not a style choice: if the
64
+ drawn columns sized themselves to their content while the spacers claimed a
65
+ declared width, the horizontal scroll position would stop agreeing with the
66
+ window index and a person scrolling to column 80 would be shown column 74.
67
+ - Every `colSpan` in the body now counts what is RENDERED, not what is
68
+ declared — a full-width row spanning the declared count would push itself
69
+ wider than its own header.
70
+
71
+ Guard: three clauses in `MatrxDataTable.gaps.test.tsx`, including
72
+ `padStart + drawn + padEnd === the rest of the table`; the red twin fails
73
+ 12/12 without the props.
74
+
75
+ ## 0.23.1 — 2026-09-20
76
+
77
+ **Ticking a row no longer moves the row under your cursor.**
78
+
79
+ Defect N11, the thirteenth cold walk of the Masterwork pipeline (blocking). Measured on a
80
+ catalogued media Library at 1440x900: before the first click the header checkbox sat at `y 580`
81
+ and rows 1-3 at `y 606 / 647 / 688`; the instant a row's checkbox was ticked the selection bar was
82
+ inserted into the flow ABOVE the table and everything moved down **86px** — two full row heights,
83
+ header checkbox to `y 666`, rows 1-3 to `y 692 / 733 / 774`. The cursor had not moved and was now
84
+ resting on the SELECT-ALL box, so a second click at the same point selected 25 of 2,981 rows. The
85
+ walker hit it twice before he thought to measure it, which is how we know a real person hits it.
86
+ Picking three rows out of a long list meant re-measuring the table between every click.
87
+
88
+ - **The selection bar is now the last child of the body region** — under the rows and under the
89
+ pagination, instead of wedged between the toolbar and the first row. The rows live in a `flex-1`
90
+ box; a flex child appended after `flex-1` can only take height from the bottom of that box and
91
+ cannot change where it STARTS, so no row can move down. It is also where the best in the world
92
+ put it: Gmail, Linear and Airtable all keep the selection bar at the bottom of the list.
93
+ - **The bar carries `data-matrx-table-bulk-bar`**, so a test or a host can address it by what it
94
+ is rather than by where it happens to fall in a flat DOM query.
95
+ - Guard: `MatrxDataTable.selection-never-shifts-rows.test.tsx`, five cases, three of which go red
96
+ the moment the block is moved back above `data-matrx-table-body-region`.
97
+
98
+ **Consumer action:** none. No API changed. Every surface that hands `MatrxDataTable` a `selection`
99
+ inherits the fix. One caveat for test authors: a test that reached the selection bar's copy menu
100
+ as `getAllByRole("button", { name: /Copy, transform or export/ })[1]` was relying on the bar
101
+ rendering above the rows; address it through `[data-matrx-table-bulk-bar]` instead (this
102
+ package's own `default-copy-regressions.test.tsx` was updated the same way).
103
+
104
+ ## 0.23.0 — 2026-09-20
105
+
106
+ **The three gaps are closed in the primitive, and the spreadsheet half of `/data` now lives here.**
107
+
108
+ The owner's read of the `/data` grid named three things it could not do that Airtable, Google
109
+ Sheets and Notion all can — and named the third one a lie on screen. All three are answered in
110
+ the shared table, so every surface in the product inherits them instead of the one route that
111
+ asked.
112
+
113
+ - **`grouping`** — "group these rows by Status" with collapsible sections, a count, and a
114
+ per-column subtotal ON its own column, not crammed into a banner. Controlled for the two pieces
115
+ of state a person expects to survive (which column groups, which sections are shut), so a saved
116
+ view carries them like any other reading of the table. A blank value is its own named section
117
+ and sorts last: a section of unanswered rows is not the first thing a person wants to read. The
118
+ model is `./grouping.ts` — pure, with eleven aggregate kinds, every one of which LABELS itself
119
+ ("Sum 4,812.5", "12 filled") and says `Sum —` rather than `0` when it has nothing to add up.
120
+ - **`virtualize`** — render the rows a person can see. Off by default; on, it engages only past
121
+ its own threshold (150 rows), so short tables behave exactly as they did. Two spacer rows stand
122
+ in for the height of what the window left out, and the invariant `padStart + rendered + padEnd
123
+ === total` is asserted over a spread of inputs, because a scrollbar that describes the slice
124
+ instead of the table is its own lie. `./virtual-window.ts` also has the variable-height and
125
+ scroll-to-index math, prefix-summed and binary-searched: O(log n) per scroll, not O(n).
126
+ - **`coverage`** — THE HONEST COUNT. Declare what the current answer actually covers and the
127
+ table says so, in plain English, above the rows: *"This filter searched the first 5,000 rows
128
+ only. 84,312 rows in this table; the rest were not looked at."* A complete answer says nothing.
129
+ A partial count is never presented as exact. The sentences are asserted to contain none of
130
+ "cap", "limit", "fetch", "query", "client" or "source" — a person reading a screen is not
131
+ reading our vocabulary.
132
+ - **`MatrxDataTableProps.rowHeight`** — an explicit body row height, for a view that remembers one.
133
+
134
+ New entry points carrying the rest of the `/data` grid's reusable half, each pure and tested:
135
+
136
+ - **`@ai-matrx/design-system/formulas`** — the 28-function expression language for computed
137
+ columns, moved out of the app verbatim. No `eval`, nothing throws, every failure is an
138
+ `ok: false` with a sentence.
139
+ - **`@ai-matrx/design-system/data-table/grid-selection`** and **`/grid-clipboard`** — the range
140
+ model (shift-click, drag, keyboard, row/column/all) and real Excel/Sheets TSV.
141
+ - **`@ai-matrx/design-system/data-table/fill`** — fill-down and the drag fill handle, with series
142
+ detection: `1, 2` continues to `3, 4, 5`, a single value copies, an inconsistent run copies. A
143
+ column that cannot take a write produces a skip with a sentence, never a silent drop.
144
+ - **`@ai-matrx/design-system/data-table/cell-undo`** — the bounded, PURE undo/redo stack behind
145
+ cell edits.
146
+ - **`@ai-matrx/design-system/data-table/validation`** — the column validation model, so a refusal
147
+ is the same sentence everywhere.
148
+
149
+ One defect this work turned up and fixed in passing: an optional config field named `valueOf` is
150
+ never absent, because every object in JavaScript already has one — `config.valueOf ? … : …` called
151
+ `Object.prototype.valueOf` and grouped every row under the config object itself. The field is
152
+ `readCell` now, in both the config and the model.
153
+
3
154
  ## 0.22.0 — 2026-09-20
4
155
 
5
156
  **The data table can paint, format and freeze — so every table in the product can.**
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/data-table/cell-undo.ts
21
+ var cell_undo_exports = {};
22
+ __export(cell_undo_exports, {
23
+ DEFAULT_UNDO_DEPTH: () => DEFAULT_UNDO_DEPTH,
24
+ canRedo: () => canRedo,
25
+ canUndo: () => canUndo,
26
+ createUndoStack: () => createUndoStack,
27
+ popRedo: () => popRedo,
28
+ popUndo: () => popUndo,
29
+ pushUndo: () => pushUndo,
30
+ undoEntryFor: () => undoEntryFor
31
+ });
32
+ module.exports = __toCommonJS(cell_undo_exports);
33
+ var DEFAULT_UNDO_DEPTH = 100;
34
+ function createUndoStack(depth = DEFAULT_UNDO_DEPTH) {
35
+ const bounded = Number.isFinite(depth) && depth > 0 ? Math.floor(depth) : 0;
36
+ return { past: [], future: [], depth: bounded };
37
+ }
38
+ function pushUndo(stack, entry) {
39
+ if (stack.depth <= 0) {
40
+ return { past: [], future: [], depth: stack.depth };
41
+ }
42
+ const past = [...stack.past, entry];
43
+ while (past.length > stack.depth) past.shift();
44
+ return { past, future: [], depth: stack.depth };
45
+ }
46
+ function popUndo(stack) {
47
+ const entry = stack.past[stack.past.length - 1];
48
+ if (entry === void 0) return { stack, entry: null };
49
+ return {
50
+ stack: {
51
+ past: stack.past.slice(0, -1),
52
+ future: [...stack.future, entry],
53
+ depth: stack.depth
54
+ },
55
+ entry
56
+ };
57
+ }
58
+ function popRedo(stack) {
59
+ const entry = stack.future[stack.future.length - 1];
60
+ if (entry === void 0) return { stack, entry: null };
61
+ const past = [...stack.past, entry];
62
+ while (past.length > stack.depth) past.shift();
63
+ return {
64
+ stack: { past, future: stack.future.slice(0, -1), depth: stack.depth },
65
+ entry
66
+ };
67
+ }
68
+ function keyOf(patch) {
69
+ return JSON.stringify([patch.rowId, patch.columnId]);
70
+ }
71
+ function undoEntryFor(before, after, label) {
72
+ const priors = /* @__PURE__ */ new Map();
73
+ for (const patch of before) priors.set(keyOf(patch), patch);
74
+ const undo = after.map((patch) => {
75
+ const prior = priors.get(keyOf(patch));
76
+ return {
77
+ rowId: patch.rowId,
78
+ columnId: patch.columnId,
79
+ value: prior ? prior.value : null
80
+ };
81
+ });
82
+ return {
83
+ label,
84
+ undo,
85
+ redo: after.map((patch) => ({
86
+ rowId: patch.rowId,
87
+ columnId: patch.columnId,
88
+ value: patch.value
89
+ }))
90
+ };
91
+ }
92
+ function canUndo(stack) {
93
+ return stack.depth > 0 && stack.past.length > 0;
94
+ }
95
+ function canRedo(stack) {
96
+ return stack.depth > 0 && stack.future.length > 0;
97
+ }
98
+ //# sourceMappingURL=cell-undo.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/data-table/cell-undo.ts"],"sourcesContent":["/**\n * THE CELL UNDO STACK — the model behind Cmd-Z in a grid.\n *\n * WHY IT SHIPS WITH EASY EDITING, NOT AFTER IT. Lowering the friction to change\n * data raises the rate of accidental change: a click toggles a boolean, a bare\n * keystroke starts an edit, Delete empties a cell, and one drag of the fill\n * handle rewrites a column. Every one of those is a good affordance ONLY if the\n * floor underneath it is recoverable.\n *\n * WHAT THIS FILE IS. A bounded, PURE stack of reversible edits: no React, no\n * network, no toasts. The app's `useCellUndo` hook owned all three plus the\n * stack, which meant the stack's rules — depth, the redo contract, what an undo\n * of an added row means — could only be exercised by mounting a component and\n * mocking a database. Those rules are spreadsheet law, not app trivia, so they\n * belong in a module anyone can test in a millisecond and any client can reuse.\n *\n * WHY IT IS PATCHES, NOT CELL COORDINATES. An entry carries the patches that\n * undo it and the patches that redo it, captured BEFORE the write and never\n * derived after it: re-reading a cell later to discover what to restore races\n * with realtime and with agent writes, and would happily \"undo\" to a value\n * somebody else just set. Patches also make the entry shape indifferent to WHAT\n * changed — one cell, a filled column, or the cells of a row that was added or\n * deleted — which is how row and column operations join the same Cmd-Z the user\n * already trusts instead of living outside it.\n *\n * PURITY IS THE POINT. Every function returns a NEW stack and never mutates the\n * one it was handed, so the stack can live in React state, in a store, or in a\n * ref without the \"my undo history changed under me\" class of bug.\n */\n\nimport type { CellPatch } from \"./fill\";\n\nexport type { CellPatch };\n\nexport interface UndoEntry {\n /** What the user did, in plain English, for the toast: \"Undid the change to Day rate.\" */\n label: string;\n /** The patches that UNDO it. */\n undo: CellPatch[];\n /** The patches that REDO it. */\n redo: CellPatch[];\n}\n\nexport interface UndoStack {\n past: UndoEntry[];\n future: UndoEntry[];\n depth: number;\n}\n\n/**\n * How many steps back we remember. Deliberately generous — the cost is a few\n * kilobytes of session memory, and the failure mode of a too-short stack is a\n * user discovering their mistake is unrecoverable.\n */\nexport const DEFAULT_UNDO_DEPTH = 100;\n\nexport function createUndoStack(depth: number = DEFAULT_UNDO_DEPTH): UndoStack {\n const bounded = Number.isFinite(depth) && depth > 0 ? Math.floor(depth) : 0;\n return { past: [], future: [], depth: bounded };\n}\n\n/**\n * Record an edit that already happened.\n *\n * Pushing CLEARS the redo future — the standard editor contract: you cannot\n * redo into a future you have just diverged from. Past `depth`, the OLDEST\n * entry is dropped, so the stack is bounded memory rather than a leak.\n */\nexport function pushUndo(stack: UndoStack, entry: UndoEntry): UndoStack {\n if (stack.depth <= 0) {\n // Undo is off. Pushing keeps the stack empty rather than silently growing\n // a history nothing will ever read.\n return { past: [], future: [], depth: stack.depth };\n }\n const past = [...stack.past, entry];\n while (past.length > stack.depth) past.shift();\n return { past, future: [], depth: stack.depth };\n}\n\nexport function popUndo(stack: UndoStack): { stack: UndoStack; entry: UndoEntry | null } {\n const entry = stack.past[stack.past.length - 1];\n if (entry === undefined) return { stack, entry: null };\n return {\n stack: {\n past: stack.past.slice(0, -1),\n future: [...stack.future, entry],\n depth: stack.depth,\n },\n entry,\n };\n}\n\nexport function popRedo(stack: UndoStack): { stack: UndoStack; entry: UndoEntry | null } {\n const entry = stack.future[stack.future.length - 1];\n if (entry === undefined) return { stack, entry: null };\n const past = [...stack.past, entry];\n while (past.length > stack.depth) past.shift();\n return {\n stack: { past, future: stack.future.slice(0, -1), depth: stack.depth },\n entry,\n };\n}\n\nfunction keyOf(patch: CellPatch): string {\n // JSON, not a separator character: a row id or column id containing whatever\n // separator we picked would collide two different cells into one key, and the\n // undo would restore the wrong one.\n return JSON.stringify([patch.rowId, patch.columnId]);\n}\n\n/**\n * Build an entry from a before/after pair, so a caller never assembles one by\n * hand — hand-assembled inverses are how an undo ends up restoring the wrong\n * cell.\n *\n * An after-patch with NO matching before is still undoable: its undo sets the\n * value back to `null`. That is the added-row case — a cell that did not exist\n * before the change has no prior value, and \"undo\" for it means empty, not\n * \"leave whatever is there\".\n */\nexport function undoEntryFor(\n before: CellPatch[],\n after: CellPatch[],\n label: string,\n): UndoEntry {\n const priors = new Map<string, CellPatch>();\n for (const patch of before) priors.set(keyOf(patch), patch);\n\n const undo: CellPatch[] = after.map((patch) => {\n const prior = priors.get(keyOf(patch));\n return {\n rowId: patch.rowId,\n columnId: patch.columnId,\n value: prior ? prior.value : null,\n };\n });\n\n return {\n label,\n undo,\n redo: after.map((patch) => ({\n rowId: patch.rowId,\n columnId: patch.columnId,\n value: patch.value,\n })),\n };\n}\n\n/** True when there is a step to take back. */\nexport function canUndo(stack: UndoStack): boolean {\n return stack.depth > 0 && stack.past.length > 0;\n}\n\n/** True when there is a step to reapply. */\nexport function canRedo(stack: UndoStack): boolean {\n return stack.depth > 0 && stack.future.length > 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsDO,IAAM,qBAAqB;AAE3B,SAAS,gBAAgB,QAAgB,oBAA+B;AAC7E,QAAM,UAAU,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,KAAK,MAAM,KAAK,IAAI;AAC1E,SAAO,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,OAAO,QAAQ;AAChD;AASO,SAAS,SAAS,OAAkB,OAA6B;AACtE,MAAI,MAAM,SAAS,GAAG;AAGpB,WAAO,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,OAAO,MAAM,MAAM;AAAA,EACpD;AACA,QAAM,OAAO,CAAC,GAAG,MAAM,MAAM,KAAK;AAClC,SAAO,KAAK,SAAS,MAAM,MAAO,MAAK,MAAM;AAC7C,SAAO,EAAE,MAAM,QAAQ,CAAC,GAAG,OAAO,MAAM,MAAM;AAChD;AAEO,SAAS,QAAQ,OAAiE;AACvF,QAAM,QAAQ,MAAM,KAAK,MAAM,KAAK,SAAS,CAAC;AAC9C,MAAI,UAAU,OAAW,QAAO,EAAE,OAAO,OAAO,KAAK;AACrD,SAAO;AAAA,IACL,OAAO;AAAA,MACL,MAAM,MAAM,KAAK,MAAM,GAAG,EAAE;AAAA,MAC5B,QAAQ,CAAC,GAAG,MAAM,QAAQ,KAAK;AAAA,MAC/B,OAAO,MAAM;AAAA,IACf;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,QAAQ,OAAiE;AACvF,QAAM,QAAQ,MAAM,OAAO,MAAM,OAAO,SAAS,CAAC;AAClD,MAAI,UAAU,OAAW,QAAO,EAAE,OAAO,OAAO,KAAK;AACrD,QAAM,OAAO,CAAC,GAAG,MAAM,MAAM,KAAK;AAClC,SAAO,KAAK,SAAS,MAAM,MAAO,MAAK,MAAM;AAC7C,SAAO;AAAA,IACL,OAAO,EAAE,MAAM,QAAQ,MAAM,OAAO,MAAM,GAAG,EAAE,GAAG,OAAO,MAAM,MAAM;AAAA,IACrE;AAAA,EACF;AACF;AAEA,SAAS,MAAM,OAA0B;AAIvC,SAAO,KAAK,UAAU,CAAC,MAAM,OAAO,MAAM,QAAQ,CAAC;AACrD;AAYO,SAAS,aACd,QACA,OACA,OACW;AACX,QAAM,SAAS,oBAAI,IAAuB;AAC1C,aAAW,SAAS,OAAQ,QAAO,IAAI,MAAM,KAAK,GAAG,KAAK;AAE1D,QAAM,OAAoB,MAAM,IAAI,CAAC,UAAU;AAC7C,UAAM,QAAQ,OAAO,IAAI,MAAM,KAAK,CAAC;AACrC,WAAO;AAAA,MACL,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,OAAO,QAAQ,MAAM,QAAQ;AAAA,IAC/B;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM,MAAM,IAAI,CAAC,WAAW;AAAA,MAC1B,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,IACf,EAAE;AAAA,EACJ;AACF;AAGO,SAAS,QAAQ,OAA2B;AACjD,SAAO,MAAM,QAAQ,KAAK,MAAM,KAAK,SAAS;AAChD;AAGO,SAAS,QAAQ,OAA2B;AACjD,SAAO,MAAM,QAAQ,KAAK,MAAM,OAAO,SAAS;AAClD;","names":[]}
@@ -0,0 +1,85 @@
1
+ import { CellPatch } from './fill.cjs';
2
+
3
+ /**
4
+ * THE CELL UNDO STACK — the model behind Cmd-Z in a grid.
5
+ *
6
+ * WHY IT SHIPS WITH EASY EDITING, NOT AFTER IT. Lowering the friction to change
7
+ * data raises the rate of accidental change: a click toggles a boolean, a bare
8
+ * keystroke starts an edit, Delete empties a cell, and one drag of the fill
9
+ * handle rewrites a column. Every one of those is a good affordance ONLY if the
10
+ * floor underneath it is recoverable.
11
+ *
12
+ * WHAT THIS FILE IS. A bounded, PURE stack of reversible edits: no React, no
13
+ * network, no toasts. The app's `useCellUndo` hook owned all three plus the
14
+ * stack, which meant the stack's rules — depth, the redo contract, what an undo
15
+ * of an added row means — could only be exercised by mounting a component and
16
+ * mocking a database. Those rules are spreadsheet law, not app trivia, so they
17
+ * belong in a module anyone can test in a millisecond and any client can reuse.
18
+ *
19
+ * WHY IT IS PATCHES, NOT CELL COORDINATES. An entry carries the patches that
20
+ * undo it and the patches that redo it, captured BEFORE the write and never
21
+ * derived after it: re-reading a cell later to discover what to restore races
22
+ * with realtime and with agent writes, and would happily "undo" to a value
23
+ * somebody else just set. Patches also make the entry shape indifferent to WHAT
24
+ * changed — one cell, a filled column, or the cells of a row that was added or
25
+ * deleted — which is how row and column operations join the same Cmd-Z the user
26
+ * already trusts instead of living outside it.
27
+ *
28
+ * PURITY IS THE POINT. Every function returns a NEW stack and never mutates the
29
+ * one it was handed, so the stack can live in React state, in a store, or in a
30
+ * ref without the "my undo history changed under me" class of bug.
31
+ */
32
+
33
+ interface UndoEntry {
34
+ /** What the user did, in plain English, for the toast: "Undid the change to Day rate." */
35
+ label: string;
36
+ /** The patches that UNDO it. */
37
+ undo: CellPatch[];
38
+ /** The patches that REDO it. */
39
+ redo: CellPatch[];
40
+ }
41
+ interface UndoStack {
42
+ past: UndoEntry[];
43
+ future: UndoEntry[];
44
+ depth: number;
45
+ }
46
+ /**
47
+ * How many steps back we remember. Deliberately generous — the cost is a few
48
+ * kilobytes of session memory, and the failure mode of a too-short stack is a
49
+ * user discovering their mistake is unrecoverable.
50
+ */
51
+ declare const DEFAULT_UNDO_DEPTH = 100;
52
+ declare function createUndoStack(depth?: number): UndoStack;
53
+ /**
54
+ * Record an edit that already happened.
55
+ *
56
+ * Pushing CLEARS the redo future — the standard editor contract: you cannot
57
+ * redo into a future you have just diverged from. Past `depth`, the OLDEST
58
+ * entry is dropped, so the stack is bounded memory rather than a leak.
59
+ */
60
+ declare function pushUndo(stack: UndoStack, entry: UndoEntry): UndoStack;
61
+ declare function popUndo(stack: UndoStack): {
62
+ stack: UndoStack;
63
+ entry: UndoEntry | null;
64
+ };
65
+ declare function popRedo(stack: UndoStack): {
66
+ stack: UndoStack;
67
+ entry: UndoEntry | null;
68
+ };
69
+ /**
70
+ * Build an entry from a before/after pair, so a caller never assembles one by
71
+ * hand — hand-assembled inverses are how an undo ends up restoring the wrong
72
+ * cell.
73
+ *
74
+ * An after-patch with NO matching before is still undoable: its undo sets the
75
+ * value back to `null`. That is the added-row case — a cell that did not exist
76
+ * before the change has no prior value, and "undo" for it means empty, not
77
+ * "leave whatever is there".
78
+ */
79
+ declare function undoEntryFor(before: CellPatch[], after: CellPatch[], label: string): UndoEntry;
80
+ /** True when there is a step to take back. */
81
+ declare function canUndo(stack: UndoStack): boolean;
82
+ /** True when there is a step to reapply. */
83
+ declare function canRedo(stack: UndoStack): boolean;
84
+
85
+ export { CellPatch, DEFAULT_UNDO_DEPTH, type UndoEntry, type UndoStack, canRedo, canUndo, createUndoStack, popRedo, popUndo, pushUndo, undoEntryFor };
@@ -0,0 +1,85 @@
1
+ import { CellPatch } from './fill.js';
2
+
3
+ /**
4
+ * THE CELL UNDO STACK — the model behind Cmd-Z in a grid.
5
+ *
6
+ * WHY IT SHIPS WITH EASY EDITING, NOT AFTER IT. Lowering the friction to change
7
+ * data raises the rate of accidental change: a click toggles a boolean, a bare
8
+ * keystroke starts an edit, Delete empties a cell, and one drag of the fill
9
+ * handle rewrites a column. Every one of those is a good affordance ONLY if the
10
+ * floor underneath it is recoverable.
11
+ *
12
+ * WHAT THIS FILE IS. A bounded, PURE stack of reversible edits: no React, no
13
+ * network, no toasts. The app's `useCellUndo` hook owned all three plus the
14
+ * stack, which meant the stack's rules — depth, the redo contract, what an undo
15
+ * of an added row means — could only be exercised by mounting a component and
16
+ * mocking a database. Those rules are spreadsheet law, not app trivia, so they
17
+ * belong in a module anyone can test in a millisecond and any client can reuse.
18
+ *
19
+ * WHY IT IS PATCHES, NOT CELL COORDINATES. An entry carries the patches that
20
+ * undo it and the patches that redo it, captured BEFORE the write and never
21
+ * derived after it: re-reading a cell later to discover what to restore races
22
+ * with realtime and with agent writes, and would happily "undo" to a value
23
+ * somebody else just set. Patches also make the entry shape indifferent to WHAT
24
+ * changed — one cell, a filled column, or the cells of a row that was added or
25
+ * deleted — which is how row and column operations join the same Cmd-Z the user
26
+ * already trusts instead of living outside it.
27
+ *
28
+ * PURITY IS THE POINT. Every function returns a NEW stack and never mutates the
29
+ * one it was handed, so the stack can live in React state, in a store, or in a
30
+ * ref without the "my undo history changed under me" class of bug.
31
+ */
32
+
33
+ interface UndoEntry {
34
+ /** What the user did, in plain English, for the toast: "Undid the change to Day rate." */
35
+ label: string;
36
+ /** The patches that UNDO it. */
37
+ undo: CellPatch[];
38
+ /** The patches that REDO it. */
39
+ redo: CellPatch[];
40
+ }
41
+ interface UndoStack {
42
+ past: UndoEntry[];
43
+ future: UndoEntry[];
44
+ depth: number;
45
+ }
46
+ /**
47
+ * How many steps back we remember. Deliberately generous — the cost is a few
48
+ * kilobytes of session memory, and the failure mode of a too-short stack is a
49
+ * user discovering their mistake is unrecoverable.
50
+ */
51
+ declare const DEFAULT_UNDO_DEPTH = 100;
52
+ declare function createUndoStack(depth?: number): UndoStack;
53
+ /**
54
+ * Record an edit that already happened.
55
+ *
56
+ * Pushing CLEARS the redo future — the standard editor contract: you cannot
57
+ * redo into a future you have just diverged from. Past `depth`, the OLDEST
58
+ * entry is dropped, so the stack is bounded memory rather than a leak.
59
+ */
60
+ declare function pushUndo(stack: UndoStack, entry: UndoEntry): UndoStack;
61
+ declare function popUndo(stack: UndoStack): {
62
+ stack: UndoStack;
63
+ entry: UndoEntry | null;
64
+ };
65
+ declare function popRedo(stack: UndoStack): {
66
+ stack: UndoStack;
67
+ entry: UndoEntry | null;
68
+ };
69
+ /**
70
+ * Build an entry from a before/after pair, so a caller never assembles one by
71
+ * hand — hand-assembled inverses are how an undo ends up restoring the wrong
72
+ * cell.
73
+ *
74
+ * An after-patch with NO matching before is still undoable: its undo sets the
75
+ * value back to `null`. That is the added-row case — a cell that did not exist
76
+ * before the change has no prior value, and "undo" for it means empty, not
77
+ * "leave whatever is there".
78
+ */
79
+ declare function undoEntryFor(before: CellPatch[], after: CellPatch[], label: string): UndoEntry;
80
+ /** True when there is a step to take back. */
81
+ declare function canUndo(stack: UndoStack): boolean;
82
+ /** True when there is a step to reapply. */
83
+ declare function canRedo(stack: UndoStack): boolean;
84
+
85
+ export { CellPatch, DEFAULT_UNDO_DEPTH, type UndoEntry, type UndoStack, canRedo, canUndo, createUndoStack, popRedo, popUndo, pushUndo, undoEntryFor };
@@ -0,0 +1,78 @@
1
+
2
+ // src/data-table/cell-undo.ts
3
+ var DEFAULT_UNDO_DEPTH = 100;
4
+ function createUndoStack(depth = DEFAULT_UNDO_DEPTH) {
5
+ const bounded = Number.isFinite(depth) && depth > 0 ? Math.floor(depth) : 0;
6
+ return { past: [], future: [], depth: bounded };
7
+ }
8
+ function pushUndo(stack, entry) {
9
+ if (stack.depth <= 0) {
10
+ return { past: [], future: [], depth: stack.depth };
11
+ }
12
+ const past = [...stack.past, entry];
13
+ while (past.length > stack.depth) past.shift();
14
+ return { past, future: [], depth: stack.depth };
15
+ }
16
+ function popUndo(stack) {
17
+ const entry = stack.past[stack.past.length - 1];
18
+ if (entry === void 0) return { stack, entry: null };
19
+ return {
20
+ stack: {
21
+ past: stack.past.slice(0, -1),
22
+ future: [...stack.future, entry],
23
+ depth: stack.depth
24
+ },
25
+ entry
26
+ };
27
+ }
28
+ function popRedo(stack) {
29
+ const entry = stack.future[stack.future.length - 1];
30
+ if (entry === void 0) return { stack, entry: null };
31
+ const past = [...stack.past, entry];
32
+ while (past.length > stack.depth) past.shift();
33
+ return {
34
+ stack: { past, future: stack.future.slice(0, -1), depth: stack.depth },
35
+ entry
36
+ };
37
+ }
38
+ function keyOf(patch) {
39
+ return JSON.stringify([patch.rowId, patch.columnId]);
40
+ }
41
+ function undoEntryFor(before, after, label) {
42
+ const priors = /* @__PURE__ */ new Map();
43
+ for (const patch of before) priors.set(keyOf(patch), patch);
44
+ const undo = after.map((patch) => {
45
+ const prior = priors.get(keyOf(patch));
46
+ return {
47
+ rowId: patch.rowId,
48
+ columnId: patch.columnId,
49
+ value: prior ? prior.value : null
50
+ };
51
+ });
52
+ return {
53
+ label,
54
+ undo,
55
+ redo: after.map((patch) => ({
56
+ rowId: patch.rowId,
57
+ columnId: patch.columnId,
58
+ value: patch.value
59
+ }))
60
+ };
61
+ }
62
+ function canUndo(stack) {
63
+ return stack.depth > 0 && stack.past.length > 0;
64
+ }
65
+ function canRedo(stack) {
66
+ return stack.depth > 0 && stack.future.length > 0;
67
+ }
68
+ export {
69
+ DEFAULT_UNDO_DEPTH,
70
+ canRedo,
71
+ canUndo,
72
+ createUndoStack,
73
+ popRedo,
74
+ popUndo,
75
+ pushUndo,
76
+ undoEntryFor
77
+ };
78
+ //# sourceMappingURL=cell-undo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/data-table/cell-undo.ts"],"sourcesContent":["/**\n * THE CELL UNDO STACK — the model behind Cmd-Z in a grid.\n *\n * WHY IT SHIPS WITH EASY EDITING, NOT AFTER IT. Lowering the friction to change\n * data raises the rate of accidental change: a click toggles a boolean, a bare\n * keystroke starts an edit, Delete empties a cell, and one drag of the fill\n * handle rewrites a column. Every one of those is a good affordance ONLY if the\n * floor underneath it is recoverable.\n *\n * WHAT THIS FILE IS. A bounded, PURE stack of reversible edits: no React, no\n * network, no toasts. The app's `useCellUndo` hook owned all three plus the\n * stack, which meant the stack's rules — depth, the redo contract, what an undo\n * of an added row means — could only be exercised by mounting a component and\n * mocking a database. Those rules are spreadsheet law, not app trivia, so they\n * belong in a module anyone can test in a millisecond and any client can reuse.\n *\n * WHY IT IS PATCHES, NOT CELL COORDINATES. An entry carries the patches that\n * undo it and the patches that redo it, captured BEFORE the write and never\n * derived after it: re-reading a cell later to discover what to restore races\n * with realtime and with agent writes, and would happily \"undo\" to a value\n * somebody else just set. Patches also make the entry shape indifferent to WHAT\n * changed — one cell, a filled column, or the cells of a row that was added or\n * deleted — which is how row and column operations join the same Cmd-Z the user\n * already trusts instead of living outside it.\n *\n * PURITY IS THE POINT. Every function returns a NEW stack and never mutates the\n * one it was handed, so the stack can live in React state, in a store, or in a\n * ref without the \"my undo history changed under me\" class of bug.\n */\n\nimport type { CellPatch } from \"./fill\";\n\nexport type { CellPatch };\n\nexport interface UndoEntry {\n /** What the user did, in plain English, for the toast: \"Undid the change to Day rate.\" */\n label: string;\n /** The patches that UNDO it. */\n undo: CellPatch[];\n /** The patches that REDO it. */\n redo: CellPatch[];\n}\n\nexport interface UndoStack {\n past: UndoEntry[];\n future: UndoEntry[];\n depth: number;\n}\n\n/**\n * How many steps back we remember. Deliberately generous — the cost is a few\n * kilobytes of session memory, and the failure mode of a too-short stack is a\n * user discovering their mistake is unrecoverable.\n */\nexport const DEFAULT_UNDO_DEPTH = 100;\n\nexport function createUndoStack(depth: number = DEFAULT_UNDO_DEPTH): UndoStack {\n const bounded = Number.isFinite(depth) && depth > 0 ? Math.floor(depth) : 0;\n return { past: [], future: [], depth: bounded };\n}\n\n/**\n * Record an edit that already happened.\n *\n * Pushing CLEARS the redo future — the standard editor contract: you cannot\n * redo into a future you have just diverged from. Past `depth`, the OLDEST\n * entry is dropped, so the stack is bounded memory rather than a leak.\n */\nexport function pushUndo(stack: UndoStack, entry: UndoEntry): UndoStack {\n if (stack.depth <= 0) {\n // Undo is off. Pushing keeps the stack empty rather than silently growing\n // a history nothing will ever read.\n return { past: [], future: [], depth: stack.depth };\n }\n const past = [...stack.past, entry];\n while (past.length > stack.depth) past.shift();\n return { past, future: [], depth: stack.depth };\n}\n\nexport function popUndo(stack: UndoStack): { stack: UndoStack; entry: UndoEntry | null } {\n const entry = stack.past[stack.past.length - 1];\n if (entry === undefined) return { stack, entry: null };\n return {\n stack: {\n past: stack.past.slice(0, -1),\n future: [...stack.future, entry],\n depth: stack.depth,\n },\n entry,\n };\n}\n\nexport function popRedo(stack: UndoStack): { stack: UndoStack; entry: UndoEntry | null } {\n const entry = stack.future[stack.future.length - 1];\n if (entry === undefined) return { stack, entry: null };\n const past = [...stack.past, entry];\n while (past.length > stack.depth) past.shift();\n return {\n stack: { past, future: stack.future.slice(0, -1), depth: stack.depth },\n entry,\n };\n}\n\nfunction keyOf(patch: CellPatch): string {\n // JSON, not a separator character: a row id or column id containing whatever\n // separator we picked would collide two different cells into one key, and the\n // undo would restore the wrong one.\n return JSON.stringify([patch.rowId, patch.columnId]);\n}\n\n/**\n * Build an entry from a before/after pair, so a caller never assembles one by\n * hand — hand-assembled inverses are how an undo ends up restoring the wrong\n * cell.\n *\n * An after-patch with NO matching before is still undoable: its undo sets the\n * value back to `null`. That is the added-row case — a cell that did not exist\n * before the change has no prior value, and \"undo\" for it means empty, not\n * \"leave whatever is there\".\n */\nexport function undoEntryFor(\n before: CellPatch[],\n after: CellPatch[],\n label: string,\n): UndoEntry {\n const priors = new Map<string, CellPatch>();\n for (const patch of before) priors.set(keyOf(patch), patch);\n\n const undo: CellPatch[] = after.map((patch) => {\n const prior = priors.get(keyOf(patch));\n return {\n rowId: patch.rowId,\n columnId: patch.columnId,\n value: prior ? prior.value : null,\n };\n });\n\n return {\n label,\n undo,\n redo: after.map((patch) => ({\n rowId: patch.rowId,\n columnId: patch.columnId,\n value: patch.value,\n })),\n };\n}\n\n/** True when there is a step to take back. */\nexport function canUndo(stack: UndoStack): boolean {\n return stack.depth > 0 && stack.past.length > 0;\n}\n\n/** True when there is a step to reapply. */\nexport function canRedo(stack: UndoStack): boolean {\n return stack.depth > 0 && stack.future.length > 0;\n}\n"],"mappings":";;AAsDO,IAAM,qBAAqB;AAE3B,SAAS,gBAAgB,QAAgB,oBAA+B;AAC7E,QAAM,UAAU,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,KAAK,MAAM,KAAK,IAAI;AAC1E,SAAO,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,OAAO,QAAQ;AAChD;AASO,SAAS,SAAS,OAAkB,OAA6B;AACtE,MAAI,MAAM,SAAS,GAAG;AAGpB,WAAO,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,OAAO,MAAM,MAAM;AAAA,EACpD;AACA,QAAM,OAAO,CAAC,GAAG,MAAM,MAAM,KAAK;AAClC,SAAO,KAAK,SAAS,MAAM,MAAO,MAAK,MAAM;AAC7C,SAAO,EAAE,MAAM,QAAQ,CAAC,GAAG,OAAO,MAAM,MAAM;AAChD;AAEO,SAAS,QAAQ,OAAiE;AACvF,QAAM,QAAQ,MAAM,KAAK,MAAM,KAAK,SAAS,CAAC;AAC9C,MAAI,UAAU,OAAW,QAAO,EAAE,OAAO,OAAO,KAAK;AACrD,SAAO;AAAA,IACL,OAAO;AAAA,MACL,MAAM,MAAM,KAAK,MAAM,GAAG,EAAE;AAAA,MAC5B,QAAQ,CAAC,GAAG,MAAM,QAAQ,KAAK;AAAA,MAC/B,OAAO,MAAM;AAAA,IACf;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,QAAQ,OAAiE;AACvF,QAAM,QAAQ,MAAM,OAAO,MAAM,OAAO,SAAS,CAAC;AAClD,MAAI,UAAU,OAAW,QAAO,EAAE,OAAO,OAAO,KAAK;AACrD,QAAM,OAAO,CAAC,GAAG,MAAM,MAAM,KAAK;AAClC,SAAO,KAAK,SAAS,MAAM,MAAO,MAAK,MAAM;AAC7C,SAAO;AAAA,IACL,OAAO,EAAE,MAAM,QAAQ,MAAM,OAAO,MAAM,GAAG,EAAE,GAAG,OAAO,MAAM,MAAM;AAAA,IACrE;AAAA,EACF;AACF;AAEA,SAAS,MAAM,OAA0B;AAIvC,SAAO,KAAK,UAAU,CAAC,MAAM,OAAO,MAAM,QAAQ,CAAC;AACrD;AAYO,SAAS,aACd,QACA,OACA,OACW;AACX,QAAM,SAAS,oBAAI,IAAuB;AAC1C,aAAW,SAAS,OAAQ,QAAO,IAAI,MAAM,KAAK,GAAG,KAAK;AAE1D,QAAM,OAAoB,MAAM,IAAI,CAAC,UAAU;AAC7C,UAAM,QAAQ,OAAO,IAAI,MAAM,KAAK,CAAC;AACrC,WAAO;AAAA,MACL,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,OAAO,QAAQ,MAAM,QAAQ;AAAA,IAC/B;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM,MAAM,IAAI,CAAC,WAAW;AAAA,MAC1B,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,IACf,EAAE;AAAA,EACJ;AACF;AAGO,SAAS,QAAQ,OAA2B;AACjD,SAAO,MAAM,QAAQ,KAAK,MAAM,KAAK,SAAS;AAChD;AAGO,SAAS,QAAQ,OAA2B;AACjD,SAAO,MAAM,QAAQ,KAAK,MAAM,OAAO,SAAS;AAClD;","names":[]}
@@ -1,10 +1,14 @@
1
1
  import { AgentPayloadInput } from './copy-types.cjs';
2
- import { g as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-Sn249eoy.cjs';
2
+ import { g as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-CmQrOz-T.cjs';
3
3
  import '../content-transfer.cjs';
4
4
  import 'react';
5
5
  import '@ai-matrx/kit/content-transfer';
6
6
  import '../content-transfer/icon.cjs';
7
- import '../types-BdbvlF9-.cjs';
7
+ import '../types-CJWU1Gae.cjs';
8
+ import './grouping.cjs';
9
+ import './fill.cjs';
10
+ import './spreadsheet.cjs';
11
+ import './grid-selection.cjs';
8
12
 
9
13
  /**
10
14
  * Typed, declared-column capture for MatrxDataTable's built-in Alchemy source.
@@ -1,10 +1,14 @@
1
1
  import { AgentPayloadInput } from './copy-types.js';
2
- import { g as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-D-flTpK0.js';
2
+ import { g as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-nlLCMiqd.js';
3
3
  import '../content-transfer.js';
4
4
  import 'react';
5
5
  import '@ai-matrx/kit/content-transfer';
6
6
  import '../content-transfer/icon.js';
7
- import '../types-BdbvlF9-.js';
7
+ import '../types-CJWU1Gae.js';
8
+ import './grouping.js';
9
+ import './fill.js';
10
+ import './spreadsheet.js';
11
+ import './grid-selection.js';
8
12
 
9
13
  /**
10
14
  * Typed, declared-column capture for MatrxDataTable's built-in Alchemy source.