@rowsncolumns/spreadsheet-state 29.1.4 → 29.1.7

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 (225) hide show
  1. package/dist/cjs/api/circular-reference.d.ts +31 -0
  2. package/dist/cjs/api/circular-reference.d.ts.map +1 -0
  3. package/dist/cjs/api/circular-reference.js +85 -0
  4. package/dist/cjs/api/copy-paste.d.ts +6 -0
  5. package/dist/cjs/api/copy-paste.d.ts.map +1 -1
  6. package/dist/cjs/api/copy-paste.js +24 -15
  7. package/dist/cjs/api/datatype.d.ts +2 -0
  8. package/dist/cjs/api/datatype.d.ts.map +1 -1
  9. package/dist/cjs/api/datatype.js +61 -35
  10. package/dist/cjs/api/date.d.ts.map +1 -1
  11. package/dist/cjs/api/date.js +23 -14
  12. package/dist/cjs/api/decimals.d.ts +10 -0
  13. package/dist/cjs/api/decimals.d.ts.map +1 -1
  14. package/dist/cjs/api/decimals.js +34 -11
  15. package/dist/cjs/api/dependency.d.ts +19 -1
  16. package/dist/cjs/api/dependency.d.ts.map +1 -1
  17. package/dist/cjs/api/dependency.js +30 -14
  18. package/dist/cjs/api/filter-condition.d.ts +58 -0
  19. package/dist/cjs/api/filter-condition.d.ts.map +1 -0
  20. package/dist/cjs/api/filter-condition.js +157 -0
  21. package/dist/cjs/api/formula.d.ts.map +1 -1
  22. package/dist/cjs/api/formula.js +9 -7
  23. package/dist/cjs/api/image-embed.d.ts +41 -0
  24. package/dist/cjs/api/image-embed.d.ts.map +1 -0
  25. package/dist/cjs/api/image-embed.js +55 -0
  26. package/dist/cjs/api/immer-utils.d.ts.map +1 -1
  27. package/dist/cjs/api/immer-utils.js +43 -15
  28. package/dist/cjs/api/named-range-structural.d.ts +29 -3
  29. package/dist/cjs/api/named-range-structural.d.ts.map +1 -1
  30. package/dist/cjs/api/named-range-structural.js +36 -11
  31. package/dist/cjs/api/parse-html.d.ts.map +1 -1
  32. package/dist/cjs/api/parse-html.js +11 -5
  33. package/dist/cjs/api/structural-formula-update.d.ts +20 -1
  34. package/dist/cjs/api/structural-formula-update.d.ts.map +1 -1
  35. package/dist/cjs/api/structural-formula-update.js +264 -90
  36. package/dist/cjs/api/structural-guards.d.ts +11 -0
  37. package/dist/cjs/api/structural-guards.d.ts.map +1 -1
  38. package/dist/cjs/api/structural-guards.js +45 -1
  39. package/dist/cjs/api/structural-table-refs.d.ts +15 -2
  40. package/dist/cjs/api/structural-table-refs.d.ts.map +1 -1
  41. package/dist/cjs/api/structural-table-refs.js +79 -35
  42. package/dist/cjs/commands.d.ts +17 -3
  43. package/dist/cjs/commands.d.ts.map +1 -1
  44. package/dist/cjs/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
  45. package/dist/cjs/components/editors/conditional-format-rule-editor.js +19 -7
  46. package/dist/cjs/constants.d.ts +4 -1
  47. package/dist/cjs/constants.d.ts.map +1 -1
  48. package/dist/cjs/constants.js +4 -0
  49. package/dist/cjs/helpers/sheet-title.d.ts +2 -1
  50. package/dist/cjs/helpers/sheet-title.d.ts.map +1 -1
  51. package/dist/cjs/helpers/sheet-title.js +3 -1
  52. package/dist/cjs/hooks/use-can-edit-cellrange.d.ts +1 -1
  53. package/dist/cjs/hooks/use-can-edit-cellrange.d.ts.map +1 -1
  54. package/dist/cjs/hooks/use-can-edit-cellrange.js +1 -1
  55. package/dist/cjs/hooks/use-on-calculation-success.d.ts +5 -1
  56. package/dist/cjs/hooks/use-on-calculation-success.d.ts.map +1 -1
  57. package/dist/cjs/hooks/use-on-calculation-success.js +20 -3
  58. package/dist/cjs/hooks/use-on-copy.d.ts.map +1 -1
  59. package/dist/cjs/hooks/use-on-copy.js +23 -25
  60. package/dist/cjs/hooks/use-on-create-sheet.d.ts.map +1 -1
  61. package/dist/cjs/hooks/use-on-create-sheet.js +11 -1
  62. package/dist/cjs/hooks/use-on-delete.d.ts.map +1 -1
  63. package/dist/cjs/hooks/use-on-delete.js +15 -3
  64. package/dist/cjs/hooks/use-on-drag-n-drop.d.ts +5 -0
  65. package/dist/cjs/hooks/use-on-drag-n-drop.d.ts.map +1 -1
  66. package/dist/cjs/hooks/use-on-drag-n-drop.js +6 -5
  67. package/dist/cjs/hooks/use-on-filter-table.d.ts.map +1 -1
  68. package/dist/cjs/hooks/use-on-filter-table.js +6 -1
  69. package/dist/cjs/hooks/use-on-find-replace.d.ts.map +1 -1
  70. package/dist/cjs/hooks/use-on-find-replace.js +111 -23
  71. package/dist/cjs/hooks/use-on-insert-image.d.ts.map +1 -1
  72. package/dist/cjs/hooks/use-on-insert-image.js +20 -33
  73. package/dist/cjs/hooks/use-on-paste.d.ts +2 -1
  74. package/dist/cjs/hooks/use-on-paste.d.ts.map +1 -1
  75. package/dist/cjs/hooks/use-on-paste.js +53 -24
  76. package/dist/cjs/hooks/use-on-rename-sheet.d.ts +3 -1
  77. package/dist/cjs/hooks/use-on-rename-sheet.d.ts.map +1 -1
  78. package/dist/cjs/hooks/use-on-rename-sheet.js +19 -9
  79. package/dist/cjs/hooks/use-on-sort-column.d.ts +7 -1
  80. package/dist/cjs/hooks/use-on-sort-column.d.ts.map +1 -1
  81. package/dist/cjs/hooks/use-on-sort-column.js +25 -8
  82. package/dist/cjs/hooks/use-on-sort-range.d.ts +16 -2
  83. package/dist/cjs/hooks/use-on-sort-range.d.ts.map +1 -1
  84. package/dist/cjs/hooks/use-on-sort-range.js +72 -40
  85. package/dist/cjs/hooks/use-on-sort-table.d.ts +7 -2
  86. package/dist/cjs/hooks/use-on-sort-table.d.ts.map +1 -1
  87. package/dist/cjs/hooks/use-on-sort-table.js +25 -4
  88. package/dist/cjs/hooks/use-spreadsheet-state.d.ts +5 -3
  89. package/dist/cjs/hooks/use-spreadsheet-state.d.ts.map +1 -1
  90. package/dist/cjs/hooks/use-spreadsheet-state.js +7 -0
  91. package/dist/cjs/hooks/utils/sort-rows.d.ts +15 -0
  92. package/dist/cjs/hooks/utils/sort-rows.d.ts.map +1 -1
  93. package/dist/cjs/hooks/utils/sort-rows.js +16 -0
  94. package/dist/cjs/index.d.ts +3 -0
  95. package/dist/cjs/index.d.ts.map +1 -1
  96. package/dist/cjs/index.js +3 -0
  97. package/dist/cjs/interface/delete-column.d.ts.map +1 -1
  98. package/dist/cjs/interface/delete-column.js +254 -101
  99. package/dist/cjs/interface/delete-row.d.ts.map +1 -1
  100. package/dist/cjs/interface/delete-row.js +233 -81
  101. package/dist/cjs/interface/duplicate-sheet.d.ts.map +1 -1
  102. package/dist/cjs/interface/duplicate-sheet.js +4 -9
  103. package/dist/cjs/interface/insert-column.d.ts.map +1 -1
  104. package/dist/cjs/interface/insert-column.js +1 -1
  105. package/dist/cjs/interface/insert-row.d.ts.map +1 -1
  106. package/dist/cjs/interface/insert-row.js +1 -1
  107. package/dist/cjs/interface/new-sheet.d.ts.map +1 -1
  108. package/dist/cjs/interface/new-sheet.js +6 -13
  109. package/dist/cjs/sheet-cell.d.ts +9 -0
  110. package/dist/cjs/sheet-cell.d.ts.map +1 -1
  111. package/dist/cjs/sheet-cell.js +46 -9
  112. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  113. package/dist/esm/api/circular-reference.d.ts +31 -0
  114. package/dist/esm/api/circular-reference.d.ts.map +1 -0
  115. package/dist/esm/api/circular-reference.js +55 -0
  116. package/dist/esm/api/copy-paste.d.ts +6 -0
  117. package/dist/esm/api/copy-paste.d.ts.map +1 -1
  118. package/dist/esm/api/copy-paste.js +26 -14
  119. package/dist/esm/api/datatype.d.ts +2 -0
  120. package/dist/esm/api/datatype.d.ts.map +1 -1
  121. package/dist/esm/api/datatype.js +61 -35
  122. package/dist/esm/api/date.d.ts.map +1 -1
  123. package/dist/esm/api/date.js +23 -14
  124. package/dist/esm/api/decimals.d.ts +10 -0
  125. package/dist/esm/api/decimals.d.ts.map +1 -1
  126. package/dist/esm/api/decimals.js +31 -10
  127. package/dist/esm/api/dependency.d.ts +19 -1
  128. package/dist/esm/api/dependency.d.ts.map +1 -1
  129. package/dist/esm/api/dependency.js +15 -10
  130. package/dist/esm/api/filter-condition.d.ts +58 -0
  131. package/dist/esm/api/filter-condition.d.ts.map +1 -0
  132. package/dist/esm/api/filter-condition.js +146 -0
  133. package/dist/esm/api/formula.d.ts.map +1 -1
  134. package/dist/esm/api/formula.js +9 -7
  135. package/dist/esm/api/image-embed.d.ts +41 -0
  136. package/dist/esm/api/image-embed.d.ts.map +1 -0
  137. package/dist/esm/api/image-embed.js +52 -0
  138. package/dist/esm/api/immer-utils.d.ts.map +1 -1
  139. package/dist/esm/api/immer-utils.js +43 -14
  140. package/dist/esm/api/named-range-structural.d.ts +29 -3
  141. package/dist/esm/api/named-range-structural.d.ts.map +1 -1
  142. package/dist/esm/api/named-range-structural.js +35 -11
  143. package/dist/esm/api/parse-html.d.ts.map +1 -1
  144. package/dist/esm/api/parse-html.js +14 -5
  145. package/dist/esm/api/structural-formula-update.d.ts +20 -1
  146. package/dist/esm/api/structural-formula-update.d.ts.map +1 -1
  147. package/dist/esm/api/structural-formula-update.js +151 -55
  148. package/dist/esm/api/structural-guards.d.ts +11 -0
  149. package/dist/esm/api/structural-guards.d.ts.map +1 -1
  150. package/dist/esm/api/structural-guards.js +31 -0
  151. package/dist/esm/api/structural-table-refs.d.ts +15 -2
  152. package/dist/esm/api/structural-table-refs.d.ts.map +1 -1
  153. package/dist/esm/api/structural-table-refs.js +49 -18
  154. package/dist/esm/commands.d.ts +17 -3
  155. package/dist/esm/commands.d.ts.map +1 -1
  156. package/dist/esm/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
  157. package/dist/esm/components/editors/conditional-format-rule-editor.js +18 -7
  158. package/dist/esm/constants.d.ts +4 -1
  159. package/dist/esm/constants.d.ts.map +1 -1
  160. package/dist/esm/constants.js +4 -0
  161. package/dist/esm/helpers/sheet-title.d.ts +2 -1
  162. package/dist/esm/helpers/sheet-title.d.ts.map +1 -1
  163. package/dist/esm/helpers/sheet-title.js +3 -1
  164. package/dist/esm/hooks/use-can-edit-cellrange.d.ts +1 -1
  165. package/dist/esm/hooks/use-can-edit-cellrange.d.ts.map +1 -1
  166. package/dist/esm/hooks/use-can-edit-cellrange.js +1 -1
  167. package/dist/esm/hooks/use-on-calculation-success.d.ts +5 -1
  168. package/dist/esm/hooks/use-on-calculation-success.d.ts.map +1 -1
  169. package/dist/esm/hooks/use-on-calculation-success.js +19 -3
  170. package/dist/esm/hooks/use-on-copy.d.ts.map +1 -1
  171. package/dist/esm/hooks/use-on-copy.js +17 -17
  172. package/dist/esm/hooks/use-on-create-sheet.d.ts.map +1 -1
  173. package/dist/esm/hooks/use-on-create-sheet.js +11 -1
  174. package/dist/esm/hooks/use-on-delete.d.ts.map +1 -1
  175. package/dist/esm/hooks/use-on-delete.js +15 -3
  176. package/dist/esm/hooks/use-on-drag-n-drop.d.ts +5 -0
  177. package/dist/esm/hooks/use-on-drag-n-drop.d.ts.map +1 -1
  178. package/dist/esm/hooks/use-on-drag-n-drop.js +7 -4
  179. package/dist/esm/hooks/use-on-filter-table.d.ts.map +1 -1
  180. package/dist/esm/hooks/use-on-filter-table.js +13 -2
  181. package/dist/esm/hooks/use-on-find-replace.d.ts.map +1 -1
  182. package/dist/esm/hooks/use-on-find-replace.js +111 -23
  183. package/dist/esm/hooks/use-on-insert-image.d.ts.map +1 -1
  184. package/dist/esm/hooks/use-on-insert-image.js +15 -25
  185. package/dist/esm/hooks/use-on-paste.d.ts +2 -1
  186. package/dist/esm/hooks/use-on-paste.d.ts.map +1 -1
  187. package/dist/esm/hooks/use-on-paste.js +46 -15
  188. package/dist/esm/hooks/use-on-rename-sheet.d.ts +3 -1
  189. package/dist/esm/hooks/use-on-rename-sheet.d.ts.map +1 -1
  190. package/dist/esm/hooks/use-on-rename-sheet.js +19 -9
  191. package/dist/esm/hooks/use-on-sort-column.d.ts +7 -1
  192. package/dist/esm/hooks/use-on-sort-column.d.ts.map +1 -1
  193. package/dist/esm/hooks/use-on-sort-column.js +18 -1
  194. package/dist/esm/hooks/use-on-sort-range.d.ts +16 -2
  195. package/dist/esm/hooks/use-on-sort-range.d.ts.map +1 -1
  196. package/dist/esm/hooks/use-on-sort-range.js +30 -3
  197. package/dist/esm/hooks/use-on-sort-table.d.ts +7 -2
  198. package/dist/esm/hooks/use-on-sort-table.d.ts.map +1 -1
  199. package/dist/esm/hooks/use-on-sort-table.js +25 -4
  200. package/dist/esm/hooks/use-spreadsheet-state.d.ts +5 -3
  201. package/dist/esm/hooks/use-spreadsheet-state.d.ts.map +1 -1
  202. package/dist/esm/hooks/use-spreadsheet-state.js +7 -0
  203. package/dist/esm/hooks/utils/sort-rows.d.ts +15 -0
  204. package/dist/esm/hooks/utils/sort-rows.d.ts.map +1 -1
  205. package/dist/esm/hooks/utils/sort-rows.js +15 -0
  206. package/dist/esm/index.d.ts +3 -0
  207. package/dist/esm/index.d.ts.map +1 -1
  208. package/dist/esm/index.js +3 -0
  209. package/dist/esm/interface/delete-column.d.ts.map +1 -1
  210. package/dist/esm/interface/delete-column.js +111 -80
  211. package/dist/esm/interface/delete-row.d.ts.map +1 -1
  212. package/dist/esm/interface/delete-row.js +91 -59
  213. package/dist/esm/interface/duplicate-sheet.d.ts.map +1 -1
  214. package/dist/esm/interface/duplicate-sheet.js +4 -9
  215. package/dist/esm/interface/insert-column.d.ts.map +1 -1
  216. package/dist/esm/interface/insert-column.js +1 -1
  217. package/dist/esm/interface/insert-row.d.ts.map +1 -1
  218. package/dist/esm/interface/insert-row.js +1 -1
  219. package/dist/esm/interface/new-sheet.d.ts.map +1 -1
  220. package/dist/esm/interface/new-sheet.js +6 -13
  221. package/dist/esm/sheet-cell.d.ts +9 -0
  222. package/dist/esm/sheet-cell.d.ts.map +1 -1
  223. package/dist/esm/sheet-cell.js +46 -7
  224. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  225. package/package.json +9 -9
