@ai-matrx/office 0.8.44 → 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.
@@ -35,6 +35,7 @@ __export(collab_exports, {
35
35
  DOCS_COLLAB_PROTO: () => DOCS_COLLAB_PROTO,
36
36
  DOCS_TRANSFORM_VERSION: () => DOCS_TRANSFORM_VERSION,
37
37
  DOC_LOCAL_KEYS: () => DOC_LOCAL_KEYS,
38
+ REDO_COMMAND: () => REDO_COMMAND,
38
39
  RICH_TEXT_EDITING: () => RICH_TEXT_EDITING,
39
40
  SENDER_VIEW_PARAMS: () => SENDER_VIEW_PARAMS,
40
41
  SHEETS_COLLAB_PROTO: () => SHEETS_COLLAB_PROTO,
@@ -42,6 +43,7 @@ __export(collab_exports, {
42
43
  SHEETS_READABLE_PROTOS: () => SHEETS_READABLE_PROTOS,
43
44
  SHEET_ROOM_EDITOR_PRESETS: () => SHEET_ROOM_EDITOR_PRESETS,
44
45
  SHEET_ROOM_PLUGIN_PACKAGES: () => SHEET_ROOM_PLUGIN_PACKAGES,
46
+ UNDO_COMMAND: () => UNDO_COMMAND,
45
47
  WorkbookCollabSession: () => WorkbookCollabSession,
46
48
  applyDocsOp: () => applyDocsOp,
47
49
  asLoadedDocsSnapshot: () => asLoadedDocsSnapshot,
@@ -57,7 +59,9 @@ __export(collab_exports, {
57
59
  documentOtFactory: () => documentOtFactory,
58
60
  documentUsesOrderedRoom: () => documentUsesOrderedRoom,
59
61
  dropEmptyStyleRetains: () => dropEmptyStyleRetains,
62
+ editorBridgeCell: () => editorBridgeCell,
60
63
  encodeSheetOp: () => encodeSheetOp,
64
+ filterServiceRange: () => filterServiceRange,
61
65
  invertDocsOp: () => invertDocsOp,
62
66
  isCellEditorScratch: () => isCellEditorScratch,
63
67
  isNoopDocsOp: () => isNoopDocsOp,
@@ -1249,26 +1253,77 @@ function rebaseUndoStack(items, remote, stack) {
1249
1253
  const first = stack === "undo" ? "undoMutations" : "redoMutations";
1250
1254
  const second = stack === "undo" ? "redoMutations" : "undoMutations";
1251
1255
  let dropped = 0;
1252
- for (let i = items.length - 1; i >= 0; i--) {
1256
+ let R = remote;
1257
+ for (let i = items.length - 1; i >= 0 && !isNoopDocsOp(R); i--) {
1253
1258
  const item = items[i];
1254
1259
  try {
1255
- const a = threadThrough(item[first], remote);
1260
+ const a = threadThrough(item[first], R);
1256
1261
  const b = threadThrough(item[second], a.after);
1257
1262
  if (a.next) item[first] = a.next;
1258
1263
  if (b.next) item[second] = b.next;
1264
+ R = a.after;
1259
1265
  } catch {
1260
1266
  items.splice(i, 1);
1261
1267
  dropped++;
1268
+ R = carryPast(item[first], R);
1262
1269
  }
1263
1270
  }
1264
1271
  return dropped;
1265
1272
  }
1273
+ function carryPast(list, remote) {
1274
+ let R = remote;
1275
+ for (const m of list ?? []) {
1276
+ if (m.id !== RICH_TEXT_EDITING || isNoopDocsOp(R)) continue;
1277
+ const own = m.params.actions;
1278
+ if (touchesPageSetup(own) && touchesPageSetup(R)) continue;
1279
+ R = transformDocsOp(R, own, "right").op;
1280
+ }
1281
+ return R;
1282
+ }
1283
+ var UNDO_COMMAND = "univer.command.undo";
1284
+ var REDO_COMMAND = "univer.command.redo";
1266
1285
  function openDocsOtRoom(o) {
1267
1286
  const { port } = o;
1268
1287
  let session = null;
1269
1288
  let composing = false;
1270
1289
  let queue = [];
1271
1290
  const drainWaiters = [];
1291
+ let replay = null;
1292
+ const noteHistoryStep = (m, inverse) => {
1293
+ const side = m.cmd === UNDO_COMMAND ? "undo" : m.cmd === REDO_COMMAND ? "redo" : null;
1294
+ if (!side) {
1295
+ replay = null;
1296
+ return;
1297
+ }
1298
+ for (const t of port.undoTargets()) {
1299
+ const stacks = undoStacksOf(t.service);
1300
+ const stack = stacks ? (side === "undo" ? stacks.undo : stacks.redo).get(t.unitId) : void 0;
1301
+ const item = stack?.[stack.length - 1];
1302
+ const list = item ? side === "undo" ? item.undoMutations : item.redoMutations : void 0;
1303
+ const k = list ? list.findIndex((x) => x.params === m.params) : -1;
1304
+ if (!item || !list || k < 0) continue;
1305
+ if (k === 0 || !replay || replay.item !== item || replay.side !== side) {
1306
+ const other = (side === "undo" ? item.redoMutations : item.undoMutations)?.[0]?.params ?? {};
1307
+ const { textRanges: _t, layoutState: _l, actions: _a, ...template } = other;
1308
+ replay = { item, side, inverses: [], template };
1309
+ }
1310
+ if (inverse === void 0 || list.some((x) => x.id !== RICH_TEXT_EDITING)) {
1311
+ replay = null;
1312
+ return;
1313
+ }
1314
+ replay.inverses.unshift(inverse);
1315
+ if (k === list.length - 1) {
1316
+ const rewritten = replay.inverses.filter((op) => !isNoopDocsOp(op)).map((op) => ({ id: RICH_TEXT_EDITING, params: { ...replay.template, segmentId: m.params?.segmentId ?? "", actions: op } }));
1317
+ if (rewritten.length) {
1318
+ if (side === "undo") item.redoMutations = rewritten;
1319
+ else item.undoMutations = rewritten;
1320
+ }
1321
+ replay = null;
1322
+ }
1323
+ return;
1324
+ }
1325
+ replay = null;
1326
+ };
1272
1327
  const notice = (n) => {
1273
1328
  try {
1274
1329
  o.onNotice?.(n);
@@ -1366,7 +1421,10 @@ function openDocsOtRoom(o) {
1366
1421
  }
1367
1422
  const p = m.params ?? {};
1368
1423
  const applied = p.actions ?? null;
1369
- if (isNoopDocsOp(applied)) return;
1424
+ if (isNoopDocsOp(applied)) {
1425
+ noteHistoryStep(m, null);
1426
+ return;
1427
+ }
1370
1428
  let op = normalizeDocsOp(structuredClone(applied));
1371
1429
  let inverse;
1372
1430
  try {
@@ -1374,6 +1432,7 @@ function openDocsOtRoom(o) {
1374
1432
  } catch {
1375
1433
  inverse = void 0;
1376
1434
  }
1435
+ noteHistoryStep(m, inverse === void 0 ? void 0 : normalizeDocsOp(inverse));
1377
1436
  if (queue.length) {
1378
1437
  inverse = void 0;
1379
1438
  const next = [];
@@ -2846,6 +2905,18 @@ function transformCell(X, Y4, side) {
2846
2905
  if (styleKeys(xs).length !== styleKeys(kept ?? {}).length) xLost = true;
2847
2906
  }
2848
2907
  }
2908
+ if (hasContent(X) && hasContent(Y4)) {
2909
+ const has = (s) => !!s && typeof s === "object" && "n" in s;
2910
+ const outS = out.s;
2911
+ if (side === "left" && !has(X.s) && has(Y4.s) && X.s !== null) {
2912
+ out.s = { ...outS && typeof outS === "object" ? outS : {}, n: null };
2913
+ } else if (side === "right" && outS && typeof outS === "object" && "n" in outS) {
2914
+ const rest = withoutStyleKeys(outS, /* @__PURE__ */ new Set(["n"]));
2915
+ if (rest) out.s = rest;
2916
+ else delete out.s;
2917
+ xLost = true;
2918
+ }
2919
+ }
2849
2920
  return { entries: Object.keys(out).length ? [out, ...tail] : tail, xLost, yLost };
2850
2921
  }
2851
2922
  function transformCellsOverCells(x, y, side) {
@@ -4006,7 +4077,7 @@ function createSheetsOtAdapter(port, hooks = {}) {
4006
4077
  decode: decodeSheetOp,
4007
4078
  apply(op) {
4008
4079
  if (isNoopSheetOp(op)) return true;
4009
- if (port.busy() || queue.length) {
4080
+ if (port.busy() || queue.length || port.defers?.(op)) {
4010
4081
  queue.push(op);
4011
4082
  if (!draining) {
4012
4083
  draining = true;
@@ -4039,9 +4110,9 @@ function createSheetsOtAdapter(port, hooks = {}) {
4039
4110
  async hash() {
4040
4111
  if (port.busy() || queue.length) {
4041
4112
  await new Promise((resolve) => {
4042
- const done = setTimeout(resolve, 5e3);
4113
+ const done = queue.length ? null : setTimeout(resolve, 5e3);
4043
4114
  port.whenIdle(() => {
4044
- clearTimeout(done);
4115
+ if (done) clearTimeout(done);
4045
4116
  setTimeout(resolve, 0);
4046
4117
  });
4047
4118
  });
@@ -4071,7 +4142,6 @@ function createSheetsOtAdapter(port, hooks = {}) {
4071
4142
  function openSheetsOtRoom(o) {
4072
4143
  const { port } = o;
4073
4144
  let session = null;
4074
- const adapter = createSheetsOtAdapter(port);
4075
4145
  const notice = (n) => {
4076
4146
  try {
4077
4147
  o.onNotice?.(n);
@@ -4079,6 +4149,29 @@ function openSheetsOtRoom(o) {
4079
4149
  console.warn("[sheets-ot] notice handler failed", err);
4080
4150
  }
4081
4151
  };
4152
+ const adapter = createSheetsOtAdapter(port);
4153
+ let healing = null;
4154
+ const HEALS = /* @__PURE__ */ new Set(["hash_mismatch", "save_hash_mismatch", "ack_mismatch"]);
4155
+ const screen = () => {
4156
+ try {
4157
+ const s = port.snapshot();
4158
+ return s ? canonicalSheetString(s) : null;
4159
+ } catch {
4160
+ return null;
4161
+ }
4162
+ };
4163
+ const onIncident = (i) => {
4164
+ if (HEALS.has(i.kind) && !healing) healing = { reason: i.kind, before: screen() };
4165
+ o.onIncident?.(i);
4166
+ };
4167
+ const onStatus = (st) => {
4168
+ if (st === "live" && healing) {
4169
+ const h = healing;
4170
+ healing = null;
4171
+ if (h.before !== null && screen() !== h.before) notice({ kind: "resynced", reason: h.reason });
4172
+ } else if (st === "read_only" || st === "closed") healing = null;
4173
+ o.onStatus?.(st);
4174
+ };
4082
4175
  const onLocal = (e) => {
4083
4176
  if (!session) return;
4084
4177
  if (e.kind === "not_shared") {
@@ -4119,8 +4212,8 @@ function openSheetsOtRoom(o) {
4119
4212
  clientId: o.clientId,
4120
4213
  ...o.presence ? { presence: o.presence } : {},
4121
4214
  onNotice: (n) => notice(n),
4122
- ...o.onIncident ? { onIncident: o.onIncident } : {},
4123
- ...o.onStatus ? { onStatus: o.onStatus } : {},
4215
+ onIncident,
4216
+ onStatus,
4124
4217
  ...o.offline ? { offline: o.offline } : {},
4125
4218
  ...o.onOffline ? { onOffline: o.onOffline } : {}
4126
4219
  });
@@ -4213,6 +4306,23 @@ function releaseUnitPluginState(cs, unitId, saved) {
4213
4306
  }
4214
4307
 
4215
4308
  // src/univer/collab/sheets-ot/univer-port.ts
4309
+ function filterServiceRange(service) {
4310
+ return (unitId, subUnitId) => {
4311
+ try {
4312
+ const r = service()?.getFilterModel(unitId, subUnitId)?.getRange();
4313
+ return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn, ...r.rangeType !== void 0 ? { rangeType: r.rangeType } : {} } : null;
4314
+ } catch {
4315
+ return null;
4316
+ }
4317
+ };
4318
+ }
4319
+ function editorBridgeCell(bridge) {
4320
+ return () => {
4321
+ if (!bridge.isVisible()?.visible) return null;
4322
+ const at = bridge.getEditLocation();
4323
+ return at ? { sheetId: at.sheetId, row: at.row, col: at.column } : null;
4324
+ };
4325
+ }
4216
4326
  var COMMAND = 0;
4217
4327
  var MUTATION = 2;
4218
4328
  var VALUES = "sheet.mutation.set-range-values";
@@ -4220,6 +4330,7 @@ var ADD_MERGE = "sheet.mutation.add-worksheet-merge";
4220
4330
  var REMOVE_MERGE = "sheet.mutation.remove-worksheet-merge";
4221
4331
  var SHEET_NAME = "sheet.mutation.set-worksheet-name";
4222
4332
  var INSERT_SHEET = "sheet.mutation.insert-sheet";
4333
+ var REMOVE_SHEET2 = "sheet.mutation.remove-sheet";
4223
4334
  var FILTER_RANGE = "sheet.mutation.set-filter-range";
4224
4335
  var RESHAPE = /* @__PURE__ */ new Set(["sheet.mutation.set-worksheet-row-count", "sheet.mutation.set-worksheet-column-count", "sheet.mutation.remove-sheet", INSERT_SHEET]);
4225
4336
  var UNDO = "univer.command.undo";
@@ -4239,6 +4350,18 @@ function univerSheetsOtPort(o) {
4239
4350
  const tracker = { stack: [], settle: () => settle() };
4240
4351
  let group = null;
4241
4352
  let applying = false;
4353
+ let editorHold = false;
4354
+ const edited = () => {
4355
+ try {
4356
+ return o.cellEditor?.() ?? null;
4357
+ } catch {
4358
+ return null;
4359
+ }
4360
+ };
4361
+ const holding = () => {
4362
+ if (editorHold && !edited()) editorHold = false;
4363
+ return editorHold;
4364
+ };
4242
4365
  const unitId = () => o.workbook()?.getUnitId() ?? null;
4243
4366
  const mine = (params) => {
4244
4367
  const u = unitId();
@@ -4267,7 +4390,7 @@ function univerSheetsOtPort(o) {
4267
4390
  if (!u || !o.filterRange) return null;
4268
4391
  try {
4269
4392
  const r = o.filterRange(u, sheet);
4270
- return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn } : null;
4393
+ return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn, ...r.rangeType !== void 0 ? { rangeType: r.rangeType } : {} } : null;
4271
4394
  } catch {
4272
4395
  return null;
4273
4396
  }
@@ -4283,10 +4406,45 @@ function univerSheetsOtPort(o) {
4283
4406
  }
4284
4407
  }
4285
4408
  };
4409
+ const sweepRemovedSheetRefs = (g) => {
4410
+ const removed = g.mutations.filter((m) => m.id === REMOVE_SHEET2).map((m) => String(m.params.subUnitId ?? ""));
4411
+ const wb = o.workbook();
4412
+ const u = unitId();
4413
+ if (!removed.length || !wb || !u) return;
4414
+ const refSheets = {};
4415
+ for (const [id, name] of Object.entries(g.sheets)) refSheets[name] = id;
4416
+ for (const gone of removed) {
4417
+ const name = g.sheets[gone];
4418
+ if (!name) continue;
4419
+ for (const ws of wb.getSheets()) {
4420
+ const sheet = ws.getSheetId();
4421
+ const cells = {};
4422
+ ws.getCellMatrix?.().forValue((r, c, cell) => {
4423
+ const f = cell?.f;
4424
+ if (typeof f !== "string" || !f.includes(name)) return;
4425
+ const out = rewriteFormula(f, { ownSheet: sheet, refSheets }, { kind: "remove-sheet", sheet: gone });
4426
+ if (typeof out !== "string" && out.changed) (cells[r] ??= {})[c] = { f: out.text, si: null };
4427
+ });
4428
+ if (!Object.keys(cells).length) continue;
4429
+ applying = true;
4430
+ try {
4431
+ cs.syncExecuteCommand(VALUES, { unitId: u, subUnitId: sheet, cellValue: json(cells) });
4432
+ } finally {
4433
+ applying = false;
4434
+ }
4435
+ const done = {};
4436
+ for (const r of Object.keys(cells))
4437
+ for (const c of Object.keys(cells[r])) (done[r] ??= {})[c] = completeCellContent(cells[r][c], json(ws.getCellRaw(Number(r), Number(c)) ?? null));
4438
+ g.mutations.push({ id: VALUES, params: { subUnitId: sheet, cellValue: done } });
4439
+ g.inverses.push(void 0);
4440
+ }
4441
+ }
4442
+ };
4286
4443
  const flush = () => {
4287
4444
  const g = group;
4288
4445
  group = null;
4289
4446
  if (!g) return;
4447
+ if (!g.notShared) sweepRemovedSheetRefs(g);
4290
4448
  if (g.notShared) emit({ kind: "not_shared", mutationId: g.notShared, label: g.label });
4291
4449
  else if (g.mutations.length) {
4292
4450
  const mutations = annotateSheetOps(annotateFormulas(g.mutations, g.sheets, g.names), g.order);
@@ -4298,7 +4456,7 @@ function univerSheetsOtPort(o) {
4298
4456
  };
4299
4457
  function settle() {
4300
4458
  if (tracker.stack.length === 0) flush();
4301
- if (tracker.stack.length === 0 && !group) for (const fn of idle.splice(0)) fn();
4459
+ if (tracker.stack.length === 0 && !group && !holding()) for (const fn of idle.splice(0)) fn();
4302
4460
  }
4303
4461
  const before = cs.beforeCommandExecuted((info, options) => {
4304
4462
  if (info.id === UNDO || info.id === REDO) for (const fn of [...undoWatchers]) fn();
@@ -4312,6 +4470,7 @@ function univerSheetsOtPort(o) {
4312
4470
  const ws = o.workbook()?.getSheetBySheetId(String(p.subUnitId ?? ""));
4313
4471
  if (!ws) return;
4314
4472
  const record = { merges: json(ws.getMergeData() ?? []) };
4473
+ if (!group) record.lone = openGroup(null);
4315
4474
  if (info.id === VALUES) {
4316
4475
  record.cells = /* @__PURE__ */ new Map();
4317
4476
  const cells = p.cellValue ?? {};
@@ -4348,6 +4507,7 @@ function univerSheetsOtPort(o) {
4348
4507
  }
4349
4508
  };
4350
4509
  const after = cs.onCommandExecuted((info) => {
4510
+ if (editorHold && tracker.stack.length === 0 && !group && !edited()) settle();
4351
4511
  if (info.type !== COMMAND) return;
4352
4512
  const at = tracker.stack.lastIndexOf(info.id);
4353
4513
  if (at >= 0) tracker.stack.splice(at, 1);
@@ -4429,7 +4589,7 @@ function univerSheetsOtPort(o) {
4429
4589
  else {
4430
4590
  inv = {};
4431
4591
  if (CONTENT_KEYS.some((k) => k !== "t" && k in done)) Object.assign(inv, fullContent(p));
4432
- if ("s" in done) inv.s = p?.s ?? null;
4592
+ if ("s" in done) inv.s = inverseStyle(p?.s, done.s);
4433
4593
  }
4434
4594
  (invCells[r] ??= {})[c] = inv;
4435
4595
  }
@@ -4467,7 +4627,7 @@ function univerSheetsOtPort(o) {
4467
4627
  };
4468
4628
  const collab = cs.onMutationExecutedForCollab((info, options) => {
4469
4629
  if (applying || flagged(options) || !mine(info.params)) return;
4470
- if (!group) group = openGroup(null);
4630
+ if (!group) group = pre.get(info.params)?.lone ?? openGroup(null);
4471
4631
  const g = group;
4472
4632
  if (!g.notShared) {
4473
4633
  const r = capture(info);
@@ -4548,11 +4708,18 @@ function univerSheetsOtPort(o) {
4548
4708
  listeners.add(listener);
4549
4709
  return () => void listeners.delete(listener);
4550
4710
  },
4551
- busy: () => tracker.stack.length > 0 || group !== null,
4711
+ busy: () => tracker.stack.length > 0 || group !== null || holding(),
4712
+ defers(op) {
4713
+ if (holding()) return true;
4714
+ const at = edited();
4715
+ if (!at || !op.some((m) => touchesEditedCell(m, at))) return false;
4716
+ editorHold = true;
4717
+ return true;
4718
+ },
4552
4719
  /** The outermost commands still running here (why the port is busy), for logs. */
4553
4720
  running: () => [...tracker.stack, ...group && tracker.stack.length === 0 ? ["(group)"] : []],
4554
4721
  whenIdle(fn) {
4555
- if (tracker.stack.length === 0 && !group) fn();
4722
+ if (tracker.stack.length === 0 && !group && !holding()) fn();
4556
4723
  else idle.push(fn);
4557
4724
  },
4558
4725
  applyRemote(m) {
@@ -4612,6 +4779,20 @@ function univerSheetsOtPort(o) {
4612
4779
  }
4613
4780
  };
4614
4781
  }
4782
+ function inverseStyle(prev, wrote) {
4783
+ if (!prev || typeof prev !== "object") return null;
4784
+ if (!wrote || typeof wrote !== "object") return prev;
4785
+ const out = { ...prev };
4786
+ for (const k of Object.keys(wrote)) if (!(k in out)) out[k] = null;
4787
+ return out;
4788
+ }
4789
+ function touchesEditedCell(m, at) {
4790
+ const sheet = String(m.params.subUnitId ?? "");
4791
+ if (sheet !== at.sheetId) return false;
4792
+ if (m.id !== VALUES) return true;
4793
+ const row = m.params.cellValue?.[at.row];
4794
+ return !!row && Object.prototype.hasOwnProperty.call(row, at.col);
4795
+ }
4615
4796
  function fullContent(cell) {
4616
4797
  const out = {};
4617
4798
  for (const k of CONTENT_KEYS) out[k] = cell && cell[k] !== void 0 ? cell[k] : null;