@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.
@@ -1758,6 +1758,15 @@ var SHEET_MUTATIONS = {
1758
1758
  "sheet.mutation.set-worksheet-row-auto-height": covered("size", "rowsAutoHeightInfo"),
1759
1759
  "sheet.mutation.set-worksheet-col-width": covered("size", "ranges", "colWidth"),
1760
1760
  "sheet.mutation.set-worksheet-name": covered("name", "name"),
1761
+ // ── covered (C5c) ────────────────────────────────────────────────────────────────────────────────
1762
+ "sheet.mutation.set.numfmt": covered("numfmt", "values", "refMap"),
1763
+ "sheet.mutation.remove.numfmt": covered("numfmt", "ranges"),
1764
+ "sheet.mutation.set-worksheet-row-count": covered("count", "rowCount"),
1765
+ "sheet.mutation.set-worksheet-column-count": covered("count", "columnCount"),
1766
+ "sheet.mutation.insert-sheet": covered("sheet", "index", "sheet"),
1767
+ "sheet.mutation.remove-sheet": covered("sheet", "sheetIndex", "sheetsLeft"),
1768
+ "sheet.mutation.set-worksheet-order": covered("sheet", "fromOrder", "toOrder"),
1769
+ "sheet.mutation.reorder-range": covered("sort", "range", "order"),
1761
1770
  // ── never travels ────────────────────────────────────────────────────────────────────────────────
1762
1771
  "formula.mutation.set-formula-calculation-start": never(FORMULA_RESULT),
1763
1772
  "formula.mutation.set-trigger-formula-calculation-start": never(FORMULA_RESULT),
@@ -1791,13 +1800,7 @@ var SHEET_MUTATIONS = {
1791
1800
  "thread-comment.mutation.resolve-comment": never(UNIVER_COMMENTS),
1792
1801
  "thread-comment.mutation.delete-comment": never(UNIVER_COMMENTS),
1793
1802
  // ── barriers: X (no transform yet, design §10) ───────────────────────────────────────────────────
1794
- "sheet.mutation.reorder-range": barrier("X", "sort: a permutation, not transformed yet"),
1795
- "sheet.mutation.set-worksheet-row-count": barrier("X", "absolute row count; needs delta semantics"),
1796
- "sheet.mutation.set-worksheet-column-count": barrier("X", "absolute column count; needs delta semantics"),
1797
- "sheet.mutation.set-worksheet-order": barrier("X", "absolute sheet order; needs move semantics"),
1798
1803
  "sheet.mutation.move-range": barrier("X", "cut-paste carries the sender's cell matrices"),
1799
- "sheet.mutation.insert-sheet": barrier("X", "sheet add: not in C5a"),
1800
- "sheet.mutation.remove-sheet": barrier("X", "sheet remove: not in C5a"),
1801
1804
  "sheet.mutation.set-worksheet-hidden": barrier("X", "sheet-level setting: not in C5a"),
1802
1805
  "sheet.mutation.set-tab-color": barrier("X", "sheet-level setting: not in C5a"),
1803
1806
  "sheet.mutation.set-workbook-name": barrier("X", "workbook-level setting: not in C5a"),
@@ -1812,8 +1815,6 @@ var SHEET_MUTATIONS = {
1812
1815
  "sheet.mutation.set-row-visible": barrier("X", "row visibility: not in C5a"),
1813
1816
  "sheet.mutation.set-col-hidden": barrier("X", "column visibility: not in C5a"),
1814
1817
  "sheet.mutation.set-col-visible": barrier("X", "column visibility: not in C5a"),
1815
- "sheet.mutation.set.numfmt": barrier("X", "number formats by range: not in C5a"),
1816
- "sheet.mutation.remove.numfmt": barrier("X", "number formats by range: not in C5a"),
1817
1818
  "sheet.mutation.add-range-protection": barrier("X", "permissions: not in C5a"),
1818
1819
  "sheet.mutation.set-range-protection": barrier("X", "permissions: not in C5a"),
1819
1820
  "sheet.mutation.delete-range-protection": barrier("X", "permissions: not in C5a"),
@@ -2208,7 +2209,7 @@ function refSheetsFor(texts, sheets) {
2208
2209
  }
2209
2210
 
2210
2211
  // src/collab/sheets/transform/transform.ts
2211
- var SHEET_TRANSFORMER_VERSION = "c5b-1";
2212
+ var SHEET_TRANSFORMER_VERSION = "c5c-1";
2212
2213
  var ID = {
2213
2214
  values: "sheet.mutation.set-range-values",
2214
2215
  insertRow: "sheet.mutation.insert-row",
@@ -2225,7 +2226,15 @@ var ID = {
2225
2226
  colWidth: "sheet.mutation.set-worksheet-col-width",
2226
2227
  name: "sheet.mutation.set-worksheet-name",
2227
2228
  setName: "formula.mutation.set-defined-name",
2228
- removeName: "formula.mutation.remove-defined-name"
2229
+ removeName: "formula.mutation.remove-defined-name",
2230
+ setNumfmt: "sheet.mutation.set.numfmt",
2231
+ removeNumfmt: "sheet.mutation.remove.numfmt",
2232
+ rowCount: "sheet.mutation.set-worksheet-row-count",
2233
+ colCount: "sheet.mutation.set-worksheet-column-count",
2234
+ insertSheet: "sheet.mutation.insert-sheet",
2235
+ removeSheet: "sheet.mutation.remove-sheet",
2236
+ sheetOrder: "sheet.mutation.set-worksheet-order",
2237
+ sort: "sheet.mutation.reorder-range"
2229
2238
  };
2230
2239
  var PAIR_BARRIERS = {};
2231
2240
  var pairKey = (a, b) => a < b ? `${a}|${b}` : `${b}|${a}`;
@@ -2337,6 +2346,20 @@ function mergeThrough(s, m) {
2337
2346
  }
2338
2347
  return { range: m, fixup: false };
2339
2348
  }
2349
+ function mergeFixupsOwed(m, mergesBefore) {
2350
+ const st = structuralOf(m);
2351
+ if (!st) return null;
2352
+ const remove = [];
2353
+ const add = [];
2354
+ for (const q of mergesBefore) {
2355
+ const t = mergeThrough(st, q);
2356
+ if (!t.fixup) continue;
2357
+ remove.push({ startRow: q.startRow, endRow: q.endRow, startColumn: q.startColumn, endColumn: q.endColumn, ...q.rangeType !== void 0 ? { rangeType: q.rangeType } : {} });
2358
+ if (t.range) add.push({ ...t.range });
2359
+ }
2360
+ return remove.length ? { remove, add } : null;
2361
+ }
2362
+ var isStructuralMutation = (m) => structuralOf(m) !== null;
2340
2363
  function exactMergeRemovals(group, merges) {
2341
2364
  const sim = new Map(Object.entries(merges).map(([k, v]) => [k, v.map((r) => ({ ...r }))]));
2342
2365
  const out = [];
@@ -2383,8 +2406,24 @@ function cellsMutation(template, cells) {
2383
2406
  function putCell(cells, r, c, v) {
2384
2407
  (cells[r] ??= {})[c] = v;
2385
2408
  }
2409
+ function cellsOverlap(a, b) {
2410
+ for (const r of Object.keys(a)) {
2411
+ const br = b[r];
2412
+ if (!br) continue;
2413
+ for (const c of Object.keys(a[r] ?? {})) if (c in br) return true;
2414
+ }
2415
+ return false;
2416
+ }
2386
2417
  var isEmptyMatrix = (cells) => Object.values(cells).every((row) => Object.keys(row).length === 0);
2418
+ var cellBarrierCache = /* @__PURE__ */ new WeakMap();
2387
2419
  function cellBarrier(m) {
2420
+ const hit = cellBarrierCache.get(m);
2421
+ if (hit !== void 0) return hit;
2422
+ const why = cellBarrierOf(m);
2423
+ cellBarrierCache.set(m, why);
2424
+ return why;
2425
+ }
2426
+ function cellBarrierOf(m) {
2388
2427
  if (m.params.isOverrideStyle) return "set-range-values with isOverrideStyle (whole-style replace) is not covered";
2389
2428
  let why = null;
2390
2429
  forEachCell(cellsOf(m), (_r, _c, v) => {
@@ -2466,6 +2505,7 @@ function transformCell(X, Y4, side) {
2466
2505
  function transformCellsOverCells(x, y, side) {
2467
2506
  if (sheetOf(x) !== sheetOf(y)) return ok([x]);
2468
2507
  const ycells = cellsOf(y);
2508
+ if (!cellsOverlap(cellsOf(x), ycells)) return ok([x]);
2469
2509
  const xd = isDerived(x);
2470
2510
  const yd = isDerived(y);
2471
2511
  const eff = derivedSide(x, y, side);
@@ -2493,7 +2533,7 @@ function transformCellsOverCells(x, y, side) {
2493
2533
  const op = passes.filter((p) => !isEmptyMatrix(p)).map((p) => cellsMutation(x, p));
2494
2534
  return ok(op, lost, dropped);
2495
2535
  }
2496
- var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived"];
2536
+ var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived", "sheetIndex", "sheetsLeft"];
2497
2537
  var isDerived = (m) => m.params.derived === true;
2498
2538
  function derivedSide(x, y, side) {
2499
2539
  const xd = isDerived(x);
@@ -2515,7 +2555,15 @@ function withRefSheets(params, rs) {
2515
2555
  return out;
2516
2556
  }
2517
2557
  var hasFormulaText = (v) => !!v && (isFormulaText(v.f) || typeof v.ref === "string");
2558
+ var hasFormulaCache = /* @__PURE__ */ new WeakMap();
2518
2559
  function hasFormula(m) {
2560
+ const hit = hasFormulaCache.get(m);
2561
+ if (hit !== void 0) return hit;
2562
+ const any = hasFormulaOf(m);
2563
+ hasFormulaCache.set(m, any);
2564
+ return any;
2565
+ }
2566
+ function hasFormulaOf(m) {
2519
2567
  let any = false;
2520
2568
  forEachCell(cellsOf(m), (_r, _c, v) => {
2521
2569
  any ||= hasFormulaText(v);
@@ -2554,15 +2602,18 @@ function cellThrough(sheet, change, r, c) {
2554
2602
  return nr === null || nc === null ? null : [nr, nc];
2555
2603
  }
2556
2604
  function cellsOverChange(x, change) {
2605
+ if (!hasFormula(x) && (change.kind !== "axis" || change.sheet !== sheetOf(x))) return ok([x]);
2557
2606
  const ctx = formulaCtx(x);
2558
2607
  const out = {};
2559
2608
  const dropped = [];
2560
2609
  let why = null;
2610
+ let changed = false;
2561
2611
  forEachCell(cellsOf(x), (r, c, v) => {
2562
2612
  if (why) return;
2563
2613
  const at = cellThrough(sheetOf(x), change, r, c);
2564
2614
  if (!at) {
2565
2615
  dropped.push(cellRef(sheetOf(x), r, c));
2616
+ changed = true;
2566
2617
  return;
2567
2618
  }
2568
2619
  let e = v;
@@ -2573,14 +2624,19 @@ function cellsOverChange(x, change) {
2573
2624
  return;
2574
2625
  }
2575
2626
  e = res.entry;
2627
+ if (res.changed) changed = true;
2576
2628
  }
2629
+ if (at[0] !== r || at[1] !== c) changed = true;
2577
2630
  putCell(out, at[0], at[1], e);
2578
2631
  });
2579
2632
  if (why) return barrier2(why);
2580
- const params = { ...withRefSheets(x.params, refSheetsAfter(ctx.refSheets, change)), cellValue: out };
2633
+ const rsAfter = refSheetsAfter(ctx.refSheets, change);
2634
+ if (!changed && JSON.stringify(rsAfter ?? null) === JSON.stringify(ctx.refSheets ?? null)) return ok([x]);
2635
+ const params = { ...withRefSheets(x.params, rsAfter), cellValue: out };
2581
2636
  return ok(isEmptyMatrix(out) ? [] : [{ id: x.id, params }], [], dropped);
2582
2637
  }
2583
2638
  function rewritesOf(y, change) {
2639
+ if (!hasFormula(y)) return null;
2584
2640
  const ctx = formulaCtx(y);
2585
2641
  const out = {};
2586
2642
  let why = null;
@@ -2726,6 +2782,368 @@ function buildSize(template, values) {
2726
2782
  const value = uniform !== void 0 && [...values.values()].every((v) => v === uniform) ? uniform : Object.fromEntries(values);
2727
2783
  return { id: template.id, params: { ...p, ranges, [field]: value } };
2728
2784
  }
2785
+ var isNumfmt = (m) => m.id === ID.setNumfmt || m.id === ID.removeNumfmt;
2786
+ function nfParts(m) {
2787
+ if (m.id === ID.removeNumfmt) return [{ key: null, ranges: (m.params.ranges ?? []).map((r) => ({ ...r })) }];
2788
+ const values = m.params.values ?? {};
2789
+ return Object.keys(values).map((k) => ({ key: k, ranges: (values[k]?.ranges ?? []).map((r) => ({ ...r })) }));
2790
+ }
2791
+ function nfBuild(m, parts) {
2792
+ const keep = parts.filter((p) => p.ranges.length);
2793
+ if (!keep.length) return [];
2794
+ if (m.id === ID.removeNumfmt) return [{ id: m.id, params: { ...m.params, ranges: keep[0].ranges } }];
2795
+ const values = {};
2796
+ const refMap = {};
2797
+ const srcValues = m.params.values ?? {};
2798
+ const srcRef = m.params.refMap ?? {};
2799
+ for (const p of keep) {
2800
+ values[p.key] = { ...srcValues[p.key], ranges: p.ranges };
2801
+ refMap[p.key] = srcRef[p.key];
2802
+ }
2803
+ return [{ id: m.id, params: { ...m.params, values, refMap } }];
2804
+ }
2805
+ function nfValueAt(m, row, col) {
2806
+ for (const p of nfParts(m))
2807
+ if (p.ranges.some((r) => r.startRow <= row && row <= r.endRow && r.startColumn <= col && col <= r.endColumn)) {
2808
+ if (p.key === null) return null;
2809
+ const ref = (m.params.refMap ?? {})[p.key];
2810
+ return { pattern: ref?.pattern };
2811
+ }
2812
+ return void 0;
2813
+ }
2814
+ function spanThrough(op, lo, hi) {
2815
+ const pieces = [];
2816
+ if (op.kind === "insert") pieces.push([0, op.at - 1, 0], [op.at, Infinity, op.count]);
2817
+ else if (op.kind === "remove") pieces.push([0, op.start - 1, 0], [op.start + op.count, Infinity, -op.count]);
2818
+ else if (op.count <= 0 || op.to >= op.from && op.to <= op.from + op.count) pieces.push([0, Infinity, 0]);
2819
+ else if (op.to > op.from) {
2820
+ const n = op.count;
2821
+ 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]);
2822
+ } else {
2823
+ const n = op.count;
2824
+ 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]);
2825
+ }
2826
+ const out = [];
2827
+ for (const [a, b, d] of pieces) {
2828
+ const x0 = Math.max(a, lo);
2829
+ const x1 = Math.min(b, hi);
2830
+ if (x0 <= x1) out.push([x0 + d, x1 + d]);
2831
+ }
2832
+ out.sort((p, q) => p[0] - q[0]);
2833
+ const merged = [];
2834
+ for (const p of out) {
2835
+ const last = merged[merged.length - 1];
2836
+ if (last && last[1] + 1 >= p[0]) last[1] = Math.max(last[1], p[1]);
2837
+ else merged.push([p[0], p[1]]);
2838
+ }
2839
+ return merged;
2840
+ }
2841
+ function rectsThrough(st, rects) {
2842
+ const [a0, a1] = S(st.axis);
2843
+ const out = [];
2844
+ for (const r of rects) for (const [lo, hi] of spanThrough(st.op, r[a0], r[a1])) out.push({ ...r, [a0]: lo, [a1]: hi });
2845
+ return out;
2846
+ }
2847
+ function rectMinus(a, b) {
2848
+ if (a.startRow > b.endRow || b.startRow > a.endRow || a.startColumn > b.endColumn || b.startColumn > a.endColumn) return [a];
2849
+ const out = [];
2850
+ if (a.startRow < b.startRow) out.push({ ...a, endRow: b.startRow - 1 });
2851
+ if (a.endRow > b.endRow) out.push({ ...a, startRow: b.endRow + 1 });
2852
+ const r0 = Math.max(a.startRow, b.startRow);
2853
+ const r1 = Math.min(a.endRow, b.endRow);
2854
+ if (a.startColumn < b.startColumn) out.push({ ...a, startRow: r0, endRow: r1, endColumn: b.startColumn - 1 });
2855
+ if (a.endColumn > b.endColumn) out.push({ ...a, startRow: r0, endRow: r1, startColumn: b.endColumn + 1 });
2856
+ return out;
2857
+ }
2858
+ function rectsMinus(as, bs) {
2859
+ let cur = as;
2860
+ for (const b of bs) cur = cur.flatMap((a) => rectMinus(a, b));
2861
+ return cur;
2862
+ }
2863
+ function nWrites(m) {
2864
+ const out = [];
2865
+ forEachCell(cellsOf(m), (r, c, v) => {
2866
+ if (v === null || v.s === null || v.s && typeof v.s === "object" && "n" in v.s)
2867
+ out.push({ startRow: r, endRow: r, startColumn: c, endColumn: c });
2868
+ });
2869
+ return out;
2870
+ }
2871
+ function numfmtPair(x, y, side, sx, sy) {
2872
+ const nx = isNumfmt(x);
2873
+ const ny = isNumfmt(y);
2874
+ if (!nx && !ny) return null;
2875
+ if (nx && sy) return ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsThrough(sy, p.ranges) }))));
2876
+ if (ny && sx) return ok([x]);
2877
+ if (nx && ny) {
2878
+ if (side === "left") return ok([x]);
2879
+ const ys = nfParts(y).flatMap((p) => p.ranges);
2880
+ return ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) }))));
2881
+ }
2882
+ if (nx && y.id === ID.values) {
2883
+ if (side === "left") return ok([x]);
2884
+ const ys = nWrites(y);
2885
+ return ys.length ? ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) })))) : ok([x]);
2886
+ }
2887
+ if (ny && x.id === ID.values) {
2888
+ if (side === "left") return ok([x]);
2889
+ const out = {};
2890
+ const tail = {};
2891
+ let touched = false;
2892
+ forEachCell(cellsOf(x), (r, c, v) => {
2893
+ const n = nfValueAt(y, r, c);
2894
+ if (n === void 0) return putCell(out, r, c, v);
2895
+ if (v === null || v.s === null) {
2896
+ putCell(out, r, c, v);
2897
+ if (n) {
2898
+ putCell(tail, r, c, { s: { n } });
2899
+ touched = true;
2900
+ }
2901
+ return;
2902
+ }
2903
+ if (v.s && typeof v.s === "object" && "n" in v.s) {
2904
+ const { n: _drop, ...rest } = v.s;
2905
+ const e = { ...v };
2906
+ if (Object.keys(rest).length) e.s = rest;
2907
+ else delete e.s;
2908
+ touched = true;
2909
+ if (Object.keys(e).length) putCell(out, r, c, e);
2910
+ return;
2911
+ }
2912
+ putCell(out, r, c, v);
2913
+ });
2914
+ if (!touched) return ok([x]);
2915
+ const ops = [];
2916
+ if (!isEmptyMatrix(out)) ops.push(cellsMutation(x, out));
2917
+ if (!isEmptyMatrix(tail)) ops.push({ id: ID.values, params: { subUnitId: sheetOf(x), cellValue: tail } });
2918
+ return ok(ops);
2919
+ }
2920
+ return ok([x]);
2921
+ }
2922
+ var isCount = (m) => m.id === ID.rowCount || m.id === ID.colCount;
2923
+ var countAxis = (m) => m.id === ID.rowCount ? "row" : "col";
2924
+ var countKey = (m) => m.id === ID.rowCount ? "rowCount" : "columnCount";
2925
+ function countPair(x, y, sy) {
2926
+ if (!isCount(x)) return isCount(y) ? ok([x]) : null;
2927
+ const k = countKey(x);
2928
+ const v = Number(x.params[k]);
2929
+ if (sy) {
2930
+ if (sy.axis !== countAxis(x) || sy.op.kind === "move") return ok([x]);
2931
+ const d = sy.op.kind === "insert" ? sy.op.count : -sy.op.count;
2932
+ return ok([{ id: x.id, params: { ...x.params, [k]: Math.max(1, v + d) } }]);
2933
+ }
2934
+ if (isCount(y) && y.id === x.id) {
2935
+ const w = Number(y.params[k]);
2936
+ return ok([w > v ? { id: x.id, params: { ...x.params, [k]: w } } : x]);
2937
+ }
2938
+ return ok([x]);
2939
+ }
2940
+ var isSheetOp = (m) => m.id === ID.insertSheet || m.id === ID.removeSheet || m.id === ID.sheetOrder;
2941
+ var sheetIdOf = (m) => m.id === ID.insertSheet ? String(m.params.sheet?.id ?? "") : sheetOf(m);
2942
+ function sheetAxisOf(m) {
2943
+ const p = m.params;
2944
+ if (m.id === ID.insertSheet) return typeof p.index === "number" ? { kind: "insert", at: p.index, count: 1 } : null;
2945
+ if (m.id === ID.removeSheet) return typeof p.sheetIndex === "number" ? { kind: "remove", start: p.sheetIndex, count: 1 } : null;
2946
+ if (m.id === ID.sheetOrder) {
2947
+ const f = Number(p.fromOrder);
2948
+ const t = Number(p.toOrder);
2949
+ return { kind: "move", from: f, count: 1, to: t > f ? t + 1 : t };
2950
+ }
2951
+ return null;
2952
+ }
2953
+ function buildSheetOp(template, op) {
2954
+ if (op.kind === "insert") return { id: template.id, params: { ...template.params, index: op.at } };
2955
+ if (op.kind === "remove") return { id: template.id, params: { ...template.params, sheetIndex: op.start } };
2956
+ return { id: template.id, params: { ...template.params, fromOrder: op.from, toOrder: op.to > op.from ? op.to - 1 : op.to } };
2957
+ }
2958
+ function namesSheet(m, id) {
2959
+ const rs = refSheetsOf(m);
2960
+ return !!rs && Object.values(rs).includes(id) && (m.id === ID.setName || hasFormula(m));
2961
+ }
2962
+ function sheetPair(x, y, side) {
2963
+ const xs = isSheetOp(x);
2964
+ const ys = isSheetOp(y);
2965
+ if (!xs && !ys) return null;
2966
+ if (xs && ys) {
2967
+ const a = sheetAxisOf(x);
2968
+ const b = sheetAxisOf(y);
2969
+ if (!a || !b) return barrier2("a sheet add or remove without its index (capture must call annotateSheetOps)");
2970
+ if (x.id === ID.insertSheet && y.id === ID.insertSheet && sheetIdOf(x) === sheetIdOf(y)) {
2971
+ return JSON.stringify(x.params) === JSON.stringify(y.params) ? ok([]) : barrier2("the same sheet id added twice with different content");
2972
+ }
2973
+ if (x.id === ID.removeSheet && typeof x.params.sheetsLeft === "number" && sheetIdOf(x) !== sheetIdOf(y) && (y.id === ID.removeSheet || y.id === ID.insertSheet)) {
2974
+ const left = x.params.sheetsLeft + (y.id === ID.insertSheet ? 1 : -1);
2975
+ if (left < 1) return barrier2("concurrent sheet removes would leave the workbook without a sheet");
2976
+ const out2 = transformAxis(a, b, side);
2977
+ if (!out2) return barrier2("sheet order: no transform");
2978
+ return ok(out2.map((o) => buildSheetOp({ id: x.id, params: { ...x.params, sheetsLeft: left } }, o)));
2979
+ }
2980
+ const out = transformAxis(a, b, side);
2981
+ if (!out) return barrier2("sheet order: no transform");
2982
+ return ok(out.map((o) => buildSheetOp(x, o)), [], out.length === 0 && x.id === ID.sheetOrder ? [`${sheetIdOf(x)}: sheet order`] : []);
2983
+ }
2984
+ if (ys) {
2985
+ if (y.id !== ID.removeSheet) return ok([x]);
2986
+ const gone2 = sheetOf(y);
2987
+ if (namesSheet(x, gone2)) return barrier2("a formula names a sheet removed at the same time");
2988
+ if (sheetOf(x) === gone2 && x.id !== ID.setName && x.id !== ID.removeName)
2989
+ return ok([], [], isDerived(x) ? [] : [`${gone2}: the sheet was removed`]);
2990
+ return ok([x]);
2991
+ }
2992
+ if (x.id !== ID.removeSheet) return ok([x]);
2993
+ const gone = sheetOf(x);
2994
+ if (namesSheet(y, gone)) return barrier2("a formula names a sheet removed at the same time");
2995
+ return ok([x], sheetOf(y) === gone && !isDerived(y) && y.id !== ID.setName && y.id !== ID.removeName ? [`${gone}: the sheet was removed`] : []);
2996
+ }
2997
+ function annotateSheetOps(group, sheetOrder) {
2998
+ const order = [...sheetOrder];
2999
+ return group.map((m) => {
3000
+ if (m.id === ID.insertSheet) {
3001
+ const index = typeof m.params.index === "number" ? Math.min(m.params.index, order.length) : order.length;
3002
+ order.splice(index, 0, sheetIdOf(m));
3003
+ return index === m.params.index ? m : { id: m.id, params: { ...m.params, index } };
3004
+ }
3005
+ if (m.id === ID.removeSheet) {
3006
+ const i = order.indexOf(sheetOf(m));
3007
+ if (i >= 0) order.splice(i, 1);
3008
+ return i >= 0 ? { id: m.id, params: { ...m.params, sheetIndex: i, sheetsLeft: order.length } } : m;
3009
+ }
3010
+ if (m.id === ID.sheetOrder) {
3011
+ const f = Number(m.params.fromOrder);
3012
+ const [id] = order.splice(f, 1);
3013
+ order.splice(Number(m.params.toOrder), 0, id ?? sheetOf(m));
3014
+ }
3015
+ return m;
3016
+ });
3017
+ }
3018
+ function inlineSheetStyles(sheet, styleOf) {
3019
+ const out = JSON.parse(JSON.stringify(sheet));
3020
+ const fix = (o) => {
3021
+ if (o && typeof o.s === "string") {
3022
+ const st = styleOf(o.s);
3023
+ if (st) o.s = JSON.parse(JSON.stringify(st));
3024
+ }
3025
+ };
3026
+ for (const row of Object.values(out.cellData ?? {})) for (const cell of Object.values(row ?? {})) fix(cell);
3027
+ for (const key of ["rowData", "columnData"]) for (const v of Object.values(out[key] ?? {})) fix(v);
3028
+ if (typeof out.defaultStyle === "string") {
3029
+ const st = styleOf(out.defaultStyle);
3030
+ if (st) out.defaultStyle = JSON.parse(JSON.stringify(st));
3031
+ }
3032
+ return out;
3033
+ }
3034
+ var isSort = (m) => m.id === ID.sort;
3035
+ function sortOf(m) {
3036
+ const P = /* @__PURE__ */ new Map();
3037
+ for (const [t, src] of Object.entries(m.params.order ?? {})) P.set(Number(t), Number(src));
3038
+ return { range: { ...m.params.range }, P };
3039
+ }
3040
+ var sortQ = (o) => new Map([...o.P].map(([t, s0]) => [s0, t]));
3041
+ function buildSort(template, o) {
3042
+ const order = {};
3043
+ for (const [t, s0] of [...o.P].sort((a, b) => a[0] - b[0])) if (t !== s0) order[t] = s0;
3044
+ if (!Object.keys(order).length || o.range.startRow > o.range.endRow || o.range.startColumn > o.range.endColumn) return [];
3045
+ return [{ id: template.id, params: { ...template.params, range: o.range, order } }];
3046
+ }
3047
+ var inSortCols = (o, c) => c >= o.range.startColumn && c <= o.range.endColumn;
3048
+ function sortThrough(o, st) {
3049
+ const r = o.range;
3050
+ if (st.axis === "col") {
3051
+ if (st.op.kind === "move") {
3052
+ const { from, count, to } = st.op;
3053
+ const touches = !(from + count - 1 < r.startColumn || from > r.endColumn) || to > r.startColumn && to <= r.endColumn;
3054
+ if (touches) return null;
3055
+ const spans3 = spanThrough(st.op, r.startColumn, r.endColumn);
3056
+ return spans3.length === 1 ? { range: { ...r, startColumn: spans3[0][0], endColumn: spans3[0][1] }, P: o.P } : null;
3057
+ }
3058
+ const spans2 = spanThrough(st.op, r.startColumn, r.endColumn);
3059
+ if (!spans2.length) return { range: { ...r, startColumn: 1, endColumn: 0 }, P: /* @__PURE__ */ new Map() };
3060
+ return { range: { ...r, startColumn: spans2[0][0], endColumn: spans2[spans2.length - 1][1] }, P: o.P };
3061
+ }
3062
+ const op = st.op;
3063
+ if (op.kind === "move") {
3064
+ const touches = !(op.from + op.count - 1 < r.startRow || op.from > r.endRow) || op.to > r.startRow && op.to <= r.endRow;
3065
+ if (touches) return null;
3066
+ }
3067
+ if (op.kind === "insert" || op.kind === "move") {
3068
+ const P2 = /* @__PURE__ */ new Map();
3069
+ for (const [t, s0] of o.P) P2.set(mapIndex(op, t), mapIndex(op, s0));
3070
+ const spans2 = spanThrough(op, r.startRow, r.endRow);
3071
+ return { range: { ...r, startRow: spans2[0][0], endRow: spans2[spans2.length - 1][1] }, P: P2 };
3072
+ }
3073
+ const removed = (i) => i >= op.start && i < op.start + op.count;
3074
+ const Q = sortQ(o);
3075
+ const goneTargets = [];
3076
+ for (let i = op.start; i < op.start + op.count; i++) goneTargets.push(Q.get(i) ?? i);
3077
+ goneTargets.sort((a, b) => a - b);
3078
+ const compact = (t) => t - goneTargets.filter((g) => g < t).length;
3079
+ const P = /* @__PURE__ */ new Map();
3080
+ for (const [t, s0] of o.P) if (!removed(s0)) P.set(compact(t), mapIndex(op, s0));
3081
+ const spans = spanThrough(op, r.startRow, r.endRow);
3082
+ if (!spans.length) return { range: { ...r, startRow: 1, endRow: 0 }, P: /* @__PURE__ */ new Map() };
3083
+ return { range: { ...r, startRow: spans[0][0], endRow: spans[spans.length - 1][1] }, P };
3084
+ }
3085
+ function sortPair(x, y, sx, sy) {
3086
+ const xs = isSort(x);
3087
+ const ys = isSort(y);
3088
+ if (!xs && !ys) return null;
3089
+ if (xs && ys) {
3090
+ const a = sortOf(x).range;
3091
+ const b = sortOf(y).range;
3092
+ const overlap = a.startRow <= b.endRow && b.startRow <= a.endRow && a.startColumn <= b.endColumn && b.startColumn <= a.endColumn;
3093
+ return overlap ? barrier2("two sorts of overlapping ranges at once") : ok([x]);
3094
+ }
3095
+ if (xs) {
3096
+ if (sy) {
3097
+ const t = sortThrough(sortOf(x), sy);
3098
+ return t ? ok(buildSort(x, t)) : barrier2("a row or column move through a sorted range");
3099
+ }
3100
+ return ok([x]);
3101
+ }
3102
+ const o = sortOf(y);
3103
+ const Q = sortQ(o);
3104
+ const moved = (r) => r >= o.range.startRow && r <= o.range.endRow && Q.has(r);
3105
+ if (sx) {
3106
+ if (sx.axis === "col") return sx.op.kind === "move" && !sortThrough(o, sx) ? barrier2("a column move through a sorted range") : ok([x]);
3107
+ if (sx.op.kind === "insert") return ok([x]);
3108
+ if (sx.op.kind === "move") return sortThrough(o, sx) ? ok([x]) : barrier2("a row move through a sorted range");
3109
+ const rows = [];
3110
+ let partial = false;
3111
+ for (let i = sx.op.start; i < sx.op.start + sx.op.count; i++) {
3112
+ if (moved(i)) partial = true;
3113
+ rows.push(Q.get(i) ?? i);
3114
+ }
3115
+ if (partial) return barrier2("a row remove against a concurrent sort of those rows");
3116
+ return ok([x]);
3117
+ }
3118
+ if (x.id === ID.values) {
3119
+ const out = {};
3120
+ let changed = false;
3121
+ forEachCell(cellsOf(x), (r, c, v) => {
3122
+ if (inSortCols(o, c) && moved(r)) {
3123
+ putCell(out, Q.get(r), c, v);
3124
+ changed = true;
3125
+ } else putCell(out, r, c, v);
3126
+ });
3127
+ return changed ? ok([cellsMutation(x, out)]) : ok([x]);
3128
+ }
3129
+ if (isNumfmt(x)) {
3130
+ const parts = nfParts(x).map((p) => {
3131
+ const ranges = [];
3132
+ for (const rc of p.ranges) {
3133
+ 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) };
3134
+ if (inner.startRow > inner.endRow || inner.startColumn > inner.endColumn) {
3135
+ ranges.push(rc);
3136
+ continue;
3137
+ }
3138
+ ranges.push(...rectMinus(rc, inner));
3139
+ for (let r = inner.startRow; r <= inner.endRow; r++) ranges.push({ ...inner, startRow: Q.get(r) ?? r, endRow: Q.get(r) ?? r });
3140
+ }
3141
+ return { ...p, ranges };
3142
+ });
3143
+ return ok(nfBuild(x, parts));
3144
+ }
3145
+ return ok([x]);
3146
+ }
2729
3147
  function familyOf(id) {
2730
3148
  const e = SHEET_MUTATIONS[id];
2731
3149
  return e && e.kind === "covered" ? e.family : "";
@@ -2742,6 +3160,8 @@ function transformMutation(x, y, side) {
2742
3160
  }
2743
3161
  const pb = PAIR_BARRIERS[pairKey(x.id, y.id)];
2744
3162
  if (pb) return barrier2(`${x.id} \xD7 ${y.id}: ${pb.reason}${pb.seed === null ? "" : ` (fuzz seed ${pb.seed})`}`);
3163
+ const sp = sheetPair(x, y, side);
3164
+ if (sp) return sp;
2745
3165
  const fp = formulaPair(x, y, side);
2746
3166
  if (fp) return fp;
2747
3167
  if (sheetOf(x) !== sheetOf(y)) return ok([x]);
@@ -2749,6 +3169,12 @@ function transformMutation(x, y, side) {
2749
3169
  const fy = familyOf(y.id);
2750
3170
  const sy = structuralOf(y);
2751
3171
  const sx = structuralOf(x);
3172
+ const sortp = sortPair(x, y, sx, sy);
3173
+ if (sortp) return sortp;
3174
+ const cp = countPair(x, y, sy);
3175
+ if (cp) return cp;
3176
+ const np = numfmtPair(x, y, side, sx, sy);
3177
+ if (np) return np;
2752
3178
  if (sx && sy) {
2753
3179
  if (sx.axis !== sy.axis) return ok([x]);
2754
3180
  const out = transformAxis(sx.op, sy.op, side);
@@ -2856,22 +3282,45 @@ function tSeq(xs, ys, side, acc) {
2856
3282
  acc.dropped.push(...a.dropped);
2857
3283
  return [a.op, b.op];
2858
3284
  }
3285
+ const outX = [];
3286
+ let curY = ys;
3287
+ for (const x of xs) {
3288
+ let curX = [x];
3289
+ const nextY = [];
3290
+ for (const y of curY) {
3291
+ if (curX.length === 0) {
3292
+ nextY.push(y);
3293
+ continue;
3294
+ }
3295
+ const r = tSeq(curX, [y], side, acc);
3296
+ if (blocked(r)) return r;
3297
+ curX = r[0];
3298
+ for (const m of r[1]) nextY.push(m);
3299
+ }
3300
+ for (const m of curX) outX.push(m);
3301
+ curY = nextY;
3302
+ }
3303
+ return [outX, curY];
3304
+ }
3305
+ function tSeqOld(xs, ys, side, acc) {
3306
+ if (xs.length === 0 || ys.length === 0) return [xs, ys];
3307
+ if (xs.length === 1 && ys.length === 1) return tSeq(xs, ys, side, acc);
2859
3308
  if (xs.length > 1) {
2860
- const first2 = tSeq([xs[0]], ys, side, acc);
3309
+ const first2 = tSeqOld([xs[0]], ys, side, acc);
2861
3310
  if (blocked(first2)) return first2;
2862
- const rest2 = tSeq(xs.slice(1), first2[1], side, acc);
3311
+ const rest2 = tSeqOld(xs.slice(1), first2[1], side, acc);
2863
3312
  if (blocked(rest2)) return rest2;
2864
3313
  return [[...first2[0], ...rest2[0]], rest2[1]];
2865
3314
  }
2866
- const first = tSeq(xs, [ys[0]], side, acc);
3315
+ const first = tSeqOld(xs, [ys[0]], side, acc);
2867
3316
  if (blocked(first)) return first;
2868
- const rest = tSeq(first[0], ys.slice(1), side, acc);
3317
+ const rest = tSeqOld(first[0], ys.slice(1), side, acc);
2869
3318
  if (blocked(rest)) return rest;
2870
3319
  return [rest[0], [...first[1], ...rest[1]]];
2871
3320
  }
2872
3321
  function transformGroup(x, y, side) {
2873
3322
  const acc = { lost: [], dropped: [] };
2874
- const r = tSeq([...x], [...y], side, acc);
3323
+ const r = (process.env.OLD_TSEQ ? tSeqOld : tSeq)([...x], [...y], side, acc);
2875
3324
  if (blocked(r)) return r;
2876
3325
  return { op: r[0], lost: [...new Set(acc.lost)], dropped: [...new Set(acc.dropped)] };
2877
3326
  }
@@ -2941,7 +3390,7 @@ async function sheetsStateHash(snapshot) {
2941
3390
  }
2942
3391
 
2943
3392
  // src/univer/collab/sheets-ot/room.ts
2944
- var SHEETS_COLLAB_PROTO = 1;
3393
+ var SHEETS_COLLAB_PROTO = 2;
2945
3394
  var SHEETS_EDIT_GROUP = "sheets.edit";
2946
3395
  var flip2 = (side) => side === "left" ? "right" : "left";
2947
3396
  var isNoopSheetOp = (op) => op == null || op.length === 0;
@@ -2988,6 +3437,11 @@ function travelingShape(m) {
2988
3437
  }
2989
3438
  return { id: m.id, params };
2990
3439
  }
3440
+ var shapedLists = /* @__PURE__ */ new WeakMap();
3441
+ function cachedShape(list) {
3442
+ const hit = shapedLists.get(list);
3443
+ return hit && hit.src.length === list.length && hit.src.every((m, i) => m === list[i]) ? hit.shaped : null;
3444
+ }
2991
3445
  function rebaseSheetUndoStack(items, remote, unitId) {
2992
3446
  if (isNoopSheetOp(remote)) return 0;
2993
3447
  let dropped = 0;
@@ -2999,7 +3453,11 @@ function rebaseSheetUndoStack(items, remote, unitId) {
2999
3453
  if (!ok2 || !list?.length) continue;
3000
3454
  const isOperation = (id) => !SHEET_MUTATIONS[id] && id.includes(".operation.");
3001
3455
  const operations = list.filter((m) => isOperation(m.id));
3002
- const shaped = list.filter((m) => !isOperation(m.id)).map(travelingShape);
3456
+ let shaped = cachedShape(list);
3457
+ if (!shaped) {
3458
+ shaped = list.filter((m) => !isOperation(m.id)).map(travelingShape);
3459
+ shapedLists.set(list, { src: list.slice(), shaped });
3460
+ }
3003
3461
  if (shaped.some((m) => m === null)) {
3004
3462
  ok2 = false;
3005
3463
  continue;
@@ -3011,8 +3469,10 @@ function rebaseSheetUndoStack(items, remote, unitId) {
3011
3469
  ok2 = false;
3012
3470
  continue;
3013
3471
  }
3014
- if (JSON.stringify(r.op) === JSON.stringify(shaped)) continue;
3015
- item[key] = [...r.op.map((m) => ({ id: m.id, params: { ...forApply(m).params, unitId } })), ...operations];
3472
+ if (r.op.length === shaped.length && r.op.every((m, i2) => m === shaped[i2])) continue;
3473
+ const next = [...r.op.map((m) => ({ id: m.id, params: { ...forApply(m).params, unitId } })), ...operations];
3474
+ shapedLists.set(next, { src: next.slice(), shaped: r.op });
3475
+ item[key] = next;
3016
3476
  } catch {
3017
3477
  ok2 = false;
3018
3478
  }
@@ -3087,7 +3547,7 @@ function createSheetsOtAdapter(port, hooks = {}) {
3087
3547
  });
3088
3548
  });
