@rowsncolumns/spreadsheet 10.2.77 → 10.3.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 (176) hide show
  1. package/dist/cjs/api/insert-options.d.ts +67 -0
  2. package/dist/cjs/api/insert-options.d.ts.map +1 -0
  3. package/dist/cjs/api/insert-options.js +104 -0
  4. package/dist/cjs/api/move-overwrite.d.ts +14 -0
  5. package/dist/cjs/api/move-overwrite.d.ts.map +1 -0
  6. package/dist/cjs/api/move-overwrite.js +29 -0
  7. package/dist/cjs/api/multi-selection.d.ts +59 -0
  8. package/dist/cjs/api/multi-selection.d.ts.map +1 -0
  9. package/dist/cjs/api/multi-selection.js +166 -0
  10. package/dist/cjs/atoms/index.d.ts +3 -0
  11. package/dist/cjs/atoms/index.d.ts.map +1 -1
  12. package/dist/cjs/atoms/index.js +3 -0
  13. package/dist/cjs/atoms/insert-cells-dialog.atom.d.ts +36 -0
  14. package/dist/cjs/atoms/insert-cells-dialog.atom.d.ts.map +1 -0
  15. package/dist/cjs/atoms/insert-cells-dialog.atom.js +34 -0
  16. package/dist/cjs/atoms/insert-options.atom.d.ts +21 -0
  17. package/dist/cjs/atoms/insert-options.atom.d.ts.map +1 -0
  18. package/dist/cjs/atoms/insert-options.atom.js +11 -0
  19. package/dist/cjs/atoms/move-overwrite-confirm.atom.d.ts +24 -0
  20. package/dist/cjs/atoms/move-overwrite-confirm.atom.d.ts.map +1 -0
  21. package/dist/cjs/atoms/move-overwrite-confirm.atom.js +42 -0
  22. package/dist/cjs/atoms/sheet-context.atom.d.ts +2 -0
  23. package/dist/cjs/atoms/sheet-context.atom.d.ts.map +1 -1
  24. package/dist/cjs/atoms/sheet-context.atom.js +15 -2
  25. package/dist/cjs/components/canvas-grid/index.d.ts.map +1 -1
  26. package/dist/cjs/components/canvas-grid/index.js +284 -63
  27. package/dist/cjs/components/canvas-grid/typings.d.ts +47 -5
  28. package/dist/cjs/components/canvas-grid/typings.d.ts.map +1 -1
  29. package/dist/cjs/components/cell-editor/formula-result-preview.d.ts +4 -1
  30. package/dist/cjs/components/cell-editor/formula-result-preview.d.ts.map +1 -1
  31. package/dist/cjs/components/cell-editor/formula-result-preview.js +2 -2
  32. package/dist/cjs/components/cell-editor/index.d.ts +7 -1
  33. package/dist/cjs/components/cell-editor/index.d.ts.map +1 -1
  34. package/dist/cjs/components/cell-editor/index.js +3 -3
  35. package/dist/cjs/components/cell-input/cell-input.d.ts +13 -0
  36. package/dist/cjs/components/cell-input/cell-input.d.ts.map +1 -1
  37. package/dist/cjs/components/cell-input/cell-input.js +8 -3
  38. package/dist/cjs/components/cell-input/formula-bar-cell-input.d.ts.map +1 -1
  39. package/dist/cjs/components/cell-input/formula-bar-cell-input.js +3 -1
  40. package/dist/cjs/components/context-menu/index.d.ts +16 -1
  41. package/dist/cjs/components/context-menu/index.d.ts.map +1 -1
  42. package/dist/cjs/components/context-menu/index.js +245 -24
  43. package/dist/cjs/components/floating-cell-editor/index.d.ts.map +1 -1
  44. package/dist/cjs/components/floating-cell-editor/index.js +13 -5
  45. package/dist/cjs/components/insert-cells-dialog/index.d.ts +35 -0
  46. package/dist/cjs/components/insert-cells-dialog/index.d.ts.map +1 -0
  47. package/dist/cjs/components/insert-cells-dialog/index.js +84 -0
  48. package/dist/cjs/components/insert-options-smart-tag/index.d.ts +25 -0
  49. package/dist/cjs/components/insert-options-smart-tag/index.d.ts.map +1 -0
  50. package/dist/cjs/components/insert-options-smart-tag/index.js +41 -0
  51. package/dist/cjs/components/move-overwrite-confirm-dialog/index.d.ts +8 -0
  52. package/dist/cjs/components/move-overwrite-confirm-dialog/index.d.ts.map +1 -0
  53. package/dist/cjs/components/move-overwrite-confirm-dialog/index.js +34 -0
  54. package/dist/cjs/components/selection/index.d.ts +1 -1
  55. package/dist/cjs/components/selection/index.d.ts.map +1 -1
  56. package/dist/cjs/components/selection/index.js +4 -2
  57. package/dist/cjs/components/selection/types.d.ts +8 -0
  58. package/dist/cjs/components/selection/types.d.ts.map +1 -1
  59. package/dist/cjs/config.d.ts +6 -0
  60. package/dist/cjs/config.d.ts.map +1 -1
  61. package/dist/cjs/config.js +7 -1
  62. package/dist/cjs/hooks/use-cell-renderer.d.ts +7 -1
  63. package/dist/cjs/hooks/use-cell-renderer.d.ts.map +1 -1
  64. package/dist/cjs/hooks/use-cell-renderer.js +8 -3
  65. package/dist/cjs/hooks/use-context-setter.d.ts.map +1 -1
  66. package/dist/cjs/hooks/use-context-setter.js +5 -1
  67. package/dist/cjs/hooks/use-copy-paste-cut.d.ts +5 -0
  68. package/dist/cjs/hooks/use-copy-paste-cut.d.ts.map +1 -1
  69. package/dist/cjs/hooks/use-copy-paste-cut.js +19 -0
  70. package/dist/cjs/hooks/use-editor-change.d.ts +4 -1
  71. package/dist/cjs/hooks/use-editor-change.d.ts.map +1 -1
  72. package/dist/cjs/hooks/use-editor-change.js +4 -3
  73. package/dist/cjs/hooks/use-editor-submit.d.ts +8 -1
  74. package/dist/cjs/hooks/use-editor-submit.d.ts.map +1 -1
  75. package/dist/cjs/hooks/use-editor-submit.js +9 -1
  76. package/dist/cjs/hooks/use-move-columns-rows.d.ts.map +1 -1
  77. package/dist/cjs/hooks/use-move-columns-rows.js +6 -0
  78. package/dist/cjs/hooks/use-selection-renderer.d.ts +9 -1
  79. package/dist/cjs/hooks/use-selection-renderer.d.ts.map +1 -1
  80. package/dist/cjs/hooks/use-selection-renderer.js +26 -2
  81. package/dist/cjs/hooks/use-selection.d.ts +13 -5
  82. package/dist/cjs/hooks/use-selection.d.ts.map +1 -1
  83. package/dist/cjs/hooks/use-selection.js +48 -6
  84. package/dist/cjs/index.d.ts +7 -0
  85. package/dist/cjs/index.d.ts.map +1 -1
  86. package/dist/cjs/index.js +7 -0
  87. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  88. package/dist/esm/api/insert-options.d.ts +67 -0
  89. package/dist/esm/api/insert-options.d.ts.map +1 -0
  90. package/dist/esm/api/insert-options.js +91 -0
  91. package/dist/esm/api/move-overwrite.d.ts +14 -0
  92. package/dist/esm/api/move-overwrite.d.ts.map +1 -0
  93. package/dist/esm/api/move-overwrite.js +25 -0
  94. package/dist/esm/api/multi-selection.d.ts +59 -0
  95. package/dist/esm/api/multi-selection.d.ts.map +1 -0
  96. package/dist/esm/api/multi-selection.js +92 -0
  97. package/dist/esm/atoms/index.d.ts +3 -0
  98. package/dist/esm/atoms/index.d.ts.map +1 -1
  99. package/dist/esm/atoms/index.js +3 -0
  100. package/dist/esm/atoms/insert-cells-dialog.atom.d.ts +36 -0
  101. package/dist/esm/atoms/insert-cells-dialog.atom.d.ts.map +1 -0
  102. package/dist/esm/atoms/insert-cells-dialog.atom.js +25 -0
  103. package/dist/esm/atoms/insert-options.atom.d.ts +21 -0
  104. package/dist/esm/atoms/insert-options.atom.d.ts.map +1 -0
  105. package/dist/esm/atoms/insert-options.atom.js +5 -0
  106. package/dist/esm/atoms/move-overwrite-confirm.atom.d.ts +24 -0
  107. package/dist/esm/atoms/move-overwrite-confirm.atom.d.ts.map +1 -0
  108. package/dist/esm/atoms/move-overwrite-confirm.atom.js +29 -0
  109. package/dist/esm/atoms/sheet-context.atom.d.ts +2 -0
  110. package/dist/esm/atoms/sheet-context.atom.d.ts.map +1 -1
  111. package/dist/esm/atoms/sheet-context.atom.js +10 -0
  112. package/dist/esm/components/canvas-grid/index.d.ts.map +1 -1
  113. package/dist/esm/components/canvas-grid/index.js +236 -19
  114. package/dist/esm/components/canvas-grid/typings.d.ts +47 -5
  115. package/dist/esm/components/canvas-grid/typings.d.ts.map +1 -1
  116. package/dist/esm/components/cell-editor/formula-result-preview.d.ts +4 -1
  117. package/dist/esm/components/cell-editor/formula-result-preview.d.ts.map +1 -1
  118. package/dist/esm/components/cell-editor/formula-result-preview.js +3 -3
  119. package/dist/esm/components/cell-editor/index.d.ts +7 -1
  120. package/dist/esm/components/cell-editor/index.d.ts.map +1 -1
  121. package/dist/esm/components/cell-editor/index.js +3 -3
  122. package/dist/esm/components/cell-input/cell-input.d.ts +13 -0
  123. package/dist/esm/components/cell-input/cell-input.d.ts.map +1 -1
  124. package/dist/esm/components/cell-input/cell-input.js +10 -5
  125. package/dist/esm/components/cell-input/formula-bar-cell-input.d.ts.map +1 -1
  126. package/dist/esm/components/cell-input/formula-bar-cell-input.js +3 -1
  127. package/dist/esm/components/context-menu/index.d.ts +16 -1
  128. package/dist/esm/components/context-menu/index.d.ts.map +1 -1
  129. package/dist/esm/components/context-menu/index.js +193 -16
  130. package/dist/esm/components/floating-cell-editor/index.d.ts.map +1 -1
  131. package/dist/esm/components/floating-cell-editor/index.js +12 -6
  132. package/dist/esm/components/insert-cells-dialog/index.d.ts +35 -0
  133. package/dist/esm/components/insert-cells-dialog/index.d.ts.map +1 -0
  134. package/dist/esm/components/insert-cells-dialog/index.js +79 -0
  135. package/dist/esm/components/insert-options-smart-tag/index.d.ts +25 -0
  136. package/dist/esm/components/insert-options-smart-tag/index.d.ts.map +1 -0
  137. package/dist/esm/components/insert-options-smart-tag/index.js +35 -0
  138. package/dist/esm/components/move-overwrite-confirm-dialog/index.d.ts +8 -0
  139. package/dist/esm/components/move-overwrite-confirm-dialog/index.d.ts.map +1 -0
  140. package/dist/esm/components/move-overwrite-confirm-dialog/index.js +30 -0
  141. package/dist/esm/components/selection/index.d.ts +1 -1
  142. package/dist/esm/components/selection/index.d.ts.map +1 -1
  143. package/dist/esm/components/selection/index.js +4 -2
  144. package/dist/esm/components/selection/types.d.ts +8 -0
  145. package/dist/esm/components/selection/types.d.ts.map +1 -1
  146. package/dist/esm/config.d.ts +6 -0
  147. package/dist/esm/config.d.ts.map +1 -1
  148. package/dist/esm/config.js +6 -0
  149. package/dist/esm/hooks/use-cell-renderer.d.ts +7 -1
  150. package/dist/esm/hooks/use-cell-renderer.d.ts.map +1 -1
  151. package/dist/esm/hooks/use-cell-renderer.js +9 -4
  152. package/dist/esm/hooks/use-context-setter.d.ts.map +1 -1
  153. package/dist/esm/hooks/use-context-setter.js +5 -1
  154. package/dist/esm/hooks/use-copy-paste-cut.d.ts +5 -0
  155. package/dist/esm/hooks/use-copy-paste-cut.d.ts.map +1 -1
  156. package/dist/esm/hooks/use-copy-paste-cut.js +19 -0
  157. package/dist/esm/hooks/use-editor-change.d.ts +4 -1
  158. package/dist/esm/hooks/use-editor-change.d.ts.map +1 -1
  159. package/dist/esm/hooks/use-editor-change.js +5 -4
  160. package/dist/esm/hooks/use-editor-submit.d.ts +8 -1
  161. package/dist/esm/hooks/use-editor-submit.d.ts.map +1 -1
  162. package/dist/esm/hooks/use-editor-submit.js +10 -2
  163. package/dist/esm/hooks/use-move-columns-rows.d.ts.map +1 -1
  164. package/dist/esm/hooks/use-move-columns-rows.js +6 -0
  165. package/dist/esm/hooks/use-selection-renderer.d.ts +9 -1
  166. package/dist/esm/hooks/use-selection-renderer.d.ts.map +1 -1
  167. package/dist/esm/hooks/use-selection-renderer.js +26 -2
  168. package/dist/esm/hooks/use-selection.d.ts +13 -5
  169. package/dist/esm/hooks/use-selection.d.ts.map +1 -1
  170. package/dist/esm/hooks/use-selection.js +39 -3
  171. package/dist/esm/index.d.ts +7 -0
  172. package/dist/esm/index.d.ts.map +1 -1
  173. package/dist/esm/index.js +7 -0
  174. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  175. package/dist/spreadsheet.min.css +1 -1
  176. package/package.json +6 -6
