@ai-matrx/design-system 0.28.0 → 0.31.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 (39) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/dist/data-table/copy-helpers.d.cts +1 -1
  3. package/dist/data-table/copy-helpers.d.ts +1 -1
  4. package/dist/data-table/filter-engine.d.cts +1 -1
  5. package/dist/data-table/filter-engine.d.ts +1 -1
  6. package/dist/data-table/host.d.cts +1 -1
  7. package/dist/data-table/host.d.ts +1 -1
  8. package/dist/data-table/index.cjs +39 -7
  9. package/dist/data-table/index.cjs.map +1 -1
  10. package/dist/data-table/index.d.cts +3 -3
  11. package/dist/data-table/index.d.ts +3 -3
  12. package/dist/data-table/index.js +39 -7
  13. package/dist/data-table/index.js.map +1 -1
  14. package/dist/data-table/infer-filter.d.cts +1 -1
  15. package/dist/data-table/infer-filter.d.ts +1 -1
  16. package/dist/data-table/layered-filters.d.cts +1 -1
  17. package/dist/data-table/layered-filters.d.ts +1 -1
  18. package/dist/data-table/query-control.d.cts +1 -1
  19. package/dist/data-table/query-control.d.ts +1 -1
  20. package/dist/data-table/spreadsheet.cjs +37 -6
  21. package/dist/data-table/spreadsheet.cjs.map +1 -1
  22. package/dist/data-table/spreadsheet.d.cts +46 -1
  23. package/dist/data-table/spreadsheet.d.ts +46 -1
  24. package/dist/data-table/spreadsheet.js +37 -6
  25. package/dist/data-table/spreadsheet.js.map +1 -1
  26. package/dist/data-table/types.cjs.map +1 -1
  27. package/dist/data-table/types.d.cts +2 -2
  28. package/dist/data-table/types.d.ts +2 -2
  29. package/dist/data-table/url-state.d.cts +1 -1
  30. package/dist/data-table/url-state.d.ts +1 -1
  31. package/dist/data-table/xlsx.d.cts +1 -1
  32. package/dist/data-table/xlsx.d.ts +1 -1
  33. package/dist/index.cjs +8 -4
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.js +8 -4
  36. package/dist/index.js.map +1 -1
  37. package/dist/{types-D9JBR6ZU.d.ts → types-CFmCZXVn.d.ts} +24 -1
  38. package/dist/{types-jQddSUnj.d.cts → types-CYkwg9jR.d.cts} +24 -1
  39. package/package.json +1 -1
@@ -33,6 +33,46 @@ import { CellPatch } from './fill.js';
33
33
 
34
34
  /** What a set of cell patches was for, so a consumer can label its own toast. */
35
35
  type SpreadsheetIntent = "paste" | "fill" | "fill-down" | "undo" | "redo" | "clear";
