@rowsncolumns/y-spreadsheet 14.0.32

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 (53) hide show
  1. package/LICENSE.md +100 -0
  2. package/Readme.md +77 -0
  3. package/dist/cjs/helpers.d.ts +179 -0
  4. package/dist/cjs/helpers.d.ts.map +1 -0
  5. package/dist/cjs/helpers.js +1635 -0
  6. package/dist/cjs/index.d.ts +6 -0
  7. package/dist/cjs/index.d.ts.map +1 -0
  8. package/dist/cjs/index.js +8 -0
  9. package/dist/cjs/observables.d.ts +10 -0
  10. package/dist/cjs/observables.d.ts.map +1 -0
  11. package/dist/cjs/observables.js +90 -0
  12. package/dist/cjs/profiling/batch-profile.spec.d.ts +2 -0
  13. package/dist/cjs/profiling/batch-profile.spec.d.ts.map +1 -0
  14. package/dist/cjs/profiling/batch-profile.spec.js +175 -0
  15. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -0
  16. package/dist/cjs/types.d.ts +62 -0
  17. package/dist/cjs/types.d.ts.map +1 -0
  18. package/dist/cjs/types.js +2 -0
  19. package/dist/cjs/use-yspreadsheet-v2.d.ts +152 -0
  20. package/dist/cjs/use-yspreadsheet-v2.d.ts.map +1 -0
  21. package/dist/cjs/use-yspreadsheet-v2.js +980 -0
  22. package/dist/cjs/use-yspreadsheet.d.ts +39 -0
  23. package/dist/cjs/use-yspreadsheet.d.ts.map +1 -0
  24. package/dist/cjs/use-yspreadsheet.js +430 -0
  25. package/dist/cjs/vitest.config.d.ts +3 -0
  26. package/dist/cjs/vitest.config.d.ts.map +1 -0
  27. package/dist/cjs/vitest.config.js +23 -0
  28. package/dist/esm/helpers.d.ts +179 -0
  29. package/dist/esm/helpers.d.ts.map +1 -0
  30. package/dist/esm/helpers.js +1346 -0
  31. package/dist/esm/index.d.ts +6 -0
  32. package/dist/esm/index.d.ts.map +1 -0
  33. package/dist/esm/index.js +5 -0
  34. package/dist/esm/observables.d.ts +10 -0
  35. package/dist/esm/observables.d.ts.map +1 -0
  36. package/dist/esm/observables.js +51 -0
  37. package/dist/esm/profiling/batch-profile.spec.d.ts +2 -0
  38. package/dist/esm/profiling/batch-profile.spec.d.ts.map +1 -0
  39. package/dist/esm/profiling/batch-profile.spec.js +131 -0
  40. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -0
  41. package/dist/esm/types.d.ts +62 -0
  42. package/dist/esm/types.d.ts.map +1 -0
  43. package/dist/esm/types.js +1 -0
  44. package/dist/esm/use-yspreadsheet-v2.d.ts +152 -0
  45. package/dist/esm/use-yspreadsheet-v2.d.ts.map +1 -0
  46. package/dist/esm/use-yspreadsheet-v2.js +814 -0
  47. package/dist/esm/use-yspreadsheet.d.ts +39 -0
  48. package/dist/esm/use-yspreadsheet.d.ts.map +1 -0
  49. package/dist/esm/use-yspreadsheet.js +304 -0
  50. package/dist/esm/vitest.config.d.ts +3 -0
  51. package/dist/esm/vitest.config.d.ts.map +1 -0
  52. package/dist/esm/vitest.config.js +21 -0
  53. package/package.json +54 -0
