@ai-matrx/office 0.8.39 → 0.8.41
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.
- package/CHANGELOG.md +13 -2
- package/dist/core.cjs +9 -76
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +19 -76
- package/dist/core.js.map +1 -1
- package/dist/docs-io.cjs +113 -30
- package/dist/docs-io.cjs.map +1 -1
- package/dist/docs-io.d.cts +19 -3
- package/dist/docs-io.d.ts +19 -3
- package/dist/docs-io.js +109 -26
- package/dist/docs-io.js.map +1 -1
- package/package.json +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.41
|
|
4
|
+
|
|
5
|
+
- **The Office parity-row glyphs (`CircleHelp`, `Code2`, `FileText`, `GraduationCap`, `Megaphone`, `MessageSquareWarning`, `Puzzle`, `ShieldCheck`) are aliases of `@ai-matrx/design-system/icons`.** The inline path data is gone; names, the 24px default size and `OfficeIconProps` are unchanged. `@ai-matrx/design-system` is now a `workspace:*` dependency (office is layer 8, design-system layer 2). Consumer action: none.
|
|
6
|
+
|
|
3
7
|
## 0.8.39
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
|
|
10
|
+
so they may include breaking API changes. Consumer action is UNKNOWN: read the diff before upgrading.
|
|
11
|
+
Diff: `git diff 4d832f50ff 3fcdd8bb0e -- apps/shared/office/src`
|
|
12
|
+
|
|
13
|
+
Changed shipped source files (4):
|
|
14
|
+
- `apps/shared/office/src/collab/sheets/transform/registry.ts`
|
|
15
|
+
- `apps/shared/office/src/docs/comment-anchors.ts`
|
|
16
|
+
- `apps/shared/office/src/sheets/comment-anchors.ts`
|
|
17
|
+
- `apps/shared/office/src/sheets/note-follower.ts`
|
|
7
18
|
|
|
8
19
|
## 0.8.38
|
|
9
20
|
|
package/dist/core.cjs
CHANGED
|
@@ -237,82 +237,15 @@ function ribbonCoverage(tabs, menus, toolbar, googleOnly = {}) {
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
// src/core/icons.tsx
|
|
240
|
-
var
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
viewBox: "0 0 24 24",
|
|
250
|
-
fill: "none",
|
|
251
|
-
stroke: "currentColor",
|
|
252
|
-
strokeWidth: 2,
|
|
253
|
-
strokeLinecap: "round",
|
|
254
|
-
strokeLinejoin: "round",
|
|
255
|
-
"aria-hidden": "true",
|
|
256
|
-
focusable: "false",
|
|
257
|
-
className,
|
|
258
|
-
children
|
|
259
|
-
}
|
|
260
|
-
);
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
var CircleHelp = glyph(
|
|
264
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
265
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
|
|
266
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" }),
|
|
267
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 17h.01" })
|
|
268
|
-
] })
|
|
269
|
-
);
|
|
270
|
-
var Code2 = glyph(
|
|
271
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
272
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m18 16 4-4-4-4" }),
|
|
273
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m6 8-4 4 4 4" }),
|
|
274
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m14.5 4-5 16" })
|
|
275
|
-
] })
|
|
276
|
-
);
|
|
277
|
-
var FileText = glyph(
|
|
278
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
279
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z" }),
|
|
280
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 2v5a1 1 0 0 0 1 1h5" }),
|
|
281
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10 9H8" }),
|
|
282
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M16 13H8" }),
|
|
283
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M16 17H8" })
|
|
284
|
-
] })
|
|
285
|
-
);
|
|
286
|
-
var GraduationCap = glyph(
|
|
287
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
288
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z" }),
|
|
289
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M22 10v6" }),
|
|
290
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 12.5V16a6 3 0 0 0 12 0v-3.5" })
|
|
291
|
-
] })
|
|
292
|
-
);
|
|
293
|
-
var Megaphone = glyph(
|
|
294
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
295
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M11 6a13 13 0 0 0 8.4-2.8A1 1 0 0 1 21 4v12a1 1 0 0 1-1.6.8A13 13 0 0 0 11 14H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2z" }),
|
|
296
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 14a12 12 0 0 0 2.4 7.2 2 2 0 0 0 3.2-2.4A8 8 0 0 1 10 14" }),
|
|
297
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 6v8" })
|
|
298
|
-
] })
|
|
299
|
-
);
|
|
300
|
-
var MessageSquareWarning = glyph(
|
|
301
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
302
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z" }),
|
|
303
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 15h.01" }),
|
|
304
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 7v4" })
|
|
305
|
-
] })
|
|
306
|
-
);
|
|
307
|
-
var Puzzle = glyph(
|
|
308
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z" }) })
|
|
309
|
-
);
|
|
310
|
-
var ShieldCheck = glyph(
|
|
311
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
312
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" }),
|
|
313
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m9 12 2 2 4-4" })
|
|
314
|
-
] })
|
|
315
|
-
);
|
|
240
|
+
var import_icons = require("@ai-matrx/design-system/icons");
|
|
241
|
+
var CircleHelp = (0, import_icons.withDefaultSize)(import_icons.CircleHelpIcon, 24);
|
|
242
|
+
var Code2 = (0, import_icons.withDefaultSize)(import_icons.Code2Icon, 24);
|
|
243
|
+
var FileText = (0, import_icons.withDefaultSize)(import_icons.FileTextIcon, 24);
|
|
244
|
+
var GraduationCap = (0, import_icons.withDefaultSize)(import_icons.GraduationCapIcon, 24);
|
|
245
|
+
var Megaphone = (0, import_icons.withDefaultSize)(import_icons.MegaphoneIcon, 24);
|
|
246
|
+
var MessageSquareWarning = (0, import_icons.withDefaultSize)(import_icons.MessageSquareWarningIcon, 24);
|
|
247
|
+
var Puzzle = (0, import_icons.withDefaultSize)(import_icons.PuzzleIcon, 24);
|
|
248
|
+
var ShieldCheck = (0, import_icons.withDefaultSize)(import_icons.ShieldCheckIcon, 24);
|
|
316
249
|
|
|
317
250
|
// src/core/google-parity.ts
|
|
318
251
|
var import_outbound = require("@ai-matrx/kit/outbound");
|
package/dist/core.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/index.ts","../src/core/editor-menu-model.ts","../src/core/ribbon-model.ts","../src/core/icons.tsx","../src/core/google-parity.ts","../src/core/ribbon-parity.ts","../src/core/document-page-style.ts","../src/core/hosts.ts"],"sourcesContent":["/**\n * @ai-matrx/office/core — the pure model every Office editor shares. No window access at import, no\n * Univer runtime (page-setup-apply is its own entry, `@ai-matrx/office/core/page-setup-apply`).\n */\nexport * from \"./editor-menu-model\";\nexport * from \"./ribbon-model\";\nexport * from \"./google-parity\";\nexport * from \"./ribbon-parity\";\nexport * from \"./document-page-style\";\nexport * from \"./page-setup\";\nexport * from \"./hosts\";\nexport * from \"./types\";\n","/**\n * The editor chrome's command model — ONE data tree per editor that the menu\n * bar, the \"Menus\" search and the keyboard bindings all read. A row exists\n * only when it runs a real editor command; nothing here is decorative.\n *\n * Pure (no React, no DOM beyond KeyboardEvent shape) so the command mapping is\n * testable with a fake editor port.\n */\n\nimport type { ComponentType, ReactNode } from \"react\";\n\n/** A keyboard shortcut. `mod` is Cmd on a Mac and Ctrl elsewhere. */\nexport type EditorShortcut = {\n key: string;\n mod?: boolean;\n shift?: boolean;\n alt?: boolean;\n /**\n * true: the chrome binds this key itself (the editor engine does not).\n * false/absent: the engine already binds it; the label only tells the truth.\n */\n bind?: boolean;\n};\n\ntype IconType = ComponentType<{ className?: string }>;\n\nexport type EditorMenuAction = {\n kind: \"action\";\n id: string;\n label: string;\n icon?: IconType;\n shortcut?: EditorShortcut;\n /** Extra words the Menus search matches (e.g. \"freeze\" for \"1 row\"). */\n keywords?: string[];\n run: () => unknown;\n checked?: () => boolean;\n /** Only for edit gates (a viewer); never \"not built\". */\n disabled?: () => boolean;\n /**\n * A Google menu row we cannot run yet: the registered Coming Soon id it announces\n * (`lib/coming-soon/editor-menus.ts`). Drawn in muted ink; `run` announces the promise.\n */\n soon?: string;\n};\n\nexport type EditorMenuSubmenu = {\n kind: \"submenu\";\n id: string;\n label: string;\n icon?: IconType;\n keywords?: string[];\n items: EditorMenuEntry[];\n};\n\nexport type EditorMenuSeparator = { kind: \"separator\" };\n\nexport type EditorMenuEntry = EditorMenuAction | EditorMenuSubmenu | EditorMenuSeparator;\n\nexport type EditorMenu = {\n id: string;\n label: string;\n items: EditorMenuEntry[];\n};\n\n/** One runnable row as the Menus search sees it: the action plus its path. */\nexport type FlatEditorAction = EditorMenuAction & { path: string[] };\n\nexport function flattenMenus(menus: EditorMenu[]): FlatEditorAction[] {\n const out: FlatEditorAction[] = [];\n const walk = (entries: EditorMenuEntry[], path: string[], extraKeywords: string[]) => {\n for (const e of entries) {\n if (e.kind === \"separator\") continue;\n if (e.kind === \"submenu\") {\n walk(e.items, [...path, e.label], [...extraKeywords, ...(e.keywords ?? [])]);\n continue;\n }\n out.push({ ...e, path, keywords: [...extraKeywords, ...(e.keywords ?? [])] });\n }\n };\n for (const m of menus) walk(m.items, [m.label], []);\n return out;\n}\n\n/** Search the flattened commands: every word must hit the label, path or keywords. */\nexport function searchActions(actions: FlatEditorAction[], query: string, limit = 12): FlatEditorAction[] {\n const words = query.toLowerCase().split(/\\s+/).filter(Boolean);\n if (!words.length) return [];\n const scored: { a: FlatEditorAction; score: number }[] = [];\n for (const a of actions) {\n const label = a.label.toLowerCase();\n const hay = `${label} ${a.path.join(\" \").toLowerCase()} ${(a.keywords ?? []).join(\" \").toLowerCase()}`;\n if (!words.every((w) => hay.includes(w))) continue;\n const score = label.startsWith(words[0]!) ? 0 : label.includes(words[0]!) ? 1 : 2;\n scored.push({ a, score });\n }\n return scored.sort((x, y) => x.score - y.score).slice(0, limit).map((s) => s.a);\n}\n\nexport function isMacPlatform(): boolean {\n if (typeof navigator === \"undefined\") return true;\n return /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);\n}\n\nconst KEY_LABEL: Record<string, string> = {\n \"\\\\\": \"\\\\\",\n \"/\": \"/\",\n Delete: \"Delete\",\n Backspace: \"Backspace\",\n \"=\": \"+\",\n \"-\": \"-\",\n};\n\n/** \"⌘⇧1\" on a Mac, \"Ctrl+Shift+1\" elsewhere — Google's notation. */\nexport function formatShortcut(s: EditorShortcut, mac = isMacPlatform()): string {\n const key = KEY_LABEL[s.key] ?? (s.key.length === 1 ? s.key.toUpperCase() : s.key);\n if (mac) return `${s.mod ? \"⌘\" : \"\"}${s.alt ? \"⌥\" : \"\"}${s.shift ? \"⇧\" : \"\"}${key}`;\n return [s.mod ? \"Ctrl\" : \"\", s.alt ? \"Alt\" : \"\", s.shift ? \"Shift\" : \"\", key].filter(Boolean).join(\"+\");\n}\n\n/** The physical key of an event (layout-proof for digits and letters under Shift/Alt). */\nfunction eventKey(e: Pick<KeyboardEvent, \"key\" | \"code\">): string {\n if (/^Digit\\d$/.test(e.code)) return e.code.slice(5);\n if (/^Key[A-Z]$/.test(e.code)) return e.code.slice(3).toLowerCase();\n if (e.code === \"Backslash\") return \"\\\\\";\n if (e.code === \"Slash\") return \"/\";\n return e.key.length === 1 ? e.key.toLowerCase() : e.key;\n}\n\nexport function matchesShortcut(\n e: Pick<KeyboardEvent, \"key\" | \"code\" | \"metaKey\" | \"ctrlKey\" | \"shiftKey\" | \"altKey\">,\n s: EditorShortcut,\n mac = isMacPlatform(),\n): boolean {\n const mod = mac ? e.metaKey : e.ctrlKey;\n if (!!s.mod !== mod) return false;\n if (!!s.shift !== e.shiftKey) return false;\n if (!!s.alt !== e.altKey) return false;\n // Named keys (\"ArrowUp\", \"Enter\", \"Delete\") arrive cased; letters arrive lower-cased.\n return eventKey(e).toLowerCase() === s.key.toLowerCase();\n}\n\n/** The actions whose shortcut the chrome binds itself. */\nexport function boundActions(menus: EditorMenu[]): FlatEditorAction[] {\n return flattenMenus(menus).filter((a) => a.shortcut?.bind);\n}\n\ntype ToolbarIconType = ComponentType<{ className?: string }>;\n\n/** One control in an editor's toolbar row (moved unchanged from EditorToolbar.tsx; pure data). */\nexport type EditorToolbarItem =\n | {\n kind: \"button\";\n id: string;\n label: string;\n icon: ToolbarIconType;\n run: () => unknown;\n shortcut?: EditorShortcut;\n active?: boolean;\n disabled?: boolean;\n }\n | { kind: \"separator\"; id: string }\n | {\n kind: \"menu\";\n id: string;\n label: string;\n icon?: ToolbarIconType;\n /** Text shown on the trigger (e.g. \"100%\", \"Arial\"). */\n text?: string;\n /** Trigger width class for text triggers (keeps the row still as text changes). */\n widthClass?: string;\n items: EditorMenuEntry[];\n disabled?: boolean;\n }\n | { kind: \"node\"; id: string; node: ReactNode };\n","/**\n * The Microsoft 365 look's ribbon — a SECOND PRESENTATION of the editor's ONE command map.\n *\n * A ribbon layout is pure data: tabs → groups → controls, where each control names something that\n * already exists in the editor's model by id —\n * - a toolbar item (`tb.bold`, `tb.font`, …) from the same `EditorToolbarItem[]` the Google\n * toolbar draws,\n * - a menu row (`view.freeze`, `data.filter`, …) from the same `EditorMenu[]` the Google menu\n * bar draws (an action runs; a submenu opens as a dropdown),\n * - a whole menu (`menu:help`) as one dropdown.\n * Nothing here runs anything itself, so the two looks cannot drift: `ribbonCoverage` proves every\n * command of the model is reachable from the ribbon (forcing test per editor).\n *\n * Pure (no React) so the mapping is testable with a fake editor host.\n */\n\nimport type { ComponentType } from \"react\";\nimport type {\n EditorMenu,\n EditorMenuAction,\n EditorMenuEntry,\n EditorMenuSubmenu,\n EditorToolbarItem,\n} from \"./editor-menu-model\";\n\ntype IconType = ComponentType<{ className?: string }>;\n\n/**\n * - `large`: icon over a label, a whole column (Office's Paste, Freeze Panes).\n * - `small`: icon + label in a row, three stacked per column.\n * - `icon`: an icon (or value dropdown) in a row of tools (Office's Font group).\n */\nexport type RibbonSize = \"large\" | \"small\" | \"icon\";\n\nexport type RibbonControlSpec = {\n /** A toolbar item id, a menu entry id, or `menu:<menuId>` for a whole menu. */\n ref: string;\n size?: RibbonSize;\n /** Office's own word for the same command (\"Freeze Panes\" for Freeze). */\n label?: string;\n /** An icon for a row that has none in the model (a large control needs one). */\n icon?: IconType;\n};\n\nexport type RibbonGroupSpec = {\n id: string;\n label: string;\n controls: Array<string | RibbonControlSpec>;\n /** Icon rows hold this many tools before wrapping to the next row (default 6). */\n perRow?: number;\n};\n\nexport type RibbonTabSpec = { id: string; label: string; groups: RibbonGroupSpec[] };\n\n/** Menu rows (or whole submenus) the Microsoft ribbon deliberately does not place, with the reason. */\nexport type GoogleOnlyRows = Record<string, string>;\n\nexport type ResolvedRibbonControl =\n | { kind: \"toolbar\"; key: string; size: RibbonSize; label?: string | undefined; icon?: IconType | undefined; item: Exclude<EditorToolbarItem, { kind: \"separator\" }> }\n | { kind: \"action\"; key: string; size: RibbonSize; label?: string | undefined; icon?: IconType | undefined; action: EditorMenuAction }\n | { kind: \"submenu\"; key: string; size: RibbonSize; label?: string | undefined; icon?: IconType | undefined; submenu: Pick<EditorMenuSubmenu, \"id\" | \"label\" | \"icon\" | \"items\"> };\n\nexport type ResolvedRibbonGroup = { id: string; label: string; perRow: number; controls: ResolvedRibbonControl[] };\nexport type ResolvedRibbonTab = { id: string; label: string; groups: ResolvedRibbonGroup[] };\n\ntype Indexed =\n | { kind: \"toolbar\"; item: Exclude<EditorToolbarItem, { kind: \"separator\" }> }\n | { kind: \"action\"; action: EditorMenuAction }\n | { kind: \"submenu\"; submenu: Pick<EditorMenuSubmenu, \"id\" | \"label\" | \"icon\" | \"items\"> };\n\n/** Every addressable command of one editor: toolbar ids, menu entry ids, `menu:<id>`. */\nexport function indexCommands(menus: EditorMenu[], toolbar: EditorToolbarItem[]): Map<string, Indexed> {\n const out = new Map<string, Indexed>();\n const walk = (entries: EditorMenuEntry[]) => {\n for (const e of entries) {\n if (e.kind === \"separator\") continue;\n if (e.kind === \"submenu\") {\n if (!out.has(e.id)) out.set(e.id, { kind: \"submenu\", submenu: e });\n walk(e.items);\n } else if (!out.has(e.id)) out.set(e.id, { kind: \"action\", action: e });\n }\n };\n for (const m of menus) {\n out.set(`menu:${m.id}`, { kind: \"submenu\", submenu: { id: `menu:${m.id}`, label: m.label, items: m.items } });\n walk(m.items);\n }\n for (const t of toolbar) if (t.kind !== \"separator\") out.set(t.id, { kind: \"toolbar\", item: t });\n return out;\n}\n\nconst spec = (c: string | RibbonControlSpec): RibbonControlSpec => (typeof c === \"string\" ? { ref: c } : c);\n\n/**\n * The layout bound to the live model. A control whose id the model does not hold right now (a\n * row that exists only in some states, e.g. \"Remove image\") is left out; empty groups and tabs go.\n */\nexport function resolveRibbon(\n tabs: RibbonTabSpec[],\n menus: EditorMenu[],\n toolbar: EditorToolbarItem[],\n): ResolvedRibbonTab[] {\n const index = indexCommands(menus, toolbar);\n const out: ResolvedRibbonTab[] = [];\n for (const tab of tabs) {\n const groups: ResolvedRibbonGroup[] = [];\n for (const g of tab.groups) {\n const controls: ResolvedRibbonControl[] = [];\n for (const raw of g.controls) {\n const c = spec(raw);\n const hit = index.get(c.ref);\n if (!hit) continue;\n const base = { key: `${tab.id}/${g.id}/${c.ref}`, size: c.size ?? \"small\", label: c.label, icon: c.icon };\n if (hit.kind === \"toolbar\") controls.push({ ...base, kind: \"toolbar\", item: hit.item });\n else if (hit.kind === \"action\") controls.push({ ...base, kind: \"action\", action: hit.action });\n else controls.push({ ...base, kind: \"submenu\", submenu: hit.submenu });\n }\n if (controls.length) groups.push({ id: g.id, label: g.label, perRow: g.perRow ?? 6, controls });\n }\n if (groups.length) out.push({ id: tab.id, label: tab.label, groups });\n }\n return out;\n}\n\nfunction actionIdsIn(entries: EditorMenuEntry[], into: Set<string>) {\n for (const e of entries) {\n if (e.kind === \"separator\") continue;\n if (e.kind === \"submenu\") actionIdsIn(e.items, into);\n else into.add(e.id);\n }\n}\n\n/**\n * What the ribbon can reach vs. what the model holds. `missingActions`: menu rows no ribbon\n * control leads to; `missingToolbar`: toolbar tools absent from the ribbon; `unknownRefs`: layout\n * ids the model does not have (a typo, or a renamed command).\n */\nexport function ribbonCoverage(\n tabs: RibbonTabSpec[],\n menus: EditorMenu[],\n toolbar: EditorToolbarItem[],\n googleOnly: GoogleOnlyRows = {},\n) {\n const index = indexCommands(menus, toolbar);\n const reached = new Set<string>();\n const placedToolbar = new Set<string>();\n const unknownRefs: string[] = [];\n const wholeMenuRefs: string[] = [];\n for (const tab of tabs)\n for (const g of tab.groups)\n for (const raw of g.controls) {\n const c = spec(raw);\n const hit = index.get(c.ref);\n if (!hit) {\n unknownRefs.push(c.ref);\n continue;\n }\n // A whole-menu dropdown (\"menu:edit\") is a catch-all, not a placement: it must not make\n // a new row look covered. Rows are placed by their own id (or their submenu's).\n if (c.ref.startsWith(\"menu:\")) {\n wholeMenuRefs.push(c.ref);\n continue;\n }\n if (hit.kind === \"action\") reached.add(hit.action.id);\n else if (hit.kind === \"submenu\") actionIdsIn(hit.submenu.items, reached);\n else {\n placedToolbar.add(hit.item.id);\n if (hit.item.kind === \"menu\") actionIdsIn(hit.item.items, reached);\n }\n }\n const all = new Set<string>();\n for (const m of menus) actionIdsIn(m.items, all);\n // A toolbar button that is the same command as a reached menu row (same name or same shortcut —\n // Undo, ⌘K) is reachable through that row; it need not be placed twice.\n const flat: EditorMenuAction[] = [];\n const collect = (entries: EditorMenuEntry[]) => {\n for (const e of entries) {\n if (e.kind === \"submenu\") collect(e.items);\n else if (e.kind === \"action\") flat.push(e);\n }\n };\n for (const m of menus) collect(m.items);\n const reachedRows = flat.filter((a) => reached.has(a.id));\n const sameShortcut = (a?: EditorMenuAction[\"shortcut\"], b?: EditorMenuAction[\"shortcut\"]) =>\n !!a && !!b && a.key.toLowerCase() === b.key.toLowerCase() && !!a.mod === !!b.mod && !!a.shift === !!b.shift && !!a.alt === !!b.alt;\n const viaRow = (t: EditorToolbarItem) =>\n t.kind === \"button\" &&\n reachedRows.some((a) => a.label.toLowerCase() === t.label.toLowerCase() || sameShortcut(a.shortcut, t.shortcut));\n // Rows (or whole submenus) the layout declares Google-only, each with a reason.\n const declared = new Set<string>();\n const badGoogleOnly: string[] = [];\n for (const [id, reason] of Object.entries(googleOnly)) {\n const hit = index.get(id);\n if (!hit || !reason.trim()) {\n badGoogleOnly.push(id);\n continue;\n }\n if (hit.kind === \"action\") declared.add(hit.action.id);\n else if (hit.kind === \"submenu\") actionIdsIn(hit.submenu.items, declared);\n else badGoogleOnly.push(id);\n if (hit.kind === \"action\" && reached.has(hit.action.id)) badGoogleOnly.push(id);\n }\n return {\n missingActions: [...all].filter((id) => !reached.has(id) && !declared.has(id)),\n badGoogleOnly,\n wholeMenuRefs,\n missingToolbar: toolbar\n .filter((t) => t.kind !== \"separator\" && t.kind !== \"node\" && !placedToolbar.has(t.id) && !viaRow(t))\n .map((t) => (t as { id: string }).id),\n unknownRefs,\n };\n}\n","/**\n * The eight glyphs the shared Google/Microsoft parity rows use, inlined as SVG (C19: a package ships\n * its own icons and never depends on an icon library). Paths adapted from Lucide (ISC license,\n * https://lucide.dev), 24x24, 2px round strokes, currentColor.\n */\nimport type { ReactElement } from \"react\";\n\nexport type OfficeIconProps = { className?: string };\n\nfunction glyph(children: ReactElement) {\n return function OfficeGlyph({ className }: OfficeIconProps): ReactElement {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={24}\n height={24}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n className={className}\n >\n {children}\n </svg>\n );\n };\n}\n\nexport const CircleHelp = glyph(\n <>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\" />\n <path d=\"M12 17h.01\" />\n </>,\n);\n\nexport const Code2 = glyph(\n <>\n <path d=\"m18 16 4-4-4-4\" />\n <path d=\"m6 8-4 4 4 4\" />\n <path d=\"m14.5 4-5 16\" />\n </>,\n);\n\nexport const FileText = glyph(\n <>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M10 9H8\" />\n <path d=\"M16 13H8\" />\n <path d=\"M16 17H8\" />\n </>,\n);\n\nexport const GraduationCap = glyph(\n <>\n <path d=\"M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z\" />\n <path d=\"M22 10v6\" />\n <path d=\"M6 12.5V16a6 3 0 0 0 12 0v-3.5\" />\n </>,\n);\n\nexport const Megaphone = glyph(\n <>\n <path d=\"M11 6a13 13 0 0 0 8.4-2.8A1 1 0 0 1 21 4v12a1 1 0 0 1-1.6.8A13 13 0 0 0 11 14H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2z\" />\n <path d=\"M6 14a12 12 0 0 0 2.4 7.2 2 2 0 0 0 3.2-2.4A8 8 0 0 1 10 14\" />\n <path d=\"M8 6v8\" />\n </>,\n);\n\nexport const MessageSquareWarning = glyph(\n <>\n <path d=\"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z\" />\n <path d=\"M12 15h.01\" />\n <path d=\"M12 7v4\" />\n </>,\n);\n\nexport const Puzzle = glyph(\n <>\n <path d=\"M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z\" />\n </>,\n);\n\nexport const ShieldCheck = glyph(\n <>\n <path d=\"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\" />\n <path d=\"m9 12 2 2 4-4\" />\n </>,\n);\n","/**\n * Google parity rows the three editors share: a Coming Soon row (`soon`), Google's Extensions\n * menu, and the head of Google's Help menu. Pure data (the announce module loads on click), so\n * the menu builders stay testable without React.\n */\n\nimport { CircleHelp, Code2, FileText, GraduationCap, Megaphone, MessageSquareWarning, Puzzle, ShieldCheck } from \"./icons\";\nimport type { ComponentType } from \"react\";\nimport { openOutbound } from \"@ai-matrx/kit/outbound\";\n\nimport type { EditorMenu, EditorMenuAction, EditorMenuEntry, EditorShortcut } from \"./editor-menu-model\";\n\nexport const sep: EditorMenuEntry = { kind: \"separator\" };\n\n/** A Google row we cannot run yet: muted, and clicking it announces the registered promise. */\nexport function soon(\n id: string,\n label: string,\n promise: string,\n opts: { icon?: ComponentType<{ className?: string }>; keywords?: string[]; shortcut?: EditorShortcut } = {},\n): EditorMenuAction {\n return {\n kind: \"action\",\n id,\n label,\n soon: promise,\n ...opts,\n run: () => import(\"@ai-matrx/kit/coming-soon\").then((m) => m.announceComingSoon(promise)),\n };\n}\n\nexport type GoogleProduct = \"sheets\" | \"docs\" | \"slides\";\n\n/** Google's Extensions menu (the host's own tools follow these rows). */\nexport function googleExtensionsMenu(product: GoogleProduct, built: { macros?: EditorMenuEntry } = {}): EditorMenu {\n return {\n id: \"extensions\",\n label: \"Extensions\",\n items: [\n soon(\"extensions.add-ons\", \"Add-ons\", \"editor.extensions.add-ons\", { icon: Puzzle }),\n ...(product === \"sheets\" && built.macros ? [built.macros] : []),\n soon(\"extensions.scripts\", \"Scripts\", \"editor.extensions.scripts\", { icon: Code2, keywords: [\"apps script\", \"automation\"] }),\n ],\n };\n}\n\nfunction openPage(href: string) {\n if (typeof window !== \"undefined\") openOutbound(href, \"_blank\", \"noopener\");\n}\n\n/** The head of Google's Help menu; the editor's own rows (shortcuts, function list) follow. */\nexport function googleHelpHead(opts: { sendFeedback?: () => void } = {}): EditorMenuEntry[] {\n return [\n soon(\"help.search\", \"Help\", \"editor.help.search\", { icon: CircleHelp }),\n soon(\"help.training\", \"Training\", \"editor.help.training\", { icon: GraduationCap }),\n soon(\"help.updates\", \"Updates\", \"editor.help.updates\", { icon: Megaphone }),\n ...(opts.sendFeedback\n ? [{ kind: \"action\" as const, id: \"help.feedback\", label: \"Send feedback\", icon: MessageSquareWarning, keywords: [\"report\", \"bug\", \"improve\"], run: opts.sendFeedback }]\n : []),\n sep,\n { kind: \"action\", id: \"help.privacy\", label: \"Privacy Policy\", icon: ShieldCheck, run: () => openPage(\"/privacy-policy\") },\n { kind: \"action\", id: \"help.terms\", label: \"Terms of Service\", icon: FileText, run: () => openPage(\"/terms-of-service\") },\n sep,\n ];\n}\n","/**\n * The Microsoft look's homes for the Google parity rows every editor shares (`google-parity.ts`):\n * the Help group's head and the Automate tab (add-ins, scripts). Spread into each editor's\n * ribbon so the shared rows are placed once, the same way.\n */\n\nimport { CircleHelp, Code2, FileText, GraduationCap, Megaphone, MessageSquareWarning, Puzzle, ShieldCheck } from \"./icons\";\n\nimport type { RibbonControlSpec, RibbonTabSpec } from \"./ribbon-model\";\n\nexport const HELP_HEAD_CONTROLS: RibbonControlSpec[] = [\n { ref: \"help.search\", size: \"large\", icon: CircleHelp },\n { ref: \"help.training\", label: \"Training\", icon: GraduationCap },\n { ref: \"help.updates\", label: \"Updates\", icon: Megaphone },\n { ref: \"help.feedback\", label: \"Feedback\", icon: MessageSquareWarning },\n { ref: \"help.privacy\", label: \"Privacy Policy\", icon: ShieldCheck },\n { ref: \"help.terms\", label: \"Terms of Service\", icon: FileText },\n];\n\nexport const AUTOMATE_TAB: RibbonTabSpec = {\n id: \"automate\",\n label: \"Automate\",\n groups: [\n { id: \"add-ins\", label: \"Add-ins\", controls: [{ ref: \"extensions.add-ons\", size: \"large\", label: \"Add-ins\", icon: Puzzle }] },\n { id: \"scripts\", label: \"Scripts\", controls: [{ ref: \"extensions.scripts\", size: \"large\", label: \"Scripts\", icon: Code2 }] },\n ],\n};\n","/**\n * The ONE page geometry every Matrx cloud document is laid out with.\n *\n * Univer lays a document out inside `documentStyle.pageSize`. With no pageSize\n * the docs renderer has no page box at all: text never wraps (it runs off the\n * right edge) and the vertical extent is unbounded, so the docs viewport\n * reports nothing to scroll — the wheel is swallowed and the page sits frozen\n * at the top. Every writer of a Univer snapshot MUST stamp this style.\n *\n * Consumers: `DocumentEditor` (new empty doc), `markdown-to-univer-doc`\n * (markdown import), and `sanitizeUniverDocSnapshot` (recovery for snapshots\n * that reached storage without it — notably `origin='agent'` writes).\n */\nimport type { DocumentFlavor, IDocumentData, PageOrientType } from \"@univerjs/core\";\n\n// Univer's enum values, written out: this file is read by tests and the markdown importer, which must not\n// pull Univer's runtime in just for four numbers (guarded by the page-style test).\nconst TRADITIONAL = 1 as DocumentFlavor;\nconst MODERN = 2 as DocumentFlavor;\nconst PORTRAIT = 0 as PageOrientType;\nconst LANDSCAPE = 1 as PageOrientType;\n\ntype DocumentStyle = NonNullable<IDocumentData[\"documentStyle\"]>;\n\n/** Univer lays documents out in 96-dpi CSS pixels: one inch is 96 units. */\nexport const PX_PER_INCH = 96;\n\n/** Paper sizes the Page setup dialog offers, in 96-dpi pixels, portrait (width x height). */\nexport const PAPER_SIZES = {\n Letter: { width: 816, height: 1056, label: \"Letter (8.5 x 11 in)\" },\n Legal: { width: 816, height: 1344, label: \"Legal (8.5 x 14 in)\" },\n Tabloid: { width: 1056, height: 1632, label: \"Tabloid (11 x 17 in)\" },\n Executive: { width: 696, height: 1008, label: \"Executive (7.25 x 10.5 in)\" },\n Statement: { width: 528, height: 816, label: \"Statement (5.5 x 8.5 in)\" },\n A3: { width: 1123, height: 1587, label: \"A3 (11.69 x 16.54 in)\" },\n A4: { width: 794, height: 1124, label: \"A4 (8.27 x 11.69 in)\" },\n A5: { width: 559, height: 794, label: \"A5 (5.83 x 8.27 in)\" },\n} as const;\nexport type PaperSizeName = keyof typeof PAPER_SIZES;\n\n/** A real page, like Google Docs: Letter, one-inch margins (624px of text), paginated. */\nexport const DEFAULT_DOCUMENT_PAGE_STYLE: DocumentStyle = {\n pageSize: { width: 816, height: 1056 },\n documentFlavor: TRADITIONAL,\n pageOrient: PORTRAIT,\n marginTop: PX_PER_INCH,\n marginBottom: PX_PER_INCH,\n marginLeft: PX_PER_INCH,\n marginRight: PX_PER_INCH,\n // Univer applies no paragraph spacing to a paginated page by itself; without this every paragraph\n // runs into the next (Google Docs' own default: 1.15 lines, 10px after).\n defaultParagraphStyle: { spaceAbove: { v: 0 }, spaceBelow: { v: 10 }, lineSpacing: 1.15 },\n};\n\n/** Fresh copy — Univer mutates the style it is handed. */\nexport function defaultDocumentPageStyle(): DocumentStyle {\n return {\n ...DEFAULT_DOCUMENT_PAGE_STYLE,\n pageSize: { ...DEFAULT_DOCUMENT_PAGE_STYLE.pageSize! },\n defaultParagraphStyle: { ...DEFAULT_DOCUMENT_PAGE_STYLE.defaultParagraphStyle! },\n };\n}\n\n/**\n * The squeezed geometry every document was stamped with until 2026-10-15: A4 at 72 dpi (595 x 842)\n * with 90/72 margins, in Univer's pageless flavour, so the text column was ~415px with no paper.\n * Pageless was never offered then, so this exact shape is always the old default, never a choice.\n */\nexport function isLegacySqueezedPageStyle(style: DocumentStyle | undefined): boolean {\n const size = style?.pageSize;\n return (\n !!size &&\n size.width === 595 &&\n size.height === 842 &&\n style?.marginLeft === 90 &&\n style?.marginRight === 90 &&\n style?.marginTop === 72 &&\n style?.marginBottom === 72\n );\n}\n\n/** What the Page setup dialog edits. Margins are in inches, like Google's. */\nexport interface PageSetupValues {\n pageless: boolean;\n orientation: \"portrait\" | \"landscape\";\n paper: PaperSizeName;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /** Paper color, hex. Always a light color so the black ink stays readable. */\n pageColor: string;\n}\n\nexport const PAGE_COLORS = [\"#ffffff\", \"#fff8e7\", \"#f3f3f3\", \"#e8f0fe\", \"#e6f4ea\", \"#fef7e0\"] as const;\nexport const DEFAULT_PAGE_COLOR = PAGE_COLORS[0];\n/** Key on `documentStyle` carrying the paper color (Univer paints it from the host's surface theme). */\nexport const PAGE_COLOR_KEY = \"matrxPageColor\";\n\nconst round2 = (n: number) => Math.round(n * 100) / 100;\n\n/** The dialog's values, read from a document's style (missing parts fall back to the default page). */\nexport function pageSetupFromStyle(style: DocumentStyle | undefined): PageSetupValues {\n const landscape = style?.pageOrient === LANDSCAPE;\n const w = style?.pageSize?.width ?? DEFAULT_DOCUMENT_PAGE_STYLE.pageSize!.width!;\n const h = style?.pageSize?.height ?? DEFAULT_DOCUMENT_PAGE_STYLE.pageSize!.height!;\n const [pw, ph] = landscape ? [h, w] : [w, h];\n const paper =\n (Object.keys(PAPER_SIZES) as PaperSizeName[]).find(\n (k) => Math.abs(PAPER_SIZES[k].width - pw) <= 1 && Math.abs(PAPER_SIZES[k].height - ph) <= 1,\n ) ?? \"Letter\";\n const inch = (v: number | undefined) => round2((v ?? PX_PER_INCH) / PX_PER_INCH);\n const color = (style as Record<string, unknown> | undefined)?.[PAGE_COLOR_KEY];\n return {\n pageless: style?.documentFlavor === MODERN,\n orientation: landscape ? \"landscape\" : \"portrait\",\n paper,\n marginTop: inch(style?.marginTop),\n marginBottom: inch(style?.marginBottom),\n marginLeft: inch(style?.marginLeft),\n marginRight: inch(style?.marginRight),\n pageColor: typeof color === \"string\" && color ? color : DEFAULT_PAGE_COLOR,\n };\n}\n\n/** Params for Univer's `docs.command.page-setup` (pageSize is the as-printed size: swapped when landscape). */\nexport function pageSetupCommandParams(v: PageSetupValues) {\n const base = PAPER_SIZES[v.paper];\n const landscape = v.orientation === \"landscape\";\n return {\n documentFlavor: v.pageless ? MODERN : TRADITIONAL,\n pageOrient: landscape ? LANDSCAPE : PORTRAIT,\n pageSize: landscape ? { width: base.height, height: base.width } : { width: base.width, height: base.height },\n marginTop: Math.round(v.marginTop * PX_PER_INCH),\n marginBottom: Math.round(v.marginBottom * PX_PER_INCH),\n marginLeft: Math.round(v.marginLeft * PX_PER_INCH),\n marginRight: Math.round(v.marginRight * PX_PER_INCH),\n };\n}\n","/**\n * Where each Office product lives. The map is CONFIGURATION, not a constant: the app passes its own\n * (production `https://sheets.aimatrx.com`, development `http://sheets.localhost:5190`), so links\n * generated here always match the app that is running.\n *\n * The routes are the same on every host: `/` the product's File Home, `/templates`,\n * `/new?template=<id>`, `/f/<id>` an item.\n */\n\nexport type OfficeProduct = \"sheets\" | \"docs\" | \"slides\" | \"bases\" | \"boards\" | \"pdf\";\n\nexport const OFFICE_PRODUCTS: readonly OfficeProduct[] = [\"sheets\", \"docs\", \"slides\", \"bases\", \"boards\", \"pdf\"];\n\nexport type OfficeHostMap = Record<OfficeProduct, string>;\n\n// Module-level mutable state is banned (a dual ESM/CJS or duplicated bundle would split it): one slot on globalThis.\nconst SLOT = Symbol.for(\"ai-matrx.office.hosts\");\ntype Slot = { map: OfficeHostMap | null };\n\nfunction slot(): Slot {\n const g = globalThis as unknown as Record<symbol, Slot | undefined>;\n let s = g[SLOT];\n if (!s) {\n s = { map: null };\n g[SLOT] = s;\n }\n return s;\n}\n\n/** Set the product → origin map (an origin such as `https://sheets.aimatrx.com`, no trailing slash needed). Call once at start-up. */\nexport function configureOfficeHosts(map: OfficeHostMap): void {\n const cleaned = {} as OfficeHostMap;\n for (const product of OFFICE_PRODUCTS) {\n const origin = map[product];\n if (typeof origin !== \"string\" || !/^https?:\\/\\/[^/\\s]+$/.test(origin.replace(/\\/+$/, \"\"))) {\n throw new Error(`configureOfficeHosts: \"${product}\" needs an origin like \"https://${product}.example.com\", got ${JSON.stringify(origin)}`);\n }\n cleaned[product] = origin.replace(/\\/+$/, \"\");\n }\n slot().map = cleaned;\n}\n\n/** The configured origin of a product. Throws when the app never configured the hosts. */\nexport function officeOrigin(product: OfficeProduct): string {\n const map = slot().map;\n if (!map) throw new Error(\"officeHref: call configureOfficeHosts(map) at start-up before generating Office links\");\n return map[product];\n}\n\n/**\n * An absolute link into a product: no id is its File Home, an id opens that item (`/f/<id>`).\n * `sub` appends a path segment (`officeHref(\"docs\", undefined, { sub: \"templates\" })` is the Templates page).\n */\nexport function officeHref(product: OfficeProduct, id?: string, o?: { sub?: string }): string {\n const origin = officeOrigin(product);\n const sub = o?.sub ? `/${o.sub.replace(/^\\/+/, \"\")}` : \"\";\n if (id === undefined) return `${origin}${sub || \"/\"}`;\n return `${origin}/f/${encodeURIComponent(id)}${sub}`;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/core/index.ts","../src/core/editor-menu-model.ts","../src/core/ribbon-model.ts","../src/core/icons.tsx","../src/core/google-parity.ts","../src/core/ribbon-parity.ts","../src/core/document-page-style.ts","../src/core/hosts.ts"],"sourcesContent":["/**\n * @ai-matrx/office/core — the pure model every Office editor shares. No window access at import, no\n * Univer runtime (page-setup-apply is its own entry, `@ai-matrx/office/core/page-setup-apply`).\n */\nexport * from \"./editor-menu-model\";\nexport * from \"./ribbon-model\";\nexport * from \"./google-parity\";\nexport * from \"./ribbon-parity\";\nexport * from \"./document-page-style\";\nexport * from \"./page-setup\";\nexport * from \"./hosts\";\nexport * from \"./types\";\n","/**\n * The editor chrome's command model — ONE data tree per editor that the menu\n * bar, the \"Menus\" search and the keyboard bindings all read. A row exists\n * only when it runs a real editor command; nothing here is decorative.\n *\n * Pure (no React, no DOM beyond KeyboardEvent shape) so the command mapping is\n * testable with a fake editor port.\n */\n\nimport type { ComponentType, ReactNode } from \"react\";\n\n/** A keyboard shortcut. `mod` is Cmd on a Mac and Ctrl elsewhere. */\nexport type EditorShortcut = {\n key: string;\n mod?: boolean;\n shift?: boolean;\n alt?: boolean;\n /**\n * true: the chrome binds this key itself (the editor engine does not).\n * false/absent: the engine already binds it; the label only tells the truth.\n */\n bind?: boolean;\n};\n\ntype IconType = ComponentType<{ className?: string }>;\n\nexport type EditorMenuAction = {\n kind: \"action\";\n id: string;\n label: string;\n icon?: IconType;\n shortcut?: EditorShortcut;\n /** Extra words the Menus search matches (e.g. \"freeze\" for \"1 row\"). */\n keywords?: string[];\n run: () => unknown;\n checked?: () => boolean;\n /** Only for edit gates (a viewer); never \"not built\". */\n disabled?: () => boolean;\n /**\n * A Google menu row we cannot run yet: the registered Coming Soon id it announces\n * (`lib/coming-soon/editor-menus.ts`). Drawn in muted ink; `run` announces the promise.\n */\n soon?: string;\n};\n\nexport type EditorMenuSubmenu = {\n kind: \"submenu\";\n id: string;\n label: string;\n icon?: IconType;\n keywords?: string[];\n items: EditorMenuEntry[];\n};\n\nexport type EditorMenuSeparator = { kind: \"separator\" };\n\nexport type EditorMenuEntry = EditorMenuAction | EditorMenuSubmenu | EditorMenuSeparator;\n\nexport type EditorMenu = {\n id: string;\n label: string;\n items: EditorMenuEntry[];\n};\n\n/** One runnable row as the Menus search sees it: the action plus its path. */\nexport type FlatEditorAction = EditorMenuAction & { path: string[] };\n\nexport function flattenMenus(menus: EditorMenu[]): FlatEditorAction[] {\n const out: FlatEditorAction[] = [];\n const walk = (entries: EditorMenuEntry[], path: string[], extraKeywords: string[]) => {\n for (const e of entries) {\n if (e.kind === \"separator\") continue;\n if (e.kind === \"submenu\") {\n walk(e.items, [...path, e.label], [...extraKeywords, ...(e.keywords ?? [])]);\n continue;\n }\n out.push({ ...e, path, keywords: [...extraKeywords, ...(e.keywords ?? [])] });\n }\n };\n for (const m of menus) walk(m.items, [m.label], []);\n return out;\n}\n\n/** Search the flattened commands: every word must hit the label, path or keywords. */\nexport function searchActions(actions: FlatEditorAction[], query: string, limit = 12): FlatEditorAction[] {\n const words = query.toLowerCase().split(/\\s+/).filter(Boolean);\n if (!words.length) return [];\n const scored: { a: FlatEditorAction; score: number }[] = [];\n for (const a of actions) {\n const label = a.label.toLowerCase();\n const hay = `${label} ${a.path.join(\" \").toLowerCase()} ${(a.keywords ?? []).join(\" \").toLowerCase()}`;\n if (!words.every((w) => hay.includes(w))) continue;\n const score = label.startsWith(words[0]!) ? 0 : label.includes(words[0]!) ? 1 : 2;\n scored.push({ a, score });\n }\n return scored.sort((x, y) => x.score - y.score).slice(0, limit).map((s) => s.a);\n}\n\nexport function isMacPlatform(): boolean {\n if (typeof navigator === \"undefined\") return true;\n return /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);\n}\n\nconst KEY_LABEL: Record<string, string> = {\n \"\\\\\": \"\\\\\",\n \"/\": \"/\",\n Delete: \"Delete\",\n Backspace: \"Backspace\",\n \"=\": \"+\",\n \"-\": \"-\",\n};\n\n/** \"⌘⇧1\" on a Mac, \"Ctrl+Shift+1\" elsewhere — Google's notation. */\nexport function formatShortcut(s: EditorShortcut, mac = isMacPlatform()): string {\n const key = KEY_LABEL[s.key] ?? (s.key.length === 1 ? s.key.toUpperCase() : s.key);\n if (mac) return `${s.mod ? \"⌘\" : \"\"}${s.alt ? \"⌥\" : \"\"}${s.shift ? \"⇧\" : \"\"}${key}`;\n return [s.mod ? \"Ctrl\" : \"\", s.alt ? \"Alt\" : \"\", s.shift ? \"Shift\" : \"\", key].filter(Boolean).join(\"+\");\n}\n\n/** The physical key of an event (layout-proof for digits and letters under Shift/Alt). */\nfunction eventKey(e: Pick<KeyboardEvent, \"key\" | \"code\">): string {\n if (/^Digit\\d$/.test(e.code)) return e.code.slice(5);\n if (/^Key[A-Z]$/.test(e.code)) return e.code.slice(3).toLowerCase();\n if (e.code === \"Backslash\") return \"\\\\\";\n if (e.code === \"Slash\") return \"/\";\n return e.key.length === 1 ? e.key.toLowerCase() : e.key;\n}\n\nexport function matchesShortcut(\n e: Pick<KeyboardEvent, \"key\" | \"code\" | \"metaKey\" | \"ctrlKey\" | \"shiftKey\" | \"altKey\">,\n s: EditorShortcut,\n mac = isMacPlatform(),\n): boolean {\n const mod = mac ? e.metaKey : e.ctrlKey;\n if (!!s.mod !== mod) return false;\n if (!!s.shift !== e.shiftKey) return false;\n if (!!s.alt !== e.altKey) return false;\n // Named keys (\"ArrowUp\", \"Enter\", \"Delete\") arrive cased; letters arrive lower-cased.\n return eventKey(e).toLowerCase() === s.key.toLowerCase();\n}\n\n/** The actions whose shortcut the chrome binds itself. */\nexport function boundActions(menus: EditorMenu[]): FlatEditorAction[] {\n return flattenMenus(menus).filter((a) => a.shortcut?.bind);\n}\n\ntype ToolbarIconType = ComponentType<{ className?: string }>;\n\n/** One control in an editor's toolbar row (moved unchanged from EditorToolbar.tsx; pure data). */\nexport type EditorToolbarItem =\n | {\n kind: \"button\";\n id: string;\n label: string;\n icon: ToolbarIconType;\n run: () => unknown;\n shortcut?: EditorShortcut;\n active?: boolean;\n disabled?: boolean;\n }\n | { kind: \"separator\"; id: string }\n | {\n kind: \"menu\";\n id: string;\n label: string;\n icon?: ToolbarIconType;\n /** Text shown on the trigger (e.g. \"100%\", \"Arial\"). */\n text?: string;\n /** Trigger width class for text triggers (keeps the row still as text changes). */\n widthClass?: string;\n items: EditorMenuEntry[];\n disabled?: boolean;\n }\n | { kind: \"node\"; id: string; node: ReactNode };\n","/**\n * The Microsoft 365 look's ribbon — a SECOND PRESENTATION of the editor's ONE command map.\n *\n * A ribbon layout is pure data: tabs → groups → controls, where each control names something that\n * already exists in the editor's model by id —\n * - a toolbar item (`tb.bold`, `tb.font`, …) from the same `EditorToolbarItem[]` the Google\n * toolbar draws,\n * - a menu row (`view.freeze`, `data.filter`, …) from the same `EditorMenu[]` the Google menu\n * bar draws (an action runs; a submenu opens as a dropdown),\n * - a whole menu (`menu:help`) as one dropdown.\n * Nothing here runs anything itself, so the two looks cannot drift: `ribbonCoverage` proves every\n * command of the model is reachable from the ribbon (forcing test per editor).\n *\n * Pure (no React) so the mapping is testable with a fake editor host.\n */\n\nimport type { ComponentType } from \"react\";\nimport type {\n EditorMenu,\n EditorMenuAction,\n EditorMenuEntry,\n EditorMenuSubmenu,\n EditorToolbarItem,\n} from \"./editor-menu-model\";\n\ntype IconType = ComponentType<{ className?: string }>;\n\n/**\n * - `large`: icon over a label, a whole column (Office's Paste, Freeze Panes).\n * - `small`: icon + label in a row, three stacked per column.\n * - `icon`: an icon (or value dropdown) in a row of tools (Office's Font group).\n */\nexport type RibbonSize = \"large\" | \"small\" | \"icon\";\n\nexport type RibbonControlSpec = {\n /** A toolbar item id, a menu entry id, or `menu:<menuId>` for a whole menu. */\n ref: string;\n size?: RibbonSize;\n /** Office's own word for the same command (\"Freeze Panes\" for Freeze). */\n label?: string;\n /** An icon for a row that has none in the model (a large control needs one). */\n icon?: IconType;\n};\n\nexport type RibbonGroupSpec = {\n id: string;\n label: string;\n controls: Array<string | RibbonControlSpec>;\n /** Icon rows hold this many tools before wrapping to the next row (default 6). */\n perRow?: number;\n};\n\nexport type RibbonTabSpec = { id: string; label: string; groups: RibbonGroupSpec[] };\n\n/** Menu rows (or whole submenus) the Microsoft ribbon deliberately does not place, with the reason. */\nexport type GoogleOnlyRows = Record<string, string>;\n\nexport type ResolvedRibbonControl =\n | { kind: \"toolbar\"; key: string; size: RibbonSize; label?: string | undefined; icon?: IconType | undefined; item: Exclude<EditorToolbarItem, { kind: \"separator\" }> }\n | { kind: \"action\"; key: string; size: RibbonSize; label?: string | undefined; icon?: IconType | undefined; action: EditorMenuAction }\n | { kind: \"submenu\"; key: string; size: RibbonSize; label?: string | undefined; icon?: IconType | undefined; submenu: Pick<EditorMenuSubmenu, \"id\" | \"label\" | \"icon\" | \"items\"> };\n\nexport type ResolvedRibbonGroup = { id: string; label: string; perRow: number; controls: ResolvedRibbonControl[] };\nexport type ResolvedRibbonTab = { id: string; label: string; groups: ResolvedRibbonGroup[] };\n\ntype Indexed =\n | { kind: \"toolbar\"; item: Exclude<EditorToolbarItem, { kind: \"separator\" }> }\n | { kind: \"action\"; action: EditorMenuAction }\n | { kind: \"submenu\"; submenu: Pick<EditorMenuSubmenu, \"id\" | \"label\" | \"icon\" | \"items\"> };\n\n/** Every addressable command of one editor: toolbar ids, menu entry ids, `menu:<id>`. */\nexport function indexCommands(menus: EditorMenu[], toolbar: EditorToolbarItem[]): Map<string, Indexed> {\n const out = new Map<string, Indexed>();\n const walk = (entries: EditorMenuEntry[]) => {\n for (const e of entries) {\n if (e.kind === \"separator\") continue;\n if (e.kind === \"submenu\") {\n if (!out.has(e.id)) out.set(e.id, { kind: \"submenu\", submenu: e });\n walk(e.items);\n } else if (!out.has(e.id)) out.set(e.id, { kind: \"action\", action: e });\n }\n };\n for (const m of menus) {\n out.set(`menu:${m.id}`, { kind: \"submenu\", submenu: { id: `menu:${m.id}`, label: m.label, items: m.items } });\n walk(m.items);\n }\n for (const t of toolbar) if (t.kind !== \"separator\") out.set(t.id, { kind: \"toolbar\", item: t });\n return out;\n}\n\nconst spec = (c: string | RibbonControlSpec): RibbonControlSpec => (typeof c === \"string\" ? { ref: c } : c);\n\n/**\n * The layout bound to the live model. A control whose id the model does not hold right now (a\n * row that exists only in some states, e.g. \"Remove image\") is left out; empty groups and tabs go.\n */\nexport function resolveRibbon(\n tabs: RibbonTabSpec[],\n menus: EditorMenu[],\n toolbar: EditorToolbarItem[],\n): ResolvedRibbonTab[] {\n const index = indexCommands(menus, toolbar);\n const out: ResolvedRibbonTab[] = [];\n for (const tab of tabs) {\n const groups: ResolvedRibbonGroup[] = [];\n for (const g of tab.groups) {\n const controls: ResolvedRibbonControl[] = [];\n for (const raw of g.controls) {\n const c = spec(raw);\n const hit = index.get(c.ref);\n if (!hit) continue;\n const base = { key: `${tab.id}/${g.id}/${c.ref}`, size: c.size ?? \"small\", label: c.label, icon: c.icon };\n if (hit.kind === \"toolbar\") controls.push({ ...base, kind: \"toolbar\", item: hit.item });\n else if (hit.kind === \"action\") controls.push({ ...base, kind: \"action\", action: hit.action });\n else controls.push({ ...base, kind: \"submenu\", submenu: hit.submenu });\n }\n if (controls.length) groups.push({ id: g.id, label: g.label, perRow: g.perRow ?? 6, controls });\n }\n if (groups.length) out.push({ id: tab.id, label: tab.label, groups });\n }\n return out;\n}\n\nfunction actionIdsIn(entries: EditorMenuEntry[], into: Set<string>) {\n for (const e of entries) {\n if (e.kind === \"separator\") continue;\n if (e.kind === \"submenu\") actionIdsIn(e.items, into);\n else into.add(e.id);\n }\n}\n\n/**\n * What the ribbon can reach vs. what the model holds. `missingActions`: menu rows no ribbon\n * control leads to; `missingToolbar`: toolbar tools absent from the ribbon; `unknownRefs`: layout\n * ids the model does not have (a typo, or a renamed command).\n */\nexport function ribbonCoverage(\n tabs: RibbonTabSpec[],\n menus: EditorMenu[],\n toolbar: EditorToolbarItem[],\n googleOnly: GoogleOnlyRows = {},\n) {\n const index = indexCommands(menus, toolbar);\n const reached = new Set<string>();\n const placedToolbar = new Set<string>();\n const unknownRefs: string[] = [];\n const wholeMenuRefs: string[] = [];\n for (const tab of tabs)\n for (const g of tab.groups)\n for (const raw of g.controls) {\n const c = spec(raw);\n const hit = index.get(c.ref);\n if (!hit) {\n unknownRefs.push(c.ref);\n continue;\n }\n // A whole-menu dropdown (\"menu:edit\") is a catch-all, not a placement: it must not make\n // a new row look covered. Rows are placed by their own id (or their submenu's).\n if (c.ref.startsWith(\"menu:\")) {\n wholeMenuRefs.push(c.ref);\n continue;\n }\n if (hit.kind === \"action\") reached.add(hit.action.id);\n else if (hit.kind === \"submenu\") actionIdsIn(hit.submenu.items, reached);\n else {\n placedToolbar.add(hit.item.id);\n if (hit.item.kind === \"menu\") actionIdsIn(hit.item.items, reached);\n }\n }\n const all = new Set<string>();\n for (const m of menus) actionIdsIn(m.items, all);\n // A toolbar button that is the same command as a reached menu row (same name or same shortcut —\n // Undo, ⌘K) is reachable through that row; it need not be placed twice.\n const flat: EditorMenuAction[] = [];\n const collect = (entries: EditorMenuEntry[]) => {\n for (const e of entries) {\n if (e.kind === \"submenu\") collect(e.items);\n else if (e.kind === \"action\") flat.push(e);\n }\n };\n for (const m of menus) collect(m.items);\n const reachedRows = flat.filter((a) => reached.has(a.id));\n const sameShortcut = (a?: EditorMenuAction[\"shortcut\"], b?: EditorMenuAction[\"shortcut\"]) =>\n !!a && !!b && a.key.toLowerCase() === b.key.toLowerCase() && !!a.mod === !!b.mod && !!a.shift === !!b.shift && !!a.alt === !!b.alt;\n const viaRow = (t: EditorToolbarItem) =>\n t.kind === \"button\" &&\n reachedRows.some((a) => a.label.toLowerCase() === t.label.toLowerCase() || sameShortcut(a.shortcut, t.shortcut));\n // Rows (or whole submenus) the layout declares Google-only, each with a reason.\n const declared = new Set<string>();\n const badGoogleOnly: string[] = [];\n for (const [id, reason] of Object.entries(googleOnly)) {\n const hit = index.get(id);\n if (!hit || !reason.trim()) {\n badGoogleOnly.push(id);\n continue;\n }\n if (hit.kind === \"action\") declared.add(hit.action.id);\n else if (hit.kind === \"submenu\") actionIdsIn(hit.submenu.items, declared);\n else badGoogleOnly.push(id);\n if (hit.kind === \"action\" && reached.has(hit.action.id)) badGoogleOnly.push(id);\n }\n return {\n missingActions: [...all].filter((id) => !reached.has(id) && !declared.has(id)),\n badGoogleOnly,\n wholeMenuRefs,\n missingToolbar: toolbar\n .filter((t) => t.kind !== \"separator\" && t.kind !== \"node\" && !placedToolbar.has(t.id) && !viaRow(t))\n .map((t) => (t as { id: string }).id),\n unknownRefs,\n };\n}\n","/**\n * The eight glyphs the shared Google/Microsoft parity rows use. Drawn once, in\n * `@ai-matrx/design-system/icons` (the one lucide-free glyph home); the names and the 24px default\n * size this module always had are kept here as aliases.\n */\nimport type { ReactElement } from \"react\";\nimport {\n CircleHelpIcon,\n Code2Icon,\n FileTextIcon,\n GraduationCapIcon,\n MegaphoneIcon,\n MessageSquareWarningIcon,\n PuzzleIcon,\n ShieldCheckIcon,\n withDefaultSize,\n} from \"@ai-matrx/design-system/icons\";\n\nexport type OfficeIconProps = { className?: string };\ntype OfficeGlyph = (props: OfficeIconProps) => ReactElement;\n\nexport const CircleHelp: OfficeGlyph = withDefaultSize(CircleHelpIcon, 24);\nexport const Code2: OfficeGlyph = withDefaultSize(Code2Icon, 24);\nexport const FileText: OfficeGlyph = withDefaultSize(FileTextIcon, 24);\nexport const GraduationCap: OfficeGlyph = withDefaultSize(GraduationCapIcon, 24);\nexport const Megaphone: OfficeGlyph = withDefaultSize(MegaphoneIcon, 24);\nexport const MessageSquareWarning: OfficeGlyph = withDefaultSize(MessageSquareWarningIcon, 24);\nexport const Puzzle: OfficeGlyph = withDefaultSize(PuzzleIcon, 24);\nexport const ShieldCheck: OfficeGlyph = withDefaultSize(ShieldCheckIcon, 24);\n","/**\n * Google parity rows the three editors share: a Coming Soon row (`soon`), Google's Extensions\n * menu, and the head of Google's Help menu. Pure data (the announce module loads on click), so\n * the menu builders stay testable without React.\n */\n\nimport { CircleHelp, Code2, FileText, GraduationCap, Megaphone, MessageSquareWarning, Puzzle, ShieldCheck } from \"./icons\";\nimport type { ComponentType } from \"react\";\nimport { openOutbound } from \"@ai-matrx/kit/outbound\";\n\nimport type { EditorMenu, EditorMenuAction, EditorMenuEntry, EditorShortcut } from \"./editor-menu-model\";\n\nexport const sep: EditorMenuEntry = { kind: \"separator\" };\n\n/** A Google row we cannot run yet: muted, and clicking it announces the registered promise. */\nexport function soon(\n id: string,\n label: string,\n promise: string,\n opts: { icon?: ComponentType<{ className?: string }>; keywords?: string[]; shortcut?: EditorShortcut } = {},\n): EditorMenuAction {\n return {\n kind: \"action\",\n id,\n label,\n soon: promise,\n ...opts,\n run: () => import(\"@ai-matrx/kit/coming-soon\").then((m) => m.announceComingSoon(promise)),\n };\n}\n\nexport type GoogleProduct = \"sheets\" | \"docs\" | \"slides\";\n\n/** Google's Extensions menu (the host's own tools follow these rows). */\nexport function googleExtensionsMenu(product: GoogleProduct, built: { macros?: EditorMenuEntry } = {}): EditorMenu {\n return {\n id: \"extensions\",\n label: \"Extensions\",\n items: [\n soon(\"extensions.add-ons\", \"Add-ons\", \"editor.extensions.add-ons\", { icon: Puzzle }),\n ...(product === \"sheets\" && built.macros ? [built.macros] : []),\n soon(\"extensions.scripts\", \"Scripts\", \"editor.extensions.scripts\", { icon: Code2, keywords: [\"apps script\", \"automation\"] }),\n ],\n };\n}\n\nfunction openPage(href: string) {\n if (typeof window !== \"undefined\") openOutbound(href, \"_blank\", \"noopener\");\n}\n\n/** The head of Google's Help menu; the editor's own rows (shortcuts, function list) follow. */\nexport function googleHelpHead(opts: { sendFeedback?: () => void } = {}): EditorMenuEntry[] {\n return [\n soon(\"help.search\", \"Help\", \"editor.help.search\", { icon: CircleHelp }),\n soon(\"help.training\", \"Training\", \"editor.help.training\", { icon: GraduationCap }),\n soon(\"help.updates\", \"Updates\", \"editor.help.updates\", { icon: Megaphone }),\n ...(opts.sendFeedback\n ? [{ kind: \"action\" as const, id: \"help.feedback\", label: \"Send feedback\", icon: MessageSquareWarning, keywords: [\"report\", \"bug\", \"improve\"], run: opts.sendFeedback }]\n : []),\n sep,\n { kind: \"action\", id: \"help.privacy\", label: \"Privacy Policy\", icon: ShieldCheck, run: () => openPage(\"/privacy-policy\") },\n { kind: \"action\", id: \"help.terms\", label: \"Terms of Service\", icon: FileText, run: () => openPage(\"/terms-of-service\") },\n sep,\n ];\n}\n","/**\n * The Microsoft look's homes for the Google parity rows every editor shares (`google-parity.ts`):\n * the Help group's head and the Automate tab (add-ins, scripts). Spread into each editor's\n * ribbon so the shared rows are placed once, the same way.\n */\n\nimport { CircleHelp, Code2, FileText, GraduationCap, Megaphone, MessageSquareWarning, Puzzle, ShieldCheck } from \"./icons\";\n\nimport type { RibbonControlSpec, RibbonTabSpec } from \"./ribbon-model\";\n\nexport const HELP_HEAD_CONTROLS: RibbonControlSpec[] = [\n { ref: \"help.search\", size: \"large\", icon: CircleHelp },\n { ref: \"help.training\", label: \"Training\", icon: GraduationCap },\n { ref: \"help.updates\", label: \"Updates\", icon: Megaphone },\n { ref: \"help.feedback\", label: \"Feedback\", icon: MessageSquareWarning },\n { ref: \"help.privacy\", label: \"Privacy Policy\", icon: ShieldCheck },\n { ref: \"help.terms\", label: \"Terms of Service\", icon: FileText },\n];\n\nexport const AUTOMATE_TAB: RibbonTabSpec = {\n id: \"automate\",\n label: \"Automate\",\n groups: [\n { id: \"add-ins\", label: \"Add-ins\", controls: [{ ref: \"extensions.add-ons\", size: \"large\", label: \"Add-ins\", icon: Puzzle }] },\n { id: \"scripts\", label: \"Scripts\", controls: [{ ref: \"extensions.scripts\", size: \"large\", label: \"Scripts\", icon: Code2 }] },\n ],\n};\n","/**\n * The ONE page geometry every Matrx cloud document is laid out with.\n *\n * Univer lays a document out inside `documentStyle.pageSize`. With no pageSize\n * the docs renderer has no page box at all: text never wraps (it runs off the\n * right edge) and the vertical extent is unbounded, so the docs viewport\n * reports nothing to scroll — the wheel is swallowed and the page sits frozen\n * at the top. Every writer of a Univer snapshot MUST stamp this style.\n *\n * Consumers: `DocumentEditor` (new empty doc), `markdown-to-univer-doc`\n * (markdown import), and `sanitizeUniverDocSnapshot` (recovery for snapshots\n * that reached storage without it — notably `origin='agent'` writes).\n */\nimport type { DocumentFlavor, IDocumentData, PageOrientType } from \"@univerjs/core\";\n\n// Univer's enum values, written out: this file is read by tests and the markdown importer, which must not\n// pull Univer's runtime in just for four numbers (guarded by the page-style test).\nconst TRADITIONAL = 1 as DocumentFlavor;\nconst MODERN = 2 as DocumentFlavor;\nconst PORTRAIT = 0 as PageOrientType;\nconst LANDSCAPE = 1 as PageOrientType;\n\ntype DocumentStyle = NonNullable<IDocumentData[\"documentStyle\"]>;\n\n/** Univer lays documents out in 96-dpi CSS pixels: one inch is 96 units. */\nexport const PX_PER_INCH = 96;\n\n/** Paper sizes the Page setup dialog offers, in 96-dpi pixels, portrait (width x height). */\nexport const PAPER_SIZES = {\n Letter: { width: 816, height: 1056, label: \"Letter (8.5 x 11 in)\" },\n Legal: { width: 816, height: 1344, label: \"Legal (8.5 x 14 in)\" },\n Tabloid: { width: 1056, height: 1632, label: \"Tabloid (11 x 17 in)\" },\n Executive: { width: 696, height: 1008, label: \"Executive (7.25 x 10.5 in)\" },\n Statement: { width: 528, height: 816, label: \"Statement (5.5 x 8.5 in)\" },\n A3: { width: 1123, height: 1587, label: \"A3 (11.69 x 16.54 in)\" },\n A4: { width: 794, height: 1124, label: \"A4 (8.27 x 11.69 in)\" },\n A5: { width: 559, height: 794, label: \"A5 (5.83 x 8.27 in)\" },\n} as const;\nexport type PaperSizeName = keyof typeof PAPER_SIZES;\n\n/** A real page, like Google Docs: Letter, one-inch margins (624px of text), paginated. */\nexport const DEFAULT_DOCUMENT_PAGE_STYLE: DocumentStyle = {\n pageSize: { width: 816, height: 1056 },\n documentFlavor: TRADITIONAL,\n pageOrient: PORTRAIT,\n marginTop: PX_PER_INCH,\n marginBottom: PX_PER_INCH,\n marginLeft: PX_PER_INCH,\n marginRight: PX_PER_INCH,\n // Univer applies no paragraph spacing to a paginated page by itself; without this every paragraph\n // runs into the next (Google Docs' own default: 1.15 lines, 10px after).\n defaultParagraphStyle: { spaceAbove: { v: 0 }, spaceBelow: { v: 10 }, lineSpacing: 1.15 },\n};\n\n/** Fresh copy — Univer mutates the style it is handed. */\nexport function defaultDocumentPageStyle(): DocumentStyle {\n return {\n ...DEFAULT_DOCUMENT_PAGE_STYLE,\n pageSize: { ...DEFAULT_DOCUMENT_PAGE_STYLE.pageSize! },\n defaultParagraphStyle: { ...DEFAULT_DOCUMENT_PAGE_STYLE.defaultParagraphStyle! },\n };\n}\n\n/**\n * The squeezed geometry every document was stamped with until 2026-10-15: A4 at 72 dpi (595 x 842)\n * with 90/72 margins, in Univer's pageless flavour, so the text column was ~415px with no paper.\n * Pageless was never offered then, so this exact shape is always the old default, never a choice.\n */\nexport function isLegacySqueezedPageStyle(style: DocumentStyle | undefined): boolean {\n const size = style?.pageSize;\n return (\n !!size &&\n size.width === 595 &&\n size.height === 842 &&\n style?.marginLeft === 90 &&\n style?.marginRight === 90 &&\n style?.marginTop === 72 &&\n style?.marginBottom === 72\n );\n}\n\n/** What the Page setup dialog edits. Margins are in inches, like Google's. */\nexport interface PageSetupValues {\n pageless: boolean;\n orientation: \"portrait\" | \"landscape\";\n paper: PaperSizeName;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /** Paper color, hex. Always a light color so the black ink stays readable. */\n pageColor: string;\n}\n\nexport const PAGE_COLORS = [\"#ffffff\", \"#fff8e7\", \"#f3f3f3\", \"#e8f0fe\", \"#e6f4ea\", \"#fef7e0\"] as const;\nexport const DEFAULT_PAGE_COLOR = PAGE_COLORS[0];\n/** Key on `documentStyle` carrying the paper color (Univer paints it from the host's surface theme). */\nexport const PAGE_COLOR_KEY = \"matrxPageColor\";\n\nconst round2 = (n: number) => Math.round(n * 100) / 100;\n\n/** The dialog's values, read from a document's style (missing parts fall back to the default page). */\nexport function pageSetupFromStyle(style: DocumentStyle | undefined): PageSetupValues {\n const landscape = style?.pageOrient === LANDSCAPE;\n const w = style?.pageSize?.width ?? DEFAULT_DOCUMENT_PAGE_STYLE.pageSize!.width!;\n const h = style?.pageSize?.height ?? DEFAULT_DOCUMENT_PAGE_STYLE.pageSize!.height!;\n const [pw, ph] = landscape ? [h, w] : [w, h];\n const paper =\n (Object.keys(PAPER_SIZES) as PaperSizeName[]).find(\n (k) => Math.abs(PAPER_SIZES[k].width - pw) <= 1 && Math.abs(PAPER_SIZES[k].height - ph) <= 1,\n ) ?? \"Letter\";\n const inch = (v: number | undefined) => round2((v ?? PX_PER_INCH) / PX_PER_INCH);\n const color = (style as Record<string, unknown> | undefined)?.[PAGE_COLOR_KEY];\n return {\n pageless: style?.documentFlavor === MODERN,\n orientation: landscape ? \"landscape\" : \"portrait\",\n paper,\n marginTop: inch(style?.marginTop),\n marginBottom: inch(style?.marginBottom),\n marginLeft: inch(style?.marginLeft),\n marginRight: inch(style?.marginRight),\n pageColor: typeof color === \"string\" && color ? color : DEFAULT_PAGE_COLOR,\n };\n}\n\n/** Params for Univer's `docs.command.page-setup` (pageSize is the as-printed size: swapped when landscape). */\nexport function pageSetupCommandParams(v: PageSetupValues) {\n const base = PAPER_SIZES[v.paper];\n const landscape = v.orientation === \"landscape\";\n return {\n documentFlavor: v.pageless ? MODERN : TRADITIONAL,\n pageOrient: landscape ? LANDSCAPE : PORTRAIT,\n pageSize: landscape ? { width: base.height, height: base.width } : { width: base.width, height: base.height },\n marginTop: Math.round(v.marginTop * PX_PER_INCH),\n marginBottom: Math.round(v.marginBottom * PX_PER_INCH),\n marginLeft: Math.round(v.marginLeft * PX_PER_INCH),\n marginRight: Math.round(v.marginRight * PX_PER_INCH),\n };\n}\n","/**\n * Where each Office product lives. The map is CONFIGURATION, not a constant: the app passes its own\n * (production `https://sheets.aimatrx.com`, development `http://sheets.localhost:5190`), so links\n * generated here always match the app that is running.\n *\n * The routes are the same on every host: `/` the product's File Home, `/templates`,\n * `/new?template=<id>`, `/f/<id>` an item.\n */\n\nexport type OfficeProduct = \"sheets\" | \"docs\" | \"slides\" | \"bases\" | \"boards\" | \"pdf\";\n\nexport const OFFICE_PRODUCTS: readonly OfficeProduct[] = [\"sheets\", \"docs\", \"slides\", \"bases\", \"boards\", \"pdf\"];\n\nexport type OfficeHostMap = Record<OfficeProduct, string>;\n\n// Module-level mutable state is banned (a dual ESM/CJS or duplicated bundle would split it): one slot on globalThis.\nconst SLOT = Symbol.for(\"ai-matrx.office.hosts\");\ntype Slot = { map: OfficeHostMap | null };\n\nfunction slot(): Slot {\n const g = globalThis as unknown as Record<symbol, Slot | undefined>;\n let s = g[SLOT];\n if (!s) {\n s = { map: null };\n g[SLOT] = s;\n }\n return s;\n}\n\n/** Set the product → origin map (an origin such as `https://sheets.aimatrx.com`, no trailing slash needed). Call once at start-up. */\nexport function configureOfficeHosts(map: OfficeHostMap): void {\n const cleaned = {} as OfficeHostMap;\n for (const product of OFFICE_PRODUCTS) {\n const origin = map[product];\n if (typeof origin !== \"string\" || !/^https?:\\/\\/[^/\\s]+$/.test(origin.replace(/\\/+$/, \"\"))) {\n throw new Error(`configureOfficeHosts: \"${product}\" needs an origin like \"https://${product}.example.com\", got ${JSON.stringify(origin)}`);\n }\n cleaned[product] = origin.replace(/\\/+$/, \"\");\n }\n slot().map = cleaned;\n}\n\n/** The configured origin of a product. Throws when the app never configured the hosts. */\nexport function officeOrigin(product: OfficeProduct): string {\n const map = slot().map;\n if (!map) throw new Error(\"officeHref: call configureOfficeHosts(map) at start-up before generating Office links\");\n return map[product];\n}\n\n/**\n * An absolute link into a product: no id is its File Home, an id opens that item (`/f/<id>`).\n * `sub` appends a path segment (`officeHref(\"docs\", undefined, { sub: \"templates\" })` is the Templates page).\n */\nexport function officeHref(product: OfficeProduct, id?: string, o?: { sub?: string }): string {\n const origin = officeOrigin(product);\n const sub = o?.sub ? `/${o.sub.replace(/^\\/+/, \"\")}` : \"\";\n if (id === undefined) return `${origin}${sub || \"/\"}`;\n return `${origin}/f/${encodeURIComponent(id)}${sub}`;\n}\n"],"mappings":"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","names":[]}
|
package/dist/core.js
CHANGED
|
@@ -173,82 +173,25 @@ function ribbonCoverage(tabs, menus, toolbar, googleOnly = {}) {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
// src/core/icons.tsx
|
|
176
|
-
import {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
);
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
var CircleHelp = glyph(
|
|
200
|
-
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
201
|
-
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
202
|
-
/* @__PURE__ */ jsx("path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" }),
|
|
203
|
-
/* @__PURE__ */ jsx("path", { d: "M12 17h.01" })
|
|
204
|
-
] })
|
|
205
|
-
);
|
|
206
|
-
var Code2 = glyph(
|
|
207
|
-
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
208
|
-
/* @__PURE__ */ jsx("path", { d: "m18 16 4-4-4-4" }),
|
|
209
|
-
/* @__PURE__ */ jsx("path", { d: "m6 8-4 4 4 4" }),
|
|
210
|
-
/* @__PURE__ */ jsx("path", { d: "m14.5 4-5 16" })
|
|
211
|
-
] })
|
|
212
|
-
);
|
|
213
|
-
var FileText = glyph(
|
|
214
|
-
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
215
|
-
/* @__PURE__ */ jsx("path", { d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z" }),
|
|
216
|
-
/* @__PURE__ */ jsx("path", { d: "M14 2v5a1 1 0 0 0 1 1h5" }),
|
|
217
|
-
/* @__PURE__ */ jsx("path", { d: "M10 9H8" }),
|
|
218
|
-
/* @__PURE__ */ jsx("path", { d: "M16 13H8" }),
|
|
219
|
-
/* @__PURE__ */ jsx("path", { d: "M16 17H8" })
|
|
220
|
-
] })
|
|
221
|
-
);
|
|
222
|
-
var GraduationCap = glyph(
|
|
223
|
-
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
224
|
-
/* @__PURE__ */ jsx("path", { d: "M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z" }),
|
|
225
|
-
/* @__PURE__ */ jsx("path", { d: "M22 10v6" }),
|
|
226
|
-
/* @__PURE__ */ jsx("path", { d: "M6 12.5V16a6 3 0 0 0 12 0v-3.5" })
|
|
227
|
-
] })
|
|
228
|
-
);
|
|
229
|
-
var Megaphone = glyph(
|
|
230
|
-
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
231
|
-
/* @__PURE__ */ jsx("path", { d: "M11 6a13 13 0 0 0 8.4-2.8A1 1 0 0 1 21 4v12a1 1 0 0 1-1.6.8A13 13 0 0 0 11 14H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2z" }),
|
|
232
|
-
/* @__PURE__ */ jsx("path", { d: "M6 14a12 12 0 0 0 2.4 7.2 2 2 0 0 0 3.2-2.4A8 8 0 0 1 10 14" }),
|
|
233
|
-
/* @__PURE__ */ jsx("path", { d: "M8 6v8" })
|
|
234
|
-
] })
|
|
235
|
-
);
|
|
236
|
-
var MessageSquareWarning = glyph(
|
|
237
|
-
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
238
|
-
/* @__PURE__ */ jsx("path", { d: "M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z" }),
|
|
239
|
-
/* @__PURE__ */ jsx("path", { d: "M12 15h.01" }),
|
|
240
|
-
/* @__PURE__ */ jsx("path", { d: "M12 7v4" })
|
|
241
|
-
] })
|
|
242
|
-
);
|
|
243
|
-
var Puzzle = glyph(
|
|
244
|
-
/* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("path", { d: "M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z" }) })
|
|
245
|
-
);
|
|
246
|
-
var ShieldCheck = glyph(
|
|
247
|
-
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
248
|
-
/* @__PURE__ */ jsx("path", { d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" }),
|
|
249
|
-
/* @__PURE__ */ jsx("path", { d: "m9 12 2 2 4-4" })
|
|
250
|
-
] })
|
|
251
|
-
);
|
|
176
|
+
import {
|
|
177
|
+
CircleHelpIcon,
|
|
178
|
+
Code2Icon,
|
|
179
|
+
FileTextIcon,
|
|
180
|
+
GraduationCapIcon,
|
|
181
|
+
MegaphoneIcon,
|
|
182
|
+
MessageSquareWarningIcon,
|
|
183
|
+
PuzzleIcon,
|
|
184
|
+
ShieldCheckIcon,
|
|
185
|
+
withDefaultSize
|
|
186
|
+
} from "@ai-matrx/design-system/icons";
|
|
187
|
+
var CircleHelp = withDefaultSize(CircleHelpIcon, 24);
|
|
188
|
+
var Code2 = withDefaultSize(Code2Icon, 24);
|
|
189
|
+
var FileText = withDefaultSize(FileTextIcon, 24);
|
|
190
|
+
var GraduationCap = withDefaultSize(GraduationCapIcon, 24);
|
|
191
|
+
var Megaphone = withDefaultSize(MegaphoneIcon, 24);
|
|
192
|
+
var MessageSquareWarning = withDefaultSize(MessageSquareWarningIcon, 24);
|
|
193
|
+
var Puzzle = withDefaultSize(PuzzleIcon, 24);
|
|
194
|
+
var ShieldCheck = withDefaultSize(ShieldCheckIcon, 24);
|
|
252
195
|
|
|
253
196
|
// src/core/google-parity.ts
|
|
254
197
|
import { openOutbound } from "@ai-matrx/kit/outbound";
|