@@ -0,0 +1,31 @@
1
+ /** A formula cell the engine stamped as a member of a circular reference. */
2
+ export type CircularReferenceCell = {
3
+ sheetId: number;
4
+ rowIndex: number;
5
+ columnIndex: number;
6
+ };
7
+ export declare const CIRCULAR_REFERENCE_WARNING_TITLE = "Circular Reference";
8
+ /** Excel's circular-reference warning (iterative calculation off: the cells display 0). */
9
+ export declare const CIRCULAR_REFERENCE_WARNING = "There are one or more circular references where a formula refers to its own cell either directly or indirectly. This might cause them to calculate incorrectly. Try removing or changing these references, or moving the formulas to different cells.";
10
+ /**
11
+ * The warning text for a batch of newly circular cells: Excel's sentence plus the addresses so the
12
+ * user can find them (`Sheet2!N20` when the workbook has more than one sheet).
13
+ */
14
+ export declare const formatCircularReferenceWarning: (cells: readonly CircularReferenceCell[], getSheetName?: (sheetId: number) => string | undefined, qualifySheet?: boolean) => string;
15
+ /**
16
+ * Excel warns ONCE when a circular reference appears, not on every recalculation of the loop —
17
+ * this tracks the cells already warned about so a batch only surfaces the NEW ones. A tracked
18
+ * cell is forgotten when a later batch recalculates it without stamping it circular (the loop
19
+ * was broken), so re-creating the loop warns again.
20
+ */
21
+ export declare class CircularReferenceTracker {
22
+ private readonly known;
23
+ /**
24
+ * @param circular the cells this batch stamped circular
25
+ * @param recalculated every cell this batch recomputed (optional — without it, a broken loop is
26
+ * never forgotten, so the same cell warns once per tracker lifetime)
27
+ * @returns the circular cells not warned about before
28
+ */
29
+ next(circular: readonly CircularReferenceCell[] | undefined, recalculated?: Iterable<CircularReferenceCell>): CircularReferenceCell[];
30
+ }
31
+ //# sourceMappingURL=circular-reference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circular-reference.d.ts","sourceRoot":"","sources":["../../../api/circular-reference.ts"],"names":[],"mappings":"AAEA,6EAA6E;AAC7E,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,gCAAgC,uBAAuB,CAAC;AAErE,2FAA2F;AAC3F,eAAO,MAAM,0BAA0B,0PACkN,CAAC;AAO1P;;;GAGG;AACH,eAAO,MAAM,8BAA8B,GACzC,OAAO,SAAS,qBAAqB,EAAE,EACvC,eAAe,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,EACtD,sBAAoB,WAUrB,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAE3C;;;;;OAKG;IACH,IAAI,CACF,QAAQ,EAAE,SAAS,qBAAqB,EAAE,GAAG,SAAS,EACtD,YAAY,CAAC,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GAC7C,qBAAqB,EAAE;CAoB3B"}
@@ -0,0 +1,85 @@
1
+ import { __values } from "tslib";
2
+ import { cellToAddress } from "@rowsncolumns/utils";
3
+ export var CIRCULAR_REFERENCE_WARNING_TITLE = "Circular Reference";
4
+ /** Excel's circular-reference warning (iterative calculation off: the cells display 0). */
5
+ export var CIRCULAR_REFERENCE_WARNING = "There are one or more circular references where a formula refers to its own cell either directly or indirectly. This might cause them to calculate incorrectly. Try removing or changing these references, or moving the formulas to different cells.";
6
+ var MAX_LISTED_CELLS = 8;
7
+ var cellKey = function (cell) {
8
+ return "".concat(cell.sheetId, ":").concat(cell.rowIndex, ":").concat(cell.columnIndex);
9
+ };
10
+ /**
11
+ * The warning text for a batch of newly circular cells: Excel's sentence plus the addresses so the
12
+ * user can find them (`Sheet2!N20` when the workbook has more than one sheet).
13
+ */
14
+ export var formatCircularReferenceWarning = function (cells, getSheetName, qualifySheet) {
15
+ if (qualifySheet === void 0) { qualifySheet = false; }
16
+ var addresses = cells.slice(0, MAX_LISTED_CELLS).map(function (cell) {
17
+ var _a;
18
+ var address = (_a = cellToAddress(cell)) !== null && _a !== void 0 ? _a : "R".concat(cell.rowIndex, "C").concat(cell.columnIndex);
19
+ var sheetName = qualifySheet ? getSheetName === null || getSheetName === void 0 ? void 0 : getSheetName(cell.sheetId) : undefined;
20
+ return sheetName ? "".concat(sheetName, "!").concat(address) : address;
21
+ });
22
+ var more = cells.length - addresses.length;
23
+ var list = more > 0 ? "".concat(addresses.join(", "), " and ").concat(more, " more") : addresses.join(", ");
24
+ return list ? "".concat(CIRCULAR_REFERENCE_WARNING, "\n\nCircular references: ").concat(list) : CIRCULAR_REFERENCE_WARNING;
25
+ };
26
+ /**
27
+ * Excel warns ONCE when a circular reference appears, not on every recalculation of the loop —
28
+ * this tracks the cells already warned about so a batch only surfaces the NEW ones. A tracked
29
+ * cell is forgotten when a later batch recalculates it without stamping it circular (the loop
30
+ * was broken), so re-creating the loop warns again.
31
+ */
32
+ var CircularReferenceTracker = /** @class */ (function () {
33
+ function CircularReferenceTracker() {
34
+ this.known = new Set();
35
+ }
36
+ /**
37
+ * @param circular the cells this batch stamped circular
38
+ * @param recalculated every cell this batch recomputed (optional — without it, a broken loop is
39
+ * never forgotten, so the same cell warns once per tracker lifetime)
40
+ * @returns the circular cells not warned about before
41
+ */
42
+ CircularReferenceTracker.prototype.next = function (circular, recalculated) {
43
+ var e_1, _a, e_2, _b;
44
+ var stamped = new Set((circular !== null && circular !== void 0 ? circular : []).map(cellKey));
45
+ if (recalculated && this.known.size) {
46
+ try {
47
+ for (var recalculated_1 = __values(recalculated), recalculated_1_1 = recalculated_1.next(); !recalculated_1_1.done; recalculated_1_1 = recalculated_1.next()) {
48
+ var cell = recalculated_1_1.value;
49
+ var key = cellKey(cell);
50
+ if (!stamped.has(key)) {
51
+ this.known.delete(key);
52
+ }
53
+ }
54
+ }
55
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
56
+ finally {
57
+ try {
58
+ if (recalculated_1_1 && !recalculated_1_1.done && (_a = recalculated_1.return)) _a.call(recalculated_1);
59
+ }
60
+ finally { if (e_1) throw e_1.error; }
61
+ }
62
+ }
63
+ var fresh = [];
64
+ try {
65
+ for (var _c = __values(circular !== null && circular !== void 0 ? circular : []), _d = _c.next(); !_d.done; _d = _c.next()) {
66
+ var cell = _d.value;
67
+ var key = cellKey(cell);
68
+ if (!this.known.has(key)) {
69
+ this.known.add(key);
70
+ fresh.push(cell);
71
+ }
72
+ }
73
+ }
74
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
75
+ finally {
76
+ try {
77
+ if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
78
+ }
79
+ finally { if (e_2) throw e_2.error; }
80
+ }
81
+ return fresh;
82
+ };
83
+ return CircularReferenceTracker;
84
+ }());
85
+ export { CircularReferenceTracker };
@@ -1,6 +1,7 @@
1
1
  import type { CellInterface, GridRange } from "@rowsncolumns/common-types";
