@ai-matrx/office 0.8.20 → 0.8.22

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.
@@ -1685,6 +1685,15 @@ var SHEET_MUTATIONS = {
1685
1685
  "sheet.mutation.set-worksheet-row-auto-height": covered("size", "rowsAutoHeightInfo"),
1686
1686
  "sheet.mutation.set-worksheet-col-width": covered("size", "ranges", "colWidth"),
1687
1687
  "sheet.mutation.set-worksheet-name": covered("name", "name"),
1688
+ // ── covered (C5c) ────────────────────────────────────────────────────────────────────────────────
1689
+ "sheet.mutation.set.numfmt": covered("numfmt", "values", "refMap"),
1690
+ "sheet.mutation.remove.numfmt": covered("numfmt", "ranges"),
1691
+ "sheet.mutation.set-worksheet-row-count": covered("count", "rowCount"),
1692
+ "sheet.mutation.set-worksheet-column-count": covered("count", "columnCount"),
1693
+ "sheet.mutation.insert-sheet": covered("sheet", "index", "sheet"),
1694
+ "sheet.mutation.remove-sheet": covered("sheet", "sheetIndex", "sheetsLeft"),
1695
+ "sheet.mutation.set-worksheet-order": covered("sheet", "fromOrder", "toOrder"),
1696
+ "sheet.mutation.reorder-range": covered("sort", "range", "order"),
1688
1697
  // ── never travels ────────────────────────────────────────────────────────────────────────────────
1689
1698
  "formula.mutation.set-formula-calculation-start": never(FORMULA_RESULT),
1690
1699
  "formula.mutation.set-trigger-formula-calculation-start": never(FORMULA_RESULT),
@@ -1718,13 +1727,7 @@ var SHEET_MUTATIONS = {
1718
1727
  "thread-comment.mutation.resolve-comment": never(UNIVER_COMMENTS),
1719
1728
  "thread-comment.mutation.delete-comment": never(UNIVER_COMMENTS),
1720
1729
  // ── barriers: X (no transform yet, design §10) ───────────────────────────────────────────────────
1721
- "sheet.mutation.reorder-range": barrier("X", "sort: a permutation, not transformed yet"),
1722
- "sheet.mutation.set-worksheet-row-count": barrier("X", "absolute row count; needs delta semantics"),
1723
- "sheet.mutation.set-worksheet-column-count": barrier("X", "absolute column count; needs delta semantics"),
1724
- "sheet.mutation.set-worksheet-order": barrier("X", "absolute sheet order; needs move semantics"),
1725
1730
  "sheet.mutation.move-range": barrier("X", "cut-paste carries the sender's cell matrices"),
1726
- "sheet.mutation.insert-sheet": barrier("X", "sheet add: not in C5a"),
1727
- "sheet.mutation.remove-sheet": barrier("X", "sheet remove: not in C5a"),
1728
1731
  "sheet.mutation.set-worksheet-hidden": barrier("X", "sheet-level setting: not in C5a"),
1729
1732
  "sheet.mutation.set-tab-color": barrier("X", "sheet-level setting: not in C5a"),
1730
1733
  "sheet.mutation.set-workbook-name": barrier("X", "workbook-level setting: not in C5a"),
@@ -1739,8 +1742,6 @@ var SHEET_MUTATIONS = {
1739
1742
  "sheet.mutation.set-row-visible": barrier("X", "row visibility: not in C5a"),
1740
1743
  "sheet.mutation.set-col-hidden": barrier("X", "column visibility: not in C5a"),
1741
1744
  "sheet.mutation.set-col-visible": barrier("X", "column visibility: not in C5a"),
1742
- "sheet.mutation.set.numfmt": barrier("X", "number formats by range: not in C5a"),
1743
- "sheet.mutation.remove.numfmt": barrier("X", "number formats by range: not in C5a"),
1744
1745
  "sheet.mutation.add-range-protection": barrier("X", "permissions: not in C5a"),
1745
1746
  "sheet.mutation.set-range-protection": barrier("X", "permissions: not in C5a"),
1746
1747
  "sheet.mutation.delete-range-protection": barrier("X", "permissions: not in C5a"),
@@ -2144,7 +2145,7 @@ function refSheetsFor(texts, sheets) {
2144
2145
  }
2145
2146
 
2146
2147
  // src/collab/sheets/transform/transform.ts
2147
- var SHEET_TRANSFORMER_VERSION = "c5b-1";
2148
+ var SHEET_TRANSFORMER_VERSION = "c5c-1";
2148
2149
  var ID = {
2149
2150
  values: "sheet.mutation.set-range-values",
2150
2151
  insertRow: "sheet.mutation.insert-row",
@@ -2161,7 +2162,15 @@ var ID = {
2161
2162
  colWidth: "sheet.mutation.set-worksheet-col-width",
2162
2163
  name: "sheet.mutation.set-worksheet-name",
2163
2164
  setName: "formula.mutation.set-defined-name",
2164
- removeName: "formula.mutation.remove-defined-name"
2165
+ removeName: "formula.mutation.remove-defined-name",
2166
+ setNumfmt: "sheet.mutation.set.numfmt",
2167
+ removeNumfmt: "sheet.mutation.remove.numfmt",
2168
+ rowCount: "sheet.mutation.set-worksheet-row-count",
2169
+ colCount: "sheet.mutation.set-worksheet-column-count",
2170
+ insertSheet: "sheet.mutation.insert-sheet",
2171
+ removeSheet: "sheet.mutation.remove-sheet",
2172
+ sheetOrder: "sheet.mutation.set-worksheet-order",
2173
+ sort: "sheet.mutation.reorder-range"
2165
2174
  };
2166
2175
  var PAIR_BARRIERS = {};
2167
2176
  var pairKey = (a, b) => a < b ? `${a}|${b}` : `${b}|${a}`;
@@ -2273,6 +2282,20 @@ function mergeThrough(s, m) {
2273
2282
  }
2274
2283
  return { range: m, fixup: false };
2275
2284
  }
2285
+ function mergeFixupsOwed(m, mergesBefore) {
2286
+ const st = structuralOf(m);
2287
+ if (!st) return null;
2288
+ const remove = [];
2289
+ const add = [];
2290
+ for (const q of mergesBefore) {
2291
+ const t = mergeThrough(st, q);
2292
+ if (!t.fixup) continue;
2293
+ remove.push({ startRow: q.startRow, endRow: q.endRow, startColumn: q.startColumn, endColumn: q.endColumn, ...q.rangeType !== void 0 ? { rangeType: q.rangeType } : {} });
2294
+ if (t.range) add.push({ ...t.range });
2295
+ }
2296
+ return remove.length ? { remove, add } : null;
2297
+ }
2298
+ var isStructuralMutation = (m) => structuralOf(m) !== null;
2276
2299
  function exactMergeRemovals(group, merges) {
2277
2300
  const sim = new Map(Object.entries(merges).map(([k, v]) => [k, v.map((r) => ({ ...r }))]));
2278
2301
  const out = [];
@@ -2319,8 +2342,24 @@ function cellsMutation(template, cells) {
2319
2342
  function putCell(cells, r, c, v) {
2320
2343
  (cells[r] ??= {})[c] = v;
2321
2344
  }
2345
+ function cellsOverlap(a, b) {
2346
+ for (const r of Object.keys(a)) {
2347
+ const br = b[r];
2348
+ if (!br) continue;
2349
+ for (const c of Object.keys(a[r] ?? {})) if (c in br) return true;
2350
+ }
2351
+ return false;
2352
+ }
2322
2353
  var isEmptyMatrix = (cells) => Object.values(cells).every((row) => Object.keys(row).length === 0);
2354
+ var cellBarrierCache = /* @__PURE__ */ new WeakMap();
2323
2355
  function cellBarrier(m) {
2356
+ const hit = cellBarrierCache.get(m);
2357
+ if (hit !== void 0) return hit;
2358
+ const why = cellBarrierOf(m);
2359
+ cellBarrierCache.set(m, why);
2360
+ return why;
2361
+ }
2362
+ function cellBarrierOf(m) {
2324
2363
  if (m.params.isOverrideStyle) return "set-range-values with isOverrideStyle (whole-style replace) is not covered";
2325
2364
  let why = null;
2326
2365
  forEachCell(cellsOf(m), (_r, _c, v) => {
@@ -2402,6 +2441,7 @@ function transformCell(X, Y4, side) {
2402
2441
  function transformCellsOverCells(x, y, side) {
2403
2442
  if (sheetOf(x) !== sheetOf(y)) return ok([x]);
2404
2443
  const ycells = cellsOf(y);
2444
+ if (!cellsOverlap(cellsOf(x), ycells)) return ok([x]);
2405
2445
  const xd = isDerived(x);
2406
2446
  const yd = isDerived(y);
2407
2447
  const eff = derivedSide(x, y, side);
@@ -2429,7 +2469,7 @@ function transformCellsOverCells(x, y, side) {
2429
2469
  const op = passes.filter((p) => !isEmptyMatrix(p)).map((p) => cellsMutation(x, p));
2430
2470
  return ok(op, lost, dropped);
2431
2471
  }
2432
- var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived"];
2472
+ var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived", "sheetIndex", "sheetsLeft"];
2433
2473
  var isDerived = (m) => m.params.derived === true;
2434
2474
  function derivedSide(x, y, side) {
2435
2475
  const xd = isDerived(x);
@@ -2451,7 +2491,15 @@ function withRefSheets(params, rs) {
2451
2491
  return out;
2452
2492
  }
2453
2493
  var hasFormulaText = (v) => !!v && (isFormulaText(v.f) || typeof v.ref === "string");
2494
+ var hasFormulaCache = /* @__PURE__ */ new WeakMap();
2454
2495
  function hasFormula(m) {
2496
+ const hit = hasFormulaCache.get(m);
2497
+ if (hit !== void 0) return hit;
2498
+ const any = hasFormulaOf(m);
2499
+ hasFormulaCache.set(m, any);
2500
+ return any;
2501
+ }
2502
+ function hasFormulaOf(m) {
2455
2503
  let any = false;
2456
2504
  forEachCell(cellsOf(m), (_r, _c, v) => {
2457
2505
  any ||= hasFormulaText(v);
@@ -2490,15 +2538,18 @@ function cellThrough(sheet, change, r, c) {
2490
2538
  return nr === null || nc === null ? null : [nr, nc];
2491
2539
  }
2492
2540
  function cellsOverChange(x, change) {
2541
+ if (!hasFormula(x) && (change.kind !== "axis" || change.sheet !== sheetOf(x))) return ok([x]);
2493
2542
  const ctx = formulaCtx(x);
2494
2543
  const out = {};
2495
2544
  const dropped = [];
2496
2545
  let why = null;
2546
+ let changed = false;
2497
2547
  forEachCell(cellsOf(x), (r, c, v) => {
2498
2548
  if (why) return;
2499
2549
  const at = cellThrough(sheetOf(x), change, r, c);
2500
2550
  if (!at) {
2501
2551
  dropped.push(cellRef(sheetOf(x), r, c));
2552
+ changed = true;
2502
2553
  return;
2503
2554
  }
2504
2555
  let e = v;
@@ -2509,14 +2560,19 @@ function cellsOverChange(x, change) {
2509
2560
  return;
2510
2561
  }
2511
2562
  e = res.entry;
2563
+ if (res.changed) changed = true;
2512
2564
  }
2565
+ if (at[0] !== r || at[1] !== c) changed = true;
2513
2566
  putCell(out, at[0], at[1], e);
2514
2567
  });
2515
2568
  if (why) return barrier2(why);
2516
- const params = { ...withRefSheets(x.params, refSheetsAfter(ctx.refSheets, change)), cellValue: out };
2569
+ const rsAfter = refSheetsAfter(ctx.refSheets, change);
2570
+ if (!changed && JSON.stringify(rsAfter ?? null) === JSON.stringify(ctx.refSheets ?? null)) return ok([x]);
2571
+ const params = { ...withRefSheets(x.params, rsAfter), cellValue: out };
2517
2572
  return ok(isEmptyMatrix(out) ? [] : [{ id: x.id, params }], [], dropped);
2518
2573
  }
2519
2574
  function rewritesOf(y, change) {
2575
+ if (!hasFormula(y)) return null;
2520
2576
  const ctx = formulaCtx(y);
2521
2577
  const out = {};
2522
2578
  let why = null;
@@ -2662,6 +2718,368 @@ function buildSize(template, values) {
2662
2718
  const value = uniform !== void 0 && [...values.values()].every((v) => v === uniform) ? uniform : Object.fromEntries(values);
2663
2719
  return { id: template.id, params: { ...p, ranges, [field]: value } };
2664
2720
  }
2721
+ var isNumfmt = (m) => m.id === ID.setNumfmt || m.id === ID.removeNumfmt;
2722
+ function nfParts(m) {
2723
+ if (m.id === ID.removeNumfmt) return [{ key: null, ranges: (m.params.ranges ?? []).map((r) => ({ ...r })) }];
2724
+ const values = m.params.values ?? {};
2725
+ return Object.keys(values).map((k) => ({ key: k, ranges: (values[k]?.ranges ?? []).map((r) => ({ ...r })) }));
2726
+ }
2727
+ function nfBuild(m, parts) {
2728
+ const keep = parts.filter((p) => p.ranges.length);
2729
+ if (!keep.length) return [];
2730
+ if (m.id === ID.removeNumfmt) return [{ id: m.id, params: { ...m.params, ranges: keep[0].ranges } }];
2731
+ const values = {};
2732
+ const refMap = {};
2733
+ const srcValues = m.params.values ?? {};
2734
+ const srcRef = m.params.refMap ?? {};
2735
+ for (const p of keep) {
2736
+ values[p.key] = { ...srcValues[p.key], ranges: p.ranges };
2737
+ refMap[p.key] = srcRef[p.key];
2738
+ }
2739
+ return [{ id: m.id, params: { ...m.params, values, refMap } }];
2740
+ }
2741
+ function nfValueAt(m, row, col) {
2742
+ for (const p of nfParts(m))
2743
+ if (p.ranges.some((r) => r.startRow <= row && row <= r.endRow && r.startColumn <= col && col <= r.endColumn)) {
2744
+ if (p.key === null) return null;
2745
+ const ref = (m.params.refMap ?? {})[p.key];
2746
+ return { pattern: ref?.pattern };
2747
+ }
2748
+ return void 0;
2749
+ }
2750
+ function spanThrough(op, lo, hi) {
2751
+ const pieces = [];
2752
+ if (op.kind === "insert") pieces.push([0, op.at - 1, 0], [op.at, Infinity, op.count]);
2753
+ else if (op.kind === "remove") pieces.push([0, op.start - 1, 0], [op.start + op.count, Infinity, -op.count]);
2754
+ else if (op.count <= 0 || op.to >= op.from && op.to <= op.from + op.count) pieces.push([0, Infinity, 0]);
2755
+ else if (op.to > op.from) {
2756
+ const n = op.count;
2757
+ pieces.push([0, op.from - 1, 0], [op.from, op.from + n - 1, op.to - n - op.from], [op.from + n, op.to - 1, -n], [op.to, Infinity, 0]);
2758
+ } else {
2759
+ const n = op.count;
2760
+ pieces.push([0, op.to - 1, 0], [op.to, op.from - 1, n], [op.from, op.from + n - 1, op.to - op.from], [op.from + n, Infinity, 0]);
2761
+ }
2762
+ const out = [];
2763
+ for (const [a, b, d] of pieces) {
2764
+ const x0 = Math.max(a, lo);
2765
+ const x1 = Math.min(b, hi);
2766
+ if (x0 <= x1) out.push([x0 + d, x1 + d]);
2767
+ }
2768
+ out.sort((p, q) => p[0] - q[0]);
2769
+ const merged = [];
2770
+ for (const p of out) {
2771
+ const last = merged[merged.length - 1];
2772
+ if (last && last[1] + 1 >= p[0]) last[1] = Math.max(last[1], p[1]);
2773
+ else merged.push([p[0], p[1]]);
2774
+ }
2775
+ return merged;
2776
+ }
2777
+ function rectsThrough(st, rects) {
2778
+ const [a0, a1] = S(st.axis);
2779
+ const out = [];
2780
+ for (const r of rects) for (const [lo, hi] of spanThrough(st.op, r[a0], r[a1])) out.push({ ...r, [a0]: lo, [a1]: hi });
2781
+ return out;
2782
+ }
2783
+ function rectMinus(a, b) {
2784
+ if (a.startRow > b.endRow || b.startRow > a.endRow || a.startColumn > b.endColumn || b.startColumn > a.endColumn) return [a];
2785
+ const out = [];
2786
+ if (a.startRow < b.startRow) out.push({ ...a, endRow: b.startRow - 1 });
2787
+ if (a.endRow > b.endRow) out.push({ ...a, startRow: b.endRow + 1 });
2788
+ const r0 = Math.max(a.startRow, b.startRow);
2789
+ const r1 = Math.min(a.endRow, b.endRow);
2790
+ if (a.startColumn < b.startColumn) out.push({ ...a, startRow: r0, endRow: r1, endColumn: b.startColumn - 1 });
2791
+ if (a.endColumn > b.endColumn) out.push({ ...a, startRow: r0, endRow: r1, startColumn: b.endColumn + 1 });
2792
+ return out;
2793
+ }
2794
+ function rectsMinus(as, bs) {
2795
+ let cur = as;
2796
+ for (const b of bs) cur = cur.flatMap((a) => rectMinus(a, b));
2797
+ return cur;
2798
+ }
2799
+ function nWrites(m) {
2800
+ const out = [];
2801
+ forEachCell(cellsOf(m), (r, c, v) => {
2802
+ if (v === null || v.s === null || v.s && typeof v.s === "object" && "n" in v.s)
2803
+ out.push({ startRow: r, endRow: r, startColumn: c, endColumn: c });
2804
+ });
2805
+ return out;
2806
+ }
2807
+ function numfmtPair(x, y, side, sx, sy) {
2808
+ const nx = isNumfmt(x);
2809
+ const ny = isNumfmt(y);
2810
+ if (!nx && !ny) return null;
2811
+ if (nx && sy) return ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsThrough(sy, p.ranges) }))));
2812
+ if (ny && sx) return ok([x]);
2813
+ if (nx && ny) {
2814
+ if (side === "left") return ok([x]);
2815
+ const ys = nfParts(y).flatMap((p) => p.ranges);
2816
+ return ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) }))));
2817
+ }
2818
+ if (nx && y.id === ID.values) {
2819
+ if (side === "left") return ok([x]);
2820
+ const ys = nWrites(y);
2821
+ return ys.length ? ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) })))) : ok([x]);
2822
+ }
2823
+ if (ny && x.id === ID.values) {
2824
+ if (side === "left") return ok([x]);
2825
+ const out = {};
2826
+ const tail = {};
2827
+ let touched = false;
2828
+ forEachCell(cellsOf(x), (r, c, v) => {
2829
+ const n = nfValueAt(y, r, c);
2830
+ if (n === void 0) return putCell(out, r, c, v);
2831
+ if (v === null || v.s === null) {
2832
+ putCell(out, r, c, v);
2833
+ if (n) {
2834
+ putCell(tail, r, c, { s: { n } });
2835
+ touched = true;
2836
+ }
2837
+ return;
2838
+ }
2839
+ if (v.s && typeof v.s === "object" && "n" in v.s) {
2840
+ const { n: _drop, ...rest } = v.s;
2841
+ const e = { ...v };
2842
+ if (Object.keys(rest).length) e.s = rest;
2843
+ else delete e.s;
2844
+ touched = true;
2845
+ if (Object.keys(e).length) putCell(out, r, c, e);
2846
+ return;
2847
+ }
2848
+ putCell(out, r, c, v);
2849
+ });
2850
+ if (!touched) return ok([x]);
2851
+ const ops = [];
2852
+ if (!isEmptyMatrix(out)) ops.push(cellsMutation(x, out));
2853
+ if (!isEmptyMatrix(tail)) ops.push({ id: ID.values, params: { subUnitId: sheetOf(x), cellValue: tail } });
2854
+ return ok(ops);
2855
+ }
2856
+ return ok([x]);
2857
+ }
2858
+ var isCount = (m) => m.id === ID.rowCount || m.id === ID.colCount;
2859
+ var countAxis = (m) => m.id === ID.rowCount ? "row" : "col";
2860
+ var countKey = (m) => m.id === ID.rowCount ? "rowCount" : "columnCount";
2861
+ function countPair(x, y, sy) {
2862
+ if (!isCount(x)) return isCount(y) ? ok([x]) : null;
2863
+ const k = countKey(x);
2864
+ const v = Number(x.params[k]);
2865
+ if (sy) {
2866
+ if (sy.axis !== countAxis(x) || sy.op.kind === "move") return ok([x]);
2867
+ const d = sy.op.kind === "insert" ? sy.op.count : -sy.op.count;
2868
+ return ok([{ id: x.id, params: { ...x.params, [k]: Math.max(1, v + d) } }]);
2869
+ }
2870
+ if (isCount(y) && y.id === x.id) {
2871
+ const w = Number(y.params[k]);
2872
+ return ok([w > v ? { id: x.id, params: { ...x.params, [k]: w } } : x]);
2873
+ }
2874
+ return ok([x]);
2875
+ }
2876
+ var isSheetOp = (m) => m.id === ID.insertSheet || m.id === ID.removeSheet || m.id === ID.sheetOrder;
2877
+ var sheetIdOf = (m) => m.id === ID.insertSheet ? String(m.params.sheet?.id ?? "") : sheetOf(m);
2878
+ function sheetAxisOf(m) {
2879
+ const p = m.params;
2880
+ if (m.id === ID.insertSheet) return typeof p.index === "number" ? { kind: "insert", at: p.index, count: 1 } : null;
2881
+ if (m.id === ID.removeSheet) return typeof p.sheetIndex === "number" ? { kind: "remove", start: p.sheetIndex, count: 1 } : null;
2882
+ if (m.id === ID.sheetOrder) {
2883
+ const f = Number(p.fromOrder);
2884
+ const t = Number(p.toOrder);
2885
+ return { kind: "move", from: f, count: 1, to: t > f ? t + 1 : t };
2886
+ }
2887
+ return null;
2888
+ }
2889
+ function buildSheetOp(template, op) {
2890
+ if (op.kind === "insert") return { id: template.id, params: { ...template.params, index: op.at } };
2891
+ if (op.kind === "remove") return { id: template.id, params: { ...template.params, sheetIndex: op.start } };
2892
+ return { id: template.id, params: { ...template.params, fromOrder: op.from, toOrder: op.to > op.from ? op.to - 1 : op.to } };
2893
+ }
2894
+ function namesSheet(m, id) {
2895
+ const rs = refSheetsOf(m);
2896
+ return !!rs && Object.values(rs).includes(id) && (m.id === ID.setName || hasFormula(m));
2897
+ }
2898
+ function sheetPair(x, y, side) {
2899
+ const xs = isSheetOp(x);
2900
+ const ys = isSheetOp(y);
2901
+ if (!xs && !ys) return null;
2902
+ if (xs && ys) {
2903
+ const a = sheetAxisOf(x);
2904
+ const b = sheetAxisOf(y);
2905
+ if (!a || !b) return barrier2("a sheet add or remove without its index (capture must call annotateSheetOps)");
2906
+ if (x.id === ID.insertSheet && y.id === ID.insertSheet && sheetIdOf(x) === sheetIdOf(y)) {
2907
+ return JSON.stringify(x.params) === JSON.stringify(y.params) ? ok([]) : barrier2("the same sheet id added twice with different content");
2908
+ }
2909
+ if (x.id === ID.removeSheet && typeof x.params.sheetsLeft === "number" && sheetIdOf(x) !== sheetIdOf(y) && (y.id === ID.removeSheet || y.id === ID.insertSheet)) {
2910
+ const left = x.params.sheetsLeft + (y.id === ID.insertSheet ? 1 : -1);
2911
+ if (left < 1) return barrier2("concurrent sheet removes would leave the workbook without a sheet");
2912
+ const out2 = transformAxis(a, b, side);
2913
+ if (!out2) return barrier2("sheet order: no transform");
2914
+ return ok(out2.map((o) => buildSheetOp({ id: x.id, params: { ...x.params, sheetsLeft: left } }, o)));
2915
+ }
2916
+ const out = transformAxis(a, b, side);
2917
+ if (!out) return barrier2("sheet order: no transform");
2918
+ return ok(out.map((o) => buildSheetOp(x, o)), [], out.length === 0 && x.id === ID.sheetOrder ? [`${sheetIdOf(x)}: sheet order`] : []);
2919
+ }
2920
+ if (ys) {
2921
+ if (y.id !== ID.removeSheet) return ok([x]);
2922
+ const gone2 = sheetOf(y);
2923
+ if (namesSheet(x, gone2)) return barrier2("a formula names a sheet removed at the same time");
2924
+ if (sheetOf(x) === gone2 && x.id !== ID.setName && x.id !== ID.removeName)
2925
+ return ok([], [], isDerived(x) ? [] : [`${gone2}: the sheet was removed`]);
2926
+ return ok([x]);
2927
+ }
2928
+ if (x.id !== ID.removeSheet) return ok([x]);
2929
+ const gone = sheetOf(x);
2930
+ if (namesSheet(y, gone)) return barrier2("a formula names a sheet removed at the same time");
2931
+ return ok([x], sheetOf(y) === gone && !isDerived(y) && y.id !== ID.setName && y.id !== ID.removeName ? [`${gone}: the sheet was removed`] : []);
2932
+ }
2933
+ function annotateSheetOps(group, sheetOrder) {
2934
+ const order = [...sheetOrder];
2935
+ return group.map((m) => {
2936
+ if (m.id === ID.insertSheet) {
2937
+ const index = typeof m.params.index === "number" ? Math.min(m.params.index, order.length) : order.length;
2938
+ order.splice(index, 0, sheetIdOf(m));
2939
+ return index === m.params.index ? m : { id: m.id, params: { ...m.params, index } };
2940
+ }
2941
+ if (m.id === ID.removeSheet) {
2942
+ const i = order.indexOf(sheetOf(m));
2943
+ if (i >= 0) order.splice(i, 1);
2944
+ return i >= 0 ? { id: m.id, params: { ...m.params, sheetIndex: i, sheetsLeft: order.length } } : m;
2945
+ }
2946
+ if (m.id === ID.sheetOrder) {
2947
+ const f = Number(m.params.fromOrder);
2948
+ const [id] = order.splice(f, 1);
2949
+ order.splice(Number(m.params.toOrder), 0, id ?? sheetOf(m));
2950
+ }
2951
+ return m;
2952
+ });
2953
+ }
2954
+ function inlineSheetStyles(sheet, styleOf) {
2955
+ const out = JSON.parse(JSON.stringify(sheet));
2956
+ const fix = (o) => {
2957
+ if (o && typeof o.s === "string") {
2958
+ const st = styleOf(o.s);
2959
+ if (st) o.s = JSON.parse(JSON.stringify(st));
2960
+ }
2961
+ };
2962
+ for (const row of Object.values(out.cellData ?? {})) for (const cell of Object.values(row ?? {})) fix(cell);
2963
+ for (const key of ["rowData", "columnData"]) for (const v of Object.values(out[key] ?? {})) fix(v);
2964
+ if (typeof out.defaultStyle === "string") {
2965
+ const st = styleOf(out.defaultStyle);
2966
+ if (st) out.defaultStyle = JSON.parse(JSON.stringify(st));
2967
+ }
2968
+ return out;
2969
+ }
2970
+ var isSort = (m) => m.id === ID.sort;
2971
+ function sortOf(m) {
2972
+ const P = /* @__PURE__ */ new Map();
2973
+ for (const [t, src] of Object.entries(m.params.order ?? {})) P.set(Number(t), Number(src));
2974
+ return { range: { ...m.params.range }, P };
2975
+ }
2976
+ var sortQ = (o) => new Map([...o.P].map(([t, s0]) => [s0, t]));
2977
+ function buildSort(template, o) {
2978
+ const order = {};
2979
+ for (const [t, s0] of [...o.P].sort((a, b) => a[0] - b[0])) if (t !== s0) order[t] = s0;
2980
+ if (!Object.keys(order).length || o.range.startRow > o.range.endRow || o.range.startColumn > o.range.endColumn) return [];
2981
+ return [{ id: template.id, params: { ...template.params, range: o.range, order } }];
2982
+ }
2983
+ var inSortCols = (o, c) => c >= o.range.startColumn && c <= o.range.endColumn;
2984
+ function sortThrough(o, st) {
2985
+ const r = o.range;
2986
+ if (st.axis === "col") {
2987
+ if (st.op.kind === "move") {
2988
+ const { from, count, to } = st.op;
2989
+ const touches = !(from + count - 1 < r.startColumn || from > r.endColumn) || to > r.startColumn && to <= r.endColumn;
2990
+ if (touches) return null;
2991
+ const spans3 = spanThrough(st.op, r.startColumn, r.endColumn);
2992
+ return spans3.length === 1 ? { range: { ...r, startColumn: spans3[0][0], endColumn: spans3[0][1] }, P: o.P } : null;
2993
+ }
2994
+ const spans2 = spanThrough(st.op, r.startColumn, r.endColumn);
2995
+ if (!spans2.length) return { range: { ...r, startColumn: 1, endColumn: 0 }, P: /* @__PURE__ */ new Map() };
2996
+ return { range: { ...r, startColumn: spans2[0][0], endColumn: spans2[spans2.length - 1][1] }, P: o.P };
2997
+ }
2998
+ const op = st.op;
2999
+ if (op.kind === "move") {
3000
+ const touches = !(op.from + op.count - 1 < r.startRow || op.from > r.endRow) || op.to > r.startRow && op.to <= r.endRow;
3001
+ if (touches) return null;
3002
+ }
3003
+ if (op.kind === "insert" || op.kind === "move") {
3004
+ const P2 = /* @__PURE__ */ new Map();
3005
+ for (const [t, s0] of o.P) P2.set(mapIndex(op, t), mapIndex(op, s0));
3006
+ const spans2 = spanThrough(op, r.startRow, r.endRow);
3007
+ return { range: { ...r, startRow: spans2[0][0], endRow: spans2[spans2.length - 1][1] }, P: P2 };
3008
+ }
3009
+ const removed = (i) => i >= op.start && i < op.start + op.count;
3010
+ const Q = sortQ(o);
3011
+ const goneTargets = [];
3012
+ for (let i = op.start; i < op.start + op.count; i++) goneTargets.push(Q.get(i) ?? i);
3013
+ goneTargets.sort((a, b) => a - b);
3014
+ const compact = (t) => t - goneTargets.filter((g) => g < t).length;
3015
+ const P = /* @__PURE__ */ new Map();
3016
+ for (const [t, s0] of o.P) if (!removed(s0)) P.set(compact(t), mapIndex(op, s0));
3017
+ const spans = spanThrough(op, r.startRow, r.endRow);
3018
+ if (!spans.length) return { range: { ...r, startRow: 1, endRow: 0 }, P: /* @__PURE__ */ new Map() };
3019
+ return { range: { ...r, startRow: spans[0][0], endRow: spans[spans.length - 1][1] }, P };
3020
+ }
3021
+ function sortPair(x, y, sx, sy) {
3022
+ const xs = isSort(x);
3023
+ const ys = isSort(y);
3024
+ if (!xs && !ys) return null;
3025
+ if (xs && ys) {
3026
+ const a = sortOf(x).range;
3027
+ const b = sortOf(y).range;
3028
+ const overlap = a.startRow <= b.endRow && b.startRow <= a.endRow && a.startColumn <= b.endColumn && b.startColumn <= a.endColumn;
3029
+ return overlap ? barrier2("two sorts of overlapping ranges at once") : ok([x]);
3030
+ }
3031
+ if (xs) {
3032
+ if (sy) {
3033
+ const t = sortThrough(sortOf(x), sy);
3034
+ return t ? ok(buildSort(x, t)) : barrier2("a row or column move through a sorted range");
3035
+ }
3036
+ return ok([x]);
3037
+ }
3038
+ const o = sortOf(y);
3039
+ const Q = sortQ(o);
3040
+ const moved = (r) => r >= o.range.startRow && r <= o.range.endRow && Q.has(r);
3041
+ if (sx) {
3042
+ if (sx.axis === "col") return sx.op.kind === "move" && !sortThrough(o, sx) ? barrier2("a column move through a sorted range") : ok([x]);
3043
+ if (sx.op.kind === "insert") return ok([x]);
3044
+ if (sx.op.kind === "move") return sortThrough(o, sx) ? ok([x]) : barrier2("a row move through a sorted range");
3045
+ const rows = [];
3046
+ let partial = false;
3047
+ for (let i = sx.op.start; i < sx.op.start + sx.op.count; i++) {
3048
+ if (moved(i)) partial = true;
3049
+ rows.push(Q.get(i) ?? i);
3050
+ }
3051
+ if (partial) return barrier2("a row remove against a concurrent sort of those rows");
3052
+ return ok([x]);
3053
+ }
3054
+ if (x.id === ID.values) {
3055
+ const out = {};
3056
+ let changed = false;
3057
+ forEachCell(cellsOf(x), (r, c, v) => {
3058
+ if (inSortCols(o, c) && moved(r)) {
3059
+ putCell(out, Q.get(r), c, v);
3060
+ changed = true;
3061
+ } else putCell(out, r, c, v);
3062
+ });
3063
+ return changed ? ok([cellsMutation(x, out)]) : ok([x]);
3064
+ }
3065
+ if (isNumfmt(x)) {
3066
+ const parts = nfParts(x).map((p) => {
3067
+ const ranges = [];
3068
+ for (const rc of p.ranges) {
3069
+ const inner = { ...rc, startRow: Math.max(rc.startRow, o.range.startRow), endRow: Math.min(rc.endRow, o.range.endRow), startColumn: Math.max(rc.startColumn, o.range.startColumn), endColumn: Math.min(rc.endColumn, o.range.endColumn) };
3070
+ if (inner.startRow > inner.endRow || inner.startColumn > inner.endColumn) {
3071
+ ranges.push(rc);
3072
+ continue;
3073
+ }
3074
+ ranges.push(...rectMinus(rc, inner));
3075
+ for (let r = inner.startRow; r <= inner.endRow; r++) ranges.push({ ...inner, startRow: Q.get(r) ?? r, endRow: Q.get(r) ?? r });
3076
+ }
3077
+ return { ...p, ranges };
3078
+ });
3079
+ return ok(nfBuild(x, parts));
3080
+ }
3081
+ return ok([x]);
3082
+ }
2665
3083
  function familyOf(id) {
2666
3084
  const e = SHEET_MUTATIONS[id];
2667
3085
  return e && e.kind === "covered" ? e.family : "";
@@ -2678,6 +3096,8 @@ function transformMutation(x, y, side) {
2678
3096
  }
2679
3097
  const pb = PAIR_BARRIERS[pairKey(x.id, y.id)];
2680
3098
  if (pb) return barrier2(`${x.id} \xD7 ${y.id}: ${pb.reason}${pb.seed === null ? "" : ` (fuzz seed ${pb.seed})`}`);
3099
+ const sp = sheetPair(x, y, side);
3100
+ if (sp) return sp;
2681
3101
  const fp = formulaPair(x, y, side);
2682
3102
  if (fp) return fp;
2683
3103
  if (sheetOf(x) !== sheetOf(y)) return ok([x]);
@@ -2685,6 +3105,12 @@ function transformMutation(x, y, side) {
2685
3105
  const fy = familyOf(y.id);
2686
3106
  const sy = structuralOf(y);
2687
3107
  const sx = structuralOf(x);
3108
+ const sortp = sortPair(x, y, sx, sy);
3109
+ if (sortp) return sortp;
3110
+ const cp = countPair(x, y, sy);
3111
+ if (cp) return cp;
3112
+ const np = numfmtPair(x, y, side, sx, sy);
3113
+ if (np) return np;
2688
3114
  if (sx && sy) {
2689
3115
  if (sx.axis !== sy.axis) return ok([x]);
2690
3116
  const out = transformAxis(sx.op, sy.op, side);
@@ -2792,22 +3218,45 @@ function tSeq(xs, ys, side, acc) {
2792
3218
  acc.dropped.push(...a.dropped);
2793
3219
  return [a.op, b.op];
2794
3220
  }
3221
+ const outX = [];
3222
+ let curY = ys;
3223
+ for (const x of xs) {
3224
+ let curX = [x];
3225
+ const nextY = [];
3226
+ for (const y of curY) {
3227
+ if (curX.length === 0) {
3228
+ nextY.push(y);
3229
+ continue;
3230
+ }
3231
+ const r = tSeq(curX, [y], side, acc);
3232
+ if (blocked(r)) return r;
3233
+ curX = r[0];
3234
+ for (const m of r[1]) nextY.push(m);
3235
+ }
3236
+ for (const m of curX) outX.push(m);
3237
+ curY = nextY;
3238
+ }
3239
+ return [outX, curY];
3240
+ }
3241
+ function tSeqOld(xs, ys, side, acc) {
3242
+ if (xs.length === 0 || ys.length === 0) return [xs, ys];
3243
+ if (xs.length === 1 && ys.length === 1) return tSeq(xs, ys, side, acc);
2795
3244
  if (xs.length > 1) {
2796
- const first2 = tSeq([xs[0]], ys, side, acc);
3245
+ const first2 = tSeqOld([xs[0]], ys, side, acc);
2797
3246
  if (blocked(first2)) return first2;
2798
- const rest2 = tSeq(xs.slice(1), first2[1], side, acc);
3247
+ const rest2 = tSeqOld(xs.slice(1), first2[1], side, acc);
2799
3248
  if (blocked(rest2)) return rest2;
2800
3249
  return [[...first2[0], ...rest2[0]], rest2[1]];
2801
3250
  }
2802
- const first = tSeq(xs, [ys[0]], side, acc);
3251
+ const first = tSeqOld(xs, [ys[0]], side, acc);
2803
3252
  if (blocked(first)) return first;
2804
- const rest = tSeq(first[0], ys.slice(1), side, acc);
3253
+ const rest = tSeqOld(first[0], ys.slice(1), side, acc);
2805
3254
  if (blocked(rest)) return rest;
2806
3255
  return [rest[0], [...first[1], ...rest[1]]];
2807
3256
  }
2808
3257
  function transformGroup(x, y, side) {
2809
3258
  const acc = { lost: [], dropped: [] };
2810
- const r = tSeq([...x], [...y], side, acc);
3259
+ const r = (process.env.OLD_TSEQ ? tSeqOld : tSeq)([...x], [...y], side, acc);
2811
3260
  if (blocked(r)) return r;
2812
3261
  return { op: r[0], lost: [...new Set(acc.lost)], dropped: [...new Set(acc.dropped)] };
2813
3262
  }
@@ -2877,7 +3326,7 @@ async function sheetsStateHash(snapshot) {
2877
3326
  }
2878
3327
 
2879
3328
  // src/univer/collab/sheets-ot/room.ts
2880
- var SHEETS_COLLAB_PROTO = 1;
3329
+ var SHEETS_COLLAB_PROTO = 2;
2881
3330
  var SHEETS_EDIT_GROUP = "sheets.edit";
2882
3331
  var flip2 = (side) => side === "left" ? "right" : "left";
2883
3332
  var isNoopSheetOp = (op) => op == null || op.length === 0;
@@ -2924,6 +3373,11 @@ function travelingShape(m) {
2924
3373
  }
2925
3374
  return { id: m.id, params };
2926
3375
  }
3376
+ var shapedLists = /* @__PURE__ */ new WeakMap();
3377
+ function cachedShape(list) {
3378
+ const hit = shapedLists.get(list);
3379
+ return hit && hit.src.length === list.length && hit.src.every((m, i) => m === list[i]) ? hit.shaped : null;
3380
+ }
2927
3381
  function rebaseSheetUndoStack(items, remote, unitId) {
2928
3382
  if (isNoopSheetOp(remote)) return 0;
2929
3383
  let dropped = 0;
@@ -2935,7 +3389,11 @@ function rebaseSheetUndoStack(items, remote, unitId) {
2935
3389
  if (!ok2 || !list?.length) continue;
2936
3390
  const isOperation = (id) => !SHEET_MUTATIONS[id] && id.includes(".operation.");
2937
3391
  const operations = list.filter((m) => isOperation(m.id));
2938
- const shaped = list.filter((m) => !isOperation(m.id)).map(travelingShape);
3392
+ let shaped = cachedShape(list);
3393
+ if (!shaped) {
3394
+ shaped = list.filter((m) => !isOperation(m.id)).map(travelingShape);
3395
+ shapedLists.set(list, { src: list.slice(), shaped });
3396
+ }
2939
3397
  if (shaped.some((m) => m === null)) {
2940
3398
  ok2 = false;
2941
3399
  continue;
@@ -2947,8 +3405,10 @@ function rebaseSheetUndoStack(items, remote, unitId) {
2947
3405
  ok2 = false;
2948
3406
  continue;
2949
3407
  }
2950
- if (JSON.stringify(r.op) === JSON.stringify(shaped)) continue;
2951
- item[key] = [...r.op.map((m) => ({ id: m.id, params: { ...forApply(m).params, unitId } })), ...operations];
3408
+ if (r.op.length === shaped.length && r.op.every((m, i2) => m === shaped[i2])) continue;
3409
+ const next = [...r.op.map((m) => ({ id: m.id, params: { ...forApply(m).params, unitId } })), ...operations];
3410
+ shapedLists.set(next, { src: next.slice(), shaped: r.op });
3411
+ item[key] = next;
2952
3412
  } catch {
2953
3413
  ok2 = false;
2954
3414
  }
@@ -3023,7 +3483,7 @@ function createSheetsOtAdapter(port, hooks = {}) {
3023
3483
  });
3024
3484
  });