@@ -0,0 +1,25 @@
1
+ /** Excel's prompt before a plain drag-move overwrites non-empty destination cells. */
2
+ export const MOVE_OVERWRITE_PROMPT = "There's already data here. Do you want to replace it?";
3
+ /**
4
+ * Whether a plain (overwrite) drag-move from `from` to `to` needs Excel's
5
+ * "There's already data here. Do you want to replace it?" prompt: true when any
6
+ * destination cell OUTSIDE the source block holds a value. Cells the block itself
7
+ * currently occupies are never "data here" — they leave with the move — so an
8
+ * overlapping drag one cell over prompts only for the newly covered strip. An
9
+ * empty destination never prompts; Shift+drag (insert) and Ctrl+drag (copy) never
10
+ * reach this check.
11
+ */
12
+ export const needsOverwritePrompt = (from, to, hasValue) => {
13
+ for (let rowIndex = to.startRowIndex; rowIndex <= to.endRowIndex; rowIndex++) {
14
+ for (let columnIndex = to.startColumnIndex; columnIndex <= to.endColumnIndex; columnIndex++) {
15
+ const insideSource = rowIndex >= from.startRowIndex &&
16
+ rowIndex <= from.endRowIndex &&
17
+ columnIndex >= from.startColumnIndex &&
18
+ columnIndex <= from.endColumnIndex;
19
+ if (!insideSource && hasValue(rowIndex, columnIndex)) {
20
+ return true;
21
+ }
22
+ }
23
+ }
24
+ return false;
25
+ };
@@ -0,0 +1,59 @@
1
+ import type { GridRange, SelectionArea } from "@rowsncolumns/grid";
2
+ /**
3
+ * How Excel treats the areas of a multi-area (Ctrl-click) selection for the
4
+ * structural commands (rowsncolumns/spreadsheet#647 INS-08 / UI-07):
5
+ *
6
+ * - `single` — one area (or none): the normal Insert / Delete dialog path.
7
+ * - `all-rows` — every area is an entire-row band: insert / delete one block
8
+ * per area, sized to that area, applied bottom-up.
9
+ * - `all-columns` — every area is an entire-column band: same, per column band.
10
+ * - `mixed` — any partial area, or rows mixed with columns: Excel refuses
11
+ * with "That command cannot be used on multiple selections."
12
+ */
13
+ export type MultiSelectionKind = "single" | "all-rows" | "all-columns" | "mixed";
14
+ export type WholeBandPredicates = {
15
+ isWholeRow(range: GridRange): boolean;
16
+ isWholeColumn(range: GridRange): boolean;
17
+ };
18
+ /** Entire-row test for a sheet `columnCount` wide (the grid's left bound is column 1). */
19
+ export declare const wholeRowPredicate: (columnCount: number, selectionLeftBound?: number) => (range: GridRange) => boolean;
20
+ /** Entire-column test for a sheet `rowCount` tall (the grid's top bound is row 1). */
21
+ export declare const wholeColumnPredicate: (rowCount: number, selectionTopBound?: number) => (range: GridRange) => boolean;
22
+ /**
23
+ * Entire-row test when the sheet extent is unknown: the grid's row-header
24
+ * bookkeeping (`selectedRowHeadersIds`) already lists every row that belongs
25
+ * to a whole-row area, so an area is whole-row when its first and last rows
26
+ * are both listed.
27
+ */
28
+ export declare const wholeRowPredicateFromHeaderIds: (rowHeaderIds: readonly number[]) => (range: GridRange) => boolean;
29
+ export declare const wholeColumnPredicateFromHeaderIds: (columnHeaderIds: readonly number[]) => (range: GridRange) => boolean;
30
+ export declare const classifyMultiSelection: (selections: readonly SelectionArea[], { isWholeRow, isWholeColumn }: WholeBandPredicates) => MultiSelectionKind;
31
+ export type IndexBand = {
32
+ start: number;
33
+ end: number;
34
+ };
35
+ /**
36
+ * The bands (start..end, inclusive) a per-area structural command acts on,
37
+ * deduplicated and ordered bottom-up / right-to-left so inserting one block
38
+ * per band never shifts a band that is still to be processed (INS-08).
39
+ */
40
+ export declare const bandsForAreas: (selections: readonly SelectionArea[], axis: "row" | "column") => IndexBand[];
41
+ /**
42
+ * Groups header ids (e.g. `selectedRowHeadersIds`) into contiguous bands,
43
+ * bottom-up. Fallback for callers that only know which rows/columns are
44
+ * selected, not the areas they came from.
45
+ */
46
+ export declare const bandsFromIndexes: (indexes: readonly number[]) => IndexBand[];
47
+ /** Sorted, de-duplicated row (or column) indexes covered by ALL areas. */
48
+ export declare const indexesForAreas: (selections: readonly SelectionArea[], axis: "row" | "column") => number[];
49
+ export type InsertCellsChoice = "shift-right" | "shift-down" | "entire-row" | "entire-column";
50
+ export type DeleteCellsChoice = "shift-left" | "shift-up" | "entire-row" | "entire-column";
51
+ /**
52
+ * Excel pre-selects the shift that moves the fewest neighbours: a selection
53
+ * taller than it is wide shifts cells right; a wider-than-tall or square one
54
+ * shifts cells down (UI-06).
55
+ */
56
+ export declare const defaultInsertCellsChoice: (range: GridRange) => InsertCellsChoice;
57
+ /** Delete mirrors Insert: taller-than-wide → shift left, otherwise shift up. */
58
+ export declare const defaultDeleteCellsChoice: (range: GridRange) => DeleteCellsChoice;
59
+ //# sourceMappingURL=multi-selection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-selection.d.ts","sourceRoot":"","sources":["../../../api/multi-selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnE;;;;;;;;;;GAUG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,UAAU,GAAG,aAAa,GAAG,OAAO,CAAC;AAEjF,MAAM,MAAM,mBAAmB,GAAG;IAChC,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC;IACtC,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC;CAC1C,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,iBAAiB,GAC3B,aAAa,MAAM,EAAE,2BAAsB,MAC3C,OAAO,SAAS,YAEoB,CAAC;AAExC,sFAAsF;AACtF,eAAO,MAAM,oBAAoB,GAC9B,UAAU,MAAM,EAAE,0BAAqB,MACvC,OAAO,SAAS,YAC0D,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,GACxC,cAAc,SAAS,MAAM,EAAE,MAEtB,OAAO,SAAS,YAEzB,CAAC;AAEJ,eAAO,MAAM,iCAAiC,GAC3C,iBAAiB,SAAS,MAAM,EAAE,MAEzB,OAAO,SAAS,YAIzB,CAAC;AAEJ,eAAO,MAAM,sBAAsB,GACjC,YAAY,SAAS,aAAa,EAAE,EACpC,+BAA+B,mBAAmB,KACjD,kBAOF,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,YAAY,SAAS,aAAa,EAAE,EACpC,MAAM,KAAK,GAAG,QAAQ,KACrB,SAAS,EAcX,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,SAAS,MAAM,EAAE,KAAG,SAAS,EAYtE,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,eAAe,GAC1B,YAAY,SAAS,aAAa,EAAE,EACpC,MAAM,KAAK,GAAG,QAAQ,KACrB,MAAM,EAUR,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB,aAAa,GACb,YAAY,GACZ,YAAY,GACZ,eAAe,CAAC;AAEpB,MAAM,MAAM,iBAAiB,GACzB,YAAY,GACZ,UAAU,GACV,YAAY,GACZ,eAAe,CAAC;AAMpB;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAAI,OAAO,SAAS,KAAG,iBACJ,CAAC;AAEzD,gFAAgF;AAChF,eAAO,MAAM,wBAAwB,GAAI,OAAO,SAAS,KAAG,iBACP,CAAC"}
@@ -0,0 +1,92 @@
1
+ /** Entire-row test for a sheet `columnCount` wide (the grid's left bound is column 1). */
2
+ export const wholeRowPredicate = (columnCount, selectionLeftBound = 1) => (range) => range.startColumnIndex <= selectionLeftBound &&
3
+ range.endColumnIndex >= columnCount;
4
+ /** Entire-column test for a sheet `rowCount` tall (the grid's top bound is row 1). */
5
+ export const wholeColumnPredicate = (rowCount, selectionTopBound = 1) => (range) => range.startRowIndex <= selectionTopBound && range.endRowIndex >= rowCount;
6
+ /**
7
+ * Entire-row test when the sheet extent is unknown: the grid's row-header
8
+ * bookkeeping (`selectedRowHeadersIds`) already lists every row that belongs
9
+ * to a whole-row area, so an area is whole-row when its first and last rows
10
+ * are both listed.
11
+ */
12
+ export const wholeRowPredicateFromHeaderIds = (rowHeaderIds) => {
13
+ const ids = new Set(rowHeaderIds);
14
+ return (range) => ids.size > 0 && ids.has(range.startRowIndex) && ids.has(range.endRowIndex);
15
+ };
16
+ export const wholeColumnPredicateFromHeaderIds = (columnHeaderIds) => {
17
+ const ids = new Set(columnHeaderIds);
18
+ return (range) => ids.size > 0 &&
19
+ ids.has(range.startColumnIndex) &&
20
+ ids.has(range.endColumnIndex);
21
+ };
22
+ export const classifyMultiSelection = (selections, { isWholeRow, isWholeColumn }) => {
23
+ if (selections.length <= 1)
24
+ return "single";
25
+ if (selections.every(({ range }) => isWholeRow(range)))
26
+ return "all-rows";
27
+ if (selections.every(({ range }) => isWholeColumn(range))) {
28
+ return "all-columns";
29
+ }
30
+ return "mixed";
31
+ };
32
+ /**
33
+ * The bands (start..end, inclusive) a per-area structural command acts on,
34
+ * deduplicated and ordered bottom-up / right-to-left so inserting one block
35
+ * per band never shifts a band that is still to be processed (INS-08).
36
+ */
37
+ export const bandsForAreas = (selections, axis) => {
38
+ const seen = new Set();
39
+ const bands = [];
40
+ for (const { range } of selections) {
41
+ const band = axis === "row"
42
+ ? { start: range.startRowIndex, end: range.endRowIndex }
43
+ : { start: range.startColumnIndex, end: range.endColumnIndex };
44
+ const key = `${band.start}:${band.end}`;
45
+ if (seen.has(key))
46
+ continue;
47
+ seen.add(key);
48
+ bands.push(band);
49
+ }
50
+ return bands.sort((a, b) => b.start - a.start);
51
+ };
52
+ /**
53
+ * Groups header ids (e.g. `selectedRowHeadersIds`) into contiguous bands,
54
+ * bottom-up. Fallback for callers that only know which rows/columns are
55
+ * selected, not the areas they came from.
56
+ */
57
+ export const bandsFromIndexes = (indexes) => {
58
+ const sorted = Array.from(new Set(indexes)).sort((a, b) => a - b);
59
+ const bands = [];
60
+ for (const index of sorted) {
61
+ const last = bands[bands.length - 1];
62
+ if (last && index === last.end + 1) {
63
+ last.end = index;
64
+ }
65
+ else {
66
+ bands.push({ start: index, end: index });
67
+ }
68
+ }
69
+ return bands.sort((a, b) => b.start - a.start);
70
+ };
71
+ /** Sorted, de-duplicated row (or column) indexes covered by ALL areas. */
72
+ export const indexesForAreas = (selections, axis) => {
73
+ const indexes = new Set();
74
+ for (const { range } of selections) {
75
+ const [start, end] = axis === "row"
76
+ ? [range.startRowIndex, range.endRowIndex]
77
+ : [range.startColumnIndex, range.endColumnIndex];
78
+ for (let index = start; index <= end; index++)
79
+ indexes.add(index);
80
+ }
81
+ return Array.from(indexes).sort((a, b) => a - b);
82
+ };
83
+ const isTallerThanWide = (range) => range.endRowIndex - range.startRowIndex >
84
+ range.endColumnIndex - range.startColumnIndex;
85
+ /**
86
+ * Excel pre-selects the shift that moves the fewest neighbours: a selection
87
+ * taller than it is wide shifts cells right; a wider-than-tall or square one
88
+ * shifts cells down (UI-06).
89
+ */
90
+ export const defaultInsertCellsChoice = (range) => isTallerThanWide(range) ? "shift-right" : "shift-down";
91
+ /** Delete mirrors Insert: taller-than-wide → shift left, otherwise shift up. */
92
+ export const defaultDeleteCellsChoice = (range) => isTallerThanWide(range) ? "shift-left" : "shift-up";
@@ -19,7 +19,10 @@ export * from "./validation-alert.atom";
19
19
  export * from "./sort-dialog.atom";