2
2
  import type { CellData, EmbeddedObject, TableView } from "@rowsncolumns/spreadsheet";
3
3
  import type { UseSpreadsheetProps } from "../hooks/use-spreadsheet-state";
4
+ import { type ImageViewport } from "./image-embed";
4
5
  export type ClipBoardFormat = "text/html" | "text/csv" | "text/plain" | "application/json" | "image/apng" | "image/bmp" | "image/gif" | "image/jpeg" | "image/pjpeg" | "image/png" | "image/svg+xml" | "image/tiff" | "image/webp" | "image/x-icon";
5
6
  export declare const SUPPORTED_IMAGE_TYPES: string[];
6
7
  export declare const generateDataFromClipboard: <T extends CellData>(e: ClipboardEvent | undefined, activeCell: CellInterface, sheetId: number, activeSheetName: string, preserveFormatting?: boolean, locale?: string, idCreationStrategy?: UseSpreadsheetProps<T>["idCreationStrategy"], forcePlainText?: boolean, sanitizeHtml?: (html: string) => string, options?: {
@@ -10,6 +11,11 @@ export declare const generateDataFromClipboard: <T extends CellData>(e: Clipboar
10
11
  * only repoints references INTO the moved block, which the consumer does itself.
11
12
  */
12
13
  relocateFormulas?: boolean;
14
+ /**
15
+ * The visible grid area (`CanvasGrid.getSheetDimensions()`): a pasted image FILE becomes a
16
+ * floating picture at its natural size, scaled down to fit this viewport (Excel / Sheets).
17
+ */
18
+ imageViewport?: ImageViewport | null;
13
19
  }) => Promise<{
14
20
  results?: (CellData | null | undefined)[][];
15
21
  merges?: GridRange[];
@@ -1 +1 @@
1
- {"version":3,"file":"copy-paste.d.ts","sourceRoot":"","sources":["../../../api/copy-paste.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,aAAa,EACb,SAAS,EACV,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EACd,SAAS,EAEV,MAAM,2BAA2B,CAAC;AAcnC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAW1E,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,UAAU,GACV,YAAY,GACZ,kBAAkB,GAClB,YAAY,GACZ,WAAW,GACX,WAAW,GACX,YAAY,GACZ,aAAa,GACb,WAAW,GACX,eAAe,GACf,YAAY,GACZ,YAAY,GACZ,cAAc,CAAC;AAEnB,eAAO,MAAM,qBAAqB,UAWjC,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAU,CAAC,SAAS,QAAQ,EAChE,GAAG,cAAc,GAAG,SAAS,EAC7B,YAAY,aAAa,EACzB,SAAS,MAAM,EACf,iBAAiB,MAAM,EACvB,qBAAqB,OAAO,EAC5B,SAAS,MAAM,EACf,qBAAqB,mBAAmB,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,EACjE,iBAAiB,OAAO,EACxB,eAAe,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EACvC,UAAU;IACR;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,KACA,OAAO,CACN;IACE,OAAO,CAAC,EAAE,CAAC,QAAQ,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EAAE,CAAC;IAC5C,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,GACD,SAAS,CAqQZ,CAAC;AAEF,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,SAazC;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,QAAQ,EAC/C,MAAM,EAAE,CAAC,QAAQ,GAAG,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,yCAwB9C;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,QAAQ,EAC1C,MAAM,EAAE,CAAC,QAAQ,GAAG,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,EAC7C,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,yCAkChB;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,QAAQ,EAC5C,MAAM,EAAE,CAAC,QAAQ,GAAG,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,EAC7C,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,yCAwBhB;AAED,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAC7D,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,KACnD,MAAM,EAmBR,CAAC"}
1
+ {"version":3,"file":"copy-paste.d.ts","sourceRoot":"","sources":["../../../api/copy-paste.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,aAAa,EACb,SAAS,EACV,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EACd,SAAS,EAEV,MAAM,2BAA2B,CAAC;AAcnC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAS1E,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAGrE,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,UAAU,GACV,YAAY,GACZ,kBAAkB,GAClB,YAAY,GACZ,WAAW,GACX,WAAW,GACX,YAAY,GACZ,aAAa,GACb,WAAW,GACX,eAAe,GACf,YAAY,GACZ,YAAY,GACZ,cAAc,CAAC;AAEnB,eAAO,MAAM,qBAAqB,UAWjC,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAU,CAAC,SAAS,QAAQ,EAChE,GAAG,cAAc,GAAG,SAAS,EAC7B,YAAY,aAAa,EACzB,SAAS,MAAM,EACf,iBAAiB,MAAM,EACvB,qBAAqB,OAAO,EAC5B,SAAS,MAAM,EACf,qBAAqB,mBAAmB,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,EACjE,iBAAiB,OAAO,EACxB,eAAe,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EACvC,UAAU;IACR;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;CACtC,KACA,OAAO,CACN;IACE,OAAO,CAAC,EAAE,CAAC,QAAQ,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EAAE,CAAC;IAC5C,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,GACD,SAAS,CAkRZ,CAAC;AAEF,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,SAazC;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,QAAQ,EAC/C,MAAM,EAAE,CAAC,QAAQ,GAAG,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,yCAwB9C;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,QAAQ,EAC1C,MAAM,EAAE,CAAC,QAAQ,GAAG,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,EAC7C,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,yCAkChB;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,QAAQ,EAC5C,MAAM,EAAE,CAAC,QAAQ,GAAG,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,EAC7C,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,yCAwBhB;AAED,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAC7D,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,KACnD,MAAM,EAmBR,CAAC"}
@@ -5,6 +5,7 @@ import { uuid } from "@rowsncolumns/utils";
5
5
  import { defaultCellCoords, defaultSheetId, isStyleReference, SheetCell, } from "../sheet-cell";
6
6
  import { isRichSharedString } from "../types";
7
7
  import { isBoolean, isValidURLorEmail } from "./datatype";
8
+ import { createImageEmbed } from "./image-embed";
8
9
  import { parseHtml } from "./parse-html";
9
10
  export var SUPPORTED_IMAGE_TYPES = [
10
11
  "image/apng",
@@ -19,7 +20,7 @@ export var SUPPORTED_IMAGE_TYPES = [
19
20
  "image/x-icon",
20
21
  ];
21
22
  export var generateDataFromClipboard = function (e, activeCell, sheetId, activeSheetName, preserveFormatting, locale, idCreationStrategy, forcePlainText, sanitizeHtml, options) { return __awaiter(void 0, void 0, void 0, function () {
22
- var items, files, formatOrder, plainTextValue, isFormula, format, rows, filesArray, filesArray_1, filesArray_1_1, file, _a, imageUrl, e_1_1, clipboardValue, sheetCell, clipboard, isPlainTextOnly, _b, parsed, sheetData, tables, cellXfs, parsedSharedStrings, sharedStrings_1, tables_1, tables_1_1, table, rowDelta, colDelta, rowSpan, colSpan, merges_1, cellXfsMap_1, results, itemsArray, itemsArray_1, itemsArray_1_1, item, e_2_1, results, results;
23
+ var items, files, formatOrder, plainTextValue, isFormula, format, embeds, filesArray, filesArray_1, filesArray_1_1, file, _a, imageUrl, width, height, e_1_1, clipboardValue, sheetCell, clipboard, isPlainTextOnly, _b, parsed, sheetData, tables, cellXfs, parsedSharedStrings, sharedStrings_1, tables_1, tables_1_1, table, rowDelta, colDelta, rowSpan, colSpan, merges_1, cellXfsMap_1, results, itemsArray, itemsArray_1, itemsArray_1_1, item, e_2_1, results, results;
23
24
  var e_1, _c, e_3, _d, e_2, _e;
24
25
  var _f, _g, _h, _j, _k, _l, _m;
25
26
  return __generator(this, function (_o) {
@@ -39,7 +40,7 @@ export var generateDataFromClipboard = function (e, activeCell, sheetId, activeS
39
40
  ? "text/plain"
40
41
  : formatOrder.find(function (type) { var _a; return (_a = e === null || e === void 0 ? void 0 : e.clipboardData) === null || _a === void 0 ? void 0 : _a.getData(type); });
41
42
  if (!((files === null || files === void 0 ? void 0 : files.length) && !format)) return [3 /*break*/, 9];
42
- rows = [];
43
+ embeds = [];
43
44
  filesArray = Array.from(files);
44
45
  _o.label = 1;
45
46
  case 1:
@@ -54,12 +55,16 @@ export var generateDataFromClipboard = function (e, activeCell, sheetId, activeS
54
55
  }
55
56
  return [4 /*yield*/, readImageFileAsDataUri(file)];
56
57
  case 3:
57
- _a = __read.apply(void 0, [_o.sent(), 1]), imageUrl = _a[0];
58
- rows.push([
59
- {
60
- imageUrl: imageUrl,
61
- },
62
- ]);
58
+ _a = __read.apply(void 0, [_o.sent(), 3]), imageUrl = _a[0], width = _a[1], height = _a[2];
59
+ embeds.push(createImageEmbed({
60
+ sheetId: sheetId,
61
+ anchorCell: activeCell,
62
+ imageUrl: imageUrl,
63
+ width: width,
64
+ height: height,
65
+ viewport: options === null || options === void 0 ? void 0 : options.imageViewport,
66
+ idCreationStrategy: idCreationStrategy,
67
+ }));
63
68
  _o.label = 4;
64
69
  case 4:
65
70
  filesArray_1_1 = filesArray_1.next();
@@ -76,7 +81,8 @@ export var generateDataFromClipboard = function (e, activeCell, sheetId, activeS
76
81
  finally { if (e_1) throw e_1.error; }
77
82
  return [7 /*endfinally*/];
78
83
  case 8: return [2 /*return*/, {
79
- results: rows,
84
+ results: [],
85
+ embeds: embeds,
80
86
  }];
81
87
  case 9:
82
88
  if (!items || !format) {
@@ -252,13 +258,16 @@ export var generateDataFromClipboard = function (e, activeCell, sheetId, activeS
252
258
  results = clipboardValue.split("\n").map(function (cellValues) {
253
259
  return cellValues.split("\t").map(function (value) {
254
260
  var trimmedValue = value.trim();
255
- var isFormula = isAFormula(trimmedValue);
256
261
  var isEmptyValue = trimmedValue.length === 0;
257
- // Force text for formulas (prevent execution), and when forcePlainText
258
- // is enabled, also for booleans (prevent coercion) and URLs (prevent auto-linking)
259
- var needsTextPrefix = isFormula ||
260
- (forcePlainText &&
261
- (isBoolean(trimmedValue) || isValidURLorEmail(trimmedValue)));
262
+ // A pasted `=…` cell is classified exactly like the same text typed into the cell
263
+ // (Excel / Google Sheets parse `=`-prefixed plain text as formulas; a `'=` quote
264
+ // prefix keeps it text, as when typing). Only an explicit "paste as plain text"
265
+ // request (Ctrl/Cmd+Shift+V) forces formulas, booleans (prevent coercion) and URLs
266
+ // (prevent auto-linking) to text.
267
+ var needsTextPrefix = forcePlainText &&
268
+ (isAFormula(trimmedValue) ||
269
+ isBoolean(trimmedValue) ||
270
+ isValidURLorEmail(trimmedValue));
262
271
  var shouldForceText = isPlainTextOnly &&
263
272
  !isEmptyValue &&
264
273
  needsTextPrefix &&
@@ -5,6 +5,8 @@ export declare const pattern_percent = "0%";
5
5
  export declare const pattern_percent_decimal = "0.00%";
6
6
  export declare const pattern_currency = "\"$\"#,##0_);(\"$\"#,##0)";
7
7
  export declare const pattern_currency_decimal = "\"$\"#,##0.00_);(\"$\"#,##0.00)";
8
+ export declare const pattern_comma = "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)";
9
+ export declare const pattern_comma_rounded = "_(* #,##0_);_(* (#,##0);_(* \"-\"??_);_(@_)";
8
10
  export declare const date_pattern = "mm/dd/yyyy";
9
11
  export declare const time_pattern_base = "hh:mm:ss";
10
12
  export declare const time_pattern = "hh:mm:ss AM/PM";
@@ -1 +1 @@
1
- {"version":3,"file":"datatype.d.ts","sourceRoot":"","sources":["../../../api/datatype.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"datatype.d.ts","sourceRoot":"","sources":["../../../api/datatype.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { __read, __values } from "tslib";
2
- import { getDefaultDateFormat, getDefaultDateTimeFormat, isAFormula, isNil, ssfFormat, ssfFormatColor, toDate, toSerial, } from "@rowsncolumns/utils";
2
+ import { getDefaultDateFormat, getDefaultDateTimeFormat, isAFormula, isNil, ssfFormat, ssfFormatColor, toDate, toSerial, toSerialFromParts, } from "@rowsncolumns/utils";
3
3
  import { detectDateFormatPattern, detectDateTimeFormatPattern, isValidDate, isValidDateTime, toTimeSerial, validateDate, validateDateTime, } from "./date";
4
- import { detectDecimalPattern } from "./decimals";
4
+ import { changeDecimals, detectDecimalPattern, getDecimalPlaces, hasThousandsGrouping, pattern_number_thousands, } from "./decimals";
5
5
  import { buildGroupRegex, getGroupingInfo, getLocaleDigitMap, getLocaleSeparators, getPercentSignInfo, getSignInfo, } from "./intl";
6
6
  export var pattern_percent = "0%";
7
7
  export var pattern_percent_decimal = "0.00%";
@@ -12,6 +12,11 @@ export var pattern_percent_decimal = "0.00%";
12
12
  // Excel renders the workbook identically to one it produced itself.
13
13
  export var pattern_currency = '"$"#,##0_);("$"#,##0)';
14
14
  export var pattern_currency_decimal = '"$"#,##0.00_);("$"#,##0.00)';
15
+ // Excel's built-in "Comma Style" / "Comma [0]" cell styles (numFmtId 43 / 41):
16
+ // accounting layout without a currency symbol — negatives in parentheses,
17
+ // zero as `-`, padded so the digits align in a column. Neither is red.
18
+ export var pattern_comma = '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)';
19
+ export var pattern_comma_rounded = '_(* #,##0_);_(* (#,##0);_(* "-"??_);_(@_)';
15
20
  export var date_pattern = "mm/dd/yyyy";
16
21
  export var time_pattern_base = "hh:mm:ss";
17
22
  export var time_pattern = "hh:mm:ss AM/PM";
@@ -429,11 +434,12 @@ export var createNumberValue = function (value, numFormatType, locale, use1904,
429
434
  var isDate = numFormatType === "DATE";
430
435
  var isDateTime = numFormatType === "DATE_TIME";
431
436
  if (typeof value !== "boolean" && (isDate || isDateTime)) {
437
+ // A number is already a serial: applying the Date type only changes the
438
+ // format. Round-tripping it through `toDate`/`toSerial` moved Excel's
439
+ // phantom 1900-02-29 (60) onto the 28th (59) because no `Date` holds the
440
+ // 29th (rowsncolumns/spreadsheet#1026).
432
441
  if (typeof value === "number") {
433
- var dateValue_1 = createDateValueFromNumber(value, use1904);
434
- if (!isNil(dateValue_1) && dateValue_1 instanceof Date) {
435
- return toSerial(dateValue_1, use1904);
436
- }
442
+ return value;
437
443
  }
438
444
  var dateValue = isDate
439
445
  ? validateDate(value, locale)
@@ -443,7 +449,7 @@ export var createNumberValue = function (value, numFormatType, locale, use1904,
443
449
  if (isTimeOnly) {
444
450
  return toTimeSerial(hour !== null && hour !== void 0 ? hour : 0, minute !== null && minute !== void 0 ? minute : 0, second !== null && second !== void 0 ? second : 0);
445
451
  }
446
- return toSerial(new Date(year, month, day, hour, minute, second, 0), use1904);
452
+ return toSerialFromParts(year, month, day, hour, minute, second, use1904);
447
453
  }
448
454
  }
449
455
  return convertToNumber(value, locale, lenientGrouping);
@@ -491,6 +497,33 @@ export var detectNumberFormatType = function (value, locale, lenientGrouping) {
491
497
  return "DATE_TIME";
492
498
  }
493
499
  };
500
+ /**
501
+ * Currency base pattern for a typed literal: the detected symbol in the position it was typed
502
+ * (`$30` → `"$"#,##0`, `12,50 €` → `#,##0"€"`), defaulting to a `$` prefix.
503
+ */
504
+ var currencyBasePattern = function (value) {
505
+ var currencyInfo = extractCurrencySymbol(String(value));
506
+ var symbol = (currencyInfo === null || currencyInfo === void 0 ? void 0 : currencyInfo.symbol) || "$";
507
+ var position = (currencyInfo === null || currencyInfo === void 0 ? void 0 : currencyInfo.position) || "prefix";
508
+ return position === "suffix" ? "#,##0\"".concat(symbol, "\"") : "\"".concat(symbol, "\"#,##0");
509
+ };
510
+ /**
511
+ * Currency / percent pattern whose decimal places are the ones the user TYPED
512
+ * (`$1,234.50` → `"$"#,##0.00`, `50.00%` → `0.00%`), not the parsed number's (`1234.5` → one
513
+ * place), so trailing zeros survive like in Excel. The base already carries the symbol and
514
+ * grouping, so only the decimals are appended. Ports Rust `detect_decimal_pattern_typed`; both
515
+ * `detectValueTypeAndPattern` (typed cell entry) and `detectNumberFormatPattern` go through it
516
+ * so the two never disagree on the same literal.
517
+ */
518
+ var detectTypedDecimalPattern = function (value, numberValue, basePattern, locale) {
519
+ // A JS number carries no typed digits; its own decimal expansion is the best we have (a
520
+ // percent's `numberValue` is already /100, so it must not be the source for a numeric input).
521
+ var typed = typeof value === "string" || typeof value === "number"
522
+ ? value
523
+ : numberValue !== null && numberValue !== void 0 ? numberValue : 0;
524
+ var decimalsLen = getDecimalPlaces(typed, locale);
525
+ return decimalsLen ? changeDecimals(basePattern, decimalsLen, true) : basePattern;
526
+ };
494
527
  /**
495
528
  * Detect pattern of a number format
496
529
  * @param type
@@ -499,16 +532,10 @@ export var detectNumberFormatType = function (value, locale, lenientGrouping) {
499
532
  export var detectNumberFormatPattern = function (value, numberValue, type, locale, use1904) {
500
533
  var _a, _b;
501
534
  if (type === "PERCENT") {
502
- return detectDecimalPattern(value, pattern_percent, locale);
535
+ return detectTypedDecimalPattern(value, numberValue, pattern_percent, locale);
503
536
  }
504
537
  if (type === "CURRENCY") {
505
- // Extract the actual currency symbol and position from the input
506
- var currencyInfo = extractCurrencySymbol(String(value));
507
- var symbol = (currencyInfo === null || currencyInfo === void 0 ? void 0 : currencyInfo.symbol) || "$";
508
- var position = (currencyInfo === null || currencyInfo === void 0 ? void 0 : currencyInfo.position) || "prefix";
509
- // Create a pattern with the detected currency symbol in the correct position
510
- var baseCurrencyPattern = position === "suffix" ? "#,##0\"".concat(symbol, "\"") : "\"".concat(symbol, "\"#,##0");
511
- return detectDecimalPattern(numberValue, baseCurrencyPattern, locale);
538
+ return detectTypedDecimalPattern(value, numberValue, currencyBasePattern(value), locale);
512
539
  }
513
540
  if (type === "DATE") {
514
541
  return (_a = detectDateFormatPattern(value, locale)) !== null && _a !== void 0 ? _a : date_pattern;
@@ -517,17 +544,20 @@ export var detectNumberFormatPattern = function (value, numberValue, type, local
517
544
  return (_b = detectDateTimeFormatPattern(value)) !== null && _b !== void 0 ? _b : time_pattern;
518
545
  }
519
546
  if (type === "NUMBER") {
520
- // An integer zero with no explicit format stays "General" — typing `0`,
521
- // `00`, or a signed zero into a blank cell shouldn't manufacture a `#`
522
- // number pattern that renders the value as blank. This rule is
523
- // specific to the implicit NUMBER format; explicit CURRENCY / PERCENT
524
- // formats keep their own base pattern for zero (handled above), so `$0`
525
- // stays `"$"#,##0` rather than collapsing to a bare `0`.
526
- if (value === 0 ||
527
- (typeof value === "string" && /^[-+]?0+$/.test(value.trim()))) {
528
- return "General";
547
+ // Excel leaves a General cell General for a plain number — `5`, `5.25`,
548
+ // `1.50`, `0.0000123` all display through General (`1.5`, `1.23E-05`)
549
+ // and stamp nothing, so a later entry in the same cell is never rounded
550
+ // through an inferred `#` / `#.00`. Only a thousands-grouped literal
551
+ // (`1,000`, `1,234.56`) is a formatting cue: it stamps `#,##0` plus the
552
+ // typed decimal places, and that stamp then sticks like any other format
553
+ // (Excel shows `0` for a later `0.25`). This rule is specific to the
554
+ // implicit NUMBER format; explicit CURRENCY / PERCENT formats keep their
555
+ // own base pattern (handled above), so `$0` stays `"$"#,##0`.
556
+ if (typeof value === "string" &&
557
+ hasThousandsGrouping(value, locale, numberValue)) {
558
+ return detectDecimalPattern(value, pattern_number_thousands, locale);
529
559
  }
530
- return detectDecimalPattern(value, undefined, locale);
560
+ return "General";
531
561
  }
532
562
  return undefined;
533
563
  };
@@ -590,18 +620,12 @@ export var detectValueTypeAndPattern = function (value, locale, lenientGrouping,
590
620
  }
591
621
  // Check currency
592
622
  if (isCurr) {
593
- // Extract the actual currency symbol and position from the input
594
- var currencyInfo = extractCurrencySymbol(String(value));
595
- var symbol = (currencyInfo === null || currencyInfo === void 0 ? void 0 : currencyInfo.symbol) || "$";
596
- var position = (currencyInfo === null || currencyInfo === void 0 ? void 0 : currencyInfo.position) || "prefix";
597
- // Create a pattern with the detected currency symbol in the correct position
598
- var baseCurrencyPattern = position === "suffix" ? "#,##0\"".concat(symbol, "\"") : "\"".concat(symbol, "\"#,##0");
599
- var pattern = detectDecimalPattern(numberValue, baseCurrencyPattern, locale);
623
+ var pattern = detectTypedDecimalPattern(value, numberValue, currencyBasePattern(value), locale);
600
624
  return ["numberValue", "CURRENCY", numberValue, pattern];
601
625
  }
602
626
  // Numbers can be number, percent, date, datetime
603
627
  if (isPercentage(value, locale, lenientGrouping)) {
604
- var pattern = detectDecimalPattern(numberValue, pattern_percent, locale);
628
+ var pattern = detectTypedDecimalPattern(value, numberValue, pattern_percent, locale);
605
629
  var percentValue = convertToNumber(value, locale, lenientGrouping) / 100;
606
630
  return ["numberValue", "PERCENT", percentValue, pattern];
607
631
  }
@@ -625,14 +649,16 @@ export var detectValueTypeAndPattern = function (value, locale, lenientGrouping,
625
649
  var _a = dateTimeValue.parts, year = _a.year, month = _a.month, day = _a.day, hour = _a.hour, minute = _a.minute, second = _a.second, isTimeOnly = dateTimeValue.isTimeOnly;
626
650
  var numberValue = isTimeOnly
627
651
  ? toTimeSerial(hour !== null && hour !== void 0 ? hour : 0, minute !== null && minute !== void 0 ? minute : 0, second !== null && second !== void 0 ? second : 0)
628
- : toSerial(new Date(year, month, day, hour, minute, second, 0), use1904);
652
+ : toSerialFromParts(year, month, day, hour, minute, second, use1904);
629
653
  return ["numberValue", "DATE_TIME", numberValue, dateTimeValue.format];
630
654
  }
631
655
  // Dates
632
656
  var dateValue = validateDate(value, locale);
633
657
  if (dateValue) {
634
658
  var _b = dateValue.parts, year = _b.year, month = _b.month, day = _b.day, hour = _b.hour, minute = _b.minute, second = _b.second;
635
- var numberValue = toSerial(new Date(year, month, day, hour, minute, second, 0), use1904);
659
+ // Parts, not a `Date`: Excel's phantom 1900-02-29 must land on serial 60
660
+ // rather than roll over to March 1 (rowsncolumns/spreadsheet#1026).
661
+ var numberValue = toSerialFromParts(year, month, day, hour, minute, second, use1904);
636
662
  return ["numberValue", "DATE", numberValue, dateValue.format];
637
663
  }
638
664
  return ["stringValue"];
@@ -1 +1 @@
1
- {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../../api/date.ts"],"names":[],"mappings":"AAoCA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAYD,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,eAAe,GAAG,SAiCpB,CAAC;AAGF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,eAAe,GAAG,SAoEpB,CAAC;AA6CF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,EAAE,QAAQ,MAAM,WAGxE,CAAC;AAwBF,eAAO,MAAM,WAAW,GACtB,OAAO,GAAG,EACV,QAAQ,MAAM,GAAG,SAAS,KACzB,OAKF,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,OAAO,GAAG,KAAG,OAK5C,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAClC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,MAAM,GAAG,SAKX,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,MAAM,GAAG,SAKX,CAAC;AAYF,eAAO,MAAM,cAAc,cAA+B,CAAC;AAC3D,eAAO,MAAM,eAAe,cAAgC,CAAC;AAC7D,eAAO,MAAM,aAAa,cAA8B,CAAC"}
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../../api/date.ts"],"names":[],"mappings":"AAwCA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAYD,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,eAAe,GAAG,SAsCpB,CAAC;AAGF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,eAAe,GAAG,SAsEpB,CAAC;AA6CF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,EAAE,QAAQ,MAAM,WAGxE,CAAC;AAwBF,eAAO,MAAM,WAAW,GACtB,OAAO,GAAG,EACV,QAAQ,MAAM,GAAG,SAAS,KACzB,OAKF,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,OAAO,GAAG,KAAG,OAK5C,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAClC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,MAAM,GAAG,SAKX,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,MAAM,GAAG,SAKX,CAAC;AAYF,eAAO,MAAM,cAAc,cAA+B,CAAC;AAC3D,eAAO,MAAM,eAAe,cAAgC,CAAC;AAC7D,eAAO,MAAM,aAAa,cAA8B,CAAC"}
@@ -17,14 +17,17 @@ var TIME_FORMATS = {
17
17
  FULL: "hh:mm:ss",
18
18
  SHORT_WITH_MERIDIAN: "hh:mm AM/PM",
19
19
  SHORT: "hh:mm",
20
- // Excel "elapsed time" patterns. The square brackets around `h` tell the
21
- // formatter to display the full elapsed-hours count without wrapping at
22
- // 24 — `[h]:mm:ss` will render a 25.5-hour duration as `25:30:00`, not
23
- // `01:30:00`. Excel auto-applies these when the user types a value with
24
- // hours > 24.
25
- FULL_ELAPSED: "[h]:mm:ss",
26
- SHORT_ELAPSED: "[h]:mm",
20
+ // Excel "elapsed time" (Duration) pattern. The square brackets around `h`
21
+ // tell the formatter to display the full elapsed-hours count without
22
+ // wrapping at 24 — `[h]:mm:ss` renders a 25.5-hour duration as `25:30:00`,
23
+ // not `01:30:00`. Excel auto-applies it when the typed hours reach 24
24
+ // (`24:00` is one day, `25:00` a duration) and always shows the seconds, so
25
+ // a typed `25:00` displays `25:00:00` (rowsncolumns/spreadsheet#1027) —
26
+ // the same pattern the Number menu's "Duration" item applies.
27
+ ELAPSED: "[h]:mm:ss",
27
28
  };
29
+ // Typed hours at or past a full day are a Duration, never a clock time.
30
+ var ELAPSED_HOURS_MIN = 24;
28
31
  // Cap elapsed-time hours at Excel's documented limit (`9999:59:59`). Beyond
29
32
  // this, treat as text rather than producing absurdly large fractional
30
33
  // serials. JS `Number.isFinite` would let `Infinity` through, so we cap
@@ -60,12 +63,17 @@ export var validateDate = function (value, locale) {
60
63
  if (year < EXCEL_DATE_MIN_YEAR || year > EXCEL_DATE_MAX_YEAR) {
61
64
  return undefined;
62
65
  }
66
+ // Excel's phantom 1900-02-29 (serial 60): the parser hands back a stand-in
67
+ // `Date` on the 28th with `excelLeapDay` set, because no `Date` can hold the
68
+ // 29th. Report the day the user typed; `toSerialFromParts` maps it to 60
69
+ // (rowsncolumns/spreadsheet#1026).
70
+ var day = "excelLeapDay" in result && result.excelLeapDay ? 29 : dateValue.getDate();
63
71
  return {
64
72
  format: result.pattern,
65
73
  parts: {
66
74
  year: year,
67
75
  month: dateValue.getMonth(),
68
- day: dateValue.getDate(),
76
+ day: day,
69
77
  hour: dateValue.getHours(),
70
78
  minute: dateValue.getMinutes(),
71
79
  second: dateValue.getSeconds(),
@@ -94,10 +102,10 @@ export var validateDateTime = function (value) {
94
102
  var minute = parseInt(match[2], 10);
95
103
  var second = parseInt(match[3], 10);
96
104
  if (isValidTimeComponents(hour, minute, second)) {
97
- // Excel parity: hour > 24 is an elapsed-time entry (e.g. `25:30:00`,
98
- // `48:00:00`). Auto-apply `[h]:mm:ss` so the cell displays the full
99
- // hours count instead of wrapping to `01:30:00`.
100
- var format = hour > 24 ? TIME_FORMATS.FULL_ELAPSED : TIME_FORMATS.FULL;
105
+ // Excel parity: hours >= 24 are an elapsed-time entry (`24:00:00`,
106
+ // `25:30:00`, `48:00:00`). Auto-apply `[h]:mm:ss` so the cell displays
107
+ // the full hours count instead of wrapping to `01:30:00`.
108
+ var format = hour >= ELAPSED_HOURS_MIN ? TIME_FORMATS.ELAPSED : TIME_FORMATS.FULL;
101
109
  return createTimeResult(format, hour, minute, second);
102
110
  }
103
111
  }
@@ -115,8 +123,9 @@ export var validateDateTime = function (value) {
115
123
  var hour = parseInt(match[1], 10);
116
124
  var minute = parseInt(match[2], 10);
117
125
  if (isValidTimeComponents(hour, minute, 0)) {
118
- // Same elapsed-time auto-pattern logic as the full form above.
119
- var format = hour > 24 ? TIME_FORMATS.SHORT_ELAPSED : TIME_FORMATS.SHORT;
126
+ // Same elapsed-time rule as the full form: a duration typed without
127
+ // seconds still gets `[h]:mm:ss` (`25:00` → `25:00:00`, as Excel).
128
+ var format = hour >= ELAPSED_HOURS_MIN ? TIME_FORMATS.ELAPSED : TIME_FORMATS.SHORT;
120
129
  return createTimeResult(format, hour, minute, 0);
121
130
  }
122
131
  }
@@ -1,6 +1,16 @@
1
1
  export declare const pattern_number = "#";
2
2
  export declare const pattern_number_thousands = "#,##0";
3
3
  export declare const getDecimalPlaces: (value: string | number, locale?: string) => number;
4
+ /**
5
+ * Whether a typed literal groups its integer part with the locale's thousands
6
+ * separator (`1,000` / `1,234.56` in en-US, `1.234,56` in de-DE, `1 234` in
7
+ * fr-FR). In a comma-decimal locale a canonical dot-decimal string (`1.234`)
8
+ * is ambiguous — the programmatic decimal 1.234, or the grouped 1234 — so when
9
+ * the caller knows what the literal parsed to (`parsedValue`) that decides;
10
+ * without it the canonical reading wins, so the locale's `.` group separator
11
+ * is not mistaken for grouping. Rust `has_thousands_grouping`.
12
+ */
13
+ export declare const hasThousandsGrouping: (value: string | number, locale?: string, parsedValue?: number) => boolean;
4
14
  export declare const detectDecimalPattern: (value: string | number | boolean | Date | undefined, defaultPattern?: string, locale?: string) => string;
5
15
  export declare const changeDecimals: (pattern?: string | undefined, changeBy?: number, delta?: boolean) => string;
6
16
  export declare const getCurrentDecimalCountInPattern: (pattern?: string | undefined | null) => number;
@@ -1 +1 @@
1
- {"version":3,"file":"decimals.d.ts","sourceRoot":"","sources":["../../../api/decimals.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAyDhD,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,GAAG,MAAM,EACtB,SAAS,MAAM,KACd,MAsCF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,uBAA+B,EAC/B,SAAS,MAAM,WAkChB,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,UAAS,MAAM,GAAG,SAAc,EAChC,WAAU,MAAU,EACpB,eAAY,WAuCb,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,UAAS,MAAM,GAAG,SAAS,GAAG,IAAS,WAexC,CAAC;AAGF,eAAO,MAAM,oBAAoB,GAAI,UAAS,MAAM,GAAG,SAAc,WAwBpE,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,UAAS,MAAM,GAAG,SAAc,WAQvE,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,UAAS,MAAM,GAAG,SAAc,YAIrE,CAAC"}
1
+ {"version":3,"file":"decimals.d.ts","sourceRoot":"","sources":["../../../api/decimals.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAyDhD,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,GAAG,MAAM,EACtB,SAAS,MAAM,KACd,MAsCF,CAAC;AAcF;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,MAAM,GAAG,MAAM,EACtB,SAAS,MAAM,EACf,cAAc,MAAM,KACnB,OAeF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,uBAA+B,EAC/B,SAAS,MAAM,WAsBhB,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,UAAS,MAAM,GAAG,SAAc,EAChC,WAAU,MAAU,EACpB,eAAY,WAuCb,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,UAAS,MAAM,GAAG,SAAS,GAAG,IAAS,WAexC,CAAC;AAGF,eAAO,MAAM,oBAAoB,GAAI,UAAS,MAAM,GAAG,SAAc,WAwBpE,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,UAAS,MAAM,GAAG,SAAc,WAQvE,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,UAAS,MAAM,GAAG,SAAc,YAIrE,CAAC"}
@@ -76,20 +76,43 @@ export var getDecimalPlaces = function (value, locale) {
76
76
  // Return the length of the decimal part
77
77
  return decimalPart.length;
78
78
  };
79
- export var detectDecimalPattern = function (value, defaultPattern, locale) {
80
- if (defaultPattern === void 0) { defaultPattern = pattern_number; }
81
- var str = typeof value === "number" ? normalizeFloatingPointString(value) : String(value);
79
+ var WHITESPACE_GROUP_REGEX = /[\s\u00A0\u202F]/;
80
+ /**
81
+ * Whether `integerPart` contains the locale's group separator. Locales that
82
+ * group with a space accept the whole whitespace family (regular, no-break,
83
+ * narrow no-break) — users type a plain space for fr-FR's `\u202F`.
84
+ */
85
+ var integerPartHasGroup = function (integerPart, group) {
86
+ return group.trim() === ""
87
+ ? WHITESPACE_GROUP_REGEX.test(integerPart)
88
+ : integerPart.includes(group);
89
+ };
90
+ /**
91
+ * Whether a typed literal groups its integer part with the locale's thousands
92
+ * separator (`1,000` / `1,234.56` in en-US, `1.234,56` in de-DE, `1 234` in
93
+ * fr-FR). In a comma-decimal locale a canonical dot-decimal string (`1.234`)
94
+ * is ambiguous — the programmatic decimal 1.234, or the grouped 1234 — so when
95
+ * the caller knows what the literal parsed to (`parsedValue`) that decides;
96
+ * without it the canonical reading wins, so the locale's `.` group separator
97
+ * is not mistaken for grouping. Rust `has_thousands_grouping`.
98
+ */
99
+ export var hasThousandsGrouping = function (value, locale, parsedValue) {
100
+ var str = typeof value === "number" ? normalizeFloatingPointString(value) : value;
82
101
  var _a = getLocaleSeparators(locale), decimal = _a.decimal, group = _a.group;
83
102
  var groupSeparator = group !== null && group !== void 0 ? group : ",";
84
103
  var decimalSeparator = decimal !== null && decimal !== void 0 ? decimal : ".";
85
- var usesCanonicalDotDecimal = decimalSeparator !== "." && CANONICAL_DOT_DECIMAL_REGEX.test(str);
86
- var effectiveDecimalSeparator = usesCanonicalDotDecimal
87
- ? "."
88
- : decimalSeparator;
89
- var integerPart = effectiveDecimalSeparator
90
- ? str.split(effectiveDecimalSeparator)[0]
91
- : str;
92
- var hasThousands = Boolean(groupSeparator) && integerPart.includes(groupSeparator);
104
+ if (decimalSeparator !== "." && CANONICAL_DOT_DECIMAL_REGEX.test(str)) {
105
+ return (parsedValue !== undefined &&
106
+ Number(str) !== parsedValue &&
107
+ integerPartHasGroup(str, groupSeparator));
108
+ }
109
+ var integerPart = str.split(decimalSeparator)[0];
110
+ return Boolean(groupSeparator) && integerPartHasGroup(integerPart, groupSeparator);
111
+ };
112
+ export var detectDecimalPattern = function (value, defaultPattern, locale) {
113
+ if (defaultPattern === void 0) { defaultPattern = pattern_number; }
114
+ var str = typeof value === "number" ? normalizeFloatingPointString(value) : String(value);
115
+ var hasThousands = hasThousandsGrouping(str, locale);
93
116
  var decimalsLen = getDecimalPlaces(value, locale);
94
117
  // Use "0" pattern for numbers less than 1 to ensure leading zero
95
118
  var numValue = Number(str.replace(/[^0-9.-]/g, ""));