@ai-matrx/office 0.8.43 → 0.8.45

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.
@@ -1165,26 +1165,77 @@ function rebaseUndoStack(items, remote, stack) {
1165
1165
  const first = stack === "undo" ? "undoMutations" : "redoMutations";
1166
1166
  const second = stack === "undo" ? "redoMutations" : "undoMutations";
1167
1167
  let dropped = 0;
1168
- for (let i = items.length - 1; i >= 0; i--) {
1168
+ let R = remote;
1169
+ for (let i = items.length - 1; i >= 0 && !isNoopDocsOp(R); i--) {
1169
1170
  const item = items[i];
1170
1171
  try {
1171
- const a = threadThrough(item[first], remote);
1172
+ const a = threadThrough(item[first], R);
1172
1173
  const b = threadThrough(item[second], a.after);
1173
1174
  if (a.next) item[first] = a.next;
1174
1175
  if (b.next) item[second] = b.next;
1176
+ R = a.after;
1175
1177
  } catch {
1176
1178
  items.splice(i, 1);
1177
1179
  dropped++;
1180
+ R = carryPast(item[first], R);
1178
1181
  }
1179
1182
  }
1180
1183
  return dropped;
1181
1184
  }
1185
+ function carryPast(list, remote) {
1186
+ let R = remote;
1187
+ for (const m of list ?? []) {
1188
+ if (m.id !== RICH_TEXT_EDITING || isNoopDocsOp(R)) continue;
1189
+ const own = m.params.actions;
1190
+ if (touchesPageSetup(own) && touchesPageSetup(R)) continue;
1191
+ R = transformDocsOp(R, own, "right").op;
1192
+ }
1193
+ return R;
1194
+ }
1195
+ var UNDO_COMMAND = "univer.command.undo";
1196
+ var REDO_COMMAND = "univer.command.redo";
1182
1197
  function openDocsOtRoom(o) {
1183
1198
  const { port } = o;
1184
1199
  let session = null;
1185
1200
  let composing = false;
1186
1201
  let queue = [];
1187
1202
  const drainWaiters = [];
1203
+ let replay = null;
1204
+ const noteHistoryStep = (m, inverse) => {
1205
+ const side = m.cmd === UNDO_COMMAND ? "undo" : m.cmd === REDO_COMMAND ? "redo" : null;
1206
+ if (!side) {
1207
+ replay = null;
1208
+ return;
1209
+ }
1210
+ for (const t of port.undoTargets()) {
1211
+ const stacks = undoStacksOf(t.service);
1212
+ const stack = stacks ? (side === "undo" ? stacks.undo : stacks.redo).get(t.unitId) : void 0;
1213
+ const item = stack?.[stack.length - 1];
1214
+ const list = item ? side === "undo" ? item.undoMutations : item.redoMutations : void 0;
1215
+ const k = list ? list.findIndex((x) => x.params === m.params) : -1;
1216
+ if (!item || !list || k < 0) continue;
1217
+ if (k === 0 || !replay || replay.item !== item || replay.side !== side) {
1218
+ const other = (side === "undo" ? item.redoMutations : item.undoMutations)?.[0]?.params ?? {};
1219
+ const { textRanges: _t, layoutState: _l, actions: _a, ...template } = other;
1220
+ replay = { item, side, inverses: [], template };
1221
+ }
1222
+ if (inverse === void 0 || list.some((x) => x.id !== RICH_TEXT_EDITING)) {
1223
+ replay = null;
1224
+ return;
1225
+ }
1226
+ replay.inverses.unshift(inverse);
1227
+ if (k === list.length - 1) {
1228
+ const rewritten = replay.inverses.filter((op) => !isNoopDocsOp(op)).map((op) => ({ id: RICH_TEXT_EDITING, params: { ...replay.template, segmentId: m.params?.segmentId ?? "", actions: op } }));
1229
+ if (rewritten.length) {
1230
+ if (side === "undo") item.redoMutations = rewritten;
1231
+ else item.undoMutations = rewritten;
1232
+ }
1233
+ replay = null;
1234
+ }
1235
+ return;
1236
+ }
1237
+ replay = null;
1238
+ };
1188
1239
  const notice = (n) => {
1189
1240
  try {
1190
1241
  o.onNotice?.(n);
@@ -1282,7 +1333,10 @@ function openDocsOtRoom(o) {
1282
1333
  }
1283
1334
  const p = m.params ?? {};
1284
1335
  const applied = p.actions ?? null;
1285
- if (isNoopDocsOp(applied)) return;
1336
+ if (isNoopDocsOp(applied)) {
1337
+ noteHistoryStep(m, null);
1338
+ return;
1339
+ }
1286
1340
  let op = normalizeDocsOp(structuredClone(applied));
1287
1341
  let inverse;
1288
1342
  try {
@@ -1290,6 +1344,7 @@ function openDocsOtRoom(o) {
1290
1344
  } catch {
1291
1345
  inverse = void 0;
1292
1346
  }
1347
+ noteHistoryStep(m, inverse === void 0 ? void 0 : normalizeDocsOp(inverse));
1293
1348
  if (queue.length) {
1294
1349
  inverse = void 0;
1295
1350
  const next = [];
@@ -1567,7 +1622,7 @@ function documentOtFactory(o) {
1567
1622
  }
1568
1623
  const doc = new Y2.Doc();
1569
1624
  const awareness = new Awareness2(doc);
1570
- awareness.setLocalState({ uid: o.uid, clientId: o.clientId, name: o.displayName ?? o.uid.slice(0, 8), ts: Date.now() });
1625
+ awareness.setLocalState({ uid: o.uid, clientId: o.clientId, name: o.displayName || "Someone", ...o.avatarUrl ? { avatarUrl: o.avatarUrl } : {}, ts: Date.now() });
1571
1626
  const stopColor = claimCollaboratorColor2(awareness, { uid: o.uid, clientId: o.clientId });
1572
1627
  const carets = new RemoteCaretBook(awareness.clientID);
1573
1628
  const emit = () => onAwareness({ states: new Map(awareness.getStates()), selfUid: o.uid, carets: carets.list() });
@@ -2781,6 +2836,18 @@ function transformCell(X, Y4, side) {
2781
2836
  if (styleKeys(xs).length !== styleKeys(kept ?? {}).length) xLost = true;
2782
2837
  }
2783
2838
  }
2839
+ if (hasContent(X) && hasContent(Y4)) {
2840
+ const has = (s) => !!s && typeof s === "object" && "n" in s;
2841
+ const outS = out.s;
2842
+ if (side === "left" && !has(X.s) && has(Y4.s) && X.s !== null) {
2843
+ out.s = { ...outS && typeof outS === "object" ? outS : {}, n: null };
2844
+ } else if (side === "right" && outS && typeof outS === "object" && "n" in outS) {
2845
+ const rest = withoutStyleKeys(outS, /* @__PURE__ */ new Set(["n"]));
2846
+ if (rest) out.s = rest;
2847
+ else delete out.s;
2848
+ xLost = true;
2849
+ }
2850
+ }
2784
2851
  return { entries: Object.keys(out).length ? [out, ...tail] : tail, xLost, yLost };
2785
2852
  }
2786
2853
  function transformCellsOverCells(x, y, side) {
@@ -3941,7 +4008,7 @@ function createSheetsOtAdapter(port, hooks = {}) {
3941
4008
  decode: decodeSheetOp,
3942
4009
  apply(op) {
3943
4010
  if (isNoopSheetOp(op)) return true;
3944
- if (port.busy() || queue.length) {
4011
+ if (port.busy() || queue.length || port.defers?.(op)) {
3945
4012
  queue.push(op);
3946
4013
  if (!draining) {
3947
4014
  draining = true;
@@ -3974,9 +4041,9 @@ function createSheetsOtAdapter(port, hooks = {}) {
3974
4041
  async hash() {
3975
4042
  if (port.busy() || queue.length) {
3976
4043
  await new Promise((resolve) => {
3977
- const done = setTimeout(resolve, 5e3);
4044
+ const done = queue.length ? null : setTimeout(resolve, 5e3);
3978
4045
  port.whenIdle(() => {
3979
- clearTimeout(done);
4046
+ if (done) clearTimeout(done);
3980
4047
  setTimeout(resolve, 0);
3981
4048
  });
3982
4049
  });
@@ -4006,7 +4073,6 @@ function createSheetsOtAdapter(port, hooks = {}) {
4006
4073
  function openSheetsOtRoom(o) {
4007
4074
  const { port } = o;
4008
4075
  let session = null;
4009
- const adapter = createSheetsOtAdapter(port);
4010
4076
  const notice = (n) => {
4011
4077
  try {
4012
4078
  o.onNotice?.(n);
@@ -4014,6 +4080,29 @@ function openSheetsOtRoom(o) {
4014
4080
  console.warn("[sheets-ot] notice handler failed", err);
4015
4081
  }
4016
4082
  };
4083
+ const adapter = createSheetsOtAdapter(port);
4084
+ let healing = null;
4085
+ const HEALS = /* @__PURE__ */ new Set(["hash_mismatch", "save_hash_mismatch", "ack_mismatch"]);
4086
+ const screen = () => {
4087
+ try {
4088
+ const s = port.snapshot();
4089
+ return s ? canonicalSheetString(s) : null;
4090
+ } catch {
4091
+ return null;
4092
+ }
4093
+ };
4094
+ const onIncident = (i) => {
4095
+ if (HEALS.has(i.kind) && !healing) healing = { reason: i.kind, before: screen() };
4096
+ o.onIncident?.(i);
4097
+ };
4098
+ const onStatus = (st) => {
4099
+ if (st === "live" && healing) {
4100
+ const h = healing;
4101
+ healing = null;
4102
+ if (h.before !== null && screen() !== h.before) notice({ kind: "resynced", reason: h.reason });
4103
+ } else if (st === "read_only" || st === "closed") healing = null;
4104
+ o.onStatus?.(st);
4105
+ };
4017
4106
  const onLocal = (e) => {
4018
4107
  if (!session) return;
4019
4108
  if (e.kind === "not_shared") {
@@ -4054,8 +4143,8 @@ function openSheetsOtRoom(o) {
4054
4143
  clientId: o.clientId,
4055
4144
  ...o.presence ? { presence: o.presence } : {},
4056
4145
  onNotice: (n) => notice(n),
4057
- ...o.onIncident ? { onIncident: o.onIncident } : {},
4058
- ...o.onStatus ? { onStatus: o.onStatus } : {},
4146
+ onIncident,
4147
+ onStatus,
4059
4148
  ...o.offline ? { offline: o.offline } : {},
4060
4149
  ...o.onOffline ? { onOffline: o.onOffline } : {}
4061
4150
  });
@@ -4148,6 +4237,23 @@ function releaseUnitPluginState(cs, unitId, saved) {
4148
4237
  }
4149
4238
 
4150
4239
  // src/univer/collab/sheets-ot/univer-port.ts
4240
+ function filterServiceRange(service) {
4241
+ return (unitId, subUnitId) => {
4242
+ try {
4243
+ const r = service()?.getFilterModel(unitId, subUnitId)?.getRange();
4244
+ return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn, ...r.rangeType !== void 0 ? { rangeType: r.rangeType } : {} } : null;
4245
+ } catch {
4246
+ return null;
4247
+ }
4248
+ };
4249
+ }
4250
+ function editorBridgeCell(bridge) {
4251
+ return () => {
4252
+ if (!bridge.isVisible()?.visible) return null;
4253
+ const at = bridge.getEditLocation();
4254
+ return at ? { sheetId: at.sheetId, row: at.row, col: at.column } : null;
4255
+ };
4256
+ }
4151
4257
  var COMMAND = 0;
4152
4258
  var MUTATION = 2;
4153
4259
  var VALUES = "sheet.mutation.set-range-values";
@@ -4155,6 +4261,7 @@ var ADD_MERGE = "sheet.mutation.add-worksheet-merge";
4155
4261
  var REMOVE_MERGE = "sheet.mutation.remove-worksheet-merge";
4156
4262
  var SHEET_NAME = "sheet.mutation.set-worksheet-name";
4157
4263
  var INSERT_SHEET = "sheet.mutation.insert-sheet";
4264
+ var REMOVE_SHEET2 = "sheet.mutation.remove-sheet";
4158
4265
  var FILTER_RANGE = "sheet.mutation.set-filter-range";
4159
4266
  var RESHAPE = /* @__PURE__ */ new Set(["sheet.mutation.set-worksheet-row-count", "sheet.mutation.set-worksheet-column-count", "sheet.mutation.remove-sheet", INSERT_SHEET]);
4160
4267
  var UNDO = "univer.command.undo";
@@ -4174,6 +4281,18 @@ function univerSheetsOtPort(o) {
4174
4281
  const tracker = { stack: [], settle: () => settle() };
4175
4282
  let group = null;
4176
4283
  let applying = false;
4284
+ let editorHold = false;
4285
+ const edited = () => {
4286
+ try {
4287
+ return o.cellEditor?.() ?? null;
4288
+ } catch {
4289
+ return null;
4290
+ }
4291
+ };
4292
+ const holding = () => {
4293
+ if (editorHold && !edited()) editorHold = false;
4294
+ return editorHold;
4295
+ };
4177
4296
  const unitId = () => o.workbook()?.getUnitId() ?? null;
4178
4297
  const mine = (params) => {
4179
4298
  const u = unitId();
@@ -4202,7 +4321,7 @@ function univerSheetsOtPort(o) {
4202
4321
  if (!u || !o.filterRange) return null;
4203
4322
  try {
4204
4323
  const r = o.filterRange(u, sheet);
4205
- return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn } : null;
4324
+ return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn, ...r.rangeType !== void 0 ? { rangeType: r.rangeType } : {} } : null;
4206
4325
  } catch {
4207
4326
  return null;
4208
4327
  }
@@ -4218,10 +4337,45 @@ function univerSheetsOtPort(o) {
4218
4337
  }
4219
4338
  }
4220
4339
  };
4340
+ const sweepRemovedSheetRefs = (g) => {
4341
+ const removed = g.mutations.filter((m) => m.id === REMOVE_SHEET2).map((m) => String(m.params.subUnitId ?? ""));
4342
+ const wb = o.workbook();
4343
+ const u = unitId();
4344
+ if (!removed.length || !wb || !u) return;
4345
+ const refSheets = {};
4346
+ for (const [id, name] of Object.entries(g.sheets)) refSheets[name] = id;
4347
+ for (const gone of removed) {
4348
+ const name = g.sheets[gone];
4349
+ if (!name) continue;
4350
+ for (const ws of wb.getSheets()) {
4351
+ const sheet = ws.getSheetId();
4352
+ const cells = {};
4353
+ ws.getCellMatrix?.().forValue((r, c, cell) => {
4354
+ const f = cell?.f;
4355
+ if (typeof f !== "string" || !f.includes(name)) return;
4356
+ const out = rewriteFormula(f, { ownSheet: sheet, refSheets }, { kind: "remove-sheet", sheet: gone });
4357
+ if (typeof out !== "string" && out.changed) (cells[r] ??= {})[c] = { f: out.text, si: null };
4358
+ });
4359
+ if (!Object.keys(cells).length) continue;
4360
+ applying = true;
4361
+ try {
4362
+ cs.syncExecuteCommand(VALUES, { unitId: u, subUnitId: sheet, cellValue: json(cells) });
4363
+ } finally {
4364
+ applying = false;
4365
+ }
4366
+ const done = {};
4367
+ for (const r of Object.keys(cells))
4368
+ for (const c of Object.keys(cells[r])) (done[r] ??= {})[c] = completeCellContent(cells[r][c], json(ws.getCellRaw(Number(r), Number(c)) ?? null));
4369
+ g.mutations.push({ id: VALUES, params: { subUnitId: sheet, cellValue: done } });
4370
+ g.inverses.push(void 0);
4371
+ }
4372
+ }
4373
+ };
4221
4374
  const flush = () => {
4222
4375
  const g = group;
4223
4376
  group = null;
4224
4377
  if (!g) return;
4378
+ if (!g.notShared) sweepRemovedSheetRefs(g);
4225
4379
  if (g.notShared) emit({ kind: "not_shared", mutationId: g.notShared, label: g.label });
4226
4380
  else if (g.mutations.length) {
4227
4381
  const mutations = annotateSheetOps(annotateFormulas(g.mutations, g.sheets, g.names), g.order);
@@ -4233,7 +4387,7 @@ function univerSheetsOtPort(o) {
4233
4387
  };
4234
4388
  function settle() {
4235
4389
  if (tracker.stack.length === 0) flush();
4236
- if (tracker.stack.length === 0 && !group) for (const fn of idle.splice(0)) fn();
4390
+ if (tracker.stack.length === 0 && !group && !holding()) for (const fn of idle.splice(0)) fn();
4237
4391
  }
4238
4392
  const before = cs.beforeCommandExecuted((info, options) => {
4239
4393
  if (info.id === UNDO || info.id === REDO) for (const fn of [...undoWatchers]) fn();
@@ -4247,6 +4401,7 @@ function univerSheetsOtPort(o) {
4247
4401
  const ws = o.workbook()?.getSheetBySheetId(String(p.subUnitId ?? ""));
4248
4402
  if (!ws) return;
4249
4403
  const record = { merges: json(ws.getMergeData() ?? []) };
4404
+ if (!group) record.lone = openGroup(null);
4250
4405
  if (info.id === VALUES) {
4251
4406
  record.cells = /* @__PURE__ */ new Map();
4252
4407
  const cells = p.cellValue ?? {};
@@ -4283,6 +4438,7 @@ function univerSheetsOtPort(o) {
4283
4438
  }
4284
4439
  };
4285
4440
  const after = cs.onCommandExecuted((info) => {
4441
+ if (editorHold && tracker.stack.length === 0 && !group && !edited()) settle();
4286
4442
  if (info.type !== COMMAND) return;
4287
4443
  const at = tracker.stack.lastIndexOf(info.id);
4288
4444
  if (at >= 0) tracker.stack.splice(at, 1);
@@ -4364,7 +4520,7 @@ function univerSheetsOtPort(o) {
4364
4520
  else {
4365
4521
  inv = {};
4366
4522
  if (CONTENT_KEYS.some((k) => k !== "t" && k in done)) Object.assign(inv, fullContent(p));
4367
- if ("s" in done) inv.s = p?.s ?? null;
4523
+ if ("s" in done) inv.s = inverseStyle(p?.s, done.s);
4368
4524
  }
4369
4525
  (invCells[r] ??= {})[c] = inv;
4370
4526
  }
@@ -4402,7 +4558,7 @@ function univerSheetsOtPort(o) {
4402
4558
  };
4403
4559
  const collab = cs.onMutationExecutedForCollab((info, options) => {
4404
4560
  if (applying || flagged(options) || !mine(info.params)) return;
4405
- if (!group) group = openGroup(null);
4561
+ if (!group) group = pre.get(info.params)?.lone ?? openGroup(null);
4406
4562
  const g = group;
4407
4563
  if (!g.notShared) {
4408
4564
  const r = capture(info);
@@ -4483,11 +4639,18 @@ function univerSheetsOtPort(o) {
4483
4639
  listeners.add(listener);
4484
4640
  return () => void listeners.delete(listener);
4485
4641
  },
4486
- busy: () => tracker.stack.length > 0 || group !== null,
4642
+ busy: () => tracker.stack.length > 0 || group !== null || holding(),
4643
+ defers(op) {
4644
+ if (holding()) return true;
4645
+ const at = edited();
4646
+ if (!at || !op.some((m) => touchesEditedCell(m, at))) return false;
4647
+ editorHold = true;
4648
+ return true;
4649
+ },
4487
4650
  /** The outermost commands still running here (why the port is busy), for logs. */
4488
4651
  running: () => [...tracker.stack, ...group && tracker.stack.length === 0 ? ["(group)"] : []],
4489
4652
  whenIdle(fn) {
4490
- if (tracker.stack.length === 0 && !group) fn();
4653
+ if (tracker.stack.length === 0 && !group && !holding()) fn();
4491
4654
  else idle.push(fn);
4492
4655
  },
4493
4656
  applyRemote(m) {
@@ -4547,6 +4710,20 @@ function univerSheetsOtPort(o) {
4547
4710
  }
4548
4711
  };
4549
4712
  }
4713
+ function inverseStyle(prev, wrote) {
4714
+ if (!prev || typeof prev !== "object") return null;
4715
+ if (!wrote || typeof wrote !== "object") return prev;
4716
+ const out = { ...prev };
4717
+ for (const k of Object.keys(wrote)) if (!(k in out)) out[k] = null;
4718
+ return out;
4719
+ }
4720
+ function touchesEditedCell(m, at) {
4721
+ const sheet = String(m.params.subUnitId ?? "");
4722
+ if (sheet !== at.sheetId) return false;
4723
+ if (m.id !== VALUES) return true;
4724
+ const row = m.params.cellValue?.[at.row];
4725
+ return !!row && Object.prototype.hasOwnProperty.call(row, at.col);
4726
+ }
4550
4727
  function fullContent(cell) {
4551
4728
  const out = {};
4552
4729
  for (const k of CONTENT_KEYS) out[k] = cell && cell[k] !== void 0 ? cell[k] : null;
@@ -4786,7 +4963,8 @@ async function startWorkbookOtRoom(port, o) {
4786
4963
  awareness.setLocalState({
4787
4964
  uid: o.uid,
4788
4965
  clientId: o.clientId,
4789
- name: o.displayName ?? o.uid.slice(0, 8),
4966
+ name: o.displayName || "Someone",
4967
+ ...o.avatarUrl ? { avatarUrl: o.avatarUrl } : {},
4790
4968
  sheetId: null,
4791
4969
  row: null,
4792
4970
  col: null,
@@ -4856,6 +5034,7 @@ export {
4856
5034
  DOCS_COLLAB_PROTO,
4857
5035
  DOCS_TRANSFORM_VERSION,
4858
5036
  DOC_LOCAL_KEYS,
5037
+ REDO_COMMAND,
4859
5038
  RICH_TEXT_EDITING,
4860
5039
  SENDER_VIEW_PARAMS,
4861
5040
  SHEETS_COLLAB_PROTO,
@@ -4863,6 +5042,7 @@ export {
4863
5042
  SHEETS_READABLE_PROTOS,
4864
5043
  SHEET_ROOM_EDITOR_PRESETS,
4865
5044
  SHEET_ROOM_PLUGIN_PACKAGES,
5045
+ UNDO_COMMAND,
4866
5046
  WorkbookCollabSession,
4867
5047
  applyDocsOp,
4868
5048
  asLoadedDocsSnapshot,
@@ -4878,7 +5058,9 @@ export {
4878
5058
  documentOtFactory,
4879
5059
  documentUsesOrderedRoom,
4880
5060
  dropEmptyStyleRetains,
5061
+ editorBridgeCell,
4881
5062
  encodeSheetOp,
5063
+ filterServiceRange,
4882
5064
  invertDocsOp,
4883
5065
  isCellEditorScratch,
4884
5066
  isNoopDocsOp,