@ai-matrx/office 0.8.16 → 0.8.18

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.
@@ -41,6 +41,7 @@ __export(collab_exports, {
41
41
  SHEETS_EDIT_GROUP: () => SHEETS_EDIT_GROUP,
42
42
  WorkbookCollabSession: () => WorkbookCollabSession,
43
43
  applyDocsOp: () => applyDocsOp,
44
+ asLoadedDocsSnapshot: () => asLoadedDocsSnapshot,
44
45
  canonicalDocsSnapshot: () => canonicalDocsSnapshot,
45
46
  canonicalDocsString: () => canonicalDocsString,
46
47
  canonicalKeys: () => canonicalKeys,
@@ -57,6 +58,7 @@ __export(collab_exports, {
57
58
  invertDocsOp: () => invertDocsOp,
58
59
  isCellEditorScratch: () => isCellEditorScratch,
59
60
  isNoopDocsOp: () => isNoopDocsOp,
61
+ moveSelectionsThrough: () => moveSelectionsThrough,
60
62
  normalizeDocsOp: () => normalizeDocsOp,
61
63
  openDocsOtRoom: () => openDocsOtRoom,
62
64
  openSheetsOtRoom: () => openSheetsOtRoom,
@@ -948,6 +950,104 @@ function invertDocsOp(op, preDoc) {
948
950
  }
949
951
  var DOCS_TRANSFORM_VERSION = "univer-1.0.4+docs-ot-r6";
950
952
 
953
+ // src/univer/collab/docs-ot/state-hash.ts
954
+ var import_core4 = require("@univerjs/core");
955
+
956
+ // src/docs/sanitize-univer-doc-snapshot.ts
957
+ var import_core2 = require("@univerjs/core");
958
+
959
+ // src/core/document-page-style.ts
960
+ var TRADITIONAL = 1;
961
+ var PORTRAIT = 0;
962
+ var PX_PER_INCH = 96;
963
+ var DEFAULT_DOCUMENT_PAGE_STYLE = {
964
+ pageSize: { width: 816, height: 1056 },
965
+ documentFlavor: TRADITIONAL,
966
+ pageOrient: PORTRAIT,
967
+ marginTop: PX_PER_INCH,
968
+ marginBottom: PX_PER_INCH,
969
+ marginLeft: PX_PER_INCH,
970
+ marginRight: PX_PER_INCH,
971
+ // Univer applies no paragraph spacing to a paginated page by itself; without this every paragraph
972
+ // runs into the next (Google Docs' own default: 1.15 lines, 10px after).
973
+ defaultParagraphStyle: { spaceAbove: { v: 0 }, spaceBelow: { v: 10 }, lineSpacing: 1.15 }
974
+ };
975
+ function defaultDocumentPageStyle() {
976
+ return {
977
+ ...DEFAULT_DOCUMENT_PAGE_STYLE,
978
+ pageSize: { ...DEFAULT_DOCUMENT_PAGE_STYLE.pageSize },
979
+ defaultParagraphStyle: { ...DEFAULT_DOCUMENT_PAGE_STYLE.defaultParagraphStyle }
980
+ };
981
+ }
982
+ function isLegacySqueezedPageStyle(style) {
983
+ const size = style?.pageSize;
984
+ return !!size && size.width === 595 && size.height === 842 && style?.marginLeft === 90 && style?.marginRight === 90 && style?.marginTop === 72 && style?.marginBottom === 72;
985
+ }
986
+ var PAGE_COLORS = ["#ffffff", "#fff8e7", "#f3f3f3", "#e8f0fe", "#e6f4ea", "#fef7e0"];
987
+ var DEFAULT_PAGE_COLOR = PAGE_COLORS[0];
988
+
989
+ // src/docs/sanitize-univer-doc-snapshot.ts
990
+ var NAMED_STYLE_STRING_TO_NUMBER = Object.fromEntries(
991
+ Object.entries(import_core2.NamedStyleType).filter(([key, val]) => typeof val === "number" && isNaN(Number(key))).map(([key, val]) => [key, val])
992
+ );
993
+ function sanitizeUniverDocSnapshot(snapshot, docId, opts = {}) {
994
+ restorePageStyle(snapshot, docId, opts.quiet === true);
995
+ ensureTextRuns(snapshot);
996
+ const paragraphs = snapshot?.body?.paragraphs;
997
+ if (!Array.isArray(paragraphs)) return snapshot;
998
+ let fixed = 0;
999
+ for (const paragraph of paragraphs) {
1000
+ const style = paragraph?.paragraphStyle;
1001
+ const value = style?.namedStyleType;
1002
+ if (typeof value === "string") {
1003
+ const numeric = NAMED_STYLE_STRING_TO_NUMBER[value];
1004
+ if (numeric !== void 0) {
1005
+ style.namedStyleType = numeric;
1006
+ fixed += 1;
1007
+ } else {
1008
+ delete style.namedStyleType;
1009
+ fixed += 1;
1010
+ }
1011
+ }
1012
+ }
1013
+ if (fixed > 0 && opts.quiet !== true) {
1014
+ console.warn(
1015
+ `[data-tables] RECOVERY: sanitized ${fixed} string namedStyleType value(s) to numeric NamedStyleType in document snapshot${docId ? ` ${docId}` : ""}. The snapshot was written with the wrong enum encoding (string instead of number) and would have crashed Univer's <ParagraphMenu>. Fix the snapshot writer to emit numeric NamedStyleType values.`
1016
+ );
1017
+ }
1018
+ return snapshot;
1019
+ }
1020
+ function restorePageStyle(snapshot, docId, quiet = false) {
1021
+ if (!snapshot || typeof snapshot !== "object") return;
1022
+ const style = snapshot.documentStyle;
1023
+ if (style?.pageSize?.width && isLegacySqueezedPageStyle(style)) {
1024
+ const page = defaultDocumentPageStyle();
1025
+ snapshot.documentStyle = { ...style, ...page, defaultParagraphStyle: style.defaultParagraphStyle ?? page.defaultParagraphStyle };
1026
+ return;
1027
+ }
1028
+ if (style?.pageSize?.width) {
1029
+ if (!style.documentFlavor) {
1030
+ const page = defaultDocumentPageStyle();
1031
+ Object.assign(style, { documentFlavor: page.documentFlavor });
1032
+ if (page.defaultParagraphStyle) style.defaultParagraphStyle ??= page.defaultParagraphStyle;
1033
+ }
1034
+ return;
1035
+ }
1036
+ snapshot.documentStyle = {
1037
+ ...defaultDocumentPageStyle(),
1038
+ ...snapshot.documentStyle ?? {},
1039
+ pageSize: defaultDocumentPageStyle().pageSize
1040
+ };
1041
+ if (quiet) return;
1042
+ console.warn(
1043
+ `[data-tables] RECOVERY: document snapshot${docId ? ` ${docId}` : ""} had no documentStyle.pageSize \u2014 restored the default Letter page geometry. Without a page box Univer lays the body out unbounded: text does not wrap and the viewport has no scrollable extent, so the document appears frozen. Fix the snapshot writer (agent/markdown converters must stamp DEFAULT_DOCUMENT_PAGE_STYLE).`
1044
+ );
1045
+ }
1046
+ function ensureTextRuns(snapshot) {
1047
+ const body = snapshot?.body;
1048
+ if (body && typeof body === "object" && !Array.isArray(body.textRuns)) body.textRuns = [];
1049
+ }
1050
+
951
1051
  // src/univer/collab/docs-ot/state-hash.ts
952
1052
  var DOC_LOCAL_KEYS = ["rev", "__matrxCollabCovered", "__collab", "disabled", "layoutState", "textRanges", "selections"];
953
1053
  function sortDeep(v) {
@@ -1007,6 +1107,7 @@ function canonicalBody(body) {
1007
1107
  const b = { ...body };
1008
1108
  b.textRuns = canonicalRuns(b.textRuns);
1009
1109
  if (Array.isArray(b.paragraphs)) b.paragraphs = b.paragraphs.map(({ paragraphId: _p, ...p }) => p);
1110
+ if (Array.isArray(b.sectionBreaks)) b.sectionBreaks = b.sectionBreaks.map(({ sectionId: _s, ...x }) => x);
1010
1111
  b.customRanges = foldPieces(b.customRanges, (r) => JSON.stringify([rootId(r.rangeId), r.rangeType, sortDeep(r.properties ?? {})])).map((r) => ({
1011
1112
  ...r,
1012
1113
  rangeId: rootId(r.rangeId)
@@ -1021,8 +1122,20 @@ function canonicalBody(body) {
1021
1122
  }
1022
1123
  return b;
1023
1124
  }
1125
+ function asLoadedDocsSnapshot(snapshot) {
1126
+ const s = stampDeterministicIds(structuredClone(snapshot ?? {}));
1127
+ delete s.id;
1128
+ for (const k of DOC_LOCAL_KEYS) delete s[k];
1129
+ sanitizeUniverDocSnapshot(s, void 0, { quiet: true });
1130
+ const model = new import_core4.DocumentDataModel(s);
1131
+ try {
1132
+ return structuredClone(model.getSnapshot());
1133
+ } finally {
1134
+ model.dispose();
1135
+ }
1136
+ }
1024
1137
  function canonicalDocsSnapshot(snapshot) {
1025
- const s = structuredClone(snapshot ?? {});
1138
+ const s = asLoadedDocsSnapshot(snapshot);
1026
1139
  delete s.id;
1027
1140
  for (const k of DOC_LOCAL_KEYS) delete s[k];
1028
1141
  s.body = canonicalBody(s.body);
@@ -1231,7 +1344,10 @@ function openDocsOtRoom(o) {
1231
1344
  queue = next.filter((q) => !isNoopDocsOp(q));
1232
1345
  if (isNoopDocsOp(op)) return;
1233
1346
  }
1234
- if (!session.local(op, { ...inverse !== void 0 ? { inverse } : {}, label: m.cmd ?? RICH_TEXT_EDITING })) notice({ kind: "not_live" });
1347
+ if (!session.local(op, { ...inverse !== void 0 ? { inverse } : {}, label: m.cmd ?? RICH_TEXT_EDITING })) {
1348
+ notice({ kind: "not_live" });
1349
+ session.rebuild("not_live");
1350
+ }
1235
1351
  };
1236
1352
  const unsubLocal = port.onLocal(onLocal);
1237
1353
  const target = o.compositionTarget === void 0 ? typeof document !== "undefined" ? document : null : o.compositionTarget;
@@ -1293,7 +1409,7 @@ var import_awareness2 = require("y-protocols/awareness");
1293
1409
  var import_collab3 = require("@ai-matrx/data/realtime/collab");
1294
1410
 
1295
1411
  // src/docs/remote-carets.ts
1296
- var import_core2 = require("@univerjs/core");
1412
+ var import_core5 = require("@univerjs/core");
1297
1413
  var CARET_HEARTBEAT_MS = 2e3;
1298
1414
  var CARET_STALE_MS = 12e3;
1299
1415
  var CARET_MAX_RANGES = 4;
@@ -1311,8 +1427,8 @@ function movePeerRangesThroughBodyEdit(ranges, actions) {
1311
1427
  const e = sub.e;
1312
1428
  return ranges.map((r) => {
1313
1429
  const collapsed = r.start === r.end;
1314
- const start = import_core2.TextX.transformPosition(e, r.start, false);
1315
- return { start, end: collapsed ? start : import_core2.TextX.transformPosition(e, r.end, true) };
1430
+ const start = import_core5.TextX.transformPosition(e, r.start, false);
1431
+ return { start, end: collapsed ? start : import_core5.TextX.transformPosition(e, r.end, true) };
1316
1432
  });
1317
1433
  }
1318
1434
  var sameRanges = (a, b) => a.length === b.length && a.every((r, i) => r.start === b[i].start && r.end === b[i].end);
@@ -1450,15 +1566,6 @@ async function documentUsesOrderedRoom(documentId, knob, isNewDocument) {
1450
1566
  if (knob === "new") return isNewDocument();
1451
1567
  return false;
1452
1568
  }
1453
- function pickColor2(uid) {
1454
- const palette = ["#ef4444", "#f59e0b", "#10b981", "#3b82f6", "#8b5cf6", "#ec4899", "#14b8a6", "#f97316"];
1455
- let h = 2166136261;
1456
- for (let i = 0; i < uid.length; i++) {
1457
- h ^= uid.charCodeAt(i);
1458
- h = Math.imul(h, 16777619);
1459
- }
1460
- return palette[Math.abs(h) % palette.length] ?? "#ec4899";
1461
- }
1462
1569
  function documentOtFactory(o) {
1463
1570
  return async (basePort, onAwareness) => {
1464
1571
  const latest = await getLatestDocumentSnapshot(o.documentId);
@@ -1472,7 +1579,8 @@ function documentOtFactory(o) {
1472
1579
  }
1473
1580
  const doc = new Y2.Doc();
1474
1581
  const awareness = new import_awareness2.Awareness(doc);
1475
- awareness.setLocalState({ uid: o.uid, clientId: o.clientId, name: o.displayName ?? o.uid.slice(0, 8), color: pickColor2(o.uid), ts: Date.now() });
1582
+ awareness.setLocalState({ uid: o.uid, clientId: o.clientId, name: o.displayName ?? o.uid.slice(0, 8), ts: Date.now() });
1583
+ const stopColor = (0, import_collab3.claimCollaboratorColor)(awareness, { uid: o.uid, clientId: o.clientId });
1476
1584
  const carets = new RemoteCaretBook(awareness.clientID);
1477
1585
  const emit = () => onAwareness({ states: new Map(awareness.getStates()), selfUid: o.uid, carets: carets.list() });
1478
1586
  const publishAwareness = () => {
@@ -1558,6 +1666,7 @@ function documentOtFactory(o) {
1558
1666
  replace: (snapshot) => room.replace(snapshot),
1559
1667
  stop: () => {
1560
1668
  clearInterval(caretTimer);
1669
+ stopColor();
1561
1670
  room.stop();
1562
1671
  awareness.off("change", publishAwareness);
1563
1672
  provider.disconnect();
@@ -1879,7 +1988,7 @@ function transformAxis(x, y, side) {
1879
1988
  }
1880
1989
 
1881
1990
  // src/collab/sheets/transform/formula.ts
1882
- var import_core3 = require("@univerjs/core");
1991
+ var import_core6 = require("@univerjs/core");
1883
1992
  var import_engine_formula = require("@univerjs/engine-formula");
1884
1993
  var import_sheets = require("@univerjs/sheets");
1885
1994
  var REF_ERROR = "#REF!";
@@ -1931,8 +2040,8 @@ function referencedSheetNames(text) {
1931
2040
  }
1932
2041
  return [...out];
1933
2042
  }
1934
- var fullRowsRange = (start, count) => ({ startRow: start, endRow: start + count - 1, startColumn: 0, endColumn: FULL, rangeType: import_core3.RANGE_TYPE.ROW });
1935
- var fullColsRange = (start, count) => ({ startRow: 0, endRow: FULL, startColumn: start, endColumn: start + count - 1, rangeType: import_core3.RANGE_TYPE.COLUMN });
2043
+ var fullRowsRange = (start, count) => ({ startRow: start, endRow: start + count - 1, startColumn: 0, endColumn: FULL, rangeType: import_core6.RANGE_TYPE.ROW });
2044
+ var fullColsRange = (start, count) => ({ startRow: 0, endRow: FULL, startColumn: start, endColumn: start + count - 1, rangeType: import_core6.RANGE_TYPE.COLUMN });
1936
2045
  var startV = (v) => Number.isNaN(v) || v == null ? -Infinity : v;
1937
2046
  var endV = (v) => Number.isNaN(v) || v == null ? Infinity : v;
1938
2047
  function startEnd(r) {
@@ -1941,9 +2050,9 @@ function startEnd(r) {
1941
2050
  function checkMoveEdge(origin, from) {
1942
2051
  const startRow = startV(origin.startRow), endRow = endV(origin.endRow), startColumn = startV(origin.startColumn), endColumn = endV(origin.endColumn);
1943
2052
  const fromStartRow = startV(from.startRow), fromEndRow = endV(from.endRow), fromStartColumn = startV(from.startColumn), fromEndColumn = endV(from.endColumn);
1944
- const rowsCover = () => origin.rangeType === import_core3.RANGE_TYPE.COLUMN && from.rangeType === import_core3.RANGE_TYPE.COLUMN || startRow >= fromStartRow && endRow <= fromEndRow;
1945
- const columnsCover = () => origin.rangeType === import_core3.RANGE_TYPE.ROW && from.rangeType === import_core3.RANGE_TYPE.ROW || startColumn >= fromStartColumn && endColumn <= fromEndColumn;
1946
- const allCover = () => origin.rangeType === import_core3.RANGE_TYPE.ALL && from.rangeType === import_core3.RANGE_TYPE.ALL;
2053
+ const rowsCover = () => origin.rangeType === import_core6.RANGE_TYPE.COLUMN && from.rangeType === import_core6.RANGE_TYPE.COLUMN || startRow >= fromStartRow && endRow <= fromEndRow;
2054
+ const columnsCover = () => origin.rangeType === import_core6.RANGE_TYPE.ROW && from.rangeType === import_core6.RANGE_TYPE.ROW || startColumn >= fromStartColumn && endColumn <= fromEndColumn;
2055
+ const allCover = () => origin.rangeType === import_core6.RANGE_TYPE.ALL && from.rangeType === import_core6.RANGE_TYPE.ALL;
1947
2056
  if (rowsCover() && columnsCover() || allCover()) return 4;
1948
2057
  if (columnsCover() && startRow >= fromStartRow && startRow <= fromEndRow && endRow > fromEndRow) return 0;
1949
2058
  if (columnsCover() && endRow >= fromStartRow && endRow <= fromEndRow && startRow < fromStartRow) return 1;
@@ -1954,14 +2063,14 @@ function checkMoveEdge(origin, from) {
1954
2063
  function getMoveNewRange(moveEdge, result, from, to, origin, remain) {
1955
2064
  const { startRow, endRow, startColumn, endColumn, rangeType } = startEnd(result);
1956
2065
  const f = startEnd(from);
1957
- const fromRangeType = from.rangeType ?? import_core3.RANGE_TYPE.NORMAL;
2066
+ const fromRangeType = from.rangeType ?? import_core6.RANGE_TYPE.NORMAL;
1958
2067
  const t = startEnd(to);
1959
2068
  const rm = startEnd(remain);
1960
2069
  const o = startEnd(origin);
1961
- const originRangeType = origin.rangeType ?? import_core3.RANGE_TYPE.NORMAL;
2070
+ const originRangeType = origin.rangeType ?? import_core6.RANGE_TYPE.NORMAL;
1962
2071
  const newRange = { ...origin };
1963
- const rowsCover = () => rangeType === import_core3.RANGE_TYPE.COLUMN && originRangeType === import_core3.RANGE_TYPE.COLUMN || startColumn >= o.startColumn && endColumn <= o.endColumn;
1964
- const columnsCover = () => rangeType === import_core3.RANGE_TYPE.ROW && originRangeType === import_core3.RANGE_TYPE.ROW || startRow >= o.startRow && endRow <= o.endRow;
2072
+ const rowsCover = () => rangeType === import_core6.RANGE_TYPE.COLUMN && originRangeType === import_core6.RANGE_TYPE.COLUMN || startColumn >= o.startColumn && endColumn <= o.endColumn;
2073
+ const columnsCover = () => rangeType === import_core6.RANGE_TYPE.ROW && originRangeType === import_core6.RANGE_TYPE.ROW || startRow >= o.startRow && endRow <= o.endRow;
1965
2074
  if (moveEdge === 0) {
1966
2075
  if (!rowsCover()) return void 0;
1967
2076
  if (startRow < o.startRow) newRange.startRow = startRow;
@@ -1984,7 +2093,7 @@ function getMoveNewRange(moveEdge, result, from, to, origin, remain) {
1984
2093
  else return void 0;
1985
2094
  } else if (moveEdge === 4) {
1986
2095
  Object.assign(newRange, { startRow, startColumn, endRow, endColumn });
1987
- } else if (f.startColumn <= o.startColumn && f.endColumn >= o.endColumn || fromRangeType === import_core3.RANGE_TYPE.ROW && originRangeType === import_core3.RANGE_TYPE.ROW) {
2096
+ } else if (f.startColumn <= o.startColumn && f.endColumn >= o.endColumn || fromRangeType === import_core6.RANGE_TYPE.ROW && originRangeType === import_core6.RANGE_TYPE.ROW) {
1988
2097
  const n = f.endRow - f.startRow + 1;
1989
2098
  if (from.endRow < o.startRow) {
1990
2099
  if (t.startRow >= o.startRow) newRange.startRow -= n;
@@ -1996,7 +2105,7 @@ function getMoveNewRange(moveEdge, result, from, to, origin, remain) {
1996
2105
  if (t.startRow <= o.startRow) newRange.startRow += n;
1997
2106
  else if (t.startRow >= o.endRow) newRange.endRow -= n;
1998
2107
  }
1999
- } else if (f.startRow <= o.startRow && f.endRow >= o.endRow || fromRangeType === import_core3.RANGE_TYPE.COLUMN && originRangeType === import_core3.RANGE_TYPE.COLUMN) {
2108
+ } else if (f.startRow <= o.startRow && f.endRow >= o.endRow || fromRangeType === import_core6.RANGE_TYPE.COLUMN && originRangeType === import_core6.RANGE_TYPE.COLUMN) {
2000
2109
  const n = f.endColumn - f.startColumn + 1;
2001
2110
  if (from.endColumn < o.startColumn) {
2002
2111
  if (t.startColumn >= o.startColumn) newRange.startColumn -= n;
@@ -2018,7 +2127,7 @@ function moveRange(range, axis, op) {
2018
2127
  const isRow = axis === "row";
2019
2128
  if (op.kind === "insert") {
2020
2129
  const r = isRow ? fullRowsRange(op.at, op.count) : fullColsRange(op.at, op.count);
2021
- const ops2 = isRow ? (0, import_sheets.handleInsertRow)({ id: import_sheets.EffectRefRangId.InsertRowCommandId, params: { range: r, unitId: "", subUnitId: "", direction: import_core3.Direction.DOWN } }, range) : (0, import_sheets.handleInsertCol)({ id: import_sheets.EffectRefRangId.InsertColCommandId, params: { range: r, unitId: "", subUnitId: "", direction: import_core3.Direction.RIGHT } }, range);
2130
+ const ops2 = isRow ? (0, import_sheets.handleInsertRow)({ id: import_sheets.EffectRefRangId.InsertRowCommandId, params: { range: r, unitId: "", subUnitId: "", direction: import_core6.Direction.DOWN } }, range) : (0, import_sheets.handleInsertCol)({ id: import_sheets.EffectRefRangId.InsertColCommandId, params: { range: r, unitId: "", subUnitId: "", direction: import_core6.Direction.RIGHT } }, range);
2022
2131
  const res2 = (0, import_sheets.runRefRangeMutations)(ops2, range);
2023
2132
  return res2 == null ? void 0 : { ...range, ...res2 };
2024
2133
  }
@@ -2031,11 +2140,11 @@ function moveRange(range, axis, op) {
2031
2140
  const from = isRow ? fullRowsRange(op.from, op.count) : fullColsRange(op.from, op.count);
2032
2141
  const to = isRow ? fullRowsRange(op.to, op.count) : fullColsRange(op.to, op.count);
2033
2142
  const moveEdge = checkMoveEdge(range, from);
2034
- let remain = (0, import_core3.getIntersectRange)(range, from);
2143
+ let remain = (0, import_core6.getIntersectRange)(range, from);
2035
2144
  if (isRow) {
2036
2145
  if (remain == null && (from.endRow < range.startRow && to.endRow <= range.startRow || from.startRow > range.endRow && to.startRow > range.endRow)) return void 0;
2037
2146
  } else if (remain == null && (from.endColumn < range.startColumn && to.endColumn <= range.startColumn || from.startColumn > range.endColumn && to.startColumn > range.endColumn)) return void 0;
2038
- remain ??= { startRow: range.startRow, endRow: range.endRow, startColumn: range.startColumn, endColumn: range.endColumn, rangeType: import_core3.RANGE_TYPE.NORMAL };
2147
+ remain ??= { startRow: range.startRow, endRow: range.endRow, startColumn: range.startColumn, endColumn: range.endColumn, rangeType: import_core6.RANGE_TYPE.NORMAL };
2039
2148
  const ops = isRow ? (0, import_sheets.handleMoveRows)({ id: import_sheets.EffectRefRangId.MoveRowsCommandId, params: { toRange: to, fromRange: from } }, remain) : (0, import_sheets.handleMoveCols)({ id: import_sheets.EffectRefRangId.MoveColsCommandId, params: { toRange: to, fromRange: from } }, remain);
2040
2149
  const res = (0, import_sheets.runRefRangeMutations)(ops, remain);
2041
2150
  if (res == null) return REF_ERROR;
@@ -2066,7 +2175,7 @@ function rewriteFormula(text, ctx, change) {
2066
2175
  if (!sheetName) continue;
2067
2176
  token = (0, import_engine_formula.serializeRangeToRefString)({ range, sheetName: change.name, unitId });
2068
2177
  } else {
2069
- const moved = moveRange(import_core3.Rectangle.moveOffset(range, 0, 0), change.axis, change.op);
2178
+ const moved = moveRange(import_core6.Rectangle.moveOffset(range, 0, 0), change.axis, change.op);
2070
2179
  if (moved === void 0) continue;
2071
2180
  token = moved === REF_ERROR ? REF_ERROR : (0, import_engine_formula.serializeRangeToRefString)({ range: moved, sheetName: target === ctx.ownSheet && !ctx.keepQualifier ? "" : sheetName, unitId });
2072
2181
  }
@@ -3303,12 +3412,30 @@ function univerSheetsOtPort(o) {
3303
3412
  }
3304
3413
  if (lone && tracker.stack.length === 0) settle();
3305
3414
  });
3415
+ const followSelection = (m) => {
3416
+ const sel = o.selections;
3417
+ if (!sel || !axisOpOf(m)) return;
3418
+ try {
3419
+ const sheet = String(m.params.subUnitId ?? "");
3420
+ if (sel.sheetId() !== sheet) return;
3421
+ const ws = o.workbook()?.getSheetBySheetId(sheet);
3422
+ const current = sel.get();
3423
+ if (!ws || !current?.length) return;
3424
+ const rows = ws.getMaxRows?.() ?? Number.MAX_SAFE_INTEGER;
3425
+ const cols = ws.getMaxColumns?.() ?? Number.MAX_SAFE_INTEGER;
3426
+ sel.set(moveSelectionsThrough(json(current), m, rows, cols));
3427
+ } catch (err) {
3428
+ console.warn("[sheets-ot] could not move this seat's selection past a collaborator's row or column change", err);
3429
+ }
3430
+ };
3306
3431
  return {
3307
3432
  onLocal(listener) {
3308
3433
  listeners.add(listener);
3309
3434
  return () => void listeners.delete(listener);
3310
3435
  },
3311
3436
  busy: () => tracker.stack.length > 0 || group !== null,
3437
+ /** The outermost commands still running here (why the port is busy), for logs. */
3438
+ running: () => [...tracker.stack, ...group && tracker.stack.length === 0 ? ["(group)"] : []],
3312
3439
  whenIdle(fn) {
3313
3440
  if (tracker.stack.length === 0 && !group) fn();
3314
3441
  else idle.push(fn);
@@ -3319,11 +3446,12 @@ function univerSheetsOtPort(o) {
3319
3446
  const a = forApply(m);
3320
3447
  applying = true;
3321
3448
  try {
3322
- const ok2 = cs.syncExecuteCommand(a.id, { ...json(a.params), unitId: u }, { onlyLocal: true, fromCollab: true });
3449
+ const ok2 = cs.syncExecuteCommand(a.id, { ...json(a.params), unitId: u }, { fromCollab: true });
3323
3450
  if (ok2 === false) throw new Error(`"${m.id}" was refused by the editor`);
3324
3451
  } finally {
3325
3452
  applying = false;
3326
3453
  }
3454
+ followSelection(m);
3327
3455
  },
3328
3456
  snapshot() {
3329
3457
  const wb = o.workbook();
@@ -3361,6 +3489,68 @@ function fullContent(cell) {
3361
3489
  if (out.v === null) delete out.t;
3362
3490
  return out;
3363
3491
  }
3492
+ function axisOpOf(m) {
3493
+ const p = m.params;
3494
+ const span = (r, axis) => axis === "row" ? [r.startRow, r.endRow - r.startRow + 1] : [r.startColumn, r.endColumn - r.startColumn + 1];
3495
+ switch (m.id) {
3496
+ case "sheet.mutation.insert-row": {
3497
+ const [at, count] = span(p.range, "row");
3498
+ return { axis: "row", op: { kind: "insert", at, count } };
3499
+ }
3500
+ case "sheet.mutation.insert-col": {
3501
+ const [at, count] = span(p.range, "col");
3502
+ return { axis: "col", op: { kind: "insert", at, count } };
3503
+ }
3504
+ case "sheet.mutation.remove-rows": {
3505
+ const [start, count] = span(p.range, "row");
3506
+ return { axis: "row", op: { kind: "remove", start, count } };
3507
+ }
3508
+ case "sheet.mutation.remove-col": {
3509
+ const [start, count] = span(p.range, "col");
3510
+ return { axis: "col", op: { kind: "remove", start, count } };
3511
+ }
3512
+ case "sheet.mutation.move-rows": {
3513
+ const [from, count] = span(p.sourceRange, "row");
3514
+ return { axis: "row", op: { kind: "move", from, count, to: p.targetRange.startRow } };
3515
+ }
3516
+ case "sheet.mutation.move-columns": {
3517
+ const [from, count] = span(p.sourceRange, "col");
3518
+ return { axis: "col", op: { kind: "move", from, count, to: p.targetRange.startColumn } };
3519
+ }
3520
+ default:
3521
+ return null;
3522
+ }
3523
+ }
3524
+ function moveSelectionsThrough(selections, m, maxRows, maxCols) {
3525
+ const a = axisOpOf(m);
3526
+ const clamp = (v, max) => Math.max(0, Math.min(v, Math.max(0, max - 1)));
3527
+ const through = (i, axis) => {
3528
+ if (typeof i !== "number") return i;
3529
+ let next = i;
3530
+ if (a && a.axis === axis) {
3531
+ const mapped = mapIndex(a.op, i);
3532
+ next = mapped ?? (a.op.kind === "remove" ? a.op.start : i);
3533
+ }
3534
+ return clamp(next, axis === "row" ? maxRows : maxCols);
3535
+ };
3536
+ const box = (r, rangeType) => {
3537
+ const out = { ...r };
3538
+ for (const k of ["startRow", "endRow", "actualRow"]) if (k in out) out[k] = through(out[k], "row");
3539
+ for (const k of ["startColumn", "endColumn", "actualColumn"]) if (k in out) out[k] = through(out[k], "col");
3540
+ if (typeof out.startRow === "number" && typeof out.endRow === "number" && out.endRow < out.startRow) out.endRow = out.startRow;
3541
+ if (typeof out.startColumn === "number" && typeof out.endColumn === "number" && out.endColumn < out.startColumn) out.endColumn = out.startColumn;
3542
+ if (rangeType === 1 || rangeType === 3) {
3543
+ out.startColumn = 0;
3544
+ out.endColumn = Math.max(0, maxCols - 1);
3545
+ }
3546
+ if (rangeType === 2 || rangeType === 3) {
3547
+ out.startRow = 0;
3548
+ out.endRow = Math.max(0, maxRows - 1);
3549
+ }
3550
+ return out;
3551
+ };
3552
+ return selections.map((s) => ({ ...s, range: box(s.range, s.range.rangeType), ...s.primary ? { primary: box(s.primary) } : {} }));
3553
+ }
3364
3554
 
3365
3555
  // src/sheets/workbook-ot-room.ts
3366
3556
  var Y3 = __toESM(require("yjs"), 1);
@@ -3430,7 +3620,7 @@ async function workbookUsesOrderedRoom(workbookId, knob, isNewWorkbook) {
3430
3620
  if (knob === "new") return isNewWorkbook();
3431
3621
  return false;
3432
3622
  }
3433
- function pickColor3(uid) {
3623
+ function pickColor2(uid) {
3434
3624
  const palette = ["#ef4444", "#f59e0b", "#10b981", "#3b82f6", "#8b5cf6", "#ec4899", "#14b8a6", "#f97316"];
3435
3625
  let h = 2166136261;
3436
3626
  for (let i = 0; i < uid.length; i++) {
@@ -3455,7 +3645,7 @@ async function startWorkbookOtRoom(port, o) {
3455
3645
  uid: o.uid,
3456
3646
  clientId: o.clientId,
3457
3647
  name: o.displayName ?? o.uid.slice(0, 8),
3458
- color: pickColor3(o.uid),
3648
+ color: pickColor2(o.uid),
3459
3649
  sheetId: null,
3460
3650
  row: null,
3461
3651
  col: null,