@@ -0,0 +1,1635 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processSheetDataEventsV3 = exports.addSheetDataPatchesV3 = exports.getSheetDataV3 = exports.deleteSheetV3 = exports.deleteCellV3 = exports.setCellV3 = exports.getCellV3 = exports.sheetDataV3ToV2 = exports.sheetDataV2ToV3 = exports.createCellDataV3 = exports.parseCellKeyV3 = exports.createCellKeyV3 = exports.processSheetDataEvents = exports.applyMapPatches = exports.validateSheets = exports.updateArrayType = exports.mergeErrorEffectiveValueIntoCellData = exports.shouldPersistErrorCellPatch = exports.filterErrorCellPatches = exports.getCellDataErrorValue = exports.getCellDataFromYSheetData = exports.removeRowData = exports.setCellDataInRowData = exports.getRowDataFromSheet = exports.deleteSheetFromYSheetData = exports.getSheetFromYSheetData = exports.addSheetDataPatches = exports.applyPatchesToYDoc = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var utils_1 = require("@rowsncolumns/utils");
6
+ var Y = tslib_1.__importStar(require("yjs"));
7
+ var cloneDeep_1 = tslib_1.__importDefault(require("lodash/cloneDeep"));
8
+ var isEqual_1 = tslib_1.__importDefault(require("lodash/isEqual"));
9
+ var set_1 = tslib_1.__importDefault(require("lodash/set"));
10
+ var get_1 = tslib_1.__importDefault(require("lodash/get"));
11
+ var unset_1 = tslib_1.__importDefault(require("lodash/unset"));
12
+ /**
13
+ * Apply patches to yjs
14
+ * @param doc
15
+ * @param userId
16
+ * @param patches
17
+ * @param source
18
+ * @param sheetDataVersion - Version of sheet data format ("v2" or "v3"). Falls back to docMeta if undefined.
19
+ */
20
+ var applyPatchesToYDoc = function (doc, userId, patches, source, sheetDataVersion) {
21
+ var e_1, _a;
22
+ var _b, _c;
23
+ var ySheetDataV2 = doc.getMap("sheetDataV2");
24
+ var ySheetDataV3 = doc.getMap("sheetDataV3");
25
+ var yDocMeta = doc.getMap("docMeta");
26
+ var yRecalcCells = doc.getArray("recalcCells");
27
+ var ySheets = doc.getArray("sheets");
28
+ var yTables = doc.getArray("tables");
29
+ var yEmbeds = doc.getArray("embeds");
30
+ var yCharts = doc.getArray("charts");
31
+ var yConditionalFormats = doc.getArray("conditionalFormats");
32
+ var yDataValidations = doc.getArray("dataValidations");
33
+ var yNamedRanges = doc.getArray("namedRanges");
34
+ var ySharedStringsMap = doc.getMap("sharedStringsMap");
35
+ var yProtectedRanges = doc.getArray("protectedRanges");
36
+ var yCellXfs = doc.getMap("cellXfs");
37
+ var yDisableRecalc = doc.getMap("disableRecalc");
38
+ // Check version flag to determine which sheet data format to use
39
+ // Use param if provided, otherwise fall back to docMeta for backwards compatibility
40
+ var resolvedVersion = sheetDataVersion !== null && sheetDataVersion !== void 0 ? sheetDataVersion : yDocMeta.get("sheetDataVersion");
41
+ var isV3 = resolvedVersion === "v3";
42
+ try {
43
+ for (var patches_1 = tslib_1.__values(patches), patches_1_1 = patches_1.next(); !patches_1_1.done; patches_1_1 = patches_1.next()) {
44
+ var _d = tslib_1.__read(patches_1_1.value, 2), patch = _d[0], _e = _d[1], type = _e === void 0 ? "redo" : _e;
45
+ type = type !== null && type !== void 0 ? type : "redo";
46
+ var patchKey = type === "redo" ? "patches" : "inversePatches";
47
+ if (patch.sheetData) {
48
+ var patches_2 = (_b = patch.sheetData) === null || _b === void 0 ? void 0 : _b[patchKey];
49
+ if (isV3) {
50
+ (0, exports.addSheetDataPatchesV3)(ySheetDataV3, patches_2);
51
+ }
52
+ else {
53
+ (0, exports.addSheetDataPatches)(ySheetDataV2, patches_2);
54
+ }
55
+ }
56
+ if (patch.sheets) {
57
+ var patches_3 = patch.sheets[patchKey];
58
+ (0, exports.updateArrayType)(ySheets, patches_3);
59
+ }
60
+ if (patch.tables) {
61
+ var patches_4 = patch.tables[patchKey];
62
+ (0, exports.updateArrayType)(yTables, patches_4);
63
+ }
64
+ if (patch.embeds) {
65
+ var patches_5 = patch.embeds[patchKey];
66
+ (0, exports.updateArrayType)(yEmbeds, patches_5);
67
+ }
68
+ if (patch.charts) {
69
+ var patches_6 = patch.charts[patchKey];
70
+ (0, exports.updateArrayType)(yCharts, patches_6);
71
+ }
72
+ if (patch.conditionalFormats) {
73
+ var patches_7 = patch.conditionalFormats[patchKey];
74
+ (0, exports.updateArrayType)(yConditionalFormats, patches_7);
75
+ }
76
+ if (patch.dataValidations) {
77
+ var patches_8 = patch.dataValidations[patchKey];
78
+ (0, exports.updateArrayType)(yDataValidations, patches_8);
79
+ }
80
+ if (patch.namedRanges) {
81
+ var patches_9 = patch.namedRanges[patchKey];
82
+ (0, exports.updateArrayType)(yNamedRanges, patches_9);
83
+ }
84
+ if (patch.sharedStrings) {
85
+ var patches_10 = patch.sharedStrings[patchKey];
86
+ // Always use Map for shared strings
87
+ (0, exports.applyMapPatches)(ySharedStringsMap, patches_10);
88
+ }
89
+ if (patch.protectedRanges) {
90
+ var patches_11 = patch.protectedRanges[patchKey];
91
+ (0, exports.updateArrayType)(yProtectedRanges, patches_11);
92
+ }
93
+ if (patch.cellXfs) {
94
+ var patches_12 = patch.cellXfs[patchKey];
95
+ (0, exports.applyMapPatches)(yCellXfs, patches_12);
96
+ }
97
+ // Recalc cells
98
+ if ((_c = patch.recalcCells) === null || _c === void 0 ? void 0 : _c[type]) {
99
+ // Removing this
100
+ // multiple calls to update_sheet_range deletes recalc cells
101
+ // yRecalcCells.delete(0, yRecalcCells.length);
102
+ yRecalcCells.push([
103
+ {
104
+ userId: userId,
105
+ patches: Array.from(patch.recalcCells[type]).map(function (value) {
106
+ return tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(value), false), [source !== null && source !== void 0 ? source : "agent"], false);
107
+ }),
108
+ },
109
+ ]);
110
+ }
111
+ }
112
+ }
113
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
114
+ finally {
115
+ try {
116
+ if (patches_1_1 && !patches_1_1.done && (_a = patches_1.return)) _a.call(patches_1);
117
+ }
118
+ finally { if (e_1) throw e_1.error; }
119
+ }
120
+ // Set disable recalc flag (only if it's currently truthy, to avoid redundant Y.Map writes)
121
+ if (yDisableRecalc.get("disableRecalc") !== false) {
122
+ yDisableRecalc.set("disableRecalc", false);
123
+ }
124
+ };
125
+ exports.applyPatchesToYDoc = applyPatchesToYDoc;
126
+ /**
127
+ * Add sheet data to a yjs map using immer patches
128
+ *
129
+ * Optimized for bulk operations (paste, import) by consolidating cell-level
130
+ * patches before applying to Y.js. This reduces overhead by:
131
+ * 1. Deduplicating patches targeting the same cell (later patches win)
132
+ * 2. Grouping updates by sheet/row for efficient batch application
133
+ */
134
+ var addSheetDataPatches = function (ySheetData, patches) {
135
+ var e_2, _a, e_3, _b, e_4, _c, e_5, _d, e_6, _e;
136
+ // Optimization: Pre-process and consolidate cell-level patches
137
+ // For bulk operations like paste (10k+ rows), this dramatically reduces overhead
138
+ // Key format: "sheetId:rowIndex:columnIndex"
139
+ var cellUpdates = new Map();
140
+ var otherPatches = [];
141
+ try {
142
+ // First pass: categorize and consolidate patches
143
+ for (var patches_13 = tslib_1.__values(patches), patches_13_1 = patches_13.next(); !patches_13_1.done; patches_13_1 = patches_13.next()) {
144
+ var patch = patches_13_1.value;
145
+ var op = patch.op, path = patch.path, value = patch.value;
146
+ var _f = tslib_1.__read(path, 1), sheetIdRaw = _f[0];
147
+ // Handle undefined sheetId separately (full replace)
148
+ if (typeof sheetIdRaw === "undefined") {
149
+ otherPatches.push(patch);
150
+ continue;
151
+ }
152
+ // Use string representation for sheet ID to handle both string and numeric IDs
153
+ var sheetIdStr = String(sheetIdRaw);
154
+ if (op === "replace" || op === "add") {
155
+ // [sheetId, rowIndex, 'values', columnIndex] - Single cell update (most common in paste)
156
+ if (path.length === 4) {
157
+ var _g = tslib_1.__read(path, 4), rowIndex = _g[1], columnIndex = _g[3];
158
+ var rowIdx = Number(rowIndex);
159
+ var colIdx = Number(columnIndex);
160
+ var key = "".concat(sheetIdStr, ":").concat(rowIdx, ":").concat(colIdx);
161
+ // Later patches override earlier ones for the same cell
162
+ cellUpdates.set(key, { sheetIdStr: sheetIdStr, rowIdx: rowIdx, colIdx: colIdx, value: value });
163
+ }
164
+ else {
165
+ // Row-level or sheet-level updates
166
+ otherPatches.push(patch);
167
+ }
168
+ }
169
+ else if (op === "remove") {
170
+ if (path.length === 4) {
171
+ var _h = tslib_1.__read(path, 4), rowIndex = _h[1], columnIndex = _h[3];
172
+ var rowIdx = Number(rowIndex);
173
+ var colIdx = Number(columnIndex);
174
+ var key = "".concat(sheetIdStr, ":").concat(rowIdx, ":").concat(colIdx);
175
+ cellUpdates.set(key, { sheetIdStr: sheetIdStr, rowIdx: rowIdx, colIdx: colIdx, value: null });
176
+ }
177
+ else {
178
+ otherPatches.push(patch);
179
+ }
180
+ }
181
+ else {
182
+ otherPatches.push(patch);
183
+ }
184
+ }
185
+ }
186
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
187
+ finally {
188
+ try {
189
+ if (patches_13_1 && !patches_13_1.done && (_a = patches_13.return)) _a.call(patches_13);
190
+ }
191
+ finally { if (e_2) throw e_2.error; }
192
+ }
193
+ // Second pass: Group cell updates by sheet and row for efficient batch application
194
+ // This minimizes Y.js operations by batching updates to the same row
195
+ var sheetRowUpdates = new Map();
196
+ try {
197
+ for (var cellUpdates_1 = tslib_1.__values(cellUpdates), cellUpdates_1_1 = cellUpdates_1.next(); !cellUpdates_1_1.done; cellUpdates_1_1 = cellUpdates_1.next()) {
198
+ var _j = tslib_1.__read(cellUpdates_1_1.value, 2), _k = _j[1], sheetIdStr = _k.sheetIdStr, rowIdx = _k.rowIdx, colIdx = _k.colIdx, value = _k.value;
199
+ if (!sheetRowUpdates.has(sheetIdStr)) {
200
+ sheetRowUpdates.set(sheetIdStr, new Map());
201
+ }
202
+ var rowUpdates = sheetRowUpdates.get(sheetIdStr);
203
+ if (!rowUpdates.has(rowIdx)) {
204
+ rowUpdates.set(rowIdx, new Map());
205
+ }
206
+ rowUpdates.get(rowIdx).set(colIdx, value);
207
+ }
208
+ }
209
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
210
+ finally {
211
+ try {
212
+ if (cellUpdates_1_1 && !cellUpdates_1_1.done && (_b = cellUpdates_1.return)) _b.call(cellUpdates_1);
213
+ }
214
+ finally { if (e_3) throw e_3.error; }
215
+ }
216
+ try {
217
+ // Apply batched cell updates
218
+ for (var sheetRowUpdates_1 = tslib_1.__values(sheetRowUpdates), sheetRowUpdates_1_1 = sheetRowUpdates_1.next(); !sheetRowUpdates_1_1.done; sheetRowUpdates_1_1 = sheetRowUpdates_1.next()) {
219
+ var _l = tslib_1.__read(sheetRowUpdates_1_1.value, 2), sheetIdStr = _l[0], rowUpdates = _l[1];
220
+ var ysheet = (0, exports.getSheetFromYSheetData)(ySheetData, sheetIdStr);
221
+ try {
222
+ for (var rowUpdates_1 = (e_5 = void 0, tslib_1.__values(rowUpdates)), rowUpdates_1_1 = rowUpdates_1.next(); !rowUpdates_1_1.done; rowUpdates_1_1 = rowUpdates_1.next()) {
223
+ var _m = tslib_1.__read(rowUpdates_1_1.value, 2), rowIdx = _m[0], colUpdates = _m[1];
224
+ var rowData = (0, exports.getRowDataFromSheet)(ysheet, rowIdx);
225
+ try {
226
+ for (var colUpdates_1 = (e_6 = void 0, tslib_1.__values(colUpdates)), colUpdates_1_1 = colUpdates_1.next(); !colUpdates_1_1.done; colUpdates_1_1 = colUpdates_1.next()) {
227
+ var _o = tslib_1.__read(colUpdates_1_1.value, 2), colIdx = _o[0], value = _o[1];
228
+ (0, exports.setCellDataInRowData)(rowData, colIdx, value);
229
+ }
230
+ }
231
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
232
+ finally {
233
+ try {
234
+ if (colUpdates_1_1 && !colUpdates_1_1.done && (_e = colUpdates_1.return)) _e.call(colUpdates_1);
235
+ }
236
+ finally { if (e_6) throw e_6.error; }
237
+ }
238
+ }
239
+ }
240
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
241
+ finally {
242
+ try {
243
+ if (rowUpdates_1_1 && !rowUpdates_1_1.done && (_d = rowUpdates_1.return)) _d.call(rowUpdates_1);
244
+ }
245
+ finally { if (e_5) throw e_5.error; }
246
+ }
247
+ }
248
+ }
249
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
250
+ finally {
251
+ try {
252
+ if (sheetRowUpdates_1_1 && !sheetRowUpdates_1_1.done && (_c = sheetRowUpdates_1.return)) _c.call(sheetRowUpdates_1);
253
+ }
254
+ finally { if (e_4) throw e_4.error; }
255
+ }
256
+ // Process non-cell-level patches using original logic
257
+ var processPatch = function (_a) {
258
+ var op = _a.op, path = _a.path, value = _a.value;
259
+ var _b = tslib_1.__read(path, 1), sheetId = _b[0];
260
+ if (typeof sheetId === "undefined") {
261
+ // Replace. User is replacing the entire data
262
+ if (op === "replace") {
263
+ // Remove all sheet data
264
+ ySheetData.clear();
265
+ }
266
+ // Assign values
267
+ for (var curSheetId in value) {
268
+ var sheetId_1 = Number(curSheetId);
269
+ processPatch({
270
+ op: "replace",
271
+ path: [sheetId_1],
272
+ value: value[curSheetId],
273
+ });
274
+ }
275
+ return;
276
+ }
277
+ if (op === "replace" || op === "add") {
278
+ var ysheet_1 = (0, exports.getSheetFromYSheetData)(ySheetData, sheetId);
279
+ // Cell-level patches (path.length === 4) are already handled above via consolidation
280
+ // [sheetId, rowIndex, 'values'] - Replace values array directly
281
+ if (path.length === 3 && path[2] === "values") {
282
+ var _c = tslib_1.__read(path, 2), rowIndex = _c[1];
283
+ var rowData_1 = (0, exports.getRowDataFromSheet)(ysheet_1, rowIndex);
284
+ // Clear existing row data
285
+ rowData_1.delete(0, rowData_1.length);
286
+ if (Array.isArray(value)) {
287
+ // Value is the values array directly
288
+ // Sort keys to maintain order during insertion
289
+ Object.entries(value)
290
+ .sort(function (_a, _b) {
291
+ var _c = tslib_1.__read(_a, 1), a = _c[0];
292
+ var _d = tslib_1.__read(_b, 1), b = _d[0];
293
+ return Number(a) - Number(b);
294
+ })
295
+ .forEach(function (_a) {
296
+ var _b = tslib_1.__read(_a, 2), columnIndex = _b[0], cellData = _b[1];
297
+ (0, exports.setCellDataInRowData)(rowData_1, Number(columnIndex), cellData);
298
+ });
299
+ }
300
+ }
301
+ // [sheetId, rowIndex] - Entire row update
302
+ else if (path.length === 2) {
303
+ var _d = tslib_1.__read(path, 2), rowIndex = _d[1];
304
+ if (value === null || value === void 0 ? void 0 : value.values) {
305
+ // Replace entire row with new values
306
+ var rowData_2 = (0, exports.getRowDataFromSheet)(ysheet_1, rowIndex);
307
+ // Clear existing row data
308
+ rowData_2.delete(0, rowData_2.length);
309
+ // Add new cell values
310
+ // Sort keys to maintain order during insertion
311
+ Object.entries(value.values)
312
+ .sort(function (_a, _b) {
313
+ var _c = tslib_1.__read(_a, 1), a = _c[0];
314
+ var _d = tslib_1.__read(_b, 1), b = _d[0];
315
+ return Number(a) - Number(b);
316
+ })
317
+ .forEach(function (_a) {
318
+ var _b = tslib_1.__read(_a, 2), columnIndex = _b[0], cellData = _b[1];
319
+ (0, exports.setCellDataInRowData)(rowData_2, Number(columnIndex), cellData);
320
+ });
321
+ }
322
+ else {
323
+ // Remove row if value is null/undefined
324
+ (0, exports.removeRowData)(ysheet_1, rowIndex);
325
+ }
326
+ }
327
+ // [sheetId] - Entire sheet update
328
+ else if (path.length === 1) {
329
+ if (value) {
330
+ // Clear entire sheet
331
+ ysheet_1.delete(0, ysheet_1.length);
332
+ // Add all new data
333
+ Object.entries(value)
334
+ .sort(function (_a, _b) {
335
+ var _c = tslib_1.__read(_a, 1), a = _c[0];
336
+ var _d = tslib_1.__read(_b, 1), b = _d[0];
337
+ return Number(a) - Number(b);
338
+ })
339
+ .forEach(function (_a) {
340
+ var _b = tslib_1.__read(_a, 2), rowIndex = _b[0], rowData = _b[1];
341
+ if (rowData === null || rowData === void 0 ? void 0 : rowData.values) {
342
+ var rowDataArray_1 = (0, exports.getRowDataFromSheet)(ysheet_1, Number(rowIndex));
343
+ Object.entries(rowData.values)
344
+ .sort(function (_a, _b) {
345
+ var _c = tslib_1.__read(_a, 1), a = _c[0];
346
+ var _d = tslib_1.__read(_b, 1), b = _d[0];
347
+ return Number(a) - Number(b);
348
+ })
349
+ .forEach(function (_a) {
350
+ var _b = tslib_1.__read(_a, 2), columnIndex = _b[0], cellData = _b[1];
351
+ (0, exports.setCellDataInRowData)(rowDataArray_1, Number(columnIndex), cellData);
352
+ });
353
+ }
354
+ });
355
+ }
356
+ }
357
+ }
358
+ else if (op === "remove") {
359
+ // Cell-level removes (path.length === 4) are already handled above via consolidation
360
+ // [sheetId, rowIndex] - Remove entire row
361
+ if (path.length === 2) {
362
+ var _e = tslib_1.__read(path, 2), rowIndex = _e[1];
363
+ var ysheet = (0, exports.getSheetFromYSheetData)(ySheetData, sheetId);
364
+ (0, exports.removeRowData)(ysheet, rowIndex);
365
+ }
366
+ // [sheetId] - Remove entire sheet
367
+ else if (path.length === 1) {
368
+ (0, exports.deleteSheetFromYSheetData)(ySheetData, sheetId);
369
+ }
370
+ }
371
+ };
372
+ // Only process non-cell-level patches (cell-level already handled via consolidation)
373
+ otherPatches.forEach(processPatch);
374
+ };
375
+ exports.addSheetDataPatches = addSheetDataPatches;
376
+ var getSheetFromYSheetData = function (ySheetData, sheetId) {
377
+ var id = String(sheetId);
378
+ var sheet = ySheetData.get(id);
379
+ if (!sheet) {
380
+ sheet = new Y.Array();
381
+ ySheetData.set(id, sheet);
382
+ }
383
+ return sheet;
384
+ };
385
+ exports.getSheetFromYSheetData = getSheetFromYSheetData;
386
+ var deleteSheetFromYSheetData = function (ySheetData, sheetId) {
387
+ var id = String(sheetId);
388
+ ySheetData.delete(id);
389
+ };
390
+ exports.deleteSheetFromYSheetData = deleteSheetFromYSheetData;
391
+ var getRowDataFromSheet = function (ysheet, rowIndex) {
392
+ var index = Number(rowIndex);
393
+ if (index < 0) {
394
+ throw new Error("Row index cannot be negative");
395
+ }
396
+ // Extend array if needed
397
+ if (index >= ysheet.length) {
398
+ var padding = new Array(index - ysheet.length).fill(null);
399
+ ysheet.insert(ysheet.length, padding);
400
+ ysheet.insert(index, [null]); // Insert null first
401
+ // Create new row data
402
+ var newRowData = new Y.Map();
403
+ newRowData.set("values", new Y.Array());
404
+ // Replace the null
405
+ ysheet.insert(index, [newRowData]);
406
+ ysheet.delete(index + 1, 1);
407
+ // Delete the initially inserted null (wait, index shifts)
408
+ // index is target.
409
+ // Insert padding up to index. length = index.
410
+ // Insert null at index. length = index+1.
411
+ // Replace null at index.
412
+ // Insert newRowData at index. length = index+2.
413
+ // Delete at index+1. length = index+1.
414
+ // Correct.
415
+ return newRowData.get("values");
416
+ }
417
+ // Get or create existing row data
418
+ var rowData = ysheet.get(index);
419
+ if (!rowData || !rowData.get("values")) {
420
+ // Create new row data if it doesn't exist or is incomplete
421
+ var newRowData = new Y.Map();
422
+ newRowData.set("values", new Y.Array());
423
+ // Replace the existing item
424
+ ysheet.insert(index, [newRowData]);
425
+ ysheet.delete(index + 1, 1);
426
+ return newRowData.get("values");
427
+ }
428
+ return rowData.get("values");
429
+ };
430
+ exports.getRowDataFromSheet = getRowDataFromSheet;
431
+ var setCellDataInRowData = function (rowData, columnIndex, cellData) {
432
+ if (cellData === void 0) { cellData = null; }
433
+ var index = Number(columnIndex);
434
+ // Extend array if needed
435
+ if (index >= rowData.length) {
436
+ var padding = new Array(index - rowData.length).fill(null);
437
+ if (padding.length > 0) {
438
+ rowData.insert(rowData.length, padding);
439
+ }
440
+ }
441
+ if (index === rowData.length) {
442
+ rowData.insert(index, [cellData]);
443
+ }
444
+ else {
445
+ // Replace cell data
446
+ rowData.insert(index, [cellData]);
447
+ rowData.delete(index + 1, 1);
448
+ }
449
+ };
450
+ exports.setCellDataInRowData = setCellDataInRowData;
451
+ var removeRowData = function (ysheet, rowIndex) {
452
+ var index = Number(rowIndex);
453
+ // Only remove if index is valid
454
+ if (index >= 0 && index < ysheet.length) {
455
+ ysheet.insert(index, [null]);
456
+ ysheet.delete(index + 1, 1);
457
+ }
458
+ };
459
+ exports.removeRowData = removeRowData;
460
+ /**
461
+ * Read a cell's data from the V2 Y.js structure without creating any
462
+ * missing sheet/row/values containers (unlike getSheetFromYSheetData /
463
+ * getRowDataFromSheet, which lazily create them).
464
+ */
465
+ var getCellDataFromYSheetData = function (ySheetData, sheetId, rowIndex, columnIndex) {
466
+ var sheet = ySheetData.get(String(sheetId));
467
+ var rowIdx = Number(rowIndex);
468
+ if (!sheet || rowIdx < 0 || rowIdx >= sheet.length) {
469
+ return undefined;
470
+ }
471
+ var row = sheet.get(rowIdx);
472
+ var values = row === null || row === void 0 ? void 0 : row.get("values");
473
+ var colIdx = Number(columnIndex);
474
+ if (!values || colIdx < 0 || colIdx >= values.length) {
475
+ return undefined;
476
+ }
477
+ return values.get(colIdx);
478
+ };
479
+ exports.getCellDataFromYSheetData = getCellDataFromYSheetData;
480
+ /**
481
+ * Extract the error effective value from cell data, if any.
482
+ * SheetCell.setErrorValue persists formula errors as
483
+ * `ev.ev = { type: "Error", name, message }` (legacy long form:
484
+ * `effectiveValue.errorValue`).
485
+ */
486
+ var getCellDataErrorValue = function (cellData) {
487
+ return (0, utils_1.getExtendedValueError)((0, utils_1.getCellEffectiveValue)(cellData));
488
+ };
489
+ exports.getCellDataErrorValue = getCellDataErrorValue;
490
+ /**
491
+ * Keep only the cell-level sheetData patches
492
+ * (`[sheetId, rowIndex, "values", columnIndex]`) whose new cell data carries
493
+ * an error effective value (#VALUE!, #NAME?, …). Used to let calc-result
494
+ * errors bypass the leader gate: errors must reach the Y.Doc even from
495
+ * non-leader clients, otherwise they render blank after reload.
496
+ */
497
+ var filterErrorCellPatches = function (patches) {
498
+ return patches.filter(function (patch) {
499
+ return (patch.op === "add" || patch.op === "replace") &&
500
+ patch.path.length === 4 &&
501
+ patch.path[2] === "values" &&
502
+ Boolean((0, exports.getCellDataErrorValue)(patch.value));
503
+ });
504
+ };
505
+ exports.filterErrorCellPatches = filterErrorCellPatches;
506
+ /**
507
+ * Normalize an extended value (short or legacy long keys) into the short-key
508
+ * shape so semantically identical values compare equal regardless of which
509
+ * key shape produced them.
510
+ */
511
+ var normalizeExtendedValue = function (extValue) {
512
+ if (extValue === null || extValue === undefined) {
513
+ return undefined;
514
+ }
515
+ var normalized = {};
516
+ var numberValue = (0, utils_1.getExtendedValueNumber)(extValue);
517
+ if (numberValue !== undefined) {
518
+ normalized.nv = numberValue;
519
+ }
520
+ var stringValue = (0, utils_1.getExtendedValueString)(extValue);
521
+ if (stringValue !== undefined) {
522
+ normalized.sv = stringValue;
523
+ }
524
+ var boolValue = (0, utils_1.getExtendedValueBool)(extValue);
525
+ if (boolValue !== undefined) {
526
+ normalized.bv = boolValue;
527
+ }
528
+ var formulaValue = (0, utils_1.getExtendedValueFormula)(extValue);
529
+ if (formulaValue !== undefined) {
530
+ normalized.fv = formulaValue;
531
+ }
532
+ var errorValue = (0, utils_1.getExtendedValueError)(extValue);
533
+ if (errorValue !== undefined) {
534
+ normalized.ev = errorValue;
535
+ }
536
+ return normalized;
537
+ };
538
+ /**
539
+ * Containment guard for the non-leader error-persistence path
540
+ * (use-yspreadsheet-v2 onBroadcastPatch, gated disableRecalc branch).
541
+ * A gated error cell patch may be written ONLY when all of these hold:
542
+ *
543
+ * 1. The incoming cell data carries an error effective value.
544
+ * 2. The current doc cell holds no effective value at all (the
545
+ * blank-after-reload case) or its effective value is itself an error.
546
+ * A non-error result (number/string/bool/formula result) is never
547
+ * overwritten — a stale non-leader error must not clobber a newer
548
+ * leader-written success.
549
+ * 3. If the doc cell exists, its user-entered value (`ue`, short or legacy
550
+ * key shape) matches the incoming patch's — a cell edited after the
551
+ * calculation started is never touched.
552
+ * 4. The persisted error differs from the incoming one (identical errors
553
+ * are dropped so concurrent non-leaders don't append redundant
554
+ * Y.js updates).
555
+ */
556
+ var shouldPersistErrorCellPatch = function (currentCellData, incomingCellData) {
557
+ var incomingError = (0, exports.getCellDataErrorValue)(incomingCellData);
558
+ if (!incomingError) {
559
+ return false;
560
+ }
561
+ var currentEffectiveValue = (0, utils_1.getCellEffectiveValue)(currentCellData);
562
+ var currentError = (0, utils_1.getExtendedValueError)(currentEffectiveValue);
563
+ if (currentEffectiveValue !== null &&
564
+ currentEffectiveValue !== undefined &&
565
+ !currentError) {
566
+ return false;
567
+ }
568
+ if (currentCellData !== null && currentCellData !== undefined) {
569
+ var currentUserEnteredValue = normalizeExtendedValue((0, utils_1.getCellUserEnteredValue)(currentCellData));
570
+ var incomingUserEnteredValue = normalizeExtendedValue((0, utils_1.getCellUserEnteredValue)(incomingCellData));
571
+ if (!(0, isEqual_1.default)(currentUserEnteredValue, incomingUserEnteredValue)) {
572
+ return false;
573
+ }
574
+ }
575
+ return !(0, isEqual_1.default)(currentError, incomingError);
576
+ };
577
+ exports.shouldPersistErrorCellPatch = shouldPersistErrorCellPatch;
578
+ /**
579
+ * Build the cell data to write for a gated error patch that passed
580
+ * shouldPersistErrorCellPatch. If the doc cell doesn't exist yet there is
581
+ * nothing to destroy and the incoming cell data is written as-is. If it
582
+ * does exist, ONLY the error effective value is merged in — every other
583
+ * field of the doc cell (ue, formats, notes, …) is preserved so this write
584
+ * path can never remove doc state it didn't produce. The effective value is
585
+ * written into whichever key shape(s) the doc cell already uses (short `ev`
586
+ * by default).
587
+ */
588
+ var mergeErrorEffectiveValueIntoCellData = function (currentCellData, incomingCellData) {
589
+ if (currentCellData === null || currentCellData === undefined) {
590
+ return incomingCellData;
591
+ }
592
+ var incomingEffectiveValue = (0, utils_1.getCellEffectiveValue)(incomingCellData);
593
+ var merged = tslib_1.__assign({}, currentCellData);
594
+ var hasLegacyKey = "effectiveValue" in merged;
595
+ if (hasLegacyKey) {
596
+ merged.effectiveValue = incomingEffectiveValue;
597
+ }
598
+ if ("ev" in merged || !hasLegacyKey) {
599
+ merged.ev = incomingEffectiveValue;
600
+ }
601
+ return merged;
602
+ };
603
+ exports.mergeErrorEffectiveValueIntoCellData = mergeErrorEffectiveValueIntoCellData;
604
+ /**
605
+ * Update array type with immer patches
606
+ */
607
+ var updateArrayType = function (yarray, patches) {
608
+ // Consecutive nested-path patches targeting the same array item are
609
+ // consolidated into one cloneDeep + one Y.Array write. An immer splice on
610
+ // a nested array (e.g. a sheet's rowMetadata on row insert/delete) emits
611
+ // one patch per shifted entry; writing each patch individually clones and
612
+ // re-serializes the entire item per entry — O(n²) on large sheets, which
613
+ // freezes the tab.
614
+ var pending = null;
615
+ var flushPending = function () {
616
+ if (!pending) {
617
+ return;
618
+ }
619
+ var index = pending.index, item = pending.item;
620
+ pending = null;
621
+ ensureArraySize(yarray, index);
622
+ yarray.insert(index, [item]);
623
+ yarray.delete(index + 1, 1);
624
+ };
625
+ patches.forEach(function (_a) {
626
+ var op = _a.op, path = _a.path, value = _a.value;
627
+ var _b = tslib_1.__read(path), arrayIndex = _b[0], nestedPath = _b.slice(1);
628
+ var index = Number(arrayIndex);
629
+ if (isNaN(index)) {
630
+ flushPending();
631
+ // User is replacing the entire array
632
+ if (op === "replace") {
633
+ yarray.delete(0, yarray.length);
634
+ yarray.push(value);
635
+ }
636
+ return;
637
+ }
638
+ if (op === "replace" || op === "add") {
639
+ if (nestedPath.length === 0) {
640
+ flushPending();
641
+ // Direct array item replacement
642
+ ensureArraySize(yarray, index);
643
+ yarray.insert(index, [value]);
644
+ yarray.delete(index + 1, 1);
645
+ }
646
+ else {
647
+ // Nested property update within array item
648
+ var updatedItem = void 0;
649
+ if (pending && pending.index === index) {
650
+ updatedItem = pending.item;
651
+ }
652
+ else {
653
+ flushPending();
654
+ var item = index < yarray.length ? yarray.get(index) : {};
655
+ var baseItem = item === null || item === undefined ? {} : item;
656
+ // Clone the item and use lodash to set the nested property
657
+ updatedItem = (0, cloneDeep_1.default)(baseItem);
658
+ pending = { index: index, item: updatedItem };
659
+ }
660
+ (0, set_1.default)(updatedItem, nestedPath, value);
661
+ }
662
+ }
663
+ else if (op === "remove") {
664
+ if (nestedPath.length === 0) {
665
+ flushPending();
666
+ // Remove entire array item
667
+ if (index >= 0 && index < yarray.length) {
668
+ yarray.delete(index, 1);
669
+ }
670
+ }
671
+ else {
672
+ // Remove nested property from array item
673
+ var updatedItem = null;
674
+ if (pending && pending.index === index) {
675
+ if (pending.item && typeof pending.item === "object") {
676
+ updatedItem = pending.item;
677
+ }
678
+ }
679
+ else {
680
+ flushPending();
681
+ if (index >= 0 && index < yarray.length) {
682
+ var item = yarray.get(index);
683
+ if (item && typeof item === "object") {
684
+ updatedItem = (0, cloneDeep_1.default)(item);
685
+ pending = { index: index, item: updatedItem };
686
+ }
687
+ }
688
+ }
689
+ if (updatedItem) {
690
+ // Check if we're removing from an array
691
+ var parentPath = nestedPath.slice(0, -1);
692
+ var lastKey = nestedPath[nestedPath.length - 1];
693
+ if (parentPath.length > 0) {
694
+ var parentValue = (0, get_1.default)(updatedItem, parentPath);
695
+ if (Array.isArray(parentValue) && typeof lastKey === "number") {
696
+ // Remove array element using splice
697
+ parentValue.splice(lastKey, 1);
698
+ }
699
+ else {
700
+ // Remove object property
701
+ (0, unset_1.default)(updatedItem, nestedPath);
702
+ }
703
+ }
704
+ else {
705
+ // Direct property removal
706
+ (0, unset_1.default)(updatedItem, nestedPath);
707
+ }
708
+ }
709
+ }
710
+ }
711
+ });
712
+ flushPending();
713
+ };
714
+ exports.updateArrayType = updateArrayType;
715
+ /**
716
+ * Helper function to ensure array is large enough
717
+ */
718
+ function ensureArraySize(yarray, index) {
719
+ if (index >= yarray.length) {
720
+ var gaps = new Array(index - yarray.length).fill(null);
721
+ yarray.insert(yarray.length, gaps);
722
+ yarray.insert(index, [null]); // Insert placeholder that will be replaced
723
+ }
724
+ }
725
+ /**
726
+ * Normalize values to always be an array, converting object notation if needed
727
+ */
728
+ function normalizeValuesToArray(values) {
729
+ if (!values) {
730
+ return [];
731
+ }
732
+ if (Array.isArray(values)) {
733
+ return tslib_1.__spreadArray([], tslib_1.__read(values), false);
734
+ }
735
+ // Convert object notation to array
736
+ var entries = Object.entries(values);
737
+ if (entries.length === 0) {
738
+ return [];
739
+ }
740
+ var maxIndex = Math.max.apply(Math, tslib_1.__spreadArray([], tslib_1.__read(entries.map(function (_a) {
741
+ var _b = tslib_1.__read(_a, 1), key = _b[0];
742
+ return Number(key);
743
+ })), false));
744
+ var result = new Array(maxIndex + 1).fill(null);
745
+ entries.forEach(function (_a) {
746
+ var _b = tslib_1.__read(_a, 2), key = _b[0], value = _b[1];
747
+ result[Number(key)] = value;
748
+ });
749
+ return result;
750
+ }
751
+ /**
752
+ * Validate and clean sheets data
753
+ */
754
+ var validateSheets = function (sheets) {
755
+ return sheets.filter(Boolean).map(function (sheet) {
756
+ var _a;
757
+ return (tslib_1.__assign(tslib_1.__assign({}, sheet), {
758
+ // Ensure merges is always an array and filter out falsy values
759
+ merges: (_a = sheet.merges) === null || _a === void 0 ? void 0 : _a.filter(Boolean) }));
760
+ });
761
+ };
762
+ exports.validateSheets = validateSheets;
763
+ /**
764
+ * Map operations
765
+ */
766
+ var applyMapPatches = function (yMap, patches) {
767
+ var e_7, _a, e_8, _b, e_9, _c;
768
+ try {
769
+ for (var patches_14 = tslib_1.__values(patches), patches_14_1 = patches_14.next(); !patches_14_1.done; patches_14_1 = patches_14.next()) {
770
+ var _d = patches_14_1.value, op = _d.op, path = _d.path, value = _d.value;
771
+ if (!path || !path.length) {
772
+ if (op === "remove") {
773
+ // Only clear if there's something to clear
774
+ if (yMap.size > 0)
775
+ yMap.clear();
776
+ }
777
+ else if (op === "replace") {
778
+ // Diff against current contents instead of clear-and-rewrite, so keys
779
+ // whose references haven't changed don't generate Y.Map tombstones.
780
+ var incoming = new Map(value);
781
+ try {
782
+ for (var _e = (e_8 = void 0, tslib_1.__values(Array.from(yMap.keys()))), _f = _e.next(); !_f.done; _f = _e.next()) {
783
+ var k = _f.value;
784
+ if (!incoming.has(k))
785
+ yMap.delete(k);
786
+ }
787
+ }
788
+ catch (e_8_1) { e_8 = { error: e_8_1 }; }
789
+ finally {
790
+ try {
791
+ if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
792
+ }
793
+ finally { if (e_8) throw e_8.error; }
794
+ }
795
+ try {
796
+ for (var incoming_1 = (e_9 = void 0, tslib_1.__values(incoming)), incoming_1_1 = incoming_1.next(); !incoming_1_1.done; incoming_1_1 = incoming_1.next()) {
797
+ var _g = tslib_1.__read(incoming_1_1.value, 2), k = _g[0], v = _g[1];
798
+ if (yMap.get(k) !== v)
799
+ yMap.set(k, v);
800
+ }
801
+ }
802
+ catch (e_9_1) { e_9 = { error: e_9_1 }; }
803
+ finally {
804
+ try {
805
+ if (incoming_1_1 && !incoming_1_1.done && (_c = incoming_1.return)) _c.call(incoming_1);
806
+ }
807
+ finally { if (e_9) throw e_9.error; }
808
+ }
809
+ }
810
+ continue;
811
+ }
812
+ var index = path[0];
813
+ if (op === "remove") {
814
+ if (yMap.has(index))
815
+ yMap.delete(index);
816
+ }
817
+ else if (op === "add" || op === "replace") {
818
+ if (yMap.get(index) !== value)
819
+ yMap.set(index, value);
820
+ }
821
+ }
822
+ }
823
+ catch (e_7_1) { e_7 = { error: e_7_1 }; }
824
+ finally {
825
+ try {
826
+ if (patches_14_1 && !patches_14_1.done && (_a = patches_14.return)) _a.call(patches_14);
827
+ }
828
+ finally { if (e_7) throw e_7.error; }
829
+ }
830
+ };
831
+ exports.applyMapPatches = applyMapPatches;
832
+ /**
833
+ * Process events to find changes in sheet data
834
+ * Returns a new sheet data object with only the changes applied if possible, or null if a full reload is needed
835
+ */
836
+ var processSheetDataEvents = function (events, currentSheetData, ySheetDataV2) {
837
+ var e_10, _a;
838
+ var changes = new Map();
839
+ var fullReloadSheets = new Set();
840
+ var _loop_1 = function (event_1) {
841
+ var path = event_1.path;
842
+ if (path.length > 0) {
843
+ var sheetId_2 = String(path[0]);
844
+ if (!changes.has(sheetId_2)) {
845
+ changes.set(sheetId_2, new Map());
846
+ }
847
+ var rows_1 = changes.get(sheetId_2);
848
+ // Path structure: [sheetId, rowIndex, "values", colIndex] or [sheetId, rowIndex]
849
+ if (path.length >= 4 && path[2] === "values") {
850
+ var rowIndex = Number(path[1]);
851
+ var columnIndex = Number(path[3]);
852
+ if (!isNaN(rowIndex) && !isNaN(columnIndex)) {
853
+ var existing = rows_1.get(rowIndex);
854
+ if (existing) {
855
+ if (!existing.full) {
856
+ existing.columns.add(columnIndex);
857
+ }
858
+ }
859
+ else {
860
+ rows_1.set(rowIndex, {
861
+ full: false,
862
+ columns: new Set([columnIndex]),
863
+ });
864
+ }
865
+ }
866
+ }
867
+ else if (path.length >= 2) {
868
+ var rowIndex = Number(path[1]);
869
+ if (!isNaN(rowIndex)) {
870
+ var existing = rows_1.get(rowIndex);
871
+ if (existing) {
872
+ existing.full = true;
873
+ existing.columns.clear();
874
+ }
875
+ else {
876
+ rows_1.set(rowIndex, { full: true, columns: new Set() });
877
+ }
878
+ }
879
+ }
880
+ else if (path.length === 1) {
881
+ if (event_1.isYArrayEvent && event_1.delta) {
882
+ var index_1 = 0;
883
+ event_1.delta.forEach(function (op) {
884
+ if (op.retain) {
885
+ index_1 += op.retain;
886
+ }
887
+ if (op.insert) {
888
+ var count = Array.isArray(op.insert) ? op.insert.length : 1;
889
+ for (var i = 0; i < count; i++) {
890
+ var rowIndex = index_1 + i;
891
+ var existing = rows_1.get(rowIndex);
892
+ if (existing) {
893
+ existing.full = true;
894
+ existing.columns.clear();
895
+ }
896
+ else {
897
+ rows_1.set(rowIndex, { full: true, columns: new Set() });
898
+ }
899
+ }
900
+ index_1 += count;
901
+ }
902
+ if (op.delete) {
903
+ fullReloadSheets.add(sheetId_2); // Mark full sheet reload
904
+ }
905
+ });
906
+ }
907
+ }
908
+ }
909
+ };
910
+ try {
911
+ for (var events_1 = tslib_1.__values(events), events_1_1 = events_1.next(); !events_1_1.done; events_1_1 = events_1.next()) {
912
+ var event_1 = events_1_1.value;
913
+ _loop_1(event_1);
914
+ }
915
+ }
916
+ catch (e_10_1) { e_10 = { error: e_10_1 }; }
917
+ finally {
918
+ try {
919
+ if (events_1_1 && !events_1_1.done && (_a = events_1.return)) _a.call(events_1);
920
+ }
921
+ finally { if (e_10) throw e_10.error; }
922
+ }
923
+ if (changes.size > 0 || fullReloadSheets.size > 0) {
924
+ var next_1 = tslib_1.__assign({}, currentSheetData);
925
+ var hasChanges_1 = false;
926
+ fullReloadSheets.forEach(function (sheetId) {
927
+ var ySheet = ySheetDataV2.get(sheetId);
928
+ if (!ySheet)
929
+ return;
930
+ var sheetData = ySheet.toJSON();
931
+ next_1[sheetId] = sheetData;
932
+ hasChanges_1 = true;
933
+ });
934
+ changes.forEach(function (rowIndices, sheetId) {
935
+ var ySheet = ySheetDataV2.get(sheetId);
936
+ if (!ySheet)
937
+ return;
938
+ // If full sheet reload needed
939
+ if (fullReloadSheets.has(sheetId)) {
940
+ var sheetData = ySheet.toJSON();
941
+ next_1[sheetId] = sheetData;
942
+ hasChanges_1 = true;
943
+ return;
944
+ }
945
+ // Partial update
946
+ if (!next_1[sheetId]) {
947
+ next_1[sheetId] = [];
948
+ }
949
+ if (next_1[sheetId].length < ySheet.length) {
950
+ if (next_1[sheetId].length !== ySheet.length) {
951
+ var sheetData = ySheet.toJSON();
952
+ next_1[sheetId] = sheetData;
953
+ hasChanges_1 = true;
954
+ return;
955
+ }
956
+ }
957
+ var nextSheet = tslib_1.__spreadArray([], tslib_1.__read(next_1[sheetId]), false);
958
+ rowIndices.forEach(function (change, rowIndex) {
959
+ var _a;
960
+ if (rowIndex < 0 || rowIndex >= ySheet.length)
961
+ return;
962
+ var yRow = ySheet.get(rowIndex);
963
+ if (change.full) {
964
+ var normalizedRow = null;
965
+ if (yRow) {
966
+ var rowJson = yRow.toJSON();
967
+ normalizedRow = rowJson;
968
+ }
969
+ nextSheet[rowIndex] = normalizedRow;
970
+ }
971
+ else {
972
+ var currentRow = (_a = nextSheet[rowIndex]) !== null && _a !== void 0 ? _a : null;
973
+ if (!yRow) {
974
+ if (currentRow) {
975
+ nextSheet[rowIndex] = currentRow;
976
+ }
977
+ return;
978
+ }
979
+ var yValues_1 = yRow.get("values");
980
+ if (!yValues_1) {
981
+ if (currentRow) {
982
+ nextSheet[rowIndex] = currentRow;
983
+ }
984
+ return;
985
+ }
986
+ var baseRow = currentRow !== null && currentRow !== void 0 ? currentRow : yRow.toJSON();
987
+ if (!baseRow) {
988
+ return;
989
+ }
990
+ var baseValues = baseRow.values;
991
+ // Always normalize to array to ensure .entries() works in calculation code
992
+ var mergedValues_1 = normalizeValuesToArray(baseValues);
993
+ change.columns.forEach(function (columnIndex) {
994
+ var nextValue = yValues_1.get(columnIndex);
995
+ mergedValues_1[columnIndex] =
996
+ nextValue === undefined ? null : nextValue;
997
+ });
998
+ nextSheet[rowIndex] = tslib_1.__assign(tslib_1.__assign({}, baseRow), { values: mergedValues_1 });
999
+ }
1000
+ });
1001
+ next_1[sheetId] = nextSheet;
1002
+ hasChanges_1 = true;
1003
+ });
1004
+ return hasChanges_1 ? next_1 : null;
1005
+ }
1006
+ return null;
1007
+ };
1008
+ exports.processSheetDataEvents = processSheetDataEvents;
1009
+ // ============================================================================
1010
+ // V3 Helper Functions (Flat Map Structure)
1011
+ // ============================================================================
1012
+ /**
1013
+ * Convert letter to column index (1-based)
1014
+ * A = 1, B = 2, ..., Z = 26, AA = 27, etc.
1015
+ */
1016
+ var letterToColumnIndex = function (letters) {
1017
+ return letters
1018
+ .toUpperCase()
1019
+ .split("")
1020
+ .reduce(function (r, a) { return r * 26 + parseInt(a, 36) - 9; }, 0);
1021
+ };
1022
+ /**
1023
+ * Create a V3 cell key from sheet ID, row and column indices
1024
+ * Format: `${sheetId}!${A1Address}` (e.g., "1!A1", "2!B5")
1025
+ */
1026
+ var createCellKeyV3 = function (sheetId, rowIndex, columnIndex) {
1027
+ var _a;
1028
+ var address = (_a = (0, utils_1.cellToAddress)({ rowIndex: rowIndex, columnIndex: columnIndex })) !== null && _a !== void 0 ? _a : "".concat(String.fromCharCode(65 + columnIndex - 1)).concat(rowIndex);
1029
+ return "".concat(sheetId, "!").concat(address);
1030
+ };
1031
+ exports.createCellKeyV3 = createCellKeyV3;
1032
+ /**
1033
+ * Parse a V3 cell key to extract sheet ID and position information
1034
+ * Example: parseCellKeyV3("1!A1") => { sheetId: 1, address: "A1", rowIndex: 1, columnIndex: 1 }
1035
+ */
1036
+ var parseCellKeyV3 = function (cellKey) {
1037
+ var match = cellKey.match(/^(\d+)!([A-Z]+)(\d+)$/i);
1038
+ if (!match)
1039
+ return null;
1040
+ var _a = tslib_1.__read(match, 4), sheetIdStr = _a[1], columnLetters = _a[2], rowIndexStr = _a[3];
1041
+ return {
1042
+ sheetId: Number(sheetIdStr),
1043
+ address: "".concat(columnLetters.toUpperCase()).concat(rowIndexStr),
1044
+ rowIndex: Number(rowIndexStr),
1045
+ columnIndex: letterToColumnIndex(columnLetters),
1046
+ };
1047
+ };
1048
+ exports.parseCellKeyV3 = parseCellKeyV3;
1049
+ /**
1050
+ * Create a CellDataV3 object with position and sheetId
1051
+ */
1052
+ var createCellDataV3 = function (value, sheetId, rowIndex, columnIndex) { return ({
1053
+ value: value,
1054
+ sId: sheetId,
1055
+ r: rowIndex,
1056
+ c: columnIndex,
1057
+ }); };
1058
+ exports.createCellDataV3 = createCellDataV3;
1059
+ /**
1060
+ * Convert V2 SheetData to V3 flat Map format
1061
+ * V2: { sheetId: [rows with values arrays] }
1062
+ * V3: Map<cellKey, CellDataV3>
1063
+ */
1064
+ var sheetDataV2ToV3 = function (v2Data) {
1065
+ var v3Map = new Map();
1066
+ var _loop_2 = function (sheetIdStr) {
1067
+ var sheetId = Number(sheetIdStr);
1068
+ var rows = v2Data[sheetId];
1069
+ if (!rows)
1070
+ return "continue";
1071
+ rows.forEach(function (row, rowIndex) {
1072
+ if (!(row === null || row === void 0 ? void 0 : row.values))
1073
+ return;
1074
+ row.values.forEach(function (cellData, colIndex) {
1075
+ if (cellData) {
1076
+ var key = (0, exports.createCellKeyV3)(sheetId, rowIndex, colIndex);
1077
+ v3Map.set(key, (0, exports.createCellDataV3)(cellData, sheetId, rowIndex, colIndex));
1078
+ }
1079
+ });
1080
+ });
1081
+ };
1082
+ for (var sheetIdStr in v2Data) {
1083
+ _loop_2(sheetIdStr);
1084
+ }
1085
+ return v3Map;
1086
+ };
1087
+ exports.sheetDataV2ToV3 = sheetDataV2ToV3;
1088
+ /**
1089
+ * Convert V3 flat Map format to V2 SheetData
1090
+ * V3: Map<cellKey, CellDataV3>
1091
+ * V2: { sheetId: [rows with values arrays] }
1092
+ */
1093
+ var sheetDataV3ToV2 = function (v3Data) {
1094
+ var e_11, _a;
1095
+ var sheetData = {};
1096
+ try {
1097
+ for (var v3Data_1 = tslib_1.__values(v3Data), v3Data_1_1 = v3Data_1.next(); !v3Data_1_1.done; v3Data_1_1 = v3Data_1.next()) {
1098
+ var _b = tslib_1.__read(v3Data_1_1.value, 2), _1 = _b[0], cellDataV3 = _b[1];
1099
+ if (!cellDataV3)
1100
+ continue;
1101
+ var sheetId = cellDataV3.sId, rowIdx = cellDataV3.r, colIdx = cellDataV3.c, value = cellDataV3.value;
1102
+ // Ensure sheet exists
1103
+ if (!sheetData[sheetId]) {
1104
+ sheetData[sheetId] = [];
1105
+ }
1106
+ // Ensure row exists
1107
+ while (sheetData[sheetId].length <= rowIdx) {
1108
+ sheetData[sheetId].push(null);
1109
+ }
1110
+ if (!sheetData[sheetId][rowIdx]) {
1111
+ sheetData[sheetId][rowIdx] = { values: [] };
1112
+ }
1113
+ var row = sheetData[sheetId][rowIdx];
1114
+ if (!row.values)
1115
+ row.values = [];
1116
+ // Ensure values array is long enough
1117
+ while (row.values.length <= colIdx) {
1118
+ row.values.push(null);
1119
+ }
1120
+ row.values[colIdx] = value;
1121
+ }
1122
+ }
1123
+ catch (e_11_1) { e_11 = { error: e_11_1 }; }
1124
+ finally {
1125
+ try {
1126
+ if (v3Data_1_1 && !v3Data_1_1.done && (_a = v3Data_1.return)) _a.call(v3Data_1);
1127
+ }
1128
+ finally { if (e_11) throw e_11.error; }
1129
+ }
1130
+ return sheetData;
1131
+ };
1132
+ exports.sheetDataV3ToV2 = sheetDataV3ToV2;
1133
+ /**
1134
+ * Get a cell from V3 flat structure
1135
+ */
1136
+ var getCellV3 = function (ySheetDataV3, sheetId, rowIndex, columnIndex) {
1137
+ var key = (0, exports.createCellKeyV3)(sheetId, rowIndex, columnIndex);
1138
+ return ySheetDataV3.get(key);
1139
+ };
1140
+ exports.getCellV3 = getCellV3;
1141
+ /**
1142
+ * Set a cell in V3 flat structure
1143
+ */
1144
+ var setCellV3 = function (ySheetDataV3, sheetId, rowIndex, columnIndex, value) {
1145
+ var key = (0, exports.createCellKeyV3)(sheetId, rowIndex, columnIndex);
1146
+ ySheetDataV3.set(key, (0, exports.createCellDataV3)(value, sheetId, rowIndex, columnIndex));
1147
+ };
1148
+ exports.setCellV3 = setCellV3;
1149
+ /**
1150
+ * Delete a cell from V3 flat structure
1151
+ */
1152
+ var deleteCellV3 = function (ySheetDataV3, sheetId, rowIndex, columnIndex) {
1153
+ var key = (0, exports.createCellKeyV3)(sheetId, rowIndex, columnIndex);
1154
+ ySheetDataV3.delete(key);
1155
+ };
1156
+ exports.deleteCellV3 = deleteCellV3;
1157
+ /**
1158
+ * Delete all cells for a sheet from V3 flat structure
1159
+ */
1160
+ var deleteSheetV3 = function (ySheetDataV3, sheetId) {
1161
+ var e_12, _a;
1162
+ var prefix = "".concat(sheetId, "!");
1163
+ try {
1164
+ for (var _b = tslib_1.__values(ySheetDataV3.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
1165
+ var key = _c.value;
1166
+ if (key.startsWith(prefix)) {
1167
+ ySheetDataV3.delete(key);
1168
+ }
1169
+ }
1170
+ }
1171
+ catch (e_12_1) { e_12 = { error: e_12_1 }; }
1172
+ finally {
1173
+ try {
1174
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1175
+ }
1176
+ finally { if (e_12) throw e_12.error; }
1177
+ }
1178
+ };
1179
+ exports.deleteSheetV3 = deleteSheetV3;
1180
+ /**
1181
+ * Get V3 sheet data map from Y.Doc
1182
+ */
1183
+ var getSheetDataV3 = function (doc) {
1184
+ return doc.getMap("sheetDataV3");
1185
+ };
1186
+ exports.getSheetDataV3 = getSheetDataV3;
1187
+ /**
1188
+ * Apply immer patches to V3 sheet data (flat map structure)
1189
+ *
1190
+ * Optimized for bulk operations (paste, import) by consolidating cell-level
1191
+ * patches before applying to Y.js. This reduces overhead by:
1192
+ * 1. Deduplicating patches targeting the same cell (later patches win)
1193
+ * 2. Processing all cell updates in a single pass
1194
+ */
1195
+ var addSheetDataPatchesV3 = function (ySheetDataV3, patches) {
1196
+ var e_13, _a, e_14, _b;
1197
+ // Optimization: Pre-process and consolidate cell-level patches
1198
+ // For bulk operations like paste (10k+ rows), this dramatically reduces overhead
1199
+ var cellUpdates = new Map();
1200
+ var otherPatches = [];
1201
+ try {
1202
+ // First pass: categorize and consolidate patches
1203
+ for (var patches_15 = tslib_1.__values(patches), patches_15_1 = patches_15.next(); !patches_15_1.done; patches_15_1 = patches_15.next()) {
1204
+ var patch = patches_15_1.value;
1205
+ var op = patch.op, path = patch.path, value = patch.value;
1206
+ var _c = tslib_1.__read(path, 1), sheetIdRaw = _c[0];
1207
+ // Handle undefined sheetId separately (full replace)
1208
+ if (typeof sheetIdRaw === "undefined") {
1209
+ otherPatches.push(patch);
1210
+ continue;
1211
+ }
1212
+ var sheetId = Number(sheetIdRaw);
1213
+ if (op === "replace" || op === "add") {
1214
+ // [sheetId, rowIndex, 'values', columnIndex] - Single cell update (most common in paste)
1215
+ if (path.length === 4) {
1216
+ var _d = tslib_1.__read(path, 4), rowIndex = _d[1], columnIndex = _d[3];
1217
+ var rowIdx = Number(rowIndex);
1218
+ var colIdx = Number(columnIndex);
1219
+ var key = (0, exports.createCellKeyV3)(sheetId, rowIdx, colIdx);
1220
+ // Later patches override earlier ones for the same cell
1221
+ cellUpdates.set(key, { sheetId: sheetId, rowIdx: rowIdx, colIdx: colIdx, value: value });
1222
+ }
1223
+ else {
1224
+ // Row-level or sheet-level updates
1225
+ otherPatches.push(patch);
1226
+ }
1227
+ }
1228
+ else if (op === "remove") {
1229
+ if (path.length === 4) {
1230
+ var _e = tslib_1.__read(path, 4), rowIndex = _e[1], columnIndex = _e[3];
1231
+ var rowIdx = Number(rowIndex);
1232
+ var colIdx = Number(columnIndex);
1233
+ var key = (0, exports.createCellKeyV3)(sheetId, rowIdx, colIdx);
1234
+ cellUpdates.set(key, { sheetId: sheetId, rowIdx: rowIdx, colIdx: colIdx, value: null });
1235
+ }
1236
+ else {
1237
+ otherPatches.push(patch);
1238
+ }
1239
+ }
1240
+ else {
1241
+ otherPatches.push(patch);
1242
+ }
1243
+ }
1244
+ }
1245
+ catch (e_13_1) { e_13 = { error: e_13_1 }; }
1246
+ finally {
1247
+ try {
1248
+ if (patches_15_1 && !patches_15_1.done && (_a = patches_15.return)) _a.call(patches_15);
1249
+ }
1250
+ finally { if (e_13) throw e_13.error; }
1251
+ }
1252
+ try {
1253
+ // Second pass: Apply consolidated cell updates in batch
1254
+ // This is much faster than processing each patch individually
1255
+ for (var cellUpdates_2 = tslib_1.__values(cellUpdates), cellUpdates_2_1 = cellUpdates_2.next(); !cellUpdates_2_1.done; cellUpdates_2_1 = cellUpdates_2.next()) {
1256
+ var _f = tslib_1.__read(cellUpdates_2_1.value, 2), key = _f[0], _g = _f[1], sheetId = _g.sheetId, rowIdx = _g.rowIdx, colIdx = _g.colIdx, value = _g.value;
1257
+ if (value) {
1258
+ ySheetDataV3.set(key, (0, exports.createCellDataV3)(value, sheetId, rowIdx, colIdx));
1259
+ }
1260
+ else {
1261
+ ySheetDataV3.delete(key);
1262
+ }
1263
+ }
1264
+ }
1265
+ catch (e_14_1) { e_14 = { error: e_14_1 }; }
1266
+ finally {
1267
+ try {
1268
+ if (cellUpdates_2_1 && !cellUpdates_2_1.done && (_b = cellUpdates_2.return)) _b.call(cellUpdates_2);
1269
+ }
1270
+ finally { if (e_14) throw e_14.error; }
1271
+ }
1272
+ // Row-targeted patches (e.g. the per-shifted-row patches an immer array
1273
+ // splice emits for a row insert/delete) previously scanned the entire flat
1274
+ // cell map once per patch — O(patches × totalCells), which freezes the tab
1275
+ // when inserting a row near the top of a large sheet. Build a
1276
+ // row → cell-keys index once per batch instead, and keep it in sync as
1277
+ // patches apply.
1278
+ var rowCellKeyIndex = null;
1279
+ var rowIndexKey = function (sheetId, rowIdx) {
1280
+ return "".concat(sheetId, ":").concat(rowIdx);
1281
+ };
1282
+ var ensureRowCellKeyIndex = function () {
1283
+ var e_15, _a;
1284
+ if (rowCellKeyIndex) {
1285
+ return rowCellKeyIndex;
1286
+ }
1287
+ rowCellKeyIndex = new Map();
1288
+ try {
1289
+ for (var _b = tslib_1.__values(ySheetDataV3.entries()), _c = _b.next(); !_c.done; _c = _b.next()) {
1290
+ var _d = tslib_1.__read(_c.value, 2), key = _d[0], cellData = _d[1];
1291
+ var rk = rowIndexKey(cellData === null || cellData === void 0 ? void 0 : cellData.sId, cellData === null || cellData === void 0 ? void 0 : cellData.r);
1292
+ var keys = rowCellKeyIndex.get(rk);
1293
+ if (!keys) {
1294
+ keys = new Set();
1295
+ rowCellKeyIndex.set(rk, keys);
1296
+ }
1297
+ keys.add(key);
1298
+ }
1299
+ }
1300
+ catch (e_15_1) { e_15 = { error: e_15_1 }; }
1301
+ finally {
1302
+ try {
1303
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1304
+ }
1305
+ finally { if (e_15) throw e_15.error; }
1306
+ }
1307
+ return rowCellKeyIndex;
1308
+ };
1309
+ var trackCellKeySet = function (sheetId, rowIdx, key) {
1310
+ if (!rowCellKeyIndex) {
1311
+ return;
1312
+ }
1313
+ var rk = rowIndexKey(sheetId, rowIdx);
1314
+ var keys = rowCellKeyIndex.get(rk);
1315
+ if (!keys) {
1316
+ keys = new Set();
1317
+ rowCellKeyIndex.set(rk, keys);
1318
+ }
1319
+ keys.add(key);
1320
+ };
1321
+ var deleteRowCells = function (sheetId, rowIdx) {
1322
+ var e_16, _a;
1323
+ var keys = ensureRowCellKeyIndex().get(rowIndexKey(sheetId, rowIdx));
1324
+ if (!keys) {
1325
+ return;
1326
+ }
1327
+ try {
1328
+ for (var keys_1 = tslib_1.__values(keys), keys_1_1 = keys_1.next(); !keys_1_1.done; keys_1_1 = keys_1.next()) {
1329
+ var key = keys_1_1.value;
1330
+ ySheetDataV3.delete(key);
1331
+ }
1332
+ }
1333
+ catch (e_16_1) { e_16 = { error: e_16_1 }; }
1334
+ finally {
1335
+ try {
1336
+ if (keys_1_1 && !keys_1_1.done && (_a = keys_1.return)) _a.call(keys_1);
1337
+ }
1338
+ finally { if (e_16) throw e_16.error; }
1339
+ }
1340
+ rowCellKeyIndex.delete(rowIndexKey(sheetId, rowIdx));
1341
+ };
1342
+ var dropSheetFromIndex = function (sheetId) {
1343
+ var e_17, _a;
1344
+ if (!rowCellKeyIndex) {
1345
+ return;
1346
+ }
1347
+ var prefix = "".concat(sheetId, ":");
1348
+ try {
1349
+ for (var _b = tslib_1.__values(Array.from(rowCellKeyIndex.keys())), _c = _b.next(); !_c.done; _c = _b.next()) {
1350
+ var rk = _c.value;
1351
+ if (rk.startsWith(prefix)) {
1352
+ rowCellKeyIndex.delete(rk);
1353
+ }
1354
+ }
1355
+ }
1356
+ catch (e_17_1) { e_17 = { error: e_17_1 }; }
1357
+ finally {
1358
+ try {
1359
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1360
+ }
1361
+ finally { if (e_17) throw e_17.error; }
1362
+ }
1363
+ };
1364
+ // Process non-cell-level patches using original logic
1365
+ var processPatch = function (_a) {
1366
+ var e_18, _b, e_19, _c, e_20, _d;
1367
+ var op = _a.op, path = _a.path, value = _a.value;
1368
+ var _e = tslib_1.__read(path, 1), sheetIdRaw = _e[0];
1369
+ if (typeof sheetIdRaw === "undefined") {
1370
+ // Replace entire data
1371
+ if (op === "replace") {
1372
+ try {
1373
+ // Clear all cells
1374
+ for (var _f = tslib_1.__values(ySheetDataV3.keys()), _g = _f.next(); !_g.done; _g = _f.next()) {
1375
+ var key = _g.value;
1376
+ ySheetDataV3.delete(key);
1377
+ }
1378
+ }
1379
+ catch (e_18_1) { e_18 = { error: e_18_1 }; }
1380
+ finally {
1381
+ try {
1382
+ if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
1383
+ }
1384
+ finally { if (e_18) throw e_18.error; }
1385
+ }
1386
+ if (rowCellKeyIndex) {
1387
+ rowCellKeyIndex.clear();
1388
+ }
1389
+ }
1390
+ var _loop_3 = function (curSheetId) {
1391
+ var sheetId_3 = Number(curSheetId);
1392
+ var rows = value[curSheetId];
1393
+ if (!rows)
1394
+ return "continue";
1395
+ Object.entries(rows).forEach(function (_a) {
1396
+ var _b = tslib_1.__read(_a, 2), rowIndexStr = _b[0], rowData = _b[1];
1397
+ if (!(rowData === null || rowData === void 0 ? void 0 : rowData.values))
1398
+ return;
1399
+ var rowIdx = Number(rowIndexStr);
1400
+ Object.entries(rowData.values).forEach(function (_a) {
1401
+ var _b = tslib_1.__read(_a, 2), colIndexStr = _b[0], cellData = _b[1];
1402
+ if (cellData) {
1403
+ var colIdx = Number(colIndexStr);
1404
+ var key = (0, exports.createCellKeyV3)(sheetId_3, rowIdx, colIdx);
1405
+ ySheetDataV3.set(key, (0, exports.createCellDataV3)(cellData, sheetId_3, rowIdx, colIdx));
1406
+ trackCellKeySet(sheetId_3, rowIdx, key);
1407
+ }
1408
+ });
1409
+ });
1410
+ };
1411
+ // Assign values from the replacement object
1412
+ for (var curSheetId in value) {
1413
+ _loop_3(curSheetId);
1414
+ }
1415
+ return;
1416
+ }
1417
+ var sheetId = Number(sheetIdRaw);
1418
+ if (op === "replace" || op === "add") {
1419
+ // Cell-level patches (path.length === 4) are already handled above via consolidation
1420
+ // [sheetId, rowIndex, 'values', columnIndex, ...nestedPath] - Deep nested property update
1421
+ if (path.length > 4) {
1422
+ var _h = tslib_1.__read(path), rowIndex = _h[1], columnIndex = _h[3], nestedPath = _h.slice(4);
1423
+ var rowIdx = Number(rowIndex);
1424
+ var colIdx = Number(columnIndex);
1425
+ var key = (0, exports.createCellKeyV3)(sheetId, rowIdx, colIdx);
1426
+ // Get existing cell data or create empty
1427
+ var existing = ySheetDataV3.get(key);
1428
+ var cellData = (existing === null || existing === void 0 ? void 0 : existing.value) ? (0, cloneDeep_1.default)(existing.value) : {};
1429
+ // Apply nested property change
1430
+ (0, set_1.default)(cellData, nestedPath, value);
1431
+ ySheetDataV3.set(key, (0, exports.createCellDataV3)(cellData, sheetId, rowIdx, colIdx));
1432
+ trackCellKeySet(sheetId, rowIdx, key);
1433
+ }
1434
+ // [sheetId, rowIndex, 'values'] - Replace values array
1435
+ else if (path.length === 3 && path[2] === "values") {
1436
+ var _j = tslib_1.__read(path, 2), rowIndex = _j[1];
1437
+ var rowIdx_1 = Number(rowIndex);
1438
+ // Delete existing cells for this row
1439
+ deleteRowCells(sheetId, rowIdx_1);
1440
+ // Add new cells
1441
+ if (Array.isArray(value)) {
1442
+ value.forEach(function (cellData, colIndex) {
1443
+ if (cellData) {
1444
+ var key = (0, exports.createCellKeyV3)(sheetId, rowIdx_1, colIndex);
1445
+ ySheetDataV3.set(key, (0, exports.createCellDataV3)(cellData, sheetId, rowIdx_1, colIndex));
1446
+ trackCellKeySet(sheetId, rowIdx_1, key);
1447
+ }
1448
+ });
1449
+ }
1450
+ }
1451
+ // [sheetId, rowIndex] - Entire row update
1452
+ else if (path.length === 2) {
1453
+ var _k = tslib_1.__read(path, 2), rowIndex = _k[1];
1454
+ var rowIdx_2 = Number(rowIndex);
1455
+ // Delete existing cells for this row
1456
+ deleteRowCells(sheetId, rowIdx_2);
1457
+ // Add new cells from row data
1458
+ if (value === null || value === void 0 ? void 0 : value.values) {
1459
+ Object.entries(value.values).forEach(function (_a) {
1460
+ var _b = tslib_1.__read(_a, 2), colIndexStr = _b[0], cellData = _b[1];
1461
+ if (cellData) {
1462
+ var colIndex = Number(colIndexStr);
1463
+ var key = (0, exports.createCellKeyV3)(sheetId, rowIdx_2, colIndex);
1464
+ ySheetDataV3.set(key, (0, exports.createCellDataV3)(cellData, sheetId, rowIdx_2, colIndex));
1465
+ trackCellKeySet(sheetId, rowIdx_2, key);
1466
+ }
1467
+ });
1468
+ }
1469
+ }
1470
+ // [sheetId] - Entire sheet update
1471
+ else if (path.length === 1) {
1472
+ // Delete all cells for this sheet
1473
+ var prefix = "".concat(sheetId, "!");
1474
+ try {
1475
+ for (var _l = tslib_1.__values(ySheetDataV3.keys()), _m = _l.next(); !_m.done; _m = _l.next()) {
1476
+ var key = _m.value;
1477
+ if (key.startsWith(prefix)) {
1478
+ ySheetDataV3.delete(key);
1479
+ }
1480
+ }
1481
+ }
1482
+ catch (e_19_1) { e_19 = { error: e_19_1 }; }
1483
+ finally {
1484
+ try {
1485
+ if (_m && !_m.done && (_c = _l.return)) _c.call(_l);
1486
+ }
1487
+ finally { if (e_19) throw e_19.error; }
1488
+ }
1489
+ dropSheetFromIndex(sheetId);
1490
+ // Add all new data
1491
+ if (value) {
1492
+ Object.entries(value).forEach(function (_a) {
1493
+ var _b = tslib_1.__read(_a, 2), rowIndexStr = _b[0], rowData = _b[1];
1494
+ if (rowData === null || rowData === void 0 ? void 0 : rowData.values) {
1495
+ var rowIdx_3 = Number(rowIndexStr);
1496
+ Object.entries(rowData.values).forEach(function (_a) {
1497
+ var _b = tslib_1.__read(_a, 2), colIndexStr = _b[0], cellData = _b[1];
1498
+ if (cellData) {
1499
+ var colIndex = Number(colIndexStr);
1500
+ var key = (0, exports.createCellKeyV3)(sheetId, rowIdx_3, colIndex);
1501
+ ySheetDataV3.set(key, (0, exports.createCellDataV3)(cellData, sheetId, rowIdx_3, colIndex));
1502
+ trackCellKeySet(sheetId, rowIdx_3, key);
1503
+ }
1504
+ });
1505
+ }
1506
+ });
1507
+ }
1508
+ }
1509
+ }
1510
+ else if (op === "remove") {
1511
+ // Cell-level removes (path.length === 4) are already handled above via consolidation
1512
+ // [sheetId, rowIndex, values, columnIndex, ...nestedPath] - Remove nested property
1513
+ if (path.length > 4) {
1514
+ var _o = tslib_1.__read(path), rowIndex = _o[1], columnIndex = _o[3], nestedPath = _o.slice(4);
1515
+ var rowIdx = Number(rowIndex);
1516
+ var colIdx = Number(columnIndex);
1517
+ var key = (0, exports.createCellKeyV3)(sheetId, rowIdx, colIdx);
1518
+ var existing = ySheetDataV3.get(key);
1519
+ if ((existing === null || existing === void 0 ? void 0 : existing.value) && typeof existing.value === "object") {
1520
+ var cellData = (0, cloneDeep_1.default)(existing.value);
1521
+ (0, unset_1.default)(cellData, nestedPath);
1522
+ ySheetDataV3.set(key, (0, exports.createCellDataV3)(cellData, sheetId, rowIdx, colIdx));
1523
+ trackCellKeySet(sheetId, rowIdx, key);
1524
+ }
1525
+ }
1526
+ // [sheetId, rowIndex] - Remove entire row
1527
+ else if (path.length === 2) {
1528
+ var _p = tslib_1.__read(path, 2), rowIndex = _p[1];
1529
+ var rowIdx = Number(rowIndex);
1530
+ deleteRowCells(sheetId, rowIdx);
1531
+ }
1532
+ // [sheetId] - Remove entire sheet
1533
+ else if (path.length === 1) {
1534
+ var prefix = "".concat(sheetId, "!");
1535
+ try {
1536
+ for (var _q = tslib_1.__values(ySheetDataV3.keys()), _r = _q.next(); !_r.done; _r = _q.next()) {
1537
+ var key = _r.value;
1538
+ if (key.startsWith(prefix)) {
1539
+ ySheetDataV3.delete(key);
1540
+ }
1541
+ }
1542
+ }
1543
+ catch (e_20_1) { e_20 = { error: e_20_1 }; }
1544
+ finally {
1545
+ try {
1546
+ if (_r && !_r.done && (_d = _q.return)) _d.call(_q);
1547
+ }
1548
+ finally { if (e_20) throw e_20.error; }
1549
+ }
1550
+ dropSheetFromIndex(sheetId);
1551
+ }
1552
+ }
1553
+ };
1554
+ // Only process non-cell-level patches (cell-level already handled via consolidation)
1555
+ otherPatches.forEach(processPatch);
1556
+ };
1557
+ exports.addSheetDataPatchesV3 = addSheetDataPatchesV3;
1558
+ /**
1559
+ * Process V3 events and return updated sheet data
1560
+ * @param changedKeys - Pre-extracted changes from Yjs event
1561
+ * @param currentSheetData - Current sheet data state
1562
+ * @param ySheetDataV3 - The Y.Map for V3 data
1563
+ */
1564
+ var processSheetDataEventsV3 = function (changedKeys, currentSheetData, ySheetDataV3) {
1565
+ if (changedKeys.size === 0)
1566
+ return null;
1567
+ var next = tslib_1.__assign({}, currentSheetData);
1568
+ // Track which sheets/rows have been cloned to avoid re-cloning
1569
+ var clonedSheets = new Set();
1570
+ var clonedRows = new Map(); // "sheetId:rowIdx" -> cloned
1571
+ var hasChanges = false;
1572
+ changedKeys.forEach(function (change, cellKey) {
1573
+ var parsed = (0, exports.parseCellKeyV3)(cellKey);
1574
+ if (!parsed)
1575
+ return;
1576
+ var sheetId = parsed.sheetId, rowIndex = parsed.rowIndex, columnIndex = parsed.columnIndex;
1577
+ var rowIdx = rowIndex;
1578
+ var colIdx = columnIndex;
1579
+ var rowKey = "".concat(sheetId, ":").concat(rowIdx);
1580
+ // Ensure sheet exists and is cloned (to avoid mutating frozen React state)
1581
+ if (!next[sheetId]) {
1582
+ next[sheetId] = [];
1583
+ clonedSheets.add(sheetId);
1584
+ }
1585
+ else if (!clonedSheets.has(sheetId)) {
1586
+ // Clone the sheet array to avoid mutating frozen state
1587
+ next[sheetId] = tslib_1.__spreadArray([], tslib_1.__read(next[sheetId]), false);
1588
+ clonedSheets.add(sheetId);
1589
+ }
1590
+ var sheet = next[sheetId];
1591
+ // Extend array efficiently using length assignment instead of while loop
1592
+ if (sheet.length <= rowIdx) {
1593
+ sheet.length = rowIdx + 1;
1594
+ }
1595
+ if (change.action === "delete") {
1596
+ // Cell was deleted
1597
+ var row = sheet[rowIdx];
1598
+ if ((row === null || row === void 0 ? void 0 : row.values) && colIdx < row.values.length && row.values[colIdx]) {
1599
+ // Clone row values only once per row
1600
+ if (!clonedRows.has(rowKey)) {
1601
+ sheet[rowIdx] = tslib_1.__assign(tslib_1.__assign({}, row), { values: tslib_1.__spreadArray([], tslib_1.__read(row.values), false) });
1602
+ clonedRows.set(rowKey, true);
1603
+ }
1604
+ sheet[rowIdx].values[colIdx] = null;
1605
+ hasChanges = true;
1606
+ }
1607
+ }
1608
+ else {
1609
+ // Cell was added or updated
1610
+ var cellDataV3 = ySheetDataV3.get(cellKey);
1611
+ if (cellDataV3) {
1612
+ // Ensure row exists
1613
+ if (!sheet[rowIdx]) {
1614
+ sheet[rowIdx] = { values: [] };
1615
+ clonedRows.set(rowKey, true);
1616
+ }
1617
+ else if (!clonedRows.has(rowKey)) {
1618
+ // Clone row values only once per row
1619
+ var row = sheet[rowIdx];
1620
+ sheet[rowIdx] = tslib_1.__assign(tslib_1.__assign({}, row), { values: row.values ? tslib_1.__spreadArray([], tslib_1.__read(row.values), false) : [] });
1621
+ clonedRows.set(rowKey, true);
1622
+ }
1623
+ var values = sheet[rowIdx].values;
1624
+ // Extend array efficiently using length assignment
1625
+ if (values.length <= colIdx) {
1626
+ values.length = colIdx + 1;
1627
+ }
1628
+ values[colIdx] = cellDataV3.value;
1629
+ hasChanges = true;
1630
+ }
1631
+ }
1632
+ });
1633
+ return hasChanges ? next : null;
1634
+ };
1635
+ exports.processSheetDataEventsV3 = processSheetDataEventsV3;