3025
3485
  }
3026
- return sheetsStateHash(port.snapshot());
3486
+ return (hooks.stateHash ?? sheetsStateHash)(port.snapshot());
3027
3487
  },
3028
3488
  held: () => queue.length,
3029
3489
  rebaseLocalOverHeld(local) {
@@ -3135,6 +3595,8 @@ var VALUES = "sheet.mutation.set-range-values";
3135
3595
  var ADD_MERGE = "sheet.mutation.add-worksheet-merge";
3136
3596
  var REMOVE_MERGE = "sheet.mutation.remove-worksheet-merge";
3137
3597
  var SHEET_NAME = "sheet.mutation.set-worksheet-name";
3598
+ var INSERT_SHEET = "sheet.mutation.insert-sheet";
3599
+ var RESHAPE = /* @__PURE__ */ new Set(["sheet.mutation.set-worksheet-row-count", "sheet.mutation.set-worksheet-column-count", "sheet.mutation.remove-sheet", INSERT_SHEET]);
3138
3600
  var DEPTH_GUARD = /* @__PURE__ */ Symbol.for("ai-matrx.office.sheets.command-depth-guard");
3139
3601
  var json = (v) => v === void 0 ? v : JSON.parse(JSON.stringify(v));
3140
3602
  var flagged = (options) => {
@@ -3171,7 +3633,8 @@ function univerSheetsOtPort(o) {
3171
3633
  for (const [id, d] of Object.entries(map)) out[id] = String(d?.name ?? "");
3172
3634
  return out;
3173
3635
  };
3174
- const openGroup = (label) => ({ label, sheets: sheetNames(), names: definedNames(), mutations: [], inverses: [], notShared: null });
3636
+ const sheetOrder = () => (o.workbook()?.getSheets() ?? []).map((ws) => ws.getSheetId());
3637
+ const openGroup = (label) => ({ label, order: sheetOrder(), sheets: sheetNames(), names: definedNames(), mutations: [], inverses: [], notShared: null });
3175
3638
  const emit = (e) => {
3176
3639
  for (const l of [...listeners]) {
3177
3640
  try {
@@ -3187,7 +3650,8 @@ function univerSheetsOtPort(o) {
3187
3650
  if (!g) return;
3188
3651
  if (g.notShared) emit({ kind: "not_shared", mutationId: g.notShared, label: g.label });
3189
3652
  else if (g.mutations.length) {
3190
- const mutations = annotateFormulas(g.mutations, g.sheets, g.names);
3653
+ const mutations = annotateSheetOps(annotateFormulas(g.mutations, g.sheets, g.names), g.order);
3654
+ if (mutations.some((m) => isStructuralMutation(m) || RESHAPE.has(m.id))) clampSelection();
3191
3655
  const known = g.inverses.every((i) => i !== void 0);
3192
3656
  const inverse = known ? annotateFormulas(g.inverses.slice().reverse().flat(), g.sheets, g.names) : void 0;
3193
3657
  emit({ kind: "group", mutations, ...inverse !== void 0 ? { inverse } : {}, label: g.label });
@@ -3221,7 +3685,27 @@ function univerSheetsOtPort(o) {
3221
3685
  }
3222
3686
  if (info.id === SHEET_NAME) record.name = ws.getName();
3223
3687
  pre.set(p, record);
3688
+ const owed = isStructuralMutation({ id: info.id, params: p }) ? mergeFixupsOwed({ id: info.id, params: p }, record.merges ?? []) : null;
3689
+ if (owed) {
3690
+ runOwn(REMOVE_MERGE, String(p.subUnitId), owed.remove, ADD_MERGE);
3691
+ if (owed.add.length) record.addAfter = owed.add;
3692
+ }
3224
3693
  });
3694
+ const runOwn = (id, sheet, ranges, inverseId) => {
3695
+ const u = unitId();
3696
+ if (!u) return;
3697
+ applying = true;
3698
+ try {
3699
+ cs.syncExecuteCommand(id, { unitId: u, subUnitId: sheet, ranges: json(ranges) }, { onlyLocal: true });
3700
+ } finally {
3701
+ applying = false;
3702
+ }
3703
+ if (!group) group = openGroup(null);
3704
+ if (!group.notShared) {
3705
+ group.mutations.push({ id, params: { subUnitId: sheet, ranges: json(ranges) } });
3706
+ group.inverses.push([{ id: inverseId, params: { subUnitId: sheet, ranges: json(ranges) } }]);
3707
+ }
3708
+ };
3225
3709
  const after = cs.onCommandExecuted((info) => {
3226
3710
  if (info.type !== COMMAND) return;
3227
3711
  const at = tracker.stack.lastIndexOf(info.id);
@@ -3319,6 +3803,8 @@ function univerSheetsOtPort(o) {
3319
3803
  if (!m2) return { m: null, inverse: void 0 };
3320
3804
  return { m: m2, inverse: [{ id: ADD_MERGE, params: { subUnitId: sheet, ranges: json(m2.params.ranges) } }] };
3321
3805
  }
3806
+ if (info.id === INSERT_SHEET && params.sheet && typeof params.sheet === "object")
3807
+ params.sheet = inlineSheetStyles(params.sheet, (id) => o.workbook()?.getStyles().get(id));
3322
3808
  const m = { id: info.id, params };
3323
3809
  switch (info.id) {
3324
3810
  case "sheet.mutation.insert-row":
@@ -3327,6 +3813,11 @@ function univerSheetsOtPort(o) {
3327
3813
  return { m, inverse: [{ id: "sheet.mutation.remove-col", params: { subUnitId: sheet, range: json(params.range) } }] };
3328
3814
  case ADD_MERGE:
3329
3815
  return { m, inverse: [{ id: REMOVE_MERGE, params: { subUnitId: sheet, ranges: json(params.ranges) } }] };
3816
+ case "sheet.mutation.reorder-range": {
3817
+ const order = {};
3818
+ for (const [t, src] of Object.entries(params.order ?? {})) order[String(src)] = Number(t);
3819
+ return { m, inverse: [{ id: info.id, params: { subUnitId: sheet, range: json(params.range), order } }] };
3820
+ }
3330
3821
  case SHEET_NAME:
3331
3822
  return { m, inverse: before2.name !== void 0 ? [{ id: SHEET_NAME, params: { subUnitId: sheet, name: before2.name } }] : void 0 };
3332
3823
  default:
@@ -3335,8 +3826,7 @@ function univerSheetsOtPort(o) {
3335
3826
  };
3336
3827
  const collab = cs.onMutationExecutedForCollab((info, options) => {
3337
3828
  if (applying || flagged(options) || !mine(info.params)) return;
3338
- const lone = !group;
3339
- if (lone) group = openGroup(null);
3829
+ if (!group) group = openGroup(null);
3340
3830
  const g = group;
3341
3831
  if (!g.notShared) {
3342
3832
  const r = capture(info);
@@ -3346,11 +3836,29 @@ function univerSheetsOtPort(o) {
3346
3836
  g.inverses.push(r.inverse);
3347
3837
  }
3348
3838
  }
3349
- if (lone && tracker.stack.length === 0) settle();
3839
+ const owedAdd = pre.get(info.params)?.addAfter;
3840
+ if (owedAdd?.length) runOwn(ADD_MERGE, String(info.params.subUnitId ?? ""), owedAdd, REMOVE_MERGE);
3841
+ if (tracker.stack.length === 0) settle();
3350
3842
  });
3843
+ const clampSelection = () => {
3844
+ const sel = o.selections;
3845
+ if (!sel) return;
3846
+ try {
3847
+ const sheet = sel.sheetId();
3848
+ const ws = sheet ? o.workbook()?.getSheetBySheetId(sheet) : null;
3849
+ const current = sel.get();
3850
+ if (!ws || !current?.length) return;
3851
+ const rows = ws.getMaxRows?.() ?? Number.MAX_SAFE_INTEGER;
3852
+ const cols = ws.getMaxColumns?.() ?? Number.MAX_SAFE_INTEGER;
3853
+ const next = moveSelectionsThrough(json(current), { id: "", params: {} }, rows, cols);
3854
+ if (JSON.stringify(next) !== JSON.stringify(current)) sel.set(next);
3855
+ } catch (err) {
3856
+ console.warn("[sheets-ot] could not keep this seat's selection inside the sheet after its own row or column change", err);
3857
+ }
3858
+ };
3351
3859
  const followSelection = (m) => {
3352
3860
  const sel = o.selections;
3353
- if (!sel || !axisOpOf(m)) return;
3861
+ if (!sel || !axisOpOf(m) && !RESHAPE.has(m.id)) return;
3354
3862
  try {
3355
3863
  const sheet = String(m.params.subUnitId ?? "");
3356
3864
  if (sel.sheetId() !== sheet) return;