36
+ /** One cell a paste did not write, with the sentence that says why. */
37
+ interface PasteRefusal {
38
+ /** Null when the cell belongs to no row on the grid. */
39
+ rowId: string | null;
40
+ columnId: string;
41
+ reason: string;
42
+ /**
43
+ * WHAT WAS REFUSED, kept rather than dropped.
44
+ *
45
+ * Without it a consumer showing a person their fifty pasted rows can say a
46
+ * cell was skipped but not WHICH one or what was in it — measured on Rincon
47
+ * Plumbing's September billing run, 2026-09-21: every refusal on an existing
48
+ * record read "Row 0, amount_due" because the value never reached the code
49
+ * that knew the line and the column's name. A refusal nobody can locate is
50
+ * only half a refusal.
51
+ */
52
+ value?: unknown;
53
+ }
54
+ /**
55
+ * What a paste WOULD do, handed over before any of it happens.
56
+ *
57
+ * Addresses are (rowId, columnId) like everywhere else in the grid, never
58
+ * indices — a row filtered out between the copy and the paste is not a row.
59
+ */
60
+ interface SpreadsheetPastePlan {
61
+ /** The cells that would be written, already screened by `validateCell`. */
62
+ accepted: CellPatch[];
63
+ /** Cells `validateCell` or `writableColumnIds` turned away, each with its sentence. */
64
+ refusals: PasteRefusal[];
65
+ /**
66
+ * Rows of the pasted block that fell past the last row of the grid, in the
67
+ * grid's current column order (so a hidden or reordered column is honoured).
68
+ * Each entry maps a columnId to the raw clipboard text for that cell.
69
+ */
70
+ overflow: Array<Record<string, string>>;
71
+ /** Cells that fell past the RIGHT edge — there is no column to hold them. */
72
+ pastRightEdge: number;
73
+ /** Write `accepted` through `onPatch`, exactly as an unconfirmed paste would. */
74
+ apply: () => Promise<void>;
75
+ }
36
76
  interface SpreadsheetGridOptions {
37
77
  /** Row ids currently rendered, in visual order. */
38
78
  rowIds: readonly string[];
@@ -54,6 +94,11 @@ interface SpreadsheetGridOptions {
54
94
  paste?: boolean | undefined;
55
95
  /** Says what just happened, and why something did not. */
56
96
  notify?: ((message: string) => void) | undefined;
97
+ /**
98
+ * Hand the whole paste over instead of applying it. See
99
+ * `MatrxDataTableSpreadsheetConfig.onPastePlan` for why this exists.
100
+ */
101
+ onPastePlan?: ((plan: SpreadsheetPastePlan) => void) | undefined;
57
102
  /**
58
103
  * OPEN THE EDITOR on the focused cell. Return true when the editor actually
59
104
  * opened, so the keystroke is consumed; return false and the key is left to
@@ -150,4 +195,4 @@ interface SpreadsheetClipboardEvent {
150
195
  declare const NOTHING: CellPatch[];
151
196
  declare function useSpreadsheetGrid(options: SpreadsheetGridOptions | null): SpreadsheetGrid;
152
197
 
153
- export { NOTHING as NO_PATCHES, type SpreadsheetCellProps, type SpreadsheetClipboardEvent, type SpreadsheetGrid, type SpreadsheetGridOptions, type SpreadsheetIntent, type SpreadsheetKeyEvent, useSpreadsheetGrid };
198
+ export { NOTHING as NO_PATCHES, type PasteRefusal, type SpreadsheetCellProps, type SpreadsheetClipboardEvent, type SpreadsheetGrid, type SpreadsheetGridOptions, type SpreadsheetIntent, type SpreadsheetKeyEvent, type SpreadsheetPastePlan, useSpreadsheetGrid };
@@ -657,7 +657,7 @@ function useSpreadsheetGrid(options) {
657
657
  } catch {
658
658
  reason = void 0;
659
659
  }
660
- if (reason) refusals.push({ columnId: patch.columnId, reason });
660
+ if (reason) refusals.push({ rowId: patch.rowId, columnId: patch.columnId, reason, value: patch.value });
661
661
  else accepted.push(patch);
662
662
  }
663
663
  return { accepted, refusals };
@@ -736,6 +736,7 @@ function useSpreadsheetGrid(options) {
736
736
  if (rowId === void 0 || columnId === void 0) continue;
737
737
  if (!current.isColumnWritable(columnId)) {
738
738
  skipped.push({
739
+ rowId,
739
740
  columnId,
740
741
  reason: current.columnRefusal?.(columnId) ?? `${columnId} cannot be cleared.`
741
742
  });
@@ -899,18 +900,33 @@ function useSpreadsheetGrid(options) {
899
900
  if (startRow === -1 || startCol === -1) return;
900
901
  const patches = [];
901
902
  const skipped = [];
902
- let outside = 0;
903
+ let pastRightEdge = 0;
904
+ const overflow = [];
903
905
  for (let r = 0; r < block.length; r += 1) {
904
906
  const line = block[r] ?? [];
907
+ const rowId = rowIds[startRow + r];
908
+ if (rowId === void 0) {
909
+ const beyond = {};
910
+ for (let c = 0; c < line.length; c += 1) {
911
+ const columnId = columnIds[startCol + c];
912
+ if (columnId === void 0) {
913
+ pastRightEdge += 1;
914
+ continue;
915
+ }
916
+ beyond[columnId] = line[c] ?? "";
917
+ }
918
+ overflow.push(beyond);
919
+ continue;
920
+ }
905
921
  for (let c = 0; c < line.length; c += 1) {
906
- const rowId = rowIds[startRow + r];
907
922
  const columnId = columnIds[startCol + c];
908
- if (rowId === void 0 || columnId === void 0) {
909
- outside += 1;
923
+ if (columnId === void 0) {
924
+ pastRightEdge += 1;
910
925
  continue;
911
926
  }
912
927
  if (!current.isColumnWritable(columnId)) {
913
928
  skipped.push({
929
+ rowId,
914
930
  columnId,
915
931
  reason: current.columnRefusal?.(columnId) ?? `${columnId} cannot take a pasted value.`
916
932
  });
@@ -920,9 +936,24 @@ function useSpreadsheetGrid(options) {
920
936
  }
921
937
  }
922
938
  const screened = screenPatches(patches);
939
+ const refusals = [...skipped, ...screened.refusals];
940
+ if (current.onPastePlan) {
941
+ const accepted = screened.accepted;
942
+ current.onPastePlan({
943
+ accepted,
944
+ refusals,
945
+ overflow,
946
+ pastRightEdge,
947
+ apply: async () => {
948
+ await applyPatches(accepted, "paste", "Pasted");
949
+ }
950
+ });
951
+ return;
952
+ }
923
953
  void applyPatches(screened.accepted, "paste", "Pasted");
954
+ const outside = pastRightEdge + overflow.reduce((n, row) => n + Object.keys(row).length, 0);
924
955
  const tail = outside > 0 ? ` ${outside} landed past the edge of the table and were ignored.` : "";
925
- announceSkips([...skipped, ...screened.refusals], `Pasted ${screened.accepted.length} cells.${tail}`);
956
+ announceSkips(refusals, `Pasted ${screened.accepted.length} cells.${tail}`);
926
957
  },
927
958
  [range, rowIds, columnIds, applyPatches, announceSkips, screenPatches]
928
959
  );