3089
3549
  }
3090
- return sheetsStateHash(port.snapshot());
3550
+ return (hooks.stateHash ?? sheetsStateHash)(port.snapshot());
3091
3551
  },
3092
3552
  held: () => queue.length,
3093
3553
  rebaseLocalOverHeld(local) {
@@ -3199,6 +3659,8 @@ var VALUES = "sheet.mutation.set-range-values";
3199
3659
  var ADD_MERGE = "sheet.mutation.add-worksheet-merge";
3200
3660
  var REMOVE_MERGE = "sheet.mutation.remove-worksheet-merge";
3201
3661
  var SHEET_NAME = "sheet.mutation.set-worksheet-name";
3662
+ var INSERT_SHEET = "sheet.mutation.insert-sheet";
3663
+ var RESHAPE = /* @__PURE__ */ new Set(["sheet.mutation.set-worksheet-row-count", "sheet.mutation.set-worksheet-column-count", "sheet.mutation.remove-sheet", INSERT_SHEET]);
3202
3664
  var DEPTH_GUARD = /* @__PURE__ */ Symbol.for("ai-matrx.office.sheets.command-depth-guard");
3203
3665
  var json = (v) => v === void 0 ? v : JSON.parse(JSON.stringify(v));
3204
3666
  var flagged = (options) => {
@@ -3235,7 +3697,8 @@ function univerSheetsOtPort(o) {
3235
3697
  for (const [id, d] of Object.entries(map)) out[id] = String(d?.name ?? "");
3236
3698
  return out;
3237
3699
  };
3238
- const openGroup = (label) => ({ label, sheets: sheetNames(), names: definedNames(), mutations: [], inverses: [], notShared: null });
3700
+ const sheetOrder = () => (o.workbook()?.getSheets() ?? []).map((ws) => ws.getSheetId());
3701
+ const openGroup = (label) => ({ label, order: sheetOrder(), sheets: sheetNames(), names: definedNames(), mutations: [], inverses: [], notShared: null });
3239
3702
  const emit = (e) => {
3240
3703
  for (const l of [...listeners]) {
3241
3704
  try {
@@ -3251,7 +3714,8 @@ function univerSheetsOtPort(o) {
3251
3714
  if (!g) return;
3252
3715
  if (g.notShared) emit({ kind: "not_shared", mutationId: g.notShared, label: g.label });
3253
3716
  else if (g.mutations.length) {
3254
- const mutations = annotateFormulas(g.mutations, g.sheets, g.names);
3717
+ const mutations = annotateSheetOps(annotateFormulas(g.mutations, g.sheets, g.names), g.order);
3718
+ if (mutations.some((m) => isStructuralMutation(m) || RESHAPE.has(m.id))) clampSelection();
3255
3719
  const known = g.inverses.every((i) => i !== void 0);
3256
3720
  const inverse = known ? annotateFormulas(g.inverses.slice().reverse().flat(), g.sheets, g.names) : void 0;
3257
3721
  emit({ kind: "group", mutations, ...inverse !== void 0 ? { inverse } : {}, label: g.label });
@@ -3285,7 +3749,27 @@ function univerSheetsOtPort(o) {
3285
3749
  }
3286
3750
  if (info.id === SHEET_NAME) record.name = ws.getName();
3287
3751
  pre.set(p, record);
3752
+ const owed = isStructuralMutation({ id: info.id, params: p }) ? mergeFixupsOwed({ id: info.id, params: p }, record.merges ?? []) : null;
3753
+ if (owed) {
3754
+ runOwn(REMOVE_MERGE, String(p.subUnitId), owed.remove, ADD_MERGE);
3755
+ if (owed.add.length) record.addAfter = owed.add;
3756
+ }
3288
3757
  });
3758
+ const runOwn = (id, sheet, ranges, inverseId) => {
3759
+ const u = unitId();
3760
+ if (!u) return;
3761
+ applying = true;
3762
+ try {
3763
+ cs.syncExecuteCommand(id, { unitId: u, subUnitId: sheet, ranges: json(ranges) }, { onlyLocal: true });
3764
+ } finally {
3765
+ applying = false;
3766
+ }
3767
+ if (!group) group = openGroup(null);
3768
+ if (!group.notShared) {
3769
+ group.mutations.push({ id, params: { subUnitId: sheet, ranges: json(ranges) } });
3770
+ group.inverses.push([{ id: inverseId, params: { subUnitId: sheet, ranges: json(ranges) } }]);
3771
+ }
3772
+ };
3289
3773
  const after = cs.onCommandExecuted((info) => {
3290
3774
  if (info.type !== COMMAND) return;
3291
3775
  const at = tracker.stack.lastIndexOf(info.id);
@@ -3383,6 +3867,8 @@ function univerSheetsOtPort(o) {
3383
3867
  if (!m2) return { m: null, inverse: void 0 };
3384
3868
  return { m: m2, inverse: [{ id: ADD_MERGE, params: { subUnitId: sheet, ranges: json(m2.params.ranges) } }] };
3385
3869
  }
3870
+ if (info.id === INSERT_SHEET && params.sheet && typeof params.sheet === "object")
3871
+ params.sheet = inlineSheetStyles(params.sheet, (id) => o.workbook()?.getStyles().get(id));
3386
3872
  const m = { id: info.id, params };
3387
3873
  switch (info.id) {
3388
3874
  case "sheet.mutation.insert-row":
@@ -3391,6 +3877,11 @@ function univerSheetsOtPort(o) {
3391
3877
  return { m, inverse: [{ id: "sheet.mutation.remove-col", params: { subUnitId: sheet, range: json(params.range) } }] };
3392
3878
  case ADD_MERGE:
3393
3879
  return { m, inverse: [{ id: REMOVE_MERGE, params: { subUnitId: sheet, ranges: json(params.ranges) } }] };
3880
+ case "sheet.mutation.reorder-range": {
3881
+ const order = {};
3882
+ for (const [t, src] of Object.entries(params.order ?? {})) order[String(src)] = Number(t);
3883
+ return { m, inverse: [{ id: info.id, params: { subUnitId: sheet, range: json(params.range), order } }] };
3884
+ }
3394
3885
  case SHEET_NAME:
3395
3886
  return { m, inverse: before2.name !== void 0 ? [{ id: SHEET_NAME, params: { subUnitId: sheet, name: before2.name } }] : void 0 };
3396
3887
  default:
@@ -3399,8 +3890,7 @@ function univerSheetsOtPort(o) {
3399
3890
  };
3400
3891
  const collab = cs.onMutationExecutedForCollab((info, options) => {
3401
3892
  if (applying || flagged(options) || !mine(info.params)) return;
3402
- const lone = !group;
3403
- if (lone) group = openGroup(null);
3893
+ if (!group) group = openGroup(null);
3404
3894
  const g = group;
3405
3895
  if (!g.notShared) {
3406
3896
  const r = capture(info);
@@ -3410,11 +3900,29 @@ function univerSheetsOtPort(o) {
3410
3900
  g.inverses.push(r.inverse);
3411
3901
  }
3412
3902
  }
3413
- if (lone && tracker.stack.length === 0) settle();
3903
+ const owedAdd = pre.get(info.params)?.addAfter;
3904
+ if (owedAdd?.length) runOwn(ADD_MERGE, String(info.params.subUnitId ?? ""), owedAdd, REMOVE_MERGE);
3905
+ if (tracker.stack.length === 0) settle();
3414
3906
  });
3907
+ const clampSelection = () => {
3908
+ const sel = o.selections;
3909
+ if (!sel) return;
3910
+ try {
3911
+ const sheet = sel.sheetId();
3912
+ const ws = sheet ? o.workbook()?.getSheetBySheetId(sheet) : null;
3913
+ const current = sel.get();
3914
+ if (!ws || !current?.length) return;
3915
+ const rows = ws.getMaxRows?.() ?? Number.MAX_SAFE_INTEGER;
3916
+ const cols = ws.getMaxColumns?.() ?? Number.MAX_SAFE_INTEGER;
3917
+ const next = moveSelectionsThrough(json(current), { id: "", params: {} }, rows, cols);
3918
+ if (JSON.stringify(next) !== JSON.stringify(current)) sel.set(next);
3919
+ } catch (err) {
3920
+ console.warn("[sheets-ot] could not keep this seat's selection inside the sheet after its own row or column change", err);
3921
+ }
3922
+ };
3415
3923
  const followSelection = (m) => {
3416
3924
  const sel = o.selections;
3417
- if (!sel || !axisOpOf(m)) return;
3925
+ if (!sel || !axisOpOf(m) && !RESHAPE.has(m.id)) return;
3418
3926
  try {
3419
3927
  const sheet = String(m.params.subUnitId ?? "");
3420
3928
  if (sel.sheetId() !== sheet) return;