@ai-matrx/office 0.8.21 → 0.8.23

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.
@@ -0,0 +1,217 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/sheets/comment-anchors.ts
2
+ var _core = require('@univerjs/core');
3
+
4
+ // src/collab/sheets/transform/axis.ts
5
+ function isNoopMove(op) {
6
+ return op.count <= 0 || op.to >= op.from && op.to <= op.from + op.count;
7
+ }
8
+ function movedBlockStart(op) {
9
+ return op.to > op.from ? op.to - op.count : op.to;
10
+ }
11
+ function mapIndex(op, i) {
12
+ switch (op.kind) {
13
+ case "insert":
14
+ return i >= op.at ? i + op.count : i;
15
+ case "remove":
16
+ if (i < op.start) return i;
17
+ if (i < op.start + op.count) return null;
18
+ return i - op.count;
19
+ case "move": {
20
+ if (isNoopMove(op)) return i;
21
+ const { from, count, to } = op;
22
+ if (i >= from && i < from + count) return movedBlockStart(op) + (i - from);
23
+ if (to > from) return i >= from + count && i < to ? i - count : i;
24
+ return i >= to && i < from ? i + count : i;
25
+ }
26
+ }
27
+ }
28
+
29
+ // src/collab/sheets/comment-anchor-transform.ts
30
+ var SET_SHEET_COMMENT_ANCHOR = "matrx.mutation.set-comment-anchor";
31
+ var REMOVE_SHEET = "sheet.mutation.remove-sheet";
32
+ function structuralAxisOp(id, params) {
33
+ const p = params;
34
+ switch (id) {
35
+ case "sheet.mutation.insert-row":
36
+ return p.range ? { axis: "row", op: { kind: "insert", at: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } } : null;
37
+ case "sheet.mutation.remove-rows":
38
+ return p.range ? { axis: "row", op: { kind: "remove", start: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } } : null;
39
+ case "sheet.mutation.insert-col":
40
+ return p.range ? { axis: "col", op: { kind: "insert", at: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } } : null;
41
+ case "sheet.mutation.remove-col":
42
+ return p.range ? { axis: "col", op: { kind: "remove", start: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } } : null;
43
+ case "sheet.mutation.move-rows":
44
+ return p.sourceRange && p.targetRange ? { axis: "row", op: { kind: "move", from: p.sourceRange.startRow, count: p.sourceRange.endRow - p.sourceRange.startRow + 1, to: p.targetRange.startRow } } : null;
45
+ case "sheet.mutation.move-columns":
46
+ return p.sourceRange && p.targetRange ? {
47
+ axis: "col",
48
+ op: { kind: "move", from: p.sourceRange.startColumn, count: p.sourceRange.endColumn - p.sourceRange.startColumn + 1, to: p.targetRange.startColumn }
49
+ } : null;
50
+ default:
51
+ return null;
52
+ }
53
+ }
54
+ function moveSheetAnchorCell(cell, sheet, id, params) {
55
+ if (String(_nullishCoalesce(params.subUnitId, () => ( ""))) !== sheet) return cell;
56
+ if (id === REMOVE_SHEET) return null;
57
+ const s = structuralAxisOp(id, params);
58
+ if (!s) return cell;
59
+ if (s.axis === "row") {
60
+ const row = mapIndex(s.op, cell.row);
61
+ return row === null ? null : row === cell.row ? cell : { row, col: cell.col };
62
+ }
63
+ const col = mapIndex(s.op, cell.col);
64
+ return col === null ? null : col === cell.col ? cell : { row: cell.row, col };
65
+ }
66
+ function colName(c) {
67
+ let s = "";
68
+ for (let n = c + 1; n > 0; n = Math.floor((n - 1) / 26)) s = String.fromCharCode(65 + (n - 1) % 26) + s;
69
+ return s;
70
+ }
71
+ var sheetCellName = (cell) => `${colName(cell.col)}${cell.row + 1}`;
72
+
73
+ // src/sheets/comment-anchors.ts
74
+ var SHEET_COMMENT_ANCHORS_RESOURCE = "SHEET_MATRX_COMMENT_ANCHORS_PLUGIN";
75
+ function applyToSheetAnchors(anchors, id, params) {
76
+ if (id === SET_SHEET_COMMENT_ANCHOR) {
77
+ const p = params;
78
+ const sheet2 = { ..._nullishCoalesce(anchors[p.subUnitId], () => ( {})) };
79
+ if (p.cell) sheet2[p.anchorId] = { row: p.cell.row, col: p.cell.col };
80
+ else if (sheet2[p.anchorId]) delete sheet2[p.anchorId];
81
+ else return anchors;
82
+ const next2 = { ...anchors, [p.subUnitId]: sheet2 };
83
+ if (Object.keys(sheet2).length === 0) delete next2[p.subUnitId];
84
+ return next2;
85
+ }
86
+ const sheetId = String(_nullishCoalesce(params.subUnitId, () => ( "")));
87
+ const sheet = anchors[sheetId];
88
+ if (!sheet) return anchors;
89
+ let changed = false;
90
+ const moved = {};
91
+ for (const [anchorId, cell] of Object.entries(sheet)) {
92
+ const to = moveSheetAnchorCell(cell, sheetId, id, params);
93
+ if (to !== cell) changed = true;
94
+ if (to) moved[anchorId] = to;
95
+ }
96
+ if (!changed) return anchors;
97
+ const next = { ...anchors, [sheetId]: moved };
98
+ if (Object.keys(moved).length === 0) delete next[sheetId];
99
+ return next;
100
+ }
101
+ function sheetAnchorsToJson(anchors) {
102
+ if (!anchors) return "";
103
+ const sheets = Object.keys(anchors).filter((s) => Object.keys(_nullishCoalesce(anchors[s], () => ( {}))).length > 0).sort();
104
+ if (sheets.length === 0) return "";
105
+ const out = {};
106
+ for (const s of sheets) {
107
+ const ids = Object.keys(anchors[s]).sort();
108
+ out[s] = Object.fromEntries(ids.map((id) => [id, { row: anchors[s][id].row, col: anchors[s][id].col }]));
109
+ }
110
+ return JSON.stringify(out);
111
+ }
112
+ function sheetAnchorsFromJson(bytes) {
113
+ if (!bytes) return {};
114
+ try {
115
+ const v = JSON.parse(bytes);
116
+ if (!v || typeof v !== "object") return {};
117
+ const out = {};
118
+ for (const [sheet, ids] of Object.entries(v)) {
119
+ if (!ids || typeof ids !== "object") continue;
120
+ for (const [id, c] of Object.entries(ids)) {
121
+ const cell = c;
122
+ if (typeof _optionalChain([cell, 'optionalAccess', _ => _.row]) === "number" && typeof _optionalChain([cell, 'optionalAccess', _2 => _2.col]) === "number") (out[sheet] ??= {})[id] = { row: cell.row, col: cell.col };
123
+ }
124
+ }
125
+ return out;
126
+ } catch (e) {
127
+ return {};
128
+ }
129
+ }
130
+ var INSTALLED = /* @__PURE__ */ Symbol.for("ai-matrx.office.sheet-comment-anchors");
131
+ function installSheetCommentAnchors(univer) {
132
+ const holder = univer;
133
+ if (holder[INSTALLED]) return holder[INSTALLED];
134
+ const injector = _optionalChain([holder, 'access', _3 => _3.__getInjector, 'optionalCall', _4 => _4()]);
135
+ if (!injector) throw new Error("installSheetCommentAnchors: this Univer exposes no injector");
136
+ const commands = injector.get(_core.ICommandService);
137
+ const resources = injector.get(_core.IResourceManagerService);
138
+ const byUnit = /* @__PURE__ */ new Map();
139
+ const listeners = /* @__PURE__ */ new Set();
140
+ const changed = (unitId) => {
141
+ for (const l of Array.from(listeners)) {
142
+ try {
143
+ l(unitId);
144
+ } catch (e2) {
145
+ }
146
+ }
147
+ };
148
+ const apply = (unitId, id, params) => {
149
+ const before = _nullishCoalesce(byUnit.get(unitId), () => ( {}));
150
+ const after = applyToSheetAnchors(before, id, params);
151
+ if (after === before) return;
152
+ byUnit.set(unitId, after);
153
+ changed(unitId);
154
+ };
155
+ const disposables = [];
156
+ disposables.push(
157
+ commands.registerCommand({
158
+ id: SET_SHEET_COMMENT_ANCHOR,
159
+ type: _core.CommandType.MUTATION,
160
+ handler: (_accessor, params) => {
161
+ if (!_optionalChain([params, 'optionalAccess', _5 => _5.unitId]) || !params.subUnitId || !params.anchorId) return false;
162
+ apply(params.unitId, SET_SHEET_COMMENT_ANCHOR, params);
163
+ return true;
164
+ }
165
+ })
166
+ );
167
+ disposables.push(
168
+ resources.registerPluginResource({
169
+ pluginName: SHEET_COMMENT_ANCHORS_RESOURCE,
170
+ businesses: [_core.UniverInstanceType.UNIVER_SHEET],
171
+ toJson: (unitId) => sheetAnchorsToJson(byUnit.get(unitId)),
172
+ parseJson: (bytes) => sheetAnchorsFromJson(bytes),
173
+ onLoad: (unitId, value) => {
174
+ byUnit.set(unitId, _nullishCoalesce(value, () => ( {})));
175
+ changed(unitId);
176
+ },
177
+ onUnLoad: (unitId) => {
178
+ byUnit.delete(unitId);
179
+ changed(unitId);
180
+ }
181
+ })
182
+ );
183
+ disposables.push(
184
+ commands.onCommandExecuted((info) => {
185
+ if (info.type !== _core.CommandType.MUTATION || info.id === SET_SHEET_COMMENT_ANCHOR) return;
186
+ const p = info.params;
187
+ const unitId = typeof _optionalChain([p, 'optionalAccess', _6 => _6.unitId]) === "string" ? p.unitId : null;
188
+ if (!unitId || !byUnit.has(unitId)) return;
189
+ apply(unitId, info.id, p);
190
+ })
191
+ );
192
+ const handle = {
193
+ get: (unitId) => _nullishCoalesce(byUnit.get(unitId), () => ( {})),
194
+ set: (params) => commands.syncExecuteCommand(SET_SHEET_COMMENT_ANCHOR, params) === true,
195
+ onChange: (l) => {
196
+ listeners.add(l);
197
+ return () => listeners.delete(l);
198
+ },
199
+ dispose: () => {
200
+ for (const d of disposables.splice(0)) d.dispose();
201
+ listeners.clear();
202
+ delete holder[INSTALLED];
203
+ }
204
+ };
205
+ holder[INSTALLED] = handle;
206
+ return handle;
207
+ }
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+ exports.SET_SHEET_COMMENT_ANCHOR = SET_SHEET_COMMENT_ANCHOR; exports.SHEET_COMMENT_ANCHORS_RESOURCE = SHEET_COMMENT_ANCHORS_RESOURCE; exports.applyToSheetAnchors = applyToSheetAnchors; exports.installSheetCommentAnchors = installSheetCommentAnchors; exports.sheetAnchorsFromJson = sheetAnchorsFromJson; exports.sheetAnchorsToJson = sheetAnchorsToJson; exports.sheetCellName = sheetCellName;
217
+ //# sourceMappingURL=sheets-comment-anchors.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/aidream/aidream/apps/shared/office/dist/sheets-comment-anchors.cjs","../src/sheets/comment-anchors.ts","../src/collab/sheets/transform/axis.ts","../src/collab/sheets/comment-anchor-transform.ts"],"names":["next"],"mappings":"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","file":"/home/runner/work/aidream/aidream/apps/shared/office/dist/sheets-comment-anchors.cjs","sourcesContent":[null,"/**\n * Cell comment anchors in a workbook (COLLAB-DESIGN §8, unit C9).\n *\n * The anchor is a workbook resource (`SHEET_MATRX_COMMENT_ANCHORS_PLUGIN`): per sheet, anchor id → cell. It is\n * changed only by `matrx.mutation.set-comment-anchor`, which travels in the ordered room like every covered\n * mutation (its transform is `collab/sheets/comment-anchor-transform.ts`), and it follows every row/column\n * insert, remove and move this seat applies — its own, a peer's, an undo — through `moveSheetAnchorCell`, the\n * same function the transform uses, so every seat holds the same cells. A removed row, column or sheet takes the\n * anchor out: the thread in `platform.comments` (part_anchor `anchor:<id>`) is then orphaned, never dropped.\n *\n * `installSheetCommentAnchors(univer)` must run before the workbook unit is created (the resource loads with it).\n */\nimport { CommandType, ICommandService, IResourceManagerService, UniverInstanceType } from \"@univerjs/core\";\n\nimport { SET_SHEET_COMMENT_ANCHOR, moveSheetAnchorCell, type SheetAnchorCell } from \"../collab/sheets/comment-anchor-transform\";\n\nexport { SET_SHEET_COMMENT_ANCHOR, sheetCellName, type SheetAnchorCell } from \"../collab/sheets/comment-anchor-transform\";\n\nexport const SHEET_COMMENT_ANCHORS_RESOURCE = \"SHEET_MATRX_COMMENT_ANCHORS_PLUGIN\" as const;\n\n/** Per sheet id: anchor id → cell. */\nexport type SheetAnchors = Record<string, Record<string, SheetAnchorCell>>;\n\nexport interface SetSheetCommentAnchorParams {\n unitId: string;\n subUnitId: string;\n anchorId: string;\n /** null takes the anchor out. */\n cell: SheetAnchorCell | null;\n}\n\n/** Apply one mutation to a workbook's anchors (pure; returns the same object when nothing changed). */\nexport function applyToSheetAnchors(anchors: SheetAnchors, id: string, params: Readonly<Record<string, unknown>>): SheetAnchors {\n if (id === SET_SHEET_COMMENT_ANCHOR) {\n const p = params as unknown as SetSheetCommentAnchorParams;\n const sheet = { ...(anchors[p.subUnitId] ?? {}) };\n if (p.cell) sheet[p.anchorId] = { row: p.cell.row, col: p.cell.col };\n else if (sheet[p.anchorId]) delete sheet[p.anchorId];\n else return anchors;\n const next = { ...anchors, [p.subUnitId]: sheet };\n if (Object.keys(sheet).length === 0) delete next[p.subUnitId];\n return next;\n }\n const sheetId = String(params.subUnitId ?? \"\");\n const sheet = anchors[sheetId];\n if (!sheet) return anchors;\n let changed = false;\n const moved: Record<string, SheetAnchorCell> = {};\n for (const [anchorId, cell] of Object.entries(sheet)) {\n const to = moveSheetAnchorCell(cell, sheetId, id, params);\n if (to !== cell) changed = true;\n if (to) moved[anchorId] = to;\n }\n if (!changed) return anchors;\n const next = { ...anchors, [sheetId]: moved };\n if (Object.keys(moved).length === 0) delete next[sheetId];\n return next;\n}\n\n/** The resource's stored form: keys sorted so every seat writes the same bytes (the state hash reads them). */\nexport function sheetAnchorsToJson(anchors: SheetAnchors | undefined): string {\n if (!anchors) return \"\";\n const sheets = Object.keys(anchors).filter((s) => Object.keys(anchors[s] ?? {}).length > 0).sort();\n if (sheets.length === 0) return \"\";\n const out: Record<string, Record<string, SheetAnchorCell>> = {};\n for (const s of sheets) {\n const ids = Object.keys(anchors[s]!).sort();\n out[s] = Object.fromEntries(ids.map((id) => [id, { row: anchors[s]![id]!.row, col: anchors[s]![id]!.col }]));\n }\n return JSON.stringify(out);\n}\n\nexport function sheetAnchorsFromJson(bytes: string | null | undefined): SheetAnchors {\n if (!bytes) return {};\n try {\n const v = JSON.parse(bytes) as unknown;\n if (!v || typeof v !== \"object\") return {};\n const out: SheetAnchors = {};\n for (const [sheet, ids] of Object.entries(v as Record<string, unknown>)) {\n if (!ids || typeof ids !== \"object\") continue;\n for (const [id, c] of Object.entries(ids as Record<string, unknown>)) {\n const cell = c as SheetAnchorCell;\n if (typeof cell?.row === \"number\" && typeof cell?.col === \"number\") (out[sheet] ??= {})[id] = { row: cell.row, col: cell.col };\n }\n }\n return out;\n } catch {\n return {};\n }\n}\n\nexport interface SheetCommentAnchorsHandle {\n /** The anchors of one workbook now. */\n get(unitId: string): SheetAnchors;\n /** Anchor a cell (a new thread) — or take an anchor out with `cell: null` — through the command service. */\n set(params: SetSheetCommentAnchorParams): boolean;\n /** Called after any change to a workbook's anchors (set, moved, removed, loaded). */\n onChange(listener: (unitId: string) => void): () => void;\n dispose(): void;\n}\n\ntype Injector = { get<T>(token: unknown): T };\nconst INSTALLED = Symbol.for(\"ai-matrx.office.sheet-comment-anchors\");\n\n/** Register the anchor mutation, the resource and the structural listener on one Univer (idempotent). */\nexport function installSheetCommentAnchors(univer: unknown): SheetCommentAnchorsHandle {\n const holder = univer as { [INSTALLED]?: SheetCommentAnchorsHandle; __getInjector?: () => Injector };\n if (holder[INSTALLED]) return holder[INSTALLED]!;\n const injector = holder.__getInjector?.();\n if (!injector) throw new Error(\"installSheetCommentAnchors: this Univer exposes no injector\");\n const commands = injector.get<ICommandService>(ICommandService);\n const resources = injector.get<{ registerPluginResource: (hook: unknown) => { dispose(): void } }>(IResourceManagerService);\n\n const byUnit = new Map<string, SheetAnchors>();\n const listeners = new Set<(unitId: string) => void>();\n const changed = (unitId: string) => {\n for (const l of Array.from(listeners)) {\n try {\n l(unitId);\n } catch {\n /* a listener never stops the editor */\n }\n }\n };\n const apply = (unitId: string, id: string, params: Record<string, unknown>) => {\n const before = byUnit.get(unitId) ?? {};\n const after = applyToSheetAnchors(before, id, params);\n if (after === before) return;\n byUnit.set(unitId, after);\n changed(unitId);\n };\n\n const disposables: Array<{ dispose(): void }> = [];\n disposables.push(\n commands.registerCommand({\n id: SET_SHEET_COMMENT_ANCHOR,\n type: CommandType.MUTATION,\n handler: (_accessor: unknown, params?: SetSheetCommentAnchorParams) => {\n if (!params?.unitId || !params.subUnitId || !params.anchorId) return false;\n apply(params.unitId, SET_SHEET_COMMENT_ANCHOR, params as unknown as Record<string, unknown>);\n return true;\n },\n } as never),\n );\n disposables.push(\n resources.registerPluginResource({\n pluginName: SHEET_COMMENT_ANCHORS_RESOURCE,\n businesses: [UniverInstanceType.UNIVER_SHEET],\n toJson: (unitId: string) => sheetAnchorsToJson(byUnit.get(unitId)),\n parseJson: (bytes: string) => sheetAnchorsFromJson(bytes),\n onLoad: (unitId: string, value: SheetAnchors) => {\n byUnit.set(unitId, value ?? {});\n changed(unitId);\n },\n onUnLoad: (unitId: string) => {\n byUnit.delete(unitId);\n changed(unitId);\n },\n }),\n );\n disposables.push(\n commands.onCommandExecuted((info: { id: string; type?: CommandType; params?: unknown }) => {\n if (info.type !== CommandType.MUTATION || info.id === SET_SHEET_COMMENT_ANCHOR) return;\n const p = info.params as Record<string, unknown> | undefined;\n const unitId = typeof p?.unitId === \"string\" ? p.unitId : null;\n if (!unitId || !byUnit.has(unitId)) return;\n apply(unitId, info.id, p!);\n }),\n );\n\n const handle: SheetCommentAnchorsHandle = {\n get: (unitId) => byUnit.get(unitId) ?? {},\n set: (params) => commands.syncExecuteCommand(SET_SHEET_COMMENT_ANCHOR, params) === true,\n onChange: (l) => {\n listeners.add(l);\n return () => listeners.delete(l);\n },\n dispose: () => {\n for (const d of disposables.splice(0)) d.dispose();\n listeners.clear();\n delete holder[INSTALLED];\n },\n };\n holder[INSTALLED] = handle;\n return handle;\n}\n","/**\n * One-dimensional structural algebra for rows and columns: insert, remove and move, the index map each\n * induces, and S-over-S transforms. Index arithmetic is ours (not Univer's ref-range helpers) because ties\n * need the side rule and overlapping removes must subtract, which no free helper does.\n *\n * Semantics pinned to Univer 1.0.4:\n * - insert(at, n): new rows occupy [at, at+n); old row i >= at moves to i+n (the row AT `at` moves down).\n * - remove(start, n): rows [start, start+n) go; i >= start+n moves to i-n.\n * - move(from, n, to): `moveMatrixArray` — rows [from, from+n) are placed before old row `to`. Forward\n * (to >= from+n): block lands at [to-n, to). Backward (to < from): block lands at [to, to+n). A `to` in\n * [from, from+n] moves nothing (Univer throws for [from, from+n)); we treat it as a no-op.\n */\nimport type { Side } from \"./types\";\n\nexport type Axis = \"row\" | \"col\";\n\nexport type AxisOp =\n | { kind: \"insert\"; at: number; count: number }\n | { kind: \"remove\"; start: number; count: number }\n | { kind: \"move\"; from: number; count: number; to: number };\n\nexport function isNoopMove(op: { from: number; count: number; to: number }): boolean {\n return op.count <= 0 || (op.to >= op.from && op.to <= op.from + op.count);\n}\n\n/** Where the moved block starts after the move. */\nexport function movedBlockStart(op: { from: number; count: number; to: number }): number {\n return op.to > op.from ? op.to - op.count : op.to;\n}\n\n/** Old index → new index, or null when the index is removed. */\nexport function mapIndex(op: AxisOp, i: number): number | null {\n switch (op.kind) {\n case \"insert\":\n return i >= op.at ? i + op.count : i;\n case \"remove\":\n if (i < op.start) return i;\n if (i < op.start + op.count) return null;\n return i - op.count;\n case \"move\": {\n if (isNoopMove(op)) return i;\n const { from, count, to } = op;\n if (i >= from && i < from + count) return movedBlockStart(op) + (i - from);\n if (to > from) return i >= from + count && i < to ? i - count : i;\n return i >= to && i < from ? i + count : i;\n }\n }\n}\n\n/** Contiguous runs of a sorted, de-duplicated index list. */\nexport function runs(indices: Iterable<number>): Array<{ start: number; count: number }> {\n const sorted = [...new Set(indices)].sort((a, b) => a - b);\n const out: Array<{ start: number; count: number }> = [];\n for (const i of sorted) {\n const last = out[out.length - 1];\n if (last && last.start + last.count === i) last.count++;\n else out.push({ start: i, count: 1 });\n }\n return out;\n}\n\n/**\n * A gap (insert position: \"before old row p\") through a move. Gaps strictly inside the block ride with\n * it; any other gap is a gap of the non-block rows. At the move's own target gap an insert lands BEFORE\n * the block (side-independent; `transformAxis(move, insert)` keeps the same order).\n */\nfunction mapGapThroughMove(p: number, mv: { from: number; count: number; to: number }): number {\n const { from, count, to } = mv;\n if (p > from && p < from + count) return movedBlockStart(mv) + (p - from);\n const g = p <= from ? p : p - count; // gap index among the non-block rows\n const tg = to <= from ? to : to - count;\n return g <= tg ? g : g + count;\n}\n\n/**\n * x over y on ONE axis. Returns the list of axis ops that apply after y (empty = x vanished), or null when\n * the pair has no transform (the caller turns that into a barrier).\n */\nexport function transformAxis(x: AxisOp, y: AxisOp, side: Side): AxisOp[] | null {\n if (y.kind === \"move\" && isNoopMove(y)) return [x];\n if (x.kind === \"move\" && isNoopMove(x)) return [];\n switch (x.kind) {\n case \"insert\": {\n if (y.kind === \"insert\") {\n if (x.at < y.at || (x.at === y.at && side === \"left\")) return [x];\n return [{ ...x, at: x.at + y.count }];\n }\n if (y.kind === \"remove\") {\n if (x.at <= y.start) return [x];\n if (x.at >= y.start + y.count) return [{ ...x, at: x.at - y.count }];\n return [{ ...x, at: y.start }]; // an insert inside a removed span survives at its start\n }\n return [{ ...x, at: mapGapThroughMove(x.at, y) }];\n }\n case \"remove\": {\n const kept: number[] = [];\n for (let i = x.start; i < x.start + x.count; i++) {\n const m = mapIndex(y, i);\n if (m !== null) kept.push(m);\n }\n if (y.kind === \"insert\" || y.kind === \"remove\" || y.kind === \"move\") {\n // Removes are emitted highest first so each index is still valid when it applies.\n return runs(kept)\n .reverse()\n .map((r) => ({ kind: \"remove\" as const, start: r.start, count: r.count }));\n }\n return null;\n }\n case \"move\": {\n if (y.kind === \"insert\") {\n const inside = y.at > x.from && y.at < x.from + x.count;\n const from = inside || y.at > x.from ? x.from : x.from + y.count;\n const count = inside ? x.count + y.count : x.count;\n const to = x.to >= y.at ? x.to + y.count : x.to;\n const out = { kind: \"move\" as const, from, count, to };\n return isNoopMove(out) ? [] : [out];\n }\n if (y.kind === \"remove\") {\n const kept: number[] = [];\n for (let i = x.from; i < x.from + x.count; i++) {\n const m = mapIndex(y, i);\n if (m !== null) kept.push(m);\n }\n if (kept.length === 0) return [];\n const r = runs(kept);\n if (r.length !== 1) return null;\n const to = x.to <= y.start ? x.to : x.to >= y.start + y.count ? x.to - y.count : y.start;\n const out = { kind: \"move\" as const, from: r[0]!.start, count: r[0]!.count, to };\n return isNoopMove(out) ? [] : [out];\n }\n // move over move. The same rows moved twice: the later move wins, the earlier one is dropped.\n // Blocks that only partly overlap have no transform yet.\n const overlap = Math.min(x.from + x.count, y.from + y.count) - Math.max(x.from, y.from);\n if (overlap > 0) {\n if (x.from !== y.from || x.count !== y.count) return null;\n if (side === \"right\") return [];\n const out = { kind: \"move\" as const, from: movedBlockStart(y), count: x.count, to: mapGapThroughMove(x.to, y) };\n return isNoopMove(out) ? [] : [out];\n }\n // Disjoint blocks: x's rows through y must stay contiguous; the target gap goes through y.\n const mapped: number[] = [];\n for (let i = x.from; i < x.from + x.count; i++) mapped.push(mapIndex(y, i)!);\n const r = runs(mapped);\n if (r.length !== 1) return null;\n let to: number;\n if (x.to > y.from && x.to < y.from + y.count) to = movedBlockStart(y) + (x.to - y.from);\n else to = mapGapThroughMove(x.to, y) + (x.to === y.to && side === \"right\" ? y.count : 0); // same target: later block first\n const out = { kind: \"move\" as const, from: r[0]!.start, count: r[0]!.count, to };\n if (to > out.from && to < out.from + out.count) return null;\n return isNoopMove(out) ? [] : [out];\n }\n }\n}\n","/**\n * The sheet comment-anchor transform (COLLAB-DESIGN §8 + §10 class R, unit C9). Its own file; the sheet\n * transformer calls it first for every pair (`transformMutation`) and the registry declares its mutation id.\n *\n * A cell comment is anchored by `matrx.mutation.set-comment-anchor` `{ subUnitId, anchorId, cell: {row, col} | null }`\n * (null takes the anchor out). The anchor is a ranged resource keyed by id:\n * - anchor over a structural op on its sheet: the cell moves by the same index arithmetic as cells (`mapIndex`);\n * a cell whose row or column was removed DROPS the anchor (its author is told) and the thread is orphaned;\n * - anchor over the removal of its sheet: dropped the same way;\n * - anchor over the same anchor id: the later commit wins (§6.4), the earlier side is told;\n * - anything else over an anchor, and an anchor over anything else: unchanged (anchors never move content).\n * Every seat moves its stored anchors through each structural op it applies with `moveSheetAnchorCell` — the\n * same function — so a seat that set an anchor before a peer's row insert and a seat that received the anchor\n * after it end with the same cell.\n */\nimport { mapIndex, type AxisOp } from \"./transform/axis\";\nimport type { SheetMutation, Side, TransformResult } from \"./transform/types\";\n\nexport const SET_SHEET_COMMENT_ANCHOR = \"matrx.mutation.set-comment-anchor\";\n\n/** Mutation ids this package defines itself (never emitted by Univer; the census lists them apart). */\nexport const OWN_SHEET_MUTATION_IDS: readonly string[] = [SET_SHEET_COMMENT_ANCHOR];\n\nexport interface SheetAnchorCell {\n row: number;\n col: number;\n}\n\nconst REMOVE_SHEET = \"sheet.mutation.remove-sheet\";\n\ntype R = { startRow: number; endRow: number; startColumn: number; endColumn: number };\n\n/** The row/column op a Univer structural mutation makes, from its params (the same params on every seat). */\nexport function structuralAxisOp(id: string, params: Readonly<Record<string, unknown>>): { axis: \"row\" | \"col\"; op: AxisOp } | null {\n const p = params as Record<string, R | undefined>;\n switch (id) {\n case \"sheet.mutation.insert-row\":\n return p.range ? { axis: \"row\", op: { kind: \"insert\", at: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } } : null;\n case \"sheet.mutation.remove-rows\":\n return p.range ? { axis: \"row\", op: { kind: \"remove\", start: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } } : null;\n case \"sheet.mutation.insert-col\":\n return p.range ? { axis: \"col\", op: { kind: \"insert\", at: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } } : null;\n case \"sheet.mutation.remove-col\":\n return p.range ? { axis: \"col\", op: { kind: \"remove\", start: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } } : null;\n case \"sheet.mutation.move-rows\":\n return p.sourceRange && p.targetRange\n ? { axis: \"row\", op: { kind: \"move\", from: p.sourceRange.startRow, count: p.sourceRange.endRow - p.sourceRange.startRow + 1, to: p.targetRange.startRow } }\n : null;\n case \"sheet.mutation.move-columns\":\n return p.sourceRange && p.targetRange\n ? {\n axis: \"col\",\n op: { kind: \"move\", from: p.sourceRange.startColumn, count: p.sourceRange.endColumn - p.sourceRange.startColumn + 1, to: p.targetRange.startColumn },\n }\n : null;\n default:\n return null;\n }\n}\n\n/**\n * Where an anchored cell is after one applied mutation on `sheet`: the same cell, a moved cell, or null when the\n * mutation removed it (its row, its column or its sheet).\n */\nexport function moveSheetAnchorCell(cell: SheetAnchorCell, sheet: string, id: string, params: Readonly<Record<string, unknown>>): SheetAnchorCell | null {\n if (String(params.subUnitId ?? \"\") !== sheet) return cell;\n if (id === REMOVE_SHEET) return null;\n const s = structuralAxisOp(id, params);\n if (!s) return cell;\n if (s.axis === \"row\") {\n const row = mapIndex(s.op, cell.row);\n return row === null ? null : row === cell.row ? cell : { row, col: cell.col };\n }\n const col = mapIndex(s.op, cell.col);\n return col === null ? null : col === cell.col ? cell : { row: cell.row, col };\n}\n\nfunction colName(c: number): string {\n let s = \"\";\n for (let n = c + 1; n > 0; n = Math.floor((n - 1) / 26)) s = String.fromCharCode(65 + ((n - 1) % 26)) + s;\n return s;\n}\n/** \"B5\" for row 4, column 1. */\nexport const sheetCellName = (cell: SheetAnchorCell) => `${colName(cell.col)}${cell.row + 1}`;\n\nfunction cellOf(m: SheetMutation): SheetAnchorCell | null {\n const c = m.params.cell as SheetAnchorCell | null | undefined;\n return c && typeof c.row === \"number\" && typeof c.col === \"number\" ? c : null;\n}\n\nconst ok = (op: SheetMutation[], lost: string[] = [], dropped: string[] = []): TransformResult => ({ op, lost, dropped });\nconst label = (m: SheetMutation) => {\n const c = cellOf(m);\n return `${String(m.params.subUnitId ?? \"\")}!${c ? sheetCellName(c) : \"?\"} comment`;\n};\n\n/** x over y when either is an anchor mutation; null when neither is (the sheet transformer carries on). */\nexport function transformCommentAnchor(x: SheetMutation, y: SheetMutation, side: Side): TransformResult | null {\n const xa = x.id === SET_SHEET_COMMENT_ANCHOR;\n const ya = y.id === SET_SHEET_COMMENT_ANCHOR;\n if (!xa && !ya) return null;\n if (!xa) return ok([x]); // an anchor never moves content\n if (ya) {\n // anchors are keyed by sheet and id: the same id on another sheet is another anchor\n if (x.params.anchorId !== y.params.anchorId || x.params.subUnitId !== y.params.subUnitId) return ok([x]);\n return side === \"left\" ? ok([x], [label(y)]) : ok([], [], [label(x)]);\n }\n const cell = cellOf(x);\n if (!cell) return ok([x]); // taking an anchor out commutes with every move\n const moved = moveSheetAnchorCell(cell, String(x.params.subUnitId ?? \"\"), y.id, y.params);\n if (!moved) return ok([], [], [label(x)]);\n return ok([moved === cell ? x : { id: x.id, params: { ...x.params, cell: moved } }]);\n}\n"]}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The sheet comment-anchor transform (COLLAB-DESIGN §8 + §10 class R, unit C9). Its own file; the sheet
3
+ * transformer calls it first for every pair (`transformMutation`) and the registry declares its mutation id.
4
+ *
5
+ * A cell comment is anchored by `matrx.mutation.set-comment-anchor` `{ subUnitId, anchorId, cell: {row, col} | null }`
6
+ * (null takes the anchor out). The anchor is a ranged resource keyed by id:
7
+ * - anchor over a structural op on its sheet: the cell moves by the same index arithmetic as cells (`mapIndex`);
8
+ * a cell whose row or column was removed DROPS the anchor (its author is told) and the thread is orphaned;
9
+ * - anchor over the removal of its sheet: dropped the same way;
10
+ * - anchor over the same anchor id: the later commit wins (§6.4), the earlier side is told;
11
+ * - anything else over an anchor, and an anchor over anything else: unchanged (anchors never move content).
12
+ * Every seat moves its stored anchors through each structural op it applies with `moveSheetAnchorCell` — the
13
+ * same function — so a seat that set an anchor before a peer's row insert and a seat that received the anchor
14
+ * after it end with the same cell.
15
+ */
16
+
17
+ declare const SET_SHEET_COMMENT_ANCHOR = "matrx.mutation.set-comment-anchor";
18
+ interface SheetAnchorCell {
19
+ row: number;
20
+ col: number;
21
+ }
22
+ /** "B5" for row 4, column 1. */
23
+ declare const sheetCellName: (cell: SheetAnchorCell) => string;
24
+
25
+ declare const SHEET_COMMENT_ANCHORS_RESOURCE: "SHEET_MATRX_COMMENT_ANCHORS_PLUGIN";
26
+ /** Per sheet id: anchor id → cell. */
27
+ type SheetAnchors = Record<string, Record<string, SheetAnchorCell>>;
28
+ interface SetSheetCommentAnchorParams {
29
+ unitId: string;
30
+ subUnitId: string;
31
+ anchorId: string;
32
+ /** null takes the anchor out. */
33
+ cell: SheetAnchorCell | null;
34
+ }
35
+ /** Apply one mutation to a workbook's anchors (pure; returns the same object when nothing changed). */
36
+ declare function applyToSheetAnchors(anchors: SheetAnchors, id: string, params: Readonly<Record<string, unknown>>): SheetAnchors;
37
+ /** The resource's stored form: keys sorted so every seat writes the same bytes (the state hash reads them). */
38
+ declare function sheetAnchorsToJson(anchors: SheetAnchors | undefined): string;
39
+ declare function sheetAnchorsFromJson(bytes: string | null | undefined): SheetAnchors;
40
+ interface SheetCommentAnchorsHandle {
41
+ /** The anchors of one workbook now. */
42
+ get(unitId: string): SheetAnchors;
43
+ /** Anchor a cell (a new thread) — or take an anchor out with `cell: null` — through the command service. */
44
+ set(params: SetSheetCommentAnchorParams): boolean;
45
+ /** Called after any change to a workbook's anchors (set, moved, removed, loaded). */
46
+ onChange(listener: (unitId: string) => void): () => void;
47
+ dispose(): void;
48
+ }
49
+ /** Register the anchor mutation, the resource and the structural listener on one Univer (idempotent). */
50
+ declare function installSheetCommentAnchors(univer: unknown): SheetCommentAnchorsHandle;
51
+
52
+ export { SET_SHEET_COMMENT_ANCHOR, SHEET_COMMENT_ANCHORS_RESOURCE, type SetSheetCommentAnchorParams, type SheetAnchorCell, type SheetAnchors, type SheetCommentAnchorsHandle, applyToSheetAnchors, installSheetCommentAnchors, sheetAnchorsFromJson, sheetAnchorsToJson, sheetCellName };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The sheet comment-anchor transform (COLLAB-DESIGN §8 + §10 class R, unit C9). Its own file; the sheet
3
+ * transformer calls it first for every pair (`transformMutation`) and the registry declares its mutation id.
4
+ *
5
+ * A cell comment is anchored by `matrx.mutation.set-comment-anchor` `{ subUnitId, anchorId, cell: {row, col} | null }`
6
+ * (null takes the anchor out). The anchor is a ranged resource keyed by id:
7
+ * - anchor over a structural op on its sheet: the cell moves by the same index arithmetic as cells (`mapIndex`);
8
+ * a cell whose row or column was removed DROPS the anchor (its author is told) and the thread is orphaned;
9
+ * - anchor over the removal of its sheet: dropped the same way;
10
+ * - anchor over the same anchor id: the later commit wins (§6.4), the earlier side is told;
11
+ * - anything else over an anchor, and an anchor over anything else: unchanged (anchors never move content).
12
+ * Every seat moves its stored anchors through each structural op it applies with `moveSheetAnchorCell` — the
13
+ * same function — so a seat that set an anchor before a peer's row insert and a seat that received the anchor
14
+ * after it end with the same cell.
15
+ */
16
+
17
+ declare const SET_SHEET_COMMENT_ANCHOR = "matrx.mutation.set-comment-anchor";
18
+ interface SheetAnchorCell {
19
+ row: number;
20
+ col: number;
21
+ }
22
+ /** "B5" for row 4, column 1. */
23
+ declare const sheetCellName: (cell: SheetAnchorCell) => string;
24
+
25
+ declare const SHEET_COMMENT_ANCHORS_RESOURCE: "SHEET_MATRX_COMMENT_ANCHORS_PLUGIN";
26
+ /** Per sheet id: anchor id → cell. */
27
+ type SheetAnchors = Record<string, Record<string, SheetAnchorCell>>;
28
+ interface SetSheetCommentAnchorParams {
29
+ unitId: string;
30
+ subUnitId: string;
31
+ anchorId: string;
32
+ /** null takes the anchor out. */
33
+ cell: SheetAnchorCell | null;
34
+ }
35
+ /** Apply one mutation to a workbook's anchors (pure; returns the same object when nothing changed). */
36
+ declare function applyToSheetAnchors(anchors: SheetAnchors, id: string, params: Readonly<Record<string, unknown>>): SheetAnchors;
37
+ /** The resource's stored form: keys sorted so every seat writes the same bytes (the state hash reads them). */
38
+ declare function sheetAnchorsToJson(anchors: SheetAnchors | undefined): string;
39
+ declare function sheetAnchorsFromJson(bytes: string | null | undefined): SheetAnchors;
40
+ interface SheetCommentAnchorsHandle {
41
+ /** The anchors of one workbook now. */
42
+ get(unitId: string): SheetAnchors;
43
+ /** Anchor a cell (a new thread) — or take an anchor out with `cell: null` — through the command service. */
44
+ set(params: SetSheetCommentAnchorParams): boolean;
45
+ /** Called after any change to a workbook's anchors (set, moved, removed, loaded). */
46
+ onChange(listener: (unitId: string) => void): () => void;
47
+ dispose(): void;
48
+ }
49
+ /** Register the anchor mutation, the resource and the structural listener on one Univer (idempotent). */
50
+ declare function installSheetCommentAnchors(univer: unknown): SheetCommentAnchorsHandle;
51
+
52
+ export { SET_SHEET_COMMENT_ANCHOR, SHEET_COMMENT_ANCHORS_RESOURCE, type SetSheetCommentAnchorParams, type SheetAnchorCell, type SheetAnchors, type SheetCommentAnchorsHandle, applyToSheetAnchors, installSheetCommentAnchors, sheetAnchorsFromJson, sheetAnchorsToJson, sheetCellName };
@@ -0,0 +1,217 @@
1
+ // src/sheets/comment-anchors.ts
2
+ import { CommandType, ICommandService, IResourceManagerService, UniverInstanceType } from "@univerjs/core";
3
+
4
+ // src/collab/sheets/transform/axis.ts
5
+ function isNoopMove(op) {
6
+ return op.count <= 0 || op.to >= op.from && op.to <= op.from + op.count;
7
+ }
8
+ function movedBlockStart(op) {
9
+ return op.to > op.from ? op.to - op.count : op.to;
10
+ }
11
+ function mapIndex(op, i) {
12
+ switch (op.kind) {
13
+ case "insert":
14
+ return i >= op.at ? i + op.count : i;
15
+ case "remove":
16
+ if (i < op.start) return i;
17
+ if (i < op.start + op.count) return null;
18
+ return i - op.count;
19
+ case "move": {
20
+ if (isNoopMove(op)) return i;
21
+ const { from, count, to } = op;
22
+ if (i >= from && i < from + count) return movedBlockStart(op) + (i - from);
23
+ if (to > from) return i >= from + count && i < to ? i - count : i;
24
+ return i >= to && i < from ? i + count : i;
25
+ }
26
+ }
27
+ }
28
+
29
+ // src/collab/sheets/comment-anchor-transform.ts
30
+ var SET_SHEET_COMMENT_ANCHOR = "matrx.mutation.set-comment-anchor";
31
+ var REMOVE_SHEET = "sheet.mutation.remove-sheet";
32
+ function structuralAxisOp(id, params) {
33
+ const p = params;
34
+ switch (id) {
35
+ case "sheet.mutation.insert-row":
36
+ return p.range ? { axis: "row", op: { kind: "insert", at: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } } : null;
37
+ case "sheet.mutation.remove-rows":
38
+ return p.range ? { axis: "row", op: { kind: "remove", start: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } } : null;
39
+ case "sheet.mutation.insert-col":
40
+ return p.range ? { axis: "col", op: { kind: "insert", at: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } } : null;
41
+ case "sheet.mutation.remove-col":
42
+ return p.range ? { axis: "col", op: { kind: "remove", start: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } } : null;
43
+ case "sheet.mutation.move-rows":
44
+ return p.sourceRange && p.targetRange ? { axis: "row", op: { kind: "move", from: p.sourceRange.startRow, count: p.sourceRange.endRow - p.sourceRange.startRow + 1, to: p.targetRange.startRow } } : null;
45
+ case "sheet.mutation.move-columns":
46
+ return p.sourceRange && p.targetRange ? {
47
+ axis: "col",
48
+ op: { kind: "move", from: p.sourceRange.startColumn, count: p.sourceRange.endColumn - p.sourceRange.startColumn + 1, to: p.targetRange.startColumn }
49
+ } : null;
50
+ default:
51
+ return null;
52
+ }
53
+ }
54
+ function moveSheetAnchorCell(cell, sheet, id, params) {
55
+ if (String(params.subUnitId ?? "") !== sheet) return cell;
56
+ if (id === REMOVE_SHEET) return null;
57
+ const s = structuralAxisOp(id, params);
58
+ if (!s) return cell;
59
+ if (s.axis === "row") {
60
+ const row = mapIndex(s.op, cell.row);
61
+ return row === null ? null : row === cell.row ? cell : { row, col: cell.col };
62
+ }
63
+ const col = mapIndex(s.op, cell.col);
64
+ return col === null ? null : col === cell.col ? cell : { row: cell.row, col };
65
+ }
66
+ function colName(c) {
67
+ let s = "";
68
+ for (let n = c + 1; n > 0; n = Math.floor((n - 1) / 26)) s = String.fromCharCode(65 + (n - 1) % 26) + s;
69
+ return s;
70
+ }
71
+ var sheetCellName = (cell) => `${colName(cell.col)}${cell.row + 1}`;
72
+
73
+ // src/sheets/comment-anchors.ts
74
+ var SHEET_COMMENT_ANCHORS_RESOURCE = "SHEET_MATRX_COMMENT_ANCHORS_PLUGIN";
75
+ function applyToSheetAnchors(anchors, id, params) {
76
+ if (id === SET_SHEET_COMMENT_ANCHOR) {
77
+ const p = params;
78
+ const sheet2 = { ...anchors[p.subUnitId] ?? {} };
79
+ if (p.cell) sheet2[p.anchorId] = { row: p.cell.row, col: p.cell.col };
80
+ else if (sheet2[p.anchorId]) delete sheet2[p.anchorId];
81
+ else return anchors;
82
+ const next2 = { ...anchors, [p.subUnitId]: sheet2 };
83
+ if (Object.keys(sheet2).length === 0) delete next2[p.subUnitId];
84
+ return next2;
85
+ }
86
+ const sheetId = String(params.subUnitId ?? "");
87
+ const sheet = anchors[sheetId];
88
+ if (!sheet) return anchors;
89
+ let changed = false;
90
+ const moved = {};
91
+ for (const [anchorId, cell] of Object.entries(sheet)) {
92
+ const to = moveSheetAnchorCell(cell, sheetId, id, params);
93
+ if (to !== cell) changed = true;
94
+ if (to) moved[anchorId] = to;
95
+ }
96
+ if (!changed) return anchors;
97
+ const next = { ...anchors, [sheetId]: moved };
98
+ if (Object.keys(moved).length === 0) delete next[sheetId];
99
+ return next;
100
+ }
101
+ function sheetAnchorsToJson(anchors) {
102
+ if (!anchors) return "";
103
+ const sheets = Object.keys(anchors).filter((s) => Object.keys(anchors[s] ?? {}).length > 0).sort();
104
+ if (sheets.length === 0) return "";
105
+ const out = {};
106
+ for (const s of sheets) {
107
+ const ids = Object.keys(anchors[s]).sort();
108
+ out[s] = Object.fromEntries(ids.map((id) => [id, { row: anchors[s][id].row, col: anchors[s][id].col }]));
109
+ }
110
+ return JSON.stringify(out);
111
+ }
112
+ function sheetAnchorsFromJson(bytes) {
113
+ if (!bytes) return {};
114
+ try {
115
+ const v = JSON.parse(bytes);
116
+ if (!v || typeof v !== "object") return {};
117
+ const out = {};
118
+ for (const [sheet, ids] of Object.entries(v)) {
119
+ if (!ids || typeof ids !== "object") continue;
120
+ for (const [id, c] of Object.entries(ids)) {
121
+ const cell = c;
122
+ if (typeof cell?.row === "number" && typeof cell?.col === "number") (out[sheet] ??= {})[id] = { row: cell.row, col: cell.col };
123
+ }
124
+ }
125
+ return out;
126
+ } catch {
127
+ return {};
128
+ }
129
+ }
130
+ var INSTALLED = /* @__PURE__ */ Symbol.for("ai-matrx.office.sheet-comment-anchors");
131
+ function installSheetCommentAnchors(univer) {
132
+ const holder = univer;
133
+ if (holder[INSTALLED]) return holder[INSTALLED];
134
+ const injector = holder.__getInjector?.();
135
+ if (!injector) throw new Error("installSheetCommentAnchors: this Univer exposes no injector");
136
+ const commands = injector.get(ICommandService);
137
+ const resources = injector.get(IResourceManagerService);
138
+ const byUnit = /* @__PURE__ */ new Map();
139
+ const listeners = /* @__PURE__ */ new Set();
140
+ const changed = (unitId) => {
141
+ for (const l of Array.from(listeners)) {
142
+ try {
143
+ l(unitId);
144
+ } catch {
145
+ }
146
+ }
147
+ };
148
+ const apply = (unitId, id, params) => {
149
+ const before = byUnit.get(unitId) ?? {};
150
+ const after = applyToSheetAnchors(before, id, params);
151
+ if (after === before) return;
152
+ byUnit.set(unitId, after);
153
+ changed(unitId);
154
+ };
155
+ const disposables = [];
156
+ disposables.push(
157
+ commands.registerCommand({
158
+ id: SET_SHEET_COMMENT_ANCHOR,
159
+ type: CommandType.MUTATION,
160
+ handler: (_accessor, params) => {
161
+ if (!params?.unitId || !params.subUnitId || !params.anchorId) return false;
162
+ apply(params.unitId, SET_SHEET_COMMENT_ANCHOR, params);
163
+ return true;
164
+ }
165
+ })
166
+ );
167
+ disposables.push(
168
+ resources.registerPluginResource({
169
+ pluginName: SHEET_COMMENT_ANCHORS_RESOURCE,
170
+ businesses: [UniverInstanceType.UNIVER_SHEET],
171
+ toJson: (unitId) => sheetAnchorsToJson(byUnit.get(unitId)),
172
+ parseJson: (bytes) => sheetAnchorsFromJson(bytes),
173
+ onLoad: (unitId, value) => {
174
+ byUnit.set(unitId, value ?? {});
175
+ changed(unitId);
176
+ },
177
+ onUnLoad: (unitId) => {
178
+ byUnit.delete(unitId);
179
+ changed(unitId);
180
+ }
181
+ })
182
+ );
183
+ disposables.push(
184
+ commands.onCommandExecuted((info) => {
185
+ if (info.type !== CommandType.MUTATION || info.id === SET_SHEET_COMMENT_ANCHOR) return;
186
+ const p = info.params;
187
+ const unitId = typeof p?.unitId === "string" ? p.unitId : null;
188
+ if (!unitId || !byUnit.has(unitId)) return;
189
+ apply(unitId, info.id, p);
190
+ })
191
+ );
192
+ const handle = {
193
+ get: (unitId) => byUnit.get(unitId) ?? {},
194
+ set: (params) => commands.syncExecuteCommand(SET_SHEET_COMMENT_ANCHOR, params) === true,
195
+ onChange: (l) => {
196
+ listeners.add(l);
197
+ return () => listeners.delete(l);
198
+ },
199
+ dispose: () => {
200
+ for (const d of disposables.splice(0)) d.dispose();
201
+ listeners.clear();
202
+ delete holder[INSTALLED];
203
+ }
204
+ };
205
+ holder[INSTALLED] = handle;
206
+ return handle;
207
+ }
208
+ export {
209
+ SET_SHEET_COMMENT_ANCHOR,
210
+ SHEET_COMMENT_ANCHORS_RESOURCE,
211
+ applyToSheetAnchors,
212
+ installSheetCommentAnchors,
213
+ sheetAnchorsFromJson,
214
+ sheetAnchorsToJson,
215
+ sheetCellName
216
+ };
217
+ //# sourceMappingURL=sheets-comment-anchors.js.map