20
20
  export * from "./paste-special-dialog.atom";
21
21
  export * from "./go-to-dialog.atom";
22
+ export * from "./move-overwrite-confirm.atom";
22
23
  export * from "./evaluate-formula-dialog.atom";
23
24
  export * from "./remove-duplicates-dialog.atom";
24
25
  export * from "./watch-window.atom";
26
+ export * from "./insert-cells-dialog.atom";
27
+ export * from "./insert-options.atom";
25
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../atoms/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../atoms/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC"}
@@ -19,6 +19,9 @@ export * from "./validation-alert.atom";
19
19
  export * from "./sort-dialog.atom";
20
20
  export * from "./paste-special-dialog.atom";
21
21
  export * from "./go-to-dialog.atom";
22
+ export * from "./move-overwrite-confirm.atom";
22
23
  export * from "./evaluate-formula-dialog.atom";
23
24
  export * from "./remove-duplicates-dialog.atom";
24
25
  export * from "./watch-window.atom";
26
+ export * from "./insert-cells-dialog.atom";
27
+ export * from "./insert-options.atom";
@@ -0,0 +1,36 @@
1
+ import type { DeleteCellsChoice, InsertCellsChoice } from "../api/multi-selection";
2
+ /**
3
+ * Open-state + payload for Excel's Insert / Delete cells dialog (right-click a
4
+ * cell → "Insert…" / "Delete…", `Ctrl` + `+` / `-` on a cell selection). The
5
+ * grid opens it with the shape-derived default; the host-mounted dialog routes
6
+ * the chosen entry back through `onApply`, and the opener dispatches the
7
+ * matching structural command (shift cells / entire row / entire column).
8
+ */
9
+ export type InsertCellsDialogRequest = {
10
+ mode: "insert";
11
+ defaultChoice: InsertCellsChoice;
12
+ onApply: (choice: InsertCellsChoice) => void;
13
+ } | {
14
+ mode: "delete";
15
+ defaultChoice: DeleteCellsChoice;
16
+ onApply: (choice: DeleteCellsChoice) => void;
17
+ };
18
+ export declare const insertCellsDialogAtom: import("jotai").PrimitiveAtom<InsertCellsDialogRequest | null> & {
19
+ init: InsertCellsDialogRequest | null;
20
+ };
21
+ export declare const useInsertCellsDialogState: () => [InsertCellsDialogRequest | null, (args_0: InsertCellsDialogRequest | ((prev: InsertCellsDialogRequest | null) => InsertCellsDialogRequest | null) | null) => void];
22
+ /**
23
+ * Number of mounted `InsertCellsDialogHost`s. The context menu only offers the
24
+ * dialog entry while a host is mounted; without one it keeps the direct
25
+ * submenu so a host that has not adopted the dialog never gets a dead item.
26
+ */
27
+ export declare const insertCellsDialogHostCountAtom: import("jotai").PrimitiveAtom<number> & {
28
+ init: number;
29
+ };
30
+ /** True when at least one `InsertCellsDialogHost` is mounted. */
31
+ export declare const useIsInsertCellsDialogMounted: () => boolean;
32
+ /** Registers the calling component as a dialog host for its lifetime. */
33
+ export declare const useRegisterInsertCellsDialogHost: () => void;
34
+ /** Returns a function that opens the host-mounted Insert / Delete cells dialog. */
35
+ export declare const useOpenInsertCellsDialog: () => (request: InsertCellsDialogRequest) => void;
36
+ //# sourceMappingURL=insert-cells-dialog.atom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insert-cells-dialog.atom.d.ts","sourceRoot":"","sources":["../../../atoms/insert-cells-dialog.atom.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAChC;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,EAAE,iBAAiB,CAAC;IACjC,OAAO,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC9C,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,EAAE,iBAAiB,CAAC;IACjC,OAAO,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC9C,CAAC;AAEN,eAAO,MAAM,qBAAqB;;CAEjC,CAAC;AAEF,eAAO,MAAM,yBAAyB,2KAAuC,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,8BAA8B;;CAAU,CAAC;AAEtD,iEAAiE;AACjE,eAAO,MAAM,6BAA6B,eACQ,CAAC;AAEnD,yEAAyE;AACzE,eAAO,MAAM,gCAAgC,YAM5C,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,kBAGvB,wBAAwB,SAGrC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
2
+ import { useCallback, useEffect } from "react";
3
+ export const insertCellsDialogAtom = atom(null);
4
+ export const useInsertCellsDialogState = () => useAtom(insertCellsDialogAtom);
5
+ /**
6
+ * Number of mounted `InsertCellsDialogHost`s. The context menu only offers the
7
+ * dialog entry while a host is mounted; without one it keeps the direct
8
+ * submenu so a host that has not adopted the dialog never gets a dead item.
9
+ */
10
+ export const insertCellsDialogHostCountAtom = atom(0);
11
+ /** True when at least one `InsertCellsDialogHost` is mounted. */
12
+ export const useIsInsertCellsDialogMounted = () => useAtomValue(insertCellsDialogHostCountAtom) > 0;
13
+ /** Registers the calling component as a dialog host for its lifetime. */
14
+ export const useRegisterInsertCellsDialogHost = () => {
15
+ const setCount = useSetAtom(insertCellsDialogHostCountAtom);
16
+ useEffect(() => {
17
+ setCount((count) => count + 1);
18
+ return () => setCount((count) => count - 1);
19
+ }, [setCount]);
20
+ };
21
+ /** Returns a function that opens the host-mounted Insert / Delete cells dialog. */
22
+ export const useOpenInsertCellsDialog = () => {
23
+ const setRequest = useSetAtom(insertCellsDialogAtom);
24
+ return useCallback((request) => setRequest(request), [setRequest]);
25
+ };
@@ -0,0 +1,21 @@
1
+ import type { InsertedBand, InsertFormatOption } from "../api/insert-options";
2
+ /**
3
+ * A just-inserted row / column band waiting for the user to (re)choose how it
4
+ * is formatted — Excel's Insert Options smart tag ("Format Same As Above /
5
+ * Below / Clear Formatting"; "Left / Right" for columns). The insert already
6
+ * applied `before` (the row above / column to the left); choosing another
7
+ * entry re-formats the band from the other neighbour, or clears it. Dropped
8
+ * on the next click elsewhere (a new active cell) or sheet switch.
9
+ */
10
+ export type InsertOptionsRequest = InsertedBand & {
11
+ sheetId: number;
12
+ /** The entry currently applied to the band. */
13
+ option: InsertFormatOption;
14
+ };
15
+ export declare const insertOptionsAtom: import("jotai").PrimitiveAtom<InsertOptionsRequest | null> & {
16
+ init: InsertOptionsRequest | null;
17
+ };
18
+ export declare const useInsertOptionsState: () => [InsertOptionsRequest | null, (args_0: InsertOptionsRequest | ((prev: InsertOptionsRequest | null) => InsertOptionsRequest | null) | null) => void];
19
+ export declare const useInsertOptionsValue: () => InsertOptionsRequest | null;
20
+ export declare const useSetInsertOptions: () => (args_0: InsertOptionsRequest | ((prev: InsertOptionsRequest | null) => InsertOptionsRequest | null) | null) => void;
21
+ //# sourceMappingURL=insert-options.atom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insert-options.atom.d.ts","sourceRoot":"","sources":["../../../atoms/insert-options.atom.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE9E;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,MAAM,EAAE,kBAAkB,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,iBAAiB;;CAA0C,CAAC;AAEzE,eAAO,MAAM,qBAAqB,2JAAmC,CAAC;AACtE,eAAO,MAAM,qBAAqB,mCAAwC,CAAC;AAC3E,eAAO,MAAM,mBAAmB,4HAAsC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
2
+ export const insertOptionsAtom = atom(null);
3
+ export const useInsertOptionsState = () => useAtom(insertOptionsAtom);
4
+ export const useInsertOptionsValue = () => useAtomValue(insertOptionsAtom);
5
+ export const useSetInsertOptions = () => useSetAtom(insertOptionsAtom);
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Open-state + payload for the drag-move overwrite prompt (Excel: "There's
3
+ * already data here. Do you want to replace it?"). The grid raises it from the
4
+ * selection-border drop; the host-mounted dialog answers through `resolve`.
5
+ */
6
+ export type MoveOverwriteConfirmRequest = {
7
+ message: string;
8
+ resolve: (replace: boolean) => void;
9
+ };
10
+ export declare const moveOverwriteConfirmAtom: import("jotai").PrimitiveAtom<MoveOverwriteConfirmRequest | null> & {
11
+ init: MoveOverwriteConfirmRequest | null;
12
+ };
13
+ export declare const useMoveOverwriteConfirmState: () => [MoveOverwriteConfirmRequest | null, (args_0: MoveOverwriteConfirmRequest | ((prev: MoveOverwriteConfirmRequest | null) => MoveOverwriteConfirmRequest | null) | null) => void];
14
+ /** Number of mounted `MoveOverwriteConfirmDialogHost`s. */
15
+ export declare const moveOverwriteConfirmHostCountAtom: import("jotai").PrimitiveAtom<number> & {
16
+ init: number;
17
+ };
18
+ /** True when a host has mounted the dialog; otherwise the grid falls back to `window.confirm`. */
19
+ export declare const useIsMoveOverwriteConfirmMounted: () => boolean;
20
+ /** Registers the calling component as a dialog host for its lifetime. */
21
+ export declare const useRegisterMoveOverwriteConfirmHost: () => void;
22
+ /** Returns a function that opens the host-mounted prompt and resolves with the user's answer. */
23
+ export declare const useOpenMoveOverwriteConfirm: () => (message: string) => Promise<boolean>;
24
+ //# sourceMappingURL=move-overwrite-confirm.atom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"move-overwrite-confirm.atom.d.ts","sourceRoot":"","sources":["../../../atoms/move-overwrite-confirm.atom.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;CAEpC,CAAC;AAEF,eAAO,MAAM,4BAA4B,uLACN,CAAC;AAEpC,2DAA2D;AAC3D,eAAO,MAAM,iCAAiC;;CAAU,CAAC;AAEzD,kGAAkG;AAClG,eAAO,MAAM,gCAAgC,eACQ,CAAC;AAEtD,yEAAyE;AACzE,eAAO,MAAM,mCAAmC,YAM/C,CAAC;AAEF,iGAAiG;AACjG,eAAO,MAAM,2BAA2B,kBAG1B,MAAM,qBAYnB,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
2
+ import { useCallback, useEffect } from "react";
3
+ export const moveOverwriteConfirmAtom = atom(null);
4
+ export const useMoveOverwriteConfirmState = () => useAtom(moveOverwriteConfirmAtom);
5
+ /** Number of mounted `MoveOverwriteConfirmDialogHost`s. */
6
+ export const moveOverwriteConfirmHostCountAtom = atom(0);
7
+ /** True when a host has mounted the dialog; otherwise the grid falls back to `window.confirm`. */
8
+ export const useIsMoveOverwriteConfirmMounted = () => useAtomValue(moveOverwriteConfirmHostCountAtom) > 0;
9
+ /** Registers the calling component as a dialog host for its lifetime. */
10
+ export const useRegisterMoveOverwriteConfirmHost = () => {
11
+ const setCount = useSetAtom(moveOverwriteConfirmHostCountAtom);
12
+ useEffect(() => {
13
+ setCount((count) => count + 1);
14
+ return () => setCount((count) => count - 1);
15
+ }, [setCount]);
16
+ };
17
+ /** Returns a function that opens the host-mounted prompt and resolves with the user's answer. */
18
+ export const useOpenMoveOverwriteConfirm = () => {
19
+ const setRequest = useSetAtom(moveOverwriteConfirmAtom);
20
+ return useCallback((message) => new Promise((resolve) => {
21
+ setRequest({
22
+ message,
23
+ resolve: (replace) => {
24
+ setRequest(null);
25
+ resolve(replace);
26
+ },
27
+ });
28
+ }), [setRequest]);
29
+ };
@@ -5,6 +5,8 @@ export declare const spreadsheetContextAtom: import("jotai").PrimitiveAtom<Canva
5
5
  export declare const useSpreadsheet: () => CanvasGridMethods;
6
6
  export declare const tokenizerSelector: import("jotai").Atom<(str: string) => import("..").ParsedToken[]>;
7
7
  export declare const useTokenizer: () => (str: string) => import("..").ParsedToken[];
8
+ export declare const useLocaleTokenizer: () => (str: string) => import("..").ParsedToken[];
9
+ export declare const useFormulaLocale: () => import("@rowsncolumns/utils").FormulaLocale;
8
10
  export declare const useSetSpreadsheetContext: () => (args_0: CanvasGridMethods | ((prev: CanvasGridMethods) => CanvasGridMethods)) => void;
9
11
  export declare const useGetCellBounds: () => ((coords: import("@rowsncolumns/grid").CellInterface, spanMerges?: boolean | undefined) => import("@rowsncolumns/grid").GridRange) | undefined;
10
12
  export declare const useGetSelectionsFromFormula: () => ((value: string, anchorCell?: import("@rowsncolumns/grid").CellInterface) => import("@rowsncolumns/grid").SelectionArea<import("../components/canvas-grid/typings").SelectionAttributes>[]) | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"sheet-context.atom.d.ts","sourceRoot":"","sources":["../../../atoms/sheet-context.atom.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,eAAO,MAAM,sBAAsB;;CAEjC,CAAC;AAEH,eAAO,MAAM,cAAc,yBAA6C,CAAC;AAGzE,eAAO,MAAM,iBAAiB,mEAE7B,CAAC;AAEF,eAAO,MAAM,YAAY,mDAAwC,CAAC;AAElE,eAAO,MAAM,wBAAwB,8FACD,CAAC;AAOrC,eAAO,MAAM,gBAAgB,sJAA4C,CAAC;AAO1E,eAAO,MAAM,2BAA2B,+MACK,CAAC;AAO9C,eAAO,MAAM,0BAA0B,uQACM,CAAC;AAO9C,eAAO,MAAM,8BAA8B,+GACM,CAAC;AAMlD,eAAO,MAAM,oBAAoB;;;cACQ,CAAC;AAM1C,eAAO,MAAM,eAAe,+GAA2C,CAAC;AAMxE,eAAO,MAAM,iBAAiB;;;;yBAA6C,CAAC;AAM5E,eAAO,MAAM,+BAA+B,wIACY,CAAC;AAMzD,eAAO,MAAM,0BAA0B,8HACQ,CAAC;AAMhD,eAAO,MAAM,0BAA0B,iIACQ,CAAC;AAEhD,eAAO,MAAM,wCAAwC,oPAEpD,CAAC;AAEF,eAAO,MAAM,mCAAmC,oOACQ,CAAC;AAEzD,eAAO,MAAM,mBAAmB,oHAE/B,CAAC;AAEF,eAAO,MAAM,cAAc,oGAA0C,CAAC;AAEtE,eAAO,MAAM,wBAAwB,kEAEpC,CAAC;AAEF,eAAO,MAAM,mBAAmB,kDAA+C,CAAC;AAEhF,eAAO,MAAM,2BAA2B,mDAEvC,CAAC;AAEF,eAAO,MAAM,sBAAsB,mCACQ,CAAC;AAE5C,eAAO,MAAM,0BAA0B,0GAEtC,CAAC;AAEF,eAAO,MAAM,qBAAqB,0FACQ,CAAC;AAE3C,eAAO,MAAM,mCAAmC,gHAE/C,CAAC;AAEF,eAAO,MAAM,8BAA8B,gGACQ,CAAC;AAEpD,eAAO,MAAM,kBAAkB,4OAE9B,CAAC;AAEF,eAAO,MAAM,aAAa,4NAAyC,CAAC;AAEpE,eAAO,MAAM,kBAAkB,gDAE9B,CAAC;AAEF,eAAO,MAAM,aAAa,gCAAyC,CAAC;AAEpE,eAAO,MAAM,0BAA0B,oFAEtC,CAAC;AAEF,eAAO,MAAM,qBAAqB,oEACQ,CAAC;AAE3C,eAAO,MAAM,yBAAyB,oMAErC,CAAC;AAEF,eAAO,MAAM,oBAAoB,oLACQ,CAAC;AAE1C,eAAO,MAAM,uBAAuB,sFAEnC,CAAC;AAEF,eAAO,MAAM,kBAAkB,sEAA8C,CAAC;AAE9E,eAAO,MAAM,oBAAoB,iEAEhC,CAAC;AAEF,eAAO,MAAM,eAAe,iDAA2C,CAAC;AAExE,eAAO,MAAM,kBAAkB,+EAE9B,CAAC;AAEF,eAAO,MAAM,aAAa,+DAAyC,CAAC;AAEpE,eAAO,MAAM,0BAA0B,wOAEtC,CAAC;AAEF,eAAO,MAAM,kBAAkB,wNACW,CAAC;AAE3C,eAAO,MAAM,oBAAoB,oJAEhC,CAAC;AAEF,eAAO,MAAM,eAAe,oIAA2C,CAAC;AAExE,eAAO,MAAM,kBAAkB,gDAE9B,CAAC;AAEF,eAAO,MAAM,aAAa,gCAAyC,CAAC;AAEpE,eAAO,MAAM,mBAAmB,sFAE/B,CAAC;AAEF,eAAO,MAAM,cAAc,sEAA0C,CAAC;AAEtE,eAAO,MAAM,sBAAsB,+FAElC,CAAC;AAEF,eAAO,MAAM,iBAAiB,+EAA6C,CAAC;AAE5E,eAAO,MAAM,kBAAkB,uFAE9B,CAAC;AACF,eAAO,MAAM,aAAa,uEAAyC,CAAC;AAEpE,eAAO,MAAM,4BAA4B,kLAExC,CAAC;AACF,eAAO,MAAM,uBAAuB,kKACQ,CAAC"}
1
+ {"version":3,"file":"sheet-context.atom.d.ts","sourceRoot":"","sources":["../../../atoms/sheet-context.atom.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,eAAO,MAAM,sBAAsB;;CAEjC,CAAC;AAEH,eAAO,MAAM,cAAc,yBAA6C,CAAC;AAGzE,eAAO,MAAM,iBAAiB,mEAE7B,CAAC;AAEF,eAAO,MAAM,YAAY,mDAAwC,CAAC;AAQlE,eAAO,MAAM,kBAAkB,mDAA8C,CAAC;AAO9E,eAAO,MAAM,gBAAgB,mDAA4C,CAAC;AAE1E,eAAO,MAAM,wBAAwB,8FACD,CAAC;AAOrC,eAAO,MAAM,gBAAgB,sJAA4C,CAAC;AAO1E,eAAO,MAAM,2BAA2B,+MACK,CAAC;AAO9C,eAAO,MAAM,0BAA0B,uQACM,CAAC;AAO9C,eAAO,MAAM,8BAA8B,+GACM,CAAC;AAMlD,eAAO,MAAM,oBAAoB;;;cACQ,CAAC;AAM1C,eAAO,MAAM,eAAe,+GAA2C,CAAC;AAMxE,eAAO,MAAM,iBAAiB;;;;yBAA6C,CAAC;AAM5E,eAAO,MAAM,+BAA+B,wIACY,CAAC;AAMzD,eAAO,MAAM,0BAA0B,8HACQ,CAAC;AAMhD,eAAO,MAAM,0BAA0B,iIACQ,CAAC;AAEhD,eAAO,MAAM,wCAAwC,oPAEpD,CAAC;AAEF,eAAO,MAAM,mCAAmC,oOACQ,CAAC;AAEzD,eAAO,MAAM,mBAAmB,oHAE/B,CAAC;AAEF,eAAO,MAAM,cAAc,oGAA0C,CAAC;AAEtE,eAAO,MAAM,wBAAwB,kEAEpC,CAAC;AAEF,eAAO,MAAM,mBAAmB,kDAA+C,CAAC;AAEhF,eAAO,MAAM,2BAA2B,mDAEvC,CAAC;AAEF,eAAO,MAAM,sBAAsB,mCACQ,CAAC;AAE5C,eAAO,MAAM,0BAA0B,0GAEtC,CAAC;AAEF,eAAO,MAAM,qBAAqB,0FACQ,CAAC;AAE3C,eAAO,MAAM,mCAAmC,gHAE/C,CAAC;AAEF,eAAO,MAAM,8BAA8B,gGACQ,CAAC;AAEpD,eAAO,MAAM,kBAAkB,4OAE9B,CAAC;AAEF,eAAO,MAAM,aAAa,4NAAyC,CAAC;AAEpE,eAAO,MAAM,kBAAkB,gDAE9B,CAAC;AAEF,eAAO,MAAM,aAAa,gCAAyC,CAAC;AAEpE,eAAO,MAAM,0BAA0B,oFAEtC,CAAC;AAEF,eAAO,MAAM,qBAAqB,oEACQ,CAAC;AAE3C,eAAO,MAAM,yBAAyB,oMAErC,CAAC;AAEF,eAAO,MAAM,oBAAoB,oLACQ,CAAC;AAE1C,eAAO,MAAM,uBAAuB,sFAEnC,CAAC;AAEF,eAAO,MAAM,kBAAkB,sEAA8C,CAAC;AAE9E,eAAO,MAAM,oBAAoB,iEAEhC,CAAC;AAEF,eAAO,MAAM,eAAe,iDAA2C,CAAC;AAExE,eAAO,MAAM,kBAAkB,+EAE9B,CAAC;AAEF,eAAO,MAAM,aAAa,+DAAyC,CAAC;AAEpE,eAAO,MAAM,0BAA0B,wOAEtC,CAAC;AAEF,eAAO,MAAM,kBAAkB,wNACW,CAAC;AAE3C,eAAO,MAAM,oBAAoB,oJAEhC,CAAC;AAEF,eAAO,MAAM,eAAe,oIAA2C,CAAC;AAExE,eAAO,MAAM,kBAAkB,gDAE9B,CAAC;AAEF,eAAO,MAAM,aAAa,gCAAyC,CAAC;AAEpE,eAAO,MAAM,mBAAmB,sFAE/B,CAAC;AAEF,eAAO,MAAM,cAAc,sEAA0C,CAAC;AAEtE,eAAO,MAAM,sBAAsB,+FAElC,CAAC;AAEF,eAAO,MAAM,iBAAiB,+EAA6C,CAAC;AAE5E,eAAO,MAAM,kBAAkB,uFAE9B,CAAC;AACF,eAAO,MAAM,aAAa,uEAAyC,CAAC;AAEpE,eAAO,MAAM,4BAA4B,kLAExC,CAAC;AACF,eAAO,MAAM,uBAAuB,kKACQ,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { CANONICAL_FORMULA_LOCALE } from "@rowsncolumns/utils";
1
2
  import { atom, useAtomValue, useSetAtom } from "jotai";
2
3
  export const spreadsheetContextAtom = atom({
3
4
  tokenizer: () => [],
@@ -6,6 +7,15 @@ export const useSpreadsheet = () => useAtomValue(spreadsheetContextAtom);
6
7
  // Tokenizer selector
7
8
  export const tokenizerSelector = atom((get) => get(spreadsheetContextAtom).tokenizer);
8
9
  export const useTokenizer = () => useAtomValue(tokenizerSelector);
10
+ // Formula-locale tokenizer (falls back to the canonical one before the grid publishes it)
11
+ const localeTokenizerSelector = atom((get) => {
12
+ const context = get(spreadsheetContextAtom);
13
+ return context.localeTokenizer ?? context.tokenizer;
14
+ });
15
+ export const useLocaleTokenizer = () => useAtomValue(localeTokenizerSelector);
16
+ // The grid's resolved formula locale (canonical until the grid publishes one)
17
+ const formulaLocaleSelector = atom((get) => get(spreadsheetContextAtom).formulaLocale ?? CANONICAL_FORMULA_LOCALE);
18
+ export const useFormulaLocale = () => useAtomValue(formulaLocaleSelector);
9
19
  export const useSetSpreadsheetContext = () => useSetAtom(spreadsheetContextAtom);
10
20
  // Cellbounds selector
11
21
  const getCellBoundsSelector = atom((get) => get(spreadsheetContextAtom).getCellBounds);
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/canvas-grid/index.tsx"],"names":[],"mappings":"AA2CA,OAAO,KASN,MAAM,OAAO,CAAC;AA4Lf,OAAO,KAAK,EAGV,QAAQ,EAUT,MAAM,aAAa,CAAC;AAcrB,OAAO,KAAK,EACV,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EAEhB,MAAM,WAAW,CAAC;AAmkKnB,eAAO,MAAM,UAAU,EAA4C,CACjE,CAAC,SAAS,QAAQ,CAAC,GAAG,CAAC,EAEvB,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,GACvB,wBAAwB,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;CAAE,KAChE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/canvas-grid/index.tsx"],"names":[],"mappings":"AA+CA,OAAO,KASN,MAAM,OAAO,CAAC;AAuMf,OAAO,KAAK,EAGV,QAAQ,EAUT,MAAM,aAAa,CAAC;AAcrB,OAAO,KAAK,EACV,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EAEhB,MAAM,WAAW,CAAC;AAk1KnB,eAAO,MAAM,UAAU,EAA4C,CACjE,CAAC,SAAS,QAAQ,CAAC,GAAG,CAAC,EAEvB,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,GACvB,wBAAwB,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;CAAE,KAChE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC"}