@ai-matrx/office 0.8.6 → 0.8.7
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 +15 -1
- package/dist/sheets.cjs +3 -3
- package/dist/sheets.cjs.map +1 -1
- package/dist/sheets.d.cts +2 -2
- package/dist/sheets.d.ts +2 -2
- package/dist/sheets.js +3 -3
- package/dist/sheets.js.map +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.8.
|
|
3
|
+
## 0.8.7
|
|
4
4
|
|
|
5
5
|
UNVERIFIED: this release has no Unreleased entry and the source comparison could not be made (the caller supplied no source comparison). Whether source changed is unknown; consumer action is unknown.
|
|
6
6
|
Check the package's gitHead on npm against this version's gitHead: `git diff <previous gitHead> <this gitHead> -- apps/shared/office/src`.
|
|
7
7
|
|
|
8
|
+
## 0.8.6
|
|
9
|
+
|
|
10
|
+
Automatic changed-only republish (docs/metadata drift since the last published version; verified: `git diff 6fa7cb3c19 51a788b7e7 -- apps/shared/office/src`
|
|
11
|
+
has no shipped-source changes outside tests, fixtures and docs). No consumer action required.
|
|
12
|
+
|
|
13
|
+
## 0.8.5
|
|
14
|
+
|
|
15
|
+
SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
|
|
16
|
+
so they may include breaking API changes. Consumer action is UNKNOWN: read the diff before upgrading.
|
|
17
|
+
Diff: `git diff 04ca2e385c 6fa7cb3c19 -- apps/shared/office/src`
|
|
18
|
+
|
|
19
|
+
Changed shipped source files (1):
|
|
20
|
+
- `apps/shared/office/src/sheets/sheet-output.ts`
|
|
21
|
+
|
|
8
22
|
## 0.8.4
|
|
9
23
|
|
|
10
24
|
- Bold, italic, code and strike of markdown written into a document were dropped (live: `**notes**` pasted into a blank document stayed plain; the same for the agent body write and building blocks). Cause: Univer's text insert returns early when the target body has no `textRuns` array, and a blank document has none. `sanitizeUniverDocSnapshot` now gives every body an empty `textRuns`. Test: `a-document-keeps-the-styles-of-text-written-into-it.test.ts` (red on 0.8.3).
|
package/dist/sheets.cjs
CHANGED
|
@@ -716,7 +716,7 @@ function pageHtml(sheet, page, scale, colWidths, g, setup, numbering) {
|
|
|
716
716
|
<table style="width:${tableW}px;table-layout:fixed;border-collapse:collapse;transform:scale(${scale});transform-origin:0 0;font:12px/${PRINT_ROW_HEIGHT - 2}px system-ui,sans-serif;color:#111"><colgroup>${cols}</colgroup><tbody>${body}</tbody></table>
|
|
717
717
|
</div></div></section>`;
|
|
718
718
|
}
|
|
719
|
-
function
|
|
719
|
+
function buildSheetPrintDocument(sheets, setup) {
|
|
720
720
|
const out = [];
|
|
721
721
|
let geometry = null;
|
|
722
722
|
for (const sheet of sheets) {
|
|
@@ -787,7 +787,7 @@ function printDocumentFor(snapshot, options) {
|
|
|
787
787
|
...options.sheetId ? { sheetId: options.sheetId } : {},
|
|
788
788
|
selection: _nullishCoalesce(options.selection, () => ( null))
|
|
789
789
|
});
|
|
790
|
-
return
|
|
790
|
+
return buildSheetPrintDocument(sheets, options.setup);
|
|
791
791
|
}
|
|
792
792
|
function printSheet(snapshot, options) {
|
|
793
793
|
const doc = printDocumentFor(snapshot, options);
|
|
@@ -917,5 +917,5 @@ function readWorkbookScopeSource(workbookId) {
|
|
|
917
917
|
|
|
918
918
|
|
|
919
919
|
|
|
920
|
-
exports.DEFAULT_SHEET_PAGE_SETUP = DEFAULT_SHEET_PAGE_SETUP; exports.GRID_MAX_COLUMNS = GRID_MAX_COLUMNS; exports.GRID_MAX_ROWS = GRID_MAX_ROWS; exports.MARGIN_PRESET_INCHES = MARGIN_PRESET_INCHES; exports.PRINT_ROW_HEIGHT = PRINT_ROW_HEIGHT; exports.SHEET_MARGIN_PRESETS = SHEET_MARGIN_PRESETS; exports.SHEET_PRINT_SCOPES = SHEET_PRINT_SCOPES; exports.SHEET_SCALES = SHEET_SCALES; exports.THUMB_HEIGHT = THUMB_HEIGHT; exports.THUMB_WIDTH = THUMB_WIDTH; exports.
|
|
920
|
+
exports.DEFAULT_SHEET_PAGE_SETUP = DEFAULT_SHEET_PAGE_SETUP; exports.GRID_MAX_COLUMNS = GRID_MAX_COLUMNS; exports.GRID_MAX_ROWS = GRID_MAX_ROWS; exports.MARGIN_PRESET_INCHES = MARGIN_PRESET_INCHES; exports.PRINT_ROW_HEIGHT = PRINT_ROW_HEIGHT; exports.SHEET_MARGIN_PRESETS = SHEET_MARGIN_PRESETS; exports.SHEET_PRINT_SCOPES = SHEET_PRINT_SCOPES; exports.SHEET_SCALES = SHEET_SCALES; exports.THUMB_HEIGHT = THUMB_HEIGHT; exports.THUMB_WIDTH = THUMB_WIDTH; exports.buildSheetPrintDocument = buildSheetPrintDocument; exports.cfMatch = cfMatch; exports.collectPrintSheets = collectPrintSheets; exports.configureSheetsHost = _chunkZDZCCOUBcjs.configureSheetsHost; exports.copyWorkbook = _chunkZDZCCOUBcjs.copyWorkbook; exports.createWorkbook = _chunkZDZCCOUBcjs.createWorkbook; exports.deleteWorkbook = _chunkZDZCCOUBcjs.deleteWorkbook; exports.discardFailedWorkbook = _chunkZDZCCOUBcjs.discardFailedWorkbook; exports.documentPreviewSvg = documentPreviewSvg; exports.downloadSheetAsCsv = downloadSheetAsCsv; exports.downloadSheetAsHtml = downloadSheetAsHtml; exports.downloadSheetAsPdf = downloadSheetAsPdf; exports.downloadSheetAsTsv = downloadSheetAsTsv; exports.formatCellValue = formatCellValue; exports.getLatestSnapshot = _chunkZDZCCOUBcjs.getLatestSnapshot; exports.getSheetsHost = _chunkZDZCCOUBcjs.getSheetsHost; exports.getWorkbook = _chunkZDZCCOUBcjs.getWorkbook; exports.listAccessibleWorkbooks = _chunkZDZCCOUBcjs.listAccessibleWorkbooks; exports.listSnapshots = _chunkZDZCCOUBcjs.listSnapshots; exports.listTrashedWorkbooks = _chunkZDZCCOUBcjs.listTrashedWorkbooks; exports.moveWorkbook = _chunkZDZCCOUBcjs.moveWorkbook; exports.normalizeSheetPageSetup = normalizeSheetPageSetup; exports.pageSetupFromMetadata = pageSetupFromMetadata; exports.parseResource = parseResource; exports.planSheetPrint = planSheetPrint; exports.printColumnWidths = printColumnWidths; exports.printDocumentHtml = printDocumentHtml; exports.printGeometry = printGeometry; exports.printSheet = printSheet; exports.readSheetPageSetup = readSheetPageSetup; exports.readWorkbookScopeSource = readWorkbookScopeSource; exports.registerWorkbookScopeSource = registerWorkbookScopeSource; exports.renameWorkbook = _chunkZDZCCOUBcjs.renameWorkbook; exports.restoreWorkbook = _chunkZDZCCOUBcjs.restoreWorkbook; exports.saveSnapshot = _chunkZDZCCOUBcjs.saveSnapshot; exports.sheetGridToCsv = sheetGridToCsv; exports.sheetGridToMarkdownTable = sheetGridToMarkdownTable; exports.snapshotPreviewSvg = snapshotPreviewSvg; exports.snapshotToGridSheets = snapshotToGridSheets; exports.univerSheetIds = univerSheetIds; exports.univerSnapshotToRows = univerSnapshotToRows; exports.updateWorkbookDescription = _chunkZDZCCOUBcjs.updateWorkbookDescription; exports.workbookPreviewSvg = workbookPreviewSvg; exports.workbookSourceLabel = _chunkZDZCCOUBcjs.workbookSourceLabel; exports.writeSheetPageSetup = writeSheetPageSetup;
|
|
921
921
|
//# sourceMappingURL=sheets.cjs.map
|
package/dist/sheets.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/aidream/aidream/apps/shared/office/dist/sheets.cjs","../src/sheets/univer-snapshot-rows.ts","../src/sheets/snapshot-preview-svg.ts","../src/sheets/snapshot-grid.ts","../src/core/document-page-style.ts","../src/sheets/sheet-page-setup.ts","../src/sheets/sheet-page-setup-service.ts","../src/sheets/sheet-print-pages.ts","../src/sheets/sheet-output.ts","../src/sheets/workbook-scope-source.ts"],"names":["current"],"mappings":"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A;AACO,EAAA;AACvB,EAAA;AACT;AAIE;AAGa,EAAA;AACU,EAAA;AACQ,EAAA;AACF,EAAA;AACN,EAAA;AACC,EAAA;AACjB,EAAA;AACT;AAIE;AAGa,EAAA;AACU,EAAA;AACK,EAAA;AACf,EAAA;AAAyG;AAAA;AAGlH;AAAA,sBAAA;AAE4B,EAAA;AACR,EAAA;AACjB,EAAA;AACT;AAEgC;AACE,EAAA;AAClC;AAW0B;AACT,EAAA;AACW,IAAA;AACL,IAAA;AACpB,EAAA;AACyB,EAAA;AAC5B;AAG8C;AACf,EAAA;AACZ,EAAA;AACc,EAAA;AACR,EAAA;AACD,EAAA;AACS,EAAA;AACZ,EAAA;AACD,EAAA;AACC,EAAA;AACJ,IAAA;AACN,IAAA;AACT,EAAA;AACU,EAAA;AACK,EAAA;AACJ,EAAA;AACU,EAAA;AACX,EAAA;AACA,EAAA;AACH,EAAA;AACT;AAGyC;AACT,EAAA;AACC,EAAA;AACmB,EAAA;AAErC,EAAA;AACW,EAAA;AACQ,EAAA;AAClC;AAMyC;AACV,EAAA;AACZ,EAAA;AACO,EAAA;AACf,IAAA;AACA,IAAA;AACR,EAAA;AACqB,EAAA;AACJ,EAAA;AACG,EAAA;AACJ,EAAA;AACa,EAAA;AAC1B,EAAA;AACa,IAAA;AACa,IAAA;AACN,MAAA;AACA,MAAA;AACtB,IAAA;AACwC,IAAA;AACX,IAAA;AACV,MAAA;AACX,MAAA;AACmB,MAAA;AAC1B,IAAA;AAC6B,IAAA;AAC9B,EAAA;AACY,IAAA;AACd,EAAA;AACO,EAAA;AACT;AR0rBkC;AACA;AS9yBC;AAGnB;AAGJ,EAAA;AACG,EAAA;AACmB,IAAA;AAChC,EAAA;AACF;AAQE;AAEwB,EAAA;AACJ,EAAA;AACtB;AToyBkC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/aidream/aidream/apps/shared/office/dist/sheets.cjs","sourcesContent":[null,"/**\n * features/workbooks/univer-snapshot-rows.ts\n *\n * Snapshot → rows: read a Univer `IWorkbookData` snapshot back out as a plain\n * string grid. The missing half of the workbook round trip — `export-targets`\n * pushes rows INTO a workbook; this reads the (possibly user-edited) values\n * back OUT so features can offer \"edit in the workbook, then import your\n * changes\". Values only (formulas come back as their cached value); first\n * sheet by `sheetOrder` unless a sheet id is named. A number shown through a date format reads as\n * its ISO date (a spreadsheet keeps dates as day serials). Reusable — do not fork a per-feature\n * snapshot walker. Callers: the workbook's \"Make this sheet a table\" (features/workbooks/table-link).\n */\n\ninterface CellShape {\n v?: unknown;\n s?: unknown;\n}\n\ninterface SheetShape {\n name?: string;\n /** Frozen panes: `xSplit` columns and `ySplit` rows are pinned. */\n freeze?: { xSplit?: number; ySplit?: number } | null;\n /** Univer marks a hidden column/row `hd: 1` (a table link's Record ID column is one). */\n columnData?: Record<string, { hd?: number } | null | undefined>;\n rowData?: Record<string, { hd?: number } | null | undefined>;\n cellData?: Record<string, Record<string, CellShape | null | undefined>>;\n}\n\ninterface SnapshotShape {\n sheetOrder?: string[];\n sheets?: Record<string, SheetShape>;\n styles?: Record<string, { n?: { pattern?: string } | null } | null>;\n}\n\nexport interface SnapshotRows {\n sheetName: string;\n /** Dense rectangular grid, trailing empty rows/columns trimmed. */\n rows: string[][];\n /** Rows pinned at the top of the sheet (Freeze rows), counted in `rows`. */\n frozenRows: number;\n /** Columns pinned at the left of the sheet (Freeze columns), counted in each row. */\n frozenCols: number;\n}\n\n/** A zero-based, inclusive cell range (a selection). */\nexport interface CellRange {\n startRow: number;\n endRow: number;\n startColumn: number;\n endColumn: number;\n}\n\n/** Sheet ids in tab order. */\nexport function univerSheetIds(snapshot: unknown): string[] {\n if (typeof snapshot !== \"object\" || snapshot === null) return [];\n const shape = snapshot as SnapshotShape;\n const sheets = shape.sheets ?? {};\n const ordered = (shape.sheetOrder ?? []).filter((id) => sheets[id]);\n return ordered.length ? ordered : Object.keys(sheets);\n}\n\ntype Styles = SnapshotShape[\"styles\"];\n\n/** The number-format pattern a cell is shown through, if any. */\nfunction patternOf(cell: CellShape | null | undefined, styles: Styles): string | null {\n const s = cell?.s;\n const style = typeof s === \"string\" ? styles?.[s] : s && typeof s === \"object\" ? (s as { n?: { pattern?: string } }) : null;\n const pattern = style?.n?.pattern;\n return typeof pattern === \"string\" ? pattern : null;\n}\n\nconst DAY_MS = 86_400_000;\nconst SERIAL_EPOCH_MS = Date.UTC(1899, 11, 30);\n\nfunction cellText(cell: CellShape | null | undefined, styles?: Styles): string {\n const value = cell?.v;\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"number\") {\n const pattern = patternOf(cell, styles)?.replace(/\"[^\"]*\"/g, \"\").toLowerCase() ?? \"\";\n if (/[dy]/.test(pattern)) {\n const iso = new Date(Math.round(SERIAL_EPOCH_MS + value * DAY_MS)).toISOString();\n return /h/.test(pattern) ? `${iso.slice(0, 10)} ${iso.slice(11, 16)}` : iso.slice(0, 10);\n }\n }\n return String(value);\n}\n\n/**\n * Extract the first worksheet of a Univer workbook snapshot as a string grid.\n * Returns null when the value is not snapshot-shaped or has no sheets.\n * `skipHidden` leaves out hidden columns and rows: every read-only view (a share page, an agent's\n * read) passes it, so the table link's hidden Record ID column never reaches a reader.\n */\nexport function univerSnapshotToRows(snapshot: unknown, options: { sheetId?: string; skipHidden?: boolean; range?: CellRange } = {}): SnapshotRows | null {\n if (typeof snapshot !== \"object\" || snapshot === null) return null;\n const shape = snapshot as SnapshotShape;\n const sheets = shape.sheets ?? {};\n const styles = shape.styles;\n const firstId = options.sheetId\n ? sheets[options.sheetId]\n ? options.sheetId\n : undefined\n : (shape.sheetOrder?.find((id) => sheets[id]) ?? Object.keys(sheets)[0]);\n if (!firstId) return null;\n const sheet = sheets[firstId];\n const cellData = sheet?.cellData ?? {};\n\n let maxRow = -1;\n let maxCol = -1;\n for (const [rowKey, row] of Object.entries(cellData)) {\n const rowIndex = Number(rowKey);\n if (!Number.isInteger(rowIndex) || !row) continue;\n for (const [colKey, cell] of Object.entries(row)) {\n const colIndex = Number(colKey);\n if (!Number.isInteger(colIndex)) continue;\n if (cellText(cell) === \"\") continue;\n if (rowIndex > maxRow) maxRow = rowIndex;\n if (colIndex > maxCol) maxCol = colIndex;\n }\n }\n const range = options.range;\n if (range) {\n // A selection prints exactly the cells chosen, empty ones included.\n maxRow = range.endRow;\n maxCol = range.endColumn;\n }\n if (maxRow < 0 || maxCol < 0) {\n return { sheetName: sheet?.name ?? \"Sheet1\", rows: [], frozenRows: 0, frozenCols: 0 };\n }\n const firstRow = range?.startRow ?? 0;\n const firstCol = range?.startColumn ?? 0;\n\n const hiddenCol = (c: number) => options.skipHidden === true && sheet?.columnData?.[String(c)]?.hd === 1;\n const hiddenRow = (r: number) => options.skipHidden === true && sheet?.rowData?.[String(r)]?.hd === 1;\n const rows: string[][] = [];\n const ySplit = Math.max(0, sheet?.freeze?.ySplit ?? 0);\n const xSplit = Math.max(0, sheet?.freeze?.xSplit ?? 0);\n let frozenRows = 0;\n let frozenCols = 0;\n for (let r = firstRow; r <= maxRow; r += 1) {\n if (hiddenRow(r)) continue;\n if (r < ySplit) frozenRows += 1;\n const row: string[] = [];\n const source = cellData[String(r)] ?? {};\n let colsFrozenHere = 0;\n for (let c = firstCol; c <= maxCol; c += 1) {\n if (hiddenCol(c)) continue;\n if (c < xSplit) colsFrozenHere += 1;\n row.push(cellText(source[String(c)], styles));\n }\n frozenCols = colsFrozenHere;\n rows.push(row);\n }\n return { sheetName: sheet?.name ?? \"Sheet1\", rows, frozenRows, frozenCols };\n}\n","/**\n * snapshot → SVG: a faithful miniature of a Univer workbook's first sheet or a\n * Univer document's first page — the gallery tile Google draws. Pure (no DOM,\n * no Univer runtime), so it runs in the browser (thumbnail capture), in tests\n * and in node. Reads only what a snapshot stores: cell values + styles +\n * column widths + merges + conditional formats + checkboxes for sheets; the\n * dataStream + text runs + paragraph styles + tables for documents.\n */\n\nexport const THUMB_WIDTH = 320;\nexport const THUMB_HEIGHT = 414;\n\ntype Rgb = { rgb?: string | null } | null | undefined;\ntype CellStyle = {\n bg?: Rgb;\n cl?: Rgb;\n bl?: number;\n it?: number;\n fs?: number;\n ht?: number;\n n?: { pattern?: string } | null;\n bd?: Record<string, unknown> | null;\n};\ntype Cell = { v?: unknown; s?: string | CellStyle | null; t?: number; f?: string };\ntype Sheet = {\n id?: string;\n name?: string;\n cellData?: Record<string, Record<string, Cell>>;\n columnData?: Record<string, { w?: number; hd?: number }>;\n rowData?: Record<string, { h?: number; hd?: number }>;\n defaultColumnWidth?: number;\n defaultRowHeight?: number;\n mergeData?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n showGridlines?: number;\n freeze?: { ySplit?: number; xSplit?: number };\n};\nexport type Workbook = {\n sheetOrder?: string[];\n sheets?: Record<string, Sheet>;\n styles?: Record<string, CellStyle | null>;\n resources?: Array<{ name?: string; data?: string }>;\n};\n\nconst esc = (s: string) =>\n s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n\nfunction color(c: Rgb, fallback: string): string {\n const v = c?.rgb;\n return typeof v === \"string\" && v.length > 0 ? v : fallback;\n}\n\n// ─── number formats ──────────────────────────────────────────────────────────\n\nconst EXCEL_EPOCH = Date.UTC(1899, 11, 30);\nconst MONTHS = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n\nexport function formatCellValue(v: unknown, pattern?: string | null): string {\n if (v === null || v === undefined) return \"\";\n if (typeof v === \"boolean\") return v ? \"TRUE\" : \"FALSE\";\n if (typeof v !== \"number\" || !pattern || pattern === \"General\") return String(v);\n const p = pattern.toLowerCase();\n if (/[dy]/.test(p) && !p.includes(\"$\")) {\n const d = new Date(EXCEL_EPOCH + Math.round(v) * 86400000);\n const mm = d.getUTCMonth();\n const dd = d.getUTCDate();\n const yy = d.getUTCFullYear();\n if (p.includes(\"mmm\")) return `${MONTHS[mm]} ${dd}${p.includes(\"y\") ? `, ${yy}` : \"\"}`;\n return p.includes(\"y\") ? `${mm + 1}/${dd}/${yy}` : `${mm + 1}/${dd}`;\n }\n const decimals = (pattern.split(\".\")[1]?.match(/0/g) ?? []).length;\n if (p.includes(\"%\")) return `${(v * 100).toFixed(decimals)}%`;\n const grouped = Math.abs(v).toLocaleString(\"en-US\", {\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n useGrouping: pattern.includes(\",\"),\n });\n const sign = v < 0 ? \"-\" : \"\";\n return p.includes(\"$\") ? `${sign}$${grouped}` : `${sign}${grouped}`;\n}\n\n// ─── conditional formatting (the rules a preview can evaluate) ───────────────\n\nexport type CfRule = {\n rule?: {\n type?: string;\n subType?: string;\n operator?: string;\n value?: unknown;\n style?: CellStyle;\n };\n ranges?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n};\n\nexport function parseResource<T>(wb: Workbook, name: string): T | null {\n const res = wb.resources?.find((r) => r.name === name);\n if (!res?.data) return null;\n try {\n return JSON.parse(res.data) as T;\n } catch {\n return null;\n }\n}\n\nexport function cfMatch(rule: NonNullable<CfRule[\"rule\"]>, v: unknown): boolean {\n if (rule.type !== \"highlightCell\") return false;\n if (rule.subType === \"number\" && typeof v === \"number\") {\n const x = rule.value;\n const [a = 0, b = 0] = Array.isArray(x) ? (x as number[]) : [Number(x), Number(x)];\n switch (rule.operator) {\n case \"greaterThan\": return v > a;\n case \"greaterThanOrEqual\": return v >= a;\n case \"lessThan\": return v < a;\n case \"lessThanOrEqual\": return v <= a;\n case \"equal\": return v === a;\n case \"notEqual\": return v !== a;\n case \"between\": return v >= a && v <= b;\n default: return false;\n }\n }\n if (rule.subType === \"text\" && v !== undefined && v !== null) {\n const s = String(v).toLowerCase();\n const want = String(rule.value ?? \"\").toLowerCase();\n switch (rule.operator) {\n case \"containsText\": return s.includes(want);\n case \"equal\": return s === want;\n case \"beginsWith\": return s.startsWith(want);\n default: return false;\n }\n }\n return false;\n}\n\n// ─── workbook ────────────────────────────────────────────────────────────────\n\nexport function workbookPreviewSvg(snapshot: unknown): string {\n const wb = (snapshot ?? {}) as Workbook;\n const firstId = wb.sheetOrder?.[0] ?? Object.keys(wb.sheets ?? {})[0];\n const sheet: Sheet = (firstId && wb.sheets?.[firstId]) || {};\n const sheetId = sheet.id ?? firstId ?? \"\";\n const styles = wb.styles ?? {};\n const cfAll = parseResource<Record<string, CfRule[]>>(wb, \"SHEET_CONDITIONAL_FORMATTING_PLUGIN\");\n const cf = (cfAll?.[sheetId] ?? []).filter((r) => r.rule && r.ranges);\n const dvAll = parseResource<Record<string, Array<{ type?: string; ranges?: CfRule[\"ranges\"] }>>>(\n wb,\n \"SHEET_DATA_VALIDATION_PLUGIN\",\n );\n const checkboxRanges = (dvAll?.[sheetId] ?? []).filter((d) => d.type === \"checkbox\").flatMap((d) => d.ranges ?? []);\n const inRanges = (rs: CfRule[\"ranges\"], r: number, c: number) =>\n (rs ?? []).some((x) => r >= x.startRow && r <= x.endRow && c >= x.startColumn && c <= x.endColumn);\n\n const dcw = sheet.defaultColumnWidth ?? 88;\n const drh = sheet.defaultRowHeight ?? 24;\n const colW = (c: number) => (sheet.columnData?.[c]?.hd ? 0 : sheet.columnData?.[c]?.w ?? dcw);\n const rowH = (r: number) => (sheet.rowData?.[r]?.hd ? 0 : sheet.rowData?.[r]?.h ?? drh);\n\n // Show the used width (at least ~5 default columns), scaled to the tile.\n let maxCol = 0;\n for (const row of Object.values(sheet.cellData ?? {})) {\n for (const c of Object.keys(row ?? {})) maxCol = Math.max(maxCol, Number(c));\n }\n let used = 0;\n for (let c = 0; c <= maxCol; c++) used += colW(c);\n // Google's tiles show the top-left of the sheet at a readable size, not the whole width.\n const span = Math.min(Math.max(used + 12, dcw * 5), 640);\n const scale = THUMB_WIDTH / span;\n\n const out: string[] = [];\n out.push(`<rect width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" fill=\"#ffffff\"/>`);\n const gridOn = sheet.showGridlines !== 0;\n const merges = sheet.mergeData ?? [];\n const covered = new Set<string>();\n for (const m of merges) {\n for (let r = m.startRow; r <= m.endRow; r++)\n for (let c = m.startColumn; c <= m.endColumn; c++)\n if (r !== m.startRow || c !== m.startColumn) covered.add(`${r}:${c}`);\n }\n const texts: string[] = [];\n let y = 0;\n for (let r = 0; y * scale < THUMB_HEIGHT && r < 400; r++) {\n const h = rowH(r);\n let x = 0;\n for (let c = 0; x * scale < THUMB_WIDTH && c < 60; c++) {\n const w = colW(c);\n if (w === 0 || h === 0 || covered.has(`${r}:${c}`)) {\n x += w;\n continue;\n }\n const m = merges.find((mm) => mm.startRow === r && mm.startColumn === c);\n let cw = w;\n let ch = h;\n if (m) {\n cw = 0;\n for (let k = m.startColumn; k <= m.endColumn; k++) cw += colW(k);\n ch = 0;\n for (let k = m.startRow; k <= m.endRow; k++) ch += rowH(k);\n }\n const cell = sheet.cellData?.[r]?.[c];\n const base: CellStyle =\n (typeof cell?.s === \"string\" ? styles[cell.s] : (cell?.s as CellStyle | null)) ?? {};\n let st: CellStyle = base;\n for (const rule of cf) {\n if (inRanges(rule.ranges, r, c) && rule.rule && cfMatch(rule.rule, cell?.v)) {\n st = { ...st, ...rule.rule.style };\n break;\n }\n }\n const X = x * scale;\n const Y = y * scale;\n const W = cw * scale;\n const H = ch * scale;\n const bg = st.bg?.rgb;\n if (bg) out.push(`<rect x=\"${X.toFixed(1)}\" y=\"${Y.toFixed(1)}\" width=\"${W.toFixed(1)}\" height=\"${H.toFixed(1)}\" fill=\"${esc(bg)}\"/>`);\n if (gridOn) out.push(`<rect x=\"${X.toFixed(1)}\" y=\"${Y.toFixed(1)}\" width=\"${W.toFixed(1)}\" height=\"${H.toFixed(1)}\" fill=\"none\" stroke=\"#e2e3e3\" stroke-width=\"0.5\"/>`);\n const fs = Math.max((st.fs ?? 10) * 1.333 * scale, 3);\n const midY = Y + H / 2 + fs * 0.35;\n if (inRanges(checkboxRanges, r, c) && r > 0 && (cell?.v === true || cell?.v === false || cell?.v === 1 || cell?.v === 0 || cell?.v === \"TRUE\" || cell?.v === \"FALSE\")) {\n const box = Math.min(H * 0.55, 9);\n const bx = X + W / 2 - box / 2;\n const by = Y + H / 2 - box / 2;\n const on = cell?.v === true || cell?.v === 1 || cell?.v === \"TRUE\";\n out.push(`<rect x=\"${bx.toFixed(1)}\" y=\"${by.toFixed(1)}\" width=\"${box.toFixed(1)}\" height=\"${box.toFixed(1)}\" rx=\"1\" fill=\"${on ? \"#1a73e8\" : \"#ffffff\"}\" stroke=\"${on ? \"#1a73e8\" : \"#5f6368\"}\" stroke-width=\"0.7\"/>`);\n if (on) out.push(`<path d=\"M${(bx + box * 0.2).toFixed(1)} ${(by + box * 0.5).toFixed(1)} l${(box * 0.25).toFixed(1)} ${(box * 0.25).toFixed(1)} l${(box * 0.4).toFixed(1)} ${(-box * 0.45).toFixed(1)}\" stroke=\"#fff\" stroke-width=\"0.9\" fill=\"none\"/>`);\n } else if (cell && cell.v !== undefined && cell.v !== null && cell.v !== \"\") {\n const text = formatCellValue(cell.v, st.n?.pattern);\n const numeric = typeof cell.v === \"number\";\n const ht = st.ht ?? (numeric ? 3 : 1);\n const anchor = ht === 2 ? \"middle\" : ht === 3 ? \"end\" : \"start\";\n const tx = ht === 2 ? X + W / 2 : ht === 3 ? X + W - 2 * scale * 2 : X + 3 * scale;\n const maxChars = Math.max(Math.floor((m ? W : W * (ht === 1 && !numeric ? 3 : 1)) / (fs * 0.55)), 1);\n const shown = text.length > maxChars ? text.slice(0, maxChars) : text;\n texts.push(\n `<text x=\"${tx.toFixed(1)}\" y=\"${midY.toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" text-anchor=\"${anchor}\" fill=\"${esc(color(st.cl, \"#202124\"))}\"${st.bl ? ' font-weight=\"700\"' : \"\"}${st.it ? ' font-style=\"italic\"' : \"\"}>${esc(shown)}</text>`,\n );\n }\n x += w;\n }\n y += h;\n }\n return wrapSvg([...out, ...texts].join(\"\"));\n}\n\n// ─── document ────────────────────────────────────────────────────────────────\n\ntype TextStyle = { fs?: number; bl?: number; it?: number; cl?: Rgb; ff?: string; bg?: Rgb };\ntype DocData = {\n body?: {\n dataStream?: string;\n paragraphs?: Array<{ startIndex: number; paragraphStyle?: { horizontalAlign?: number; spaceAbove?: { v?: number }; spaceBelow?: { v?: number } } }>;\n textRuns?: Array<{ st: number; ed: number; ts?: TextStyle }>;\n tables?: Array<{ startIndex: number; endIndex: number; tableId: string }>;\n };\n documentStyle?: {\n pageSize?: { width?: number; height?: number };\n marginTop?: number;\n marginLeft?: number;\n marginRight?: number;\n };\n};\n\nconst CONTROL = /[\\x1A\\x1B\\x1C\\x1D\\x0E\\x0F\\x1F\\x1E\\b]/g;\n\nexport function documentPreviewSvg(snapshot: unknown): string {\n const doc = (snapshot ?? {}) as DocData;\n const stream = doc.body?.dataStream ?? \"\";\n const pageW = doc.documentStyle?.pageSize?.width ?? 595;\n const scale = THUMB_WIDTH / pageW;\n const ml = (doc.documentStyle?.marginLeft ?? 72) * scale;\n const mr = (doc.documentStyle?.marginRight ?? 72) * scale;\n const mt = (doc.documentStyle?.marginTop ?? 72) * scale;\n const contentW = THUMB_WIDTH - ml - mr;\n const runs = [...(doc.body?.textRuns ?? [])].sort((a, b) => a.st - b.st);\n const tables = doc.body?.tables ?? [];\n const styleAt = (i: number): TextStyle => runs.find((r) => i >= r.st && i < r.ed)?.ts ?? {};\n /** The style most of a paragraph's characters carry (a bold lead-in does not make the line bold). */\n const dominantStyle = (from: number, to: number): TextStyle => {\n const counts = new Map<string, { n: number; ts: TextStyle }>();\n for (let i = from; i < to; i++) {\n if (/\\s/.test(stream[i] ?? \"\")) continue;\n const ts = styleAt(i);\n const k = JSON.stringify(ts);\n const e = counts.get(k) ?? { n: 0, ts };\n e.n++;\n counts.set(k, e);\n }\n let best: { n: number; ts: TextStyle } | null = null;\n for (const e of counts.values()) if (!best || e.n > best.n) best = e;\n return best?.ts ?? {};\n };\n const out: string[] = [`<rect width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" fill=\"#ffffff\"/>`];\n\n let y = mt;\n let start = 0;\n const paragraphs = doc.body?.paragraphs ?? [];\n for (let p = 0; p < paragraphs.length && y < THUMB_HEIGHT; p++) {\n const para = paragraphs[p];\n if (!para) break;\n const end = para.startIndex;\n const table = tables.find((t) => start >= t.startIndex && start < t.endIndex);\n if (table) {\n // Draw the whole table once: rows split on the row token, cells on the cell token.\n const raw = stream.slice(table.startIndex, table.endIndex);\n const rows = raw.split(\"\\x1B\").slice(1).map((row) =>\n row.split(\"\\x1C\").slice(1).map((cell) => cell.replace(/[\\r\\n]/g, \" \").replace(CONTROL, \"\").trim()),\n );\n const cols = Math.max(1, ...rows.map((r) => r.length));\n const cw = contentW / cols;\n // Bold header row when the first cell's text is bold.\n const headerBold = styleAt(table.startIndex + 4).bl === 1;\n for (let r = 0; r < rows.length && y < THUMB_HEIGHT; r++) {\n const rh = 16 * scale * 1.2 + 6 * scale;\n for (let c = 0; c < cols; c++) {\n const cx = ml + c * cw;\n out.push(`<rect x=\"${cx.toFixed(1)}\" y=\"${y.toFixed(1)}\" width=\"${cw.toFixed(1)}\" height=\"${rh.toFixed(1)}\" fill=\"${r === 0 && headerBold ? \"#f1f3f4\" : \"none\"}\" stroke=\"#9aa0a6\" stroke-width=\"0.4\"/>`);\n const fs = 11 * 1.333 * scale;\n const maxChars = Math.max(Math.floor((cw - 6 * scale) / (fs * 0.5)), 1);\n const t = rows[r]?.[c] ?? \"\";\n out.push(`<text x=\"${(cx + 4 * scale).toFixed(1)}\" y=\"${(y + rh / 2 + fs * 0.35).toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" fill=\"#202124\"${r === 0 && headerBold ? ' font-weight=\"700\"' : \"\"}>${esc(t.slice(0, maxChars))}</text>`);\n }\n y += rh;\n }\n // Skip every paragraph inside the table.\n while (p + 1 < paragraphs.length && (paragraphs[p + 1]?.startIndex ?? Infinity) < table.endIndex) p++;\n start = table.endIndex;\n y += 6 * scale;\n continue;\n }\n const text = stream.slice(start, end).replace(CONTROL, \"\");\n const st = dominantStyle(start, end);\n const ps = para.paragraphStyle ?? {};\n const fsPt = st.fs ?? 11;\n const fs = fsPt * 1.333 * scale;\n const lineH = fs * 1.3;\n y += (ps.spaceAbove?.v ?? (fsPt > 13 ? 8 : 0)) * scale;\n const align = ps.horizontalAlign ?? 1;\n const anchor = align === 2 ? \"middle\" : align === 3 ? \"end\" : \"start\";\n const tx = align === 2 ? ml + contentW / 2 : align === 3 ? ml + contentW : ml;\n // Paragraph shading (a filled band) when the run carries a highlight.\n if (!text.trim()) {\n y += lineH * 0.8;\n } else {\n const maxChars = Math.max(Math.floor(contentW / (fs * (st.bl ? 0.56 : 0.5))), 4);\n const words = text.split(/\\s+/);\n const lines: string[] = [];\n let line = \"\";\n for (const w of words) {\n if ((line + \" \" + w).trim().length > maxChars && line) {\n lines.push(line);\n line = w;\n } else line = (line + \" \" + w).trim();\n }\n if (line) lines.push(line);\n for (const l of lines) {\n if (y > THUMB_HEIGHT) break;\n y += lineH;\n if (st.bg?.rgb) out.push(`<rect x=\"${ml.toFixed(1)}\" y=\"${(y - fs).toFixed(1)}\" width=\"${contentW.toFixed(1)}\" height=\"${lineH.toFixed(1)}\" fill=\"${esc(st.bg.rgb)}\"/>`);\n out.push(`<text x=\"${tx.toFixed(1)}\" y=\"${y.toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" text-anchor=\"${anchor}\" fill=\"${esc(color(st.cl, \"#202124\"))}\"${st.bl ? ' font-weight=\"700\"' : \"\"}${st.it ? ' font-style=\"italic\"' : \"\"}${st.ff && /serif|georgia|times|garamond/i.test(st.ff) && !/sans/i.test(st.ff) ? ' font-family=\"Georgia, serif\"' : \"\"}>${esc(l)}</text>`);\n }\n }\n y += (ps.spaceBelow?.v ?? 4) * scale;\n start = end + 1;\n }\n return wrapSvg(out.join(\"\"));\n}\n\nfunction wrapSvg(body: string): string {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" viewBox=\"0 0 ${THUMB_WIDTH} ${THUMB_HEIGHT}\" font-family=\"Arial, Helvetica, sans-serif\">${body}</svg>`;\n}\n\nexport function snapshotPreviewSvg(kind: \"workbook\" | \"document\", snapshot: unknown): string {\n return kind === \"workbook\" ? workbookPreviewSvg(snapshot) : documentPreviewSvg(snapshot);\n}\n","/**\n * features/workbooks/snapshot-grid.ts\n *\n * Snapshot → a formatted, read-only grid model: what a spreadsheet VIEW needs and the plain-string\n * `univer-snapshot-rows` does not carry — number/currency/date formats applied, checkbox cells\n * (data-validation ranges of type checkbox), alignment, bold/italic, fill and text colour, column\n * widths, merges, frozen rows/columns, hidden rows/columns and sheets. Pure (no DOM, no Univer\n * runtime): the signed-out share page draws it. The number formatter is the thumbnail's\n * (`formatCellValue`) so a tile, a share link and the editor read the same.\n */\n\nimport {\n cfMatch,\n formatCellValue,\n parseResource,\n type CfRule,\n type Workbook,\n} from \"./snapshot-preview-svg\";\n\ntype Rgb = { rgb?: string | null } | null | undefined;\ninterface Style {\n bg?: Rgb;\n cl?: Rgb;\n bl?: number;\n it?: number;\n fs?: number;\n ht?: number;\n tb?: number;\n n?: { pattern?: string } | null;\n}\ninterface Cell {\n v?: unknown;\n s?: string | Style | null;\n}\ninterface Sheet {\n id?: string;\n name?: string;\n hidden?: number;\n cellData?: Record<string, Record<string, Cell | null | undefined>>;\n columnData?: Record<string, { w?: number; hd?: number } | null | undefined>;\n rowData?: Record<string, { h?: number; hd?: number } | null | undefined>;\n defaultColumnWidth?: number;\n defaultRowHeight?: number;\n mergeData?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n showGridlines?: number;\n freeze?: { xSplit?: number; ySplit?: number };\n}\n\nexport interface GridCell {\n text: string;\n /** A checkbox cell (a data-validation checkbox range): `checked` says its state. */\n checkbox?: { checked: boolean } | undefined;\n align: \"left\" | \"center\" | \"right\";\n bold: boolean;\n italic: boolean;\n /** Font size in px (the snapshot stores points). */\n fontPx: number;\n bg?: string | undefined;\n color?: string | undefined;\n wrap: boolean;\n rowSpan: number;\n colSpan: number;\n /** Covered by a merge that starts elsewhere: draw nothing. */\n covered: boolean;\n}\n\nexport interface GridSheet {\n id: string;\n name: string;\n /** Visible column indexes (hidden columns left out) with their pixel widths. */\n columns: Array<{ index: number; width: number }>;\n rows: Array<{ index: number; height: number; cells: GridCell[] }>;\n /** How many leading VISIBLE rows / columns stay put while scrolling. */\n frozenRows: number;\n frozenColumns: number;\n gridlines: boolean;\n /** Rows beyond the cap were left out. */\n truncatedFrom: number | null;\n}\n\nexport const GRID_MAX_ROWS = 500;\nexport const GRID_MAX_COLUMNS = 60;\n\nconst PT_TO_PX = 1.333;\nconst isCheckboxValue = (v: unknown) => v === true || v === false || v === 1 || v === 0 || v === \"TRUE\" || v === \"FALSE\";\nconst isOn = (v: unknown) => v === true || v === 1 || v === \"TRUE\";\n\nfunction hasValue(cell: Cell | null | undefined): boolean {\n const v = cell?.v;\n return v !== undefined && v !== null && v !== \"\";\n}\n\n/** Every visible sheet that has something in it, in tab order. Empty and hidden sheets are left out. */\nexport function snapshotToGridSheets(snapshot: unknown): GridSheet[] {\n if (typeof snapshot !== \"object\" || snapshot === null) return [];\n const wb = snapshot as Workbook;\n const sheets = wb.sheets ?? {};\n const order = (wb.sheetOrder ?? []).filter((id) => sheets[id]);\n const ids = order.length > 0 ? order : Object.keys(sheets);\n const out: GridSheet[] = [];\n for (const id of ids) {\n const grid = sheetToGrid(wb, id, sheets[id] as Sheet);\n if (grid) out.push(grid);\n }\n return out;\n}\n\nfunction sheetToGrid(wb: Workbook, id: string, sheet: Sheet): GridSheet | null {\n if (sheet.hidden === 1) return null;\n const cellData = sheet.cellData ?? {};\n let maxRow = -1;\n let maxCol = -1;\n for (const [rk, row] of Object.entries(cellData)) {\n const r = Number(rk);\n if (!Number.isInteger(r) || !row) continue;\n for (const [ck, cell] of Object.entries(row)) {\n const c = Number(ck);\n if (!Number.isInteger(c) || !hasValue(cell)) continue;\n if (r > maxRow) maxRow = r;\n if (c > maxCol) maxCol = c;\n }\n }\n if (maxRow < 0 || maxCol < 0) return null;\n\n const styles = wb.styles ?? {};\n const sheetId = sheet.id ?? id;\n const cfAll = parseResource<Record<string, CfRule[]>>(wb, \"SHEET_CONDITIONAL_FORMATTING_PLUGIN\");\n const cf = (cfAll?.[sheetId] ?? []).filter((r) => r.rule && r.ranges);\n const dvAll = parseResource<Record<string, Array<{ type?: string; ranges?: CfRule[\"ranges\"] }>>>(\n wb,\n \"SHEET_DATA_VALIDATION_PLUGIN\",\n );\n const checkboxRanges = (dvAll?.[sheetId] ?? []).filter((d) => d.type === \"checkbox\").flatMap((d) => d.ranges ?? []);\n const inRanges = (rs: CfRule[\"ranges\"], r: number, c: number) =>\n (rs ?? []).some((x) => r >= x.startRow && r <= x.endRow && c >= x.startColumn && c <= x.endColumn);\n\n const dcw = sheet.defaultColumnWidth ?? 88;\n const drh = sheet.defaultRowHeight ?? 24;\n const lastCol = Math.min(maxCol, GRID_MAX_COLUMNS - 1);\n const columns: GridSheet[\"columns\"] = [];\n for (let c = 0; c <= lastCol; c += 1) {\n const col = sheet.columnData?.[String(c)];\n if (col?.hd === 1) continue;\n columns.push({ index: c, width: col?.w ?? dcw });\n }\n\n const merges = sheet.mergeData ?? [];\n const covered = new Set<string>();\n for (const m of merges) {\n for (let r = m.startRow; r <= m.endRow; r += 1)\n for (let c = m.startColumn; c <= m.endColumn; c += 1) if (r !== m.startRow || c !== m.startColumn) covered.add(`${r}:${c}`);\n }\n\n const rows: GridSheet[\"rows\"] = [];\n const lastRow = Math.min(maxRow, GRID_MAX_ROWS - 1);\n for (let r = 0; r <= lastRow; r += 1) {\n const rd = sheet.rowData?.[String(r)];\n if (rd?.hd === 1) continue;\n const source = cellData[String(r)] ?? {};\n const cells: GridCell[] = columns.map(({ index: c }) => {\n const cell = source[String(c)] ?? undefined;\n const base: Style = (typeof cell?.s === \"string\" ? (styles[cell.s] as Style | null | undefined) : (cell?.s as Style | null | undefined)) ?? {};\n let st: Style = base;\n for (const rule of cf) {\n if (inRanges(rule.ranges, r, c) && rule.rule && cfMatch(rule.rule, cell?.v)) {\n st = { ...st, ...(rule.rule.style as Style | undefined) };\n break;\n }\n }\n const m = merges.find((mm) => mm.startRow === r && mm.startColumn === c);\n const v = cell?.v;\n const box = hasValue(cell) && inRanges(checkboxRanges, r, c) && isCheckboxValue(v);\n const numeric = typeof v === \"number\";\n const ht = st.ht ?? 0;\n return {\n text: box ? \"\" : hasValue(cell) ? formatCellValue(v, st.n?.pattern) : \"\",\n checkbox: box ? { checked: isOn(v) } : undefined,\n align: box || ht === 2 ? \"center\" : ht === 3 || (ht === 0 && numeric) ? \"right\" : \"left\",\n bold: st.bl === 1,\n italic: st.it === 1,\n fontPx: Math.round((st.fs ?? 10) * PT_TO_PX),\n bg: st.bg?.rgb ?? undefined,\n color: st.cl?.rgb ?? undefined,\n wrap: st.tb === 3,\n rowSpan: m ? m.endRow - m.startRow + 1 : 1,\n colSpan: m ? m.endColumn - m.startColumn + 1 : 1,\n covered: covered.has(`${r}:${c}`),\n };\n });\n rows.push({ index: r, height: rd?.h ?? drh, cells });\n }\n\n const ySplit = sheet.freeze?.ySplit ?? 0;\n const xSplit = sheet.freeze?.xSplit ?? 0;\n return {\n id: sheetId,\n name: sheet.name ?? \"Sheet1\",\n columns,\n rows,\n frozenRows: Math.min(rows.filter((r) => r.index < ySplit).length, rows.length),\n frozenColumns: Math.min(columns.filter((c) => c.index < xSplit).length, columns.length),\n gridlines: sheet.showGridlines !== 0,\n truncatedFrom: maxRow > lastRow ? maxRow + 1 : null,\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 colour, hex. Always a light colour 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 colour (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 * A workbook's print settings — Google Sheets' File → Page setup / Print, as pure data and pure\n * pagination (no React, no IO). They live on the workbook (`udt_workbooks.metadata.page_setup`),\n * so Print, Download as PDF and the Page setup dialog all read the same values.\n *\n * Geometry is in 96-dpi CSS pixels, like the rest of the document stack (`PX_PER_INCH`).\n */\n\nimport { PAPER_SIZES, PX_PER_INCH, type PaperSizeName } from \"../core\";\n\nexport const SHEET_SCALES = [\"normal\", \"width\", \"height\", \"page\"] as const;\nexport type SheetScale = (typeof SHEET_SCALES)[number];\nexport const SHEET_MARGIN_PRESETS = [\"normal\", \"narrow\", \"wide\", \"custom\"] as const;\nexport type SheetMarginPreset = (typeof SHEET_MARGIN_PRESETS)[number];\nexport const SHEET_PRINT_SCOPES = [\"sheet\", \"workbook\", \"selection\"] as const;\nexport type SheetPrintScope = (typeof SHEET_PRINT_SCOPES)[number];\nexport type SheetPageOrder = \"down-over\" | \"over-down\";\nexport type SheetAlignH = \"left\" | \"center\" | \"right\";\nexport type SheetAlignV = \"top\" | \"middle\" | \"bottom\";\n\nexport interface SheetPageSetup {\n paper: PaperSizeName;\n orientation: \"portrait\" | \"landscape\";\n scale: SheetScale;\n margins: SheetMarginPreset;\n /** Inches; read only when `margins` is \"custom\". */\n customMargins: { top: number; bottom: number; left: number; right: number };\n scope: SheetPrintScope;\n gridlines: boolean;\n repeatFrozenRows: boolean;\n repeatFrozenColumns: boolean;\n pageOrder: SheetPageOrder;\n alignH: SheetAlignH;\n alignV: SheetAlignV;\n}\n\n/** Google Sheets' defaults: Letter, portrait, 100%, normal margins, current sheet, gridlines on. */\nexport const DEFAULT_SHEET_PAGE_SETUP: SheetPageSetup = {\n paper: \"Letter\",\n orientation: \"portrait\",\n scale: \"normal\",\n margins: \"normal\",\n customMargins: { top: 0.75, bottom: 0.75, left: 0.7, right: 0.7 },\n scope: \"sheet\",\n gridlines: true,\n repeatFrozenRows: false,\n repeatFrozenColumns: false,\n pageOrder: \"down-over\",\n alignH: \"left\",\n alignV: \"top\",\n};\n\n/** Google's three preset margins, in inches. */\nexport const MARGIN_PRESET_INCHES: Record<Exclude<SheetMarginPreset, \"custom\">, { top: number; bottom: number; left: number; right: number }> = {\n normal: { top: 0.75, bottom: 0.75, left: 0.7, right: 0.7 },\n narrow: { top: 0.25, bottom: 0.25, left: 0.25, right: 0.25 },\n wide: { top: 1, bottom: 1, left: 1, right: 1 },\n};\n\nconst isPaper = (v: unknown): v is PaperSizeName => typeof v === \"string\" && v in PAPER_SIZES;\nconst oneOf = <T extends string>(list: readonly T[], v: unknown, fallback: T): T => (typeof v === \"string\" && (list as readonly string[]).includes(v) ? (v as T) : fallback);\nconst inches = (v: unknown, fallback: number) => (typeof v === \"number\" && Number.isFinite(v) && v >= 0 && v <= 5 ? v : fallback);\n\n/** Any stored value → a complete, valid setup. Unknown or broken parts fall back to the default. */\nexport function normalizeSheetPageSetup(raw: unknown): SheetPageSetup {\n const r = (raw && typeof raw === \"object\" ? raw : {}) as Record<string, unknown>;\n const m = (r.customMargins && typeof r.customMargins === \"object\" ? r.customMargins : {}) as Record<string, unknown>;\n const d = DEFAULT_SHEET_PAGE_SETUP;\n return {\n paper: isPaper(r.paper) ? r.paper : d.paper,\n orientation: r.orientation === \"landscape\" ? \"landscape\" : \"portrait\",\n scale: oneOf(SHEET_SCALES, r.scale, d.scale),\n margins: oneOf(SHEET_MARGIN_PRESETS, r.margins, d.margins),\n customMargins: {\n top: inches(m.top, d.customMargins.top),\n bottom: inches(m.bottom, d.customMargins.bottom),\n left: inches(m.left, d.customMargins.left),\n right: inches(m.right, d.customMargins.right),\n },\n scope: oneOf(SHEET_PRINT_SCOPES, r.scope, d.scope),\n gridlines: typeof r.gridlines === \"boolean\" ? r.gridlines : d.gridlines,\n repeatFrozenRows: r.repeatFrozenRows === true,\n repeatFrozenColumns: r.repeatFrozenColumns === true,\n pageOrder: r.pageOrder === \"over-down\" ? \"over-down\" : \"down-over\",\n alignH: oneOf([\"left\", \"center\", \"right\"] as const, r.alignH, d.alignH),\n alignV: oneOf([\"top\", \"middle\", \"bottom\"] as const, r.alignV, d.alignV),\n };\n}\n\n/** The setup stored on a workbook's metadata (`metadata.page_setup`), complete and valid. */\nexport function pageSetupFromMetadata(metadata: unknown): SheetPageSetup {\n return normalizeSheetPageSetup((metadata as { page_setup?: unknown } | null)?.page_setup);\n}\n\nexport interface PrintGeometry {\n /** Paper as printed (orientation applied), px. */\n paperWidth: number;\n paperHeight: number;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /** The printable box inside the margins, px. */\n areaWidth: number;\n areaHeight: number;\n}\n\nexport function printGeometry(setup: SheetPageSetup): PrintGeometry {\n const base = PAPER_SIZES[setup.paper];\n const landscape = setup.orientation === \"landscape\";\n const paperWidth = landscape ? base.height : base.width;\n const paperHeight = landscape ? base.width : base.height;\n const m = setup.margins === \"custom\" ? setup.customMargins : MARGIN_PRESET_INCHES[setup.margins];\n const px = (n: number) => Math.round(n * PX_PER_INCH);\n const geometry = {\n paperWidth,\n paperHeight,\n marginTop: px(m.top),\n marginBottom: px(m.bottom),\n marginLeft: px(m.left),\n marginRight: px(m.right),\n };\n return {\n ...geometry,\n areaWidth: Math.max(48, paperWidth - geometry.marginLeft - geometry.marginRight),\n areaHeight: Math.max(48, paperHeight - geometry.marginTop - geometry.marginBottom),\n };\n}\n\nexport const PRINT_ROW_HEIGHT = 22;\nconst MIN_COL = 48;\nconst MAX_COL = 320;\nconst CHAR_PX = 7;\n\n/** Column widths (px) fitted to the text the column holds. */\nexport function printColumnWidths(rows: readonly (readonly string[])[]): number[] {\n const width = rows.reduce((n, r) => Math.max(n, r.length), 0);\n const out: number[] = [];\n for (let c = 0; c < width; c += 1) {\n let longest = 0;\n for (const r of rows) longest = Math.max(longest, (r[c] ?? \"\").length);\n out.push(Math.min(MAX_COL, Math.max(MIN_COL, longest * CHAR_PX + 16)));\n }\n return out;\n}\n\nexport interface PrintPage {\n /** Grid row indexes drawn on this page, in order (repeated frozen rows first). */\n rows: number[];\n /** Grid column indexes drawn on this page, in order (repeated frozen columns first). */\n cols: number[];\n}\n\nexport interface PrintPlan {\n scale: number;\n geometry: PrintGeometry;\n colWidths: number[];\n pages: PrintPage[];\n}\n\n/** Splits `count` items into bands that fit `capacity(px)`, repeating `frozen` leading items on every band after the first. */\nfunction bands(sizes: readonly number[], capacityPx: number, frozen: number, repeat: boolean): number[][] {\n const total = sizes.length;\n if (total === 0) return [];\n const result: number[][] = [];\n const lead = repeat ? Math.min(frozen, total) : 0;\n const leadPx = sizes.slice(0, lead).reduce((a, b) => a + b, 0);\n let at = 0;\n while (at < total) {\n const first = result.length === 0;\n const carry = !first && lead > 0 ? Array.from({ length: lead }, (_, i) => i) : [];\n let used = first ? 0 : leadPx;\n const band = [...carry];\n // A repeated header never leaves a page with no room for a body item.\n if (!first && leadPx >= capacityPx) used = 0;\n let added = 0;\n while (at < total) {\n const size = sizes[at]!;\n if (used + size > capacityPx && added > 0) break;\n band.push(at);\n used += size;\n added += 1;\n at += 1;\n }\n result.push(band);\n }\n return result;\n}\n\n/** The pages one grid prints on under `setup`: scale, repeated frozen panes, and page order. */\nexport function planSheetPrint(\n rows: readonly (readonly string[])[],\n setup: SheetPageSetup,\n frozen: { rows: number; cols: number } = { rows: 0, cols: 0 },\n): PrintPlan {\n const geometry = printGeometry(setup);\n const colWidths = printColumnWidths(rows);\n const totalW = colWidths.reduce((a, b) => a + b, 0) || 1;\n const totalH = rows.length * PRINT_ROW_HEIGHT || 1;\n const fitW = geometry.areaWidth / totalW;\n const fitH = geometry.areaHeight / totalH;\n const scale =\n setup.scale === \"width\" ? Math.min(1, fitW) : setup.scale === \"height\" ? Math.min(1, fitH) : setup.scale === \"page\" ? Math.min(1, fitW, fitH) : 1;\n const rowBands = bands(\n rows.map(() => PRINT_ROW_HEIGHT),\n geometry.areaHeight / scale,\n frozen.rows,\n setup.repeatFrozenRows,\n );\n const colBands = bands(colWidths, geometry.areaWidth / scale, frozen.cols, setup.repeatFrozenColumns);\n const pages: PrintPage[] = [];\n if (setup.pageOrder === \"down-over\") {\n for (const cols of colBands) for (const r of rowBands) pages.push({ rows: r, cols });\n } else {\n for (const r of rowBands) for (const cols of colBands) pages.push({ rows: r, cols });\n }\n return { scale, geometry, colWidths, pages };\n}\n","/**\n * A workbook's print settings, read and written on the workbook itself:\n * `udt_workbooks.metadata.page_setup` (merged with `mergeJsonColumn`, like the table links beside it).\n */\nimport { mergeJsonColumn } from \"@ai-matrx/data/db\";\n\nimport { getSheetsHost } from \"./ports\";\nimport { normalizeSheetPageSetup, pageSetupFromMetadata, type SheetPageSetup } from \"./sheet-page-setup\";\n\nconst db = () => getSheetsHost().getSupabase();\n\ntype WorkbookMetaRow = { id: string; version: number; metadata: unknown };\n\nexport type PageSetupResult = { ok: true; data: SheetPageSetup } | { ok: false; error: string };\n\nexport async function readSheetPageSetup(workbookId: string): Promise<PageSetupResult> {\n const { data, error } = await db().schema(\"workbench\").from(\"udt_workbooks\").select(\"metadata\").eq(\"id\", workbookId).maybeSingle();\n if (error) return { ok: false, error: error.message };\n return { ok: true, data: pageSetupFromMetadata(data?.metadata) };\n}\n\nexport async function writeSheetPageSetup(workbookId: string, setup: SheetPageSetup): Promise<PageSetupResult> {\n const clean = normalizeSheetPageSetup(setup);\n const result = await mergeJsonColumn<WorkbookMetaRow>({\n fetchCurrent: () => db().schema(\"workbench\").from(\"udt_workbooks\").select(\"id, version, metadata\").eq(\"id\", workbookId).maybeSingle(),\n readColumn: (row) => row.metadata,\n merge: (current) => ({ ...current, page_setup: clean }),\n applyUpdate: ({ value, expectedVersion, nextVersion }) =>\n db()\n .schema(\"workbench\")\n .from(\"udt_workbooks\")\n .update({ metadata: value as never, version: nextVersion })\n .eq(\"id\", workbookId)\n .eq(\"version\", expectedVersion)\n .select(\"id, version, metadata\")\n .maybeSingle(),\n });\n if (result.status === \"saved\") return { ok: true, data: pageSetupFromMetadata(result.row.metadata) };\n if (result.status === \"not_found\") return { ok: false, error: \"This workbook could not be found\" };\n if (result.status === \"conflict\") return { ok: false, error: \"The workbook changed while saving; try again\" };\n const reason: unknown = result.error;\n return { ok: false, error: reason instanceof Error ? reason.message : typeof reason === \"string\" ? reason : \"Something went wrong\" };\n}\n","/**\n * The pages a workbook prints on: the snapshot's cells → paper-sized HTML pages that follow the\n * workbook's print settings (`sheet-page-setup.ts`). Print and Download as PDF both draw these\n * same pages, so what the browser prints is what the PDF holds.\n */\n\nimport { PX_PER_INCH } from \"../core\";\nimport {\n PRINT_ROW_HEIGHT,\n planSheetPrint,\n type PrintGeometry,\n type SheetPageSetup,\n} from \"./sheet-page-setup\";\nimport { univerSheetIds, univerSnapshotToRows, type CellRange } from \"./univer-snapshot-rows\";\n\nexport interface PrintSheet {\n name: string;\n rows: string[][];\n frozenRows: number;\n frozenCols: number;\n}\n\n/** The sheets the setup's \"what to print\" asks for (empty sheets left out). */\nexport function collectPrintSheets(\n snapshot: unknown,\n setup: SheetPageSetup,\n options: { sheetId?: string; selection?: CellRange | null },\n): PrintSheet[] {\n const read = (sheetId: string | undefined, range?: CellRange): PrintSheet | null => {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(sheetId ? { sheetId } : {}), ...(range ? { range } : {}) });\n if (!grid || grid.rows.length === 0) return null;\n return { name: grid.sheetName, rows: grid.rows, frozenRows: grid.frozenRows, frozenCols: grid.frozenCols };\n };\n if (setup.scope === \"workbook\") {\n return univerSheetIds(snapshot)\n .map((id) => read(id))\n .filter((s): s is PrintSheet => s !== null);\n }\n if (setup.scope === \"selection\") {\n const sel = options.selection;\n if (!sel || (sel.startRow === sel.endRow && sel.startColumn === sel.endColumn)) return [];\n const one = read(options.sheetId, sel);\n return one ? [one] : [];\n }\n const one = read(options.sheetId);\n return one ? [one] : [];\n}\n\nconst esc = (s: string) => s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n\nconst JUSTIFY = { left: \"flex-start\", center: \"center\", right: \"flex-end\" } as const;\nconst ALIGN = { top: \"flex-start\", middle: \"center\", bottom: \"flex-end\" } as const;\n\nfunction pageHtml(\n sheet: PrintSheet,\n page: { rows: number[]; cols: number[] },\n scale: number,\n colWidths: number[],\n g: PrintGeometry,\n setup: SheetPageSetup,\n numbering: { sheet: string; at: number; of: number },\n): string {\n const widths = page.cols.map((c) => colWidths[c] ?? 0);\n const tableW = widths.reduce((a, b) => a + b, 0);\n const tableH = page.rows.length * PRINT_ROW_HEIGHT;\n const border = setup.gridlines ? \"1px solid #b7b7b7\" : \"none\";\n const body = page.rows\n .map(\n (r) =>\n `<tr style=\"height:${PRINT_ROW_HEIGHT}px\">${page.cols\n .map((c) => `<td style=\"border:${border}\">${esc(sheet.rows[r]?.[c] ?? \"\")}</td>`)\n .join(\"\")}</tr>`,\n )\n .join(\"\");\n const cols = widths.map((w) => `<col style=\"width:${w}px\">`).join(\"\");\n return `<section data-print-page data-sheet=\"${esc(numbering.sheet)}\" data-page-number=\"${numbering.at}\" data-page-count=\"${numbering.of}\" data-page-rows=\"${page.rows.length}\" data-page-cols=\"${page.cols.length}\" style=\"width:${g.paperWidth}px;height:${g.paperHeight}px;box-sizing:border-box;padding:${g.marginTop}px ${g.marginRight}px ${g.marginBottom}px ${g.marginLeft}px;background:#fff;overflow:hidden;break-after:page;page-break-after:always\">\n<div style=\"width:${g.areaWidth}px;height:${g.areaHeight}px;display:flex;justify-content:${JUSTIFY[setup.alignH]};align-items:${ALIGN[setup.alignV]};overflow:hidden\">\n<div data-print-content style=\"width:${tableW * scale}px;height:${tableH * scale}px;flex:none;overflow:hidden\">\n<table style=\"width:${tableW}px;table-layout:fixed;border-collapse:collapse;transform:scale(${scale});transform-origin:0 0;font:12px/${PRINT_ROW_HEIGHT - 2}px system-ui,sans-serif;color:#111\"><colgroup>${cols}</colgroup><tbody>${body}</tbody></table>\n</div></div></section>`;\n}\n\nexport interface PrintDocument {\n /** Every page, in print order. */\n pagesHtml: string[];\n pageWidth: number;\n pageHeight: number;\n /** `@page` size in inches, for the browser's print engine. */\n pageSizeInches: { width: number; height: number };\n}\n\n/** All the printed pages of the chosen sheets under the setup (empty when there is nothing to print). */\nexport function buildPrintDocument(sheets: readonly PrintSheet[], setup: SheetPageSetup): PrintDocument | null {\n const out: string[] = [];\n let geometry: PrintGeometry | null = null;\n for (const sheet of sheets) {\n const plan = planSheetPrint(sheet.rows, setup, { rows: sheet.frozenRows, cols: sheet.frozenCols });\n geometry = plan.geometry;\n plan.pages.forEach((page, i) => {\n out.push(pageHtml(sheet, page, plan.scale, plan.colWidths, plan.geometry, setup, { sheet: sheet.name, at: i + 1, of: plan.pages.length }));\n });\n }\n if (!geometry || out.length === 0) return null;\n return {\n pagesHtml: out,\n pageWidth: geometry.paperWidth,\n pageHeight: geometry.paperHeight,\n pageSizeInches: { width: geometry.paperWidth / PX_PER_INCH, height: geometry.paperHeight / PX_PER_INCH },\n };\n}\n\n/** The whole printable web page: `@page` set to the paper, one section per page. */\nexport function printDocumentHtml(doc: PrintDocument, title: string): string {\n const { width, height } = doc.pageSizeInches;\n return `<!doctype html><html><head><meta charset=\"utf-8\"><title>${esc(title)}</title>\n<style>@page{size:${width.toFixed(3)}in ${height.toFixed(3)}in;margin:0}html,body{margin:0;padding:0;background:#fff}td{padding:0 6px;overflow:hidden;white-space:nowrap;text-overflow:clip;vertical-align:middle}section:last-child{break-after:auto;page-break-after:auto}</style></head>\n<body data-print-paper=\"${width.toFixed(3)}x${height.toFixed(3)}in\">${doc.pagesHtml.join(\"\\n\")}</body></html>`;\n}\n","/**\n * Outputs of a workbook: CSV/TSV/HTML downloads of the current sheet, and Print / PDF of what its page setup asks for.\n * Both read the same string grid the rest of the workbook code reads\n * (`univerSnapshotToRows`) — one source of what \"the sheet\" contains.\n */\n\nimport { downloadFile } from \"@ai-matrx/kit/download\";\nimport { toDelimitedText } from \"@ai-matrx/alchemy/operate/read\";\nimport { PX_PER_INCH } from \"../core\";\nimport type { SheetPageSetup } from \"./sheet-page-setup\";\nimport { buildPrintDocument, collectPrintSheets, printDocumentHtml } from \"./sheet-print-pages\";\nimport { univerSnapshotToRows, type CellRange } from \"./univer-snapshot-rows\";\n\nexport function sheetGridToCsv(rows: readonly (readonly string[])[]): string {\n const [header, ...body] = rows;\n if (!header) return \"\";\n return toDelimitedText(header, body, { spreadsheetSafe: false });\n}\n\nexport function downloadSheetAsCsv(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const name = `${options.filename.replace(/\\.csv$/i, \"\")}.csv`;\n // BOM so Excel reads UTF-8.\n const blob = new Blob([\"\", sheetGridToCsv(grid.rows)], { type: \"text/csv;charset=utf-8\" });\n downloadFile(name, blob, blob.type);\n return true;\n}\n\n/** Tab-separated values of the current sheet (Google's .tsv download). */\nexport function downloadSheetAsTsv(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const [header, ...body] = grid.rows;\n const text = toDelimitedText(header!, body, { format: \"tsv\", spreadsheetSafe: false });\n const blob = new Blob([\"\\uFEFF\", text], { type: \"text/tab-separated-values;charset=utf-8\" });\n downloadFile(`${options.filename.replace(/\\.tsv$/i, \"\")}.tsv`, blob, blob.type);\n return true;\n}\n\n/** The current sheet as a standalone web page (Google's .html download). */\nexport function downloadSheetAsHtml(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const body = grid.rows.map((r) => `<tr>${r.map((c) => `<td>${esc(c)}</td>`).join(\"\")}</tr>`).join(\"\\n\");\n const html = `<!doctype html><html><head><meta charset=\"utf-8\"><title>${esc(options.filename)} — ${esc(grid.sheetName)}</title>\n<style>body{font:13px system-ui,sans-serif;margin:16px}table{border-collapse:collapse}td{border:1px solid #c0c0c0;padding:2px 6px;vertical-align:top}</style></head>\n<body><table>\n${body}\n</table></body></html>`;\n const blob = new Blob([html], { type: \"text/html;charset=utf-8\" });\n downloadFile(`${options.filename.replace(/\\.html?$/i, \"\")}.html`, blob, blob.type);\n return true;\n}\n\nfunction esc(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\n/** What a print or PDF needs besides the snapshot: the workbook's page setup and the live selection. */\nexport interface SheetPrintOptions {\n sheetId?: string;\n title: string;\n setup: SheetPageSetup;\n /** The cells selected right now (used when the setup prints \"selected cells\"). */\n selection?: CellRange | null;\n}\n\nfunction printDocumentFor(snapshot: unknown, options: SheetPrintOptions) {\n const sheets = collectPrintSheets(snapshot, options.setup, {\n ...(options.sheetId ? { sheetId: options.sheetId } : {}),\n selection: options.selection ?? null,\n });\n return buildPrintDocument(sheets, options.setup);\n}\n\n/** Opens the browser print sheet for what the workbook's page setup asks to print (choose \"Save as PDF\" there). */\nexport function printSheet(snapshot: unknown, options: SheetPrintOptions): boolean {\n const doc = printDocumentFor(snapshot, options);\n if (!doc) return false;\n const html = printDocumentHtml(doc, options.title);\n const frame = document.createElement(\"iframe\");\n frame.style.cssText = \"position:fixed;right:0;bottom:0;width:0;height:0;border:0\";\n document.body.appendChild(frame);\n const fdoc = frame.contentDocument;\n const win = frame.contentWindow;\n if (!fdoc || !win) {\n frame.remove();\n return false;\n }\n fdoc.open();\n fdoc.write(html);\n fdoc.close();\n win.addEventListener(\"afterprint\", () => frame.remove());\n win.focus();\n win.print();\n return true;\n}\n\n/** The sheet's grid as a markdown table (first row is the header row). */\nexport function sheetGridToMarkdownTable(rows: readonly (readonly string[])[]): string {\n if (rows.length === 0) return \"\";\n const width = Math.max(...rows.map((r) => r.length));\n const cell = (v: string | undefined) => (v ?? \"\").replace(/\\|/g, \"\\\\|\").replace(/\\r?\\n/g, \" \");\n const line = (r: readonly string[]) =>\n `| ${Array.from({ length: width }, (_, i) => cell(r[i])).join(\" | \")} |`;\n const [head, ...rest] = rows;\n return [line(head!), `| ${Array.from({ length: width }, () => \"---\").join(\" | \")} |`, ...rest.map(line)].join(\"\\n\");\n}\n\n/**\n * Real PDF download of what the workbook's page setup prints: the same pages Print draws, each one\n * captured and laid on a PDF page of the chosen paper size and orientation. Returns false when empty.\n */\nexport async function downloadSheetAsPdf(snapshot: unknown, options: SheetPrintOptions): Promise<boolean> {\n const doc = printDocumentFor(snapshot, options);\n if (!doc) return false;\n const [{ renderElement, pagesToPdf }, { downloadFile: save }] = await Promise.all([\n import(\"@ai-matrx/alchemy/operate/capture\"),\n import(\"@ai-matrx/kit/download\"),\n ]);\n const host = document.createElement(\"div\");\n host.setAttribute(\"aria-hidden\", \"true\");\n host.style.cssText = \"position:fixed;left:-20000px;top:0\";\n host.innerHTML = `<style>td{padding:0 6px;overflow:hidden;white-space:nowrap;vertical-align:middle}</style>${doc.pagesHtml.join(\"\")}`;\n document.body.appendChild(host);\n try {\n const pages = [];\n for (const el of Array.from(host.querySelectorAll<HTMLElement>(\"[data-print-page]\"))) {\n const image = await renderElement(el, { pixelRatio: 2, backgroundColor: \"#ffffff\", cacheBust: true });\n pages.push({ image, imageType: \"JPEG\" as const, quality: 0.92, placement: \"fill\" as const });\n }\n const mm = (px: number) => Math.round(((px / PX_PER_INCH) * 25.4) * 100) / 100;\n const pdf = await pagesToPdf(pages, {\n orientation: doc.pageWidth > doc.pageHeight ? \"landscape\" : \"portrait\",\n unit: \"mm\",\n format: [mm(Math.min(doc.pageWidth, doc.pageHeight)), mm(Math.max(doc.pageWidth, doc.pageHeight))],\n });\n save(`${options.title.replace(/[\\\\/:*?\"<>|]+/g, \" \").trim() || \"workbook\"}.pdf`, pdf, \"application/pdf\");\n } finally {\n host.remove();\n }\n return true;\n}\n","// features/workbooks/workbook-scope-source.ts\n//\n// Live bridge from the mounted `WorkbookEditor` to the `matrx-user/workbooks`\n// surface emitter on `/workbooks/[id]`.\n//\n// Why a module slot rather than props: the page owns the workbook row and\n// mounts `<SurfaceRuntimeProvider>`, but the sheets / snapshot / save status\n// live inside the editor (Univer refs + local state), one level DOWN. Pushing\n// them up as state would re-render the editor on every keystroke; a\n// registered getter is read once, at Run time, when the user actually\n// launches an agent.\n//\n// Exactly one editor is mounted at a time (one workbook per route), so a\n// single slot keyed by workbookId is enough. The getter returns null when the\n// editor has not booted — callers omit the values, they never fake them.\n\nexport interface WorkbookLiveScope {\n sheets: Array<{ id: string; name: string; index: number }>;\n activeSheetId: string | null;\n activeSheetName: string | null;\n snapshot: Record<string, unknown> | null;\n bootState: \"booting\" | \"ready\" | \"load_error\";\n loadError: string | null;\n saveStatus: string;\n collab: {\n enabled: boolean;\n is_host: boolean;\n self_uid: string;\n remote_peers: number;\n };\n}\n\ninterface Registration {\n workbookId: string;\n read: () => WorkbookLiveScope | null;\n}\n\nlet current: Registration | null = null;\n\n/** Called by `WorkbookEditor` while mounted. Returns an unregister. */\nexport function registerWorkbookScopeSource(\n registration: Registration,\n): () => void {\n current = registration;\n return () => {\n if (current === registration) current = null;\n };\n}\n\n/**\n * Read the live editor state for `workbookId`. Returns null when no editor is\n * mounted, when a different workbook is mounted, or when Univer has not\n * booted yet — never a fabricated shape.\n */\nexport function readWorkbookScopeSource(\n workbookId: string,\n): WorkbookLiveScope | null {\n if (!current || current.workbookId !== workbookId) return null;\n return current.read();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/aidream/aidream/apps/shared/office/dist/sheets.cjs","../src/sheets/univer-snapshot-rows.ts","../src/sheets/snapshot-preview-svg.ts","../src/sheets/snapshot-grid.ts","../src/core/document-page-style.ts","../src/sheets/sheet-page-setup.ts","../src/sheets/sheet-page-setup-service.ts","../src/sheets/sheet-print-pages.ts","../src/sheets/sheet-output.ts","../src/sheets/workbook-scope-source.ts"],"names":["current"],"mappings":"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A;AACO,EAAA;AACvB,EAAA;AACT;AAIE;AAGa,EAAA;AACU,EAAA;AACQ,EAAA;AACF,EAAA;AACN,EAAA;AACC,EAAA;AACjB,EAAA;AACT;AAIE;AAGa,EAAA;AACU,EAAA;AACK,EAAA;AACf,EAAA;AAAyG;AAAA;AAGlH;AAAA,sBAAA;AAE4B,EAAA;AACR,EAAA;AACjB,EAAA;AACT;AAEgC;AACE,EAAA;AAClC;AAW0B;AACT,EAAA;AACW,IAAA;AACL,IAAA;AACpB,EAAA;AAC8B,EAAA;AACjC;AAG8C;AACf,EAAA;AACZ,EAAA;AACc,EAAA;AACR,EAAA;AACD,EAAA;AACS,EAAA;AACZ,EAAA;AACD,EAAA;AACC,EAAA;AACJ,IAAA;AACN,IAAA;AACT,EAAA;AACU,EAAA;AACK,EAAA;AACJ,EAAA;AACU,EAAA;AACX,EAAA;AACA,EAAA;AACH,EAAA;AACT;AAGyC;AACT,EAAA;AACC,EAAA;AACmB,EAAA;AAErC,EAAA;AACW,EAAA;AACQ,EAAA;AAClC;AAMyC;AACV,EAAA;AACZ,EAAA;AACO,EAAA;AACf,IAAA;AACA,IAAA;AACR,EAAA;AACqB,EAAA;AACJ,EAAA;AACG,EAAA;AACJ,EAAA;AACa,EAAA;AAC1B,EAAA;AACa,IAAA;AACa,IAAA;AACN,MAAA;AACA,MAAA;AACtB,IAAA;AACwC,IAAA;AACX,IAAA;AACV,MAAA;AACX,MAAA;AACmB,MAAA;AAC1B,IAAA;AAC6B,IAAA;AAC9B,EAAA;AACY,IAAA;AACd,EAAA;AACO,EAAA;AACT;AR0rBkC;AACA;AS9yBC;AAGnB;AAGJ,EAAA;AACG,EAAA;AACmB,IAAA;AAChC,EAAA;AACF;AAQE;AAEwB,EAAA;AACJ,EAAA;AACtB;AToyBkC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/aidream/aidream/apps/shared/office/dist/sheets.cjs","sourcesContent":[null,"/**\n * features/workbooks/univer-snapshot-rows.ts\n *\n * Snapshot → rows: read a Univer `IWorkbookData` snapshot back out as a plain\n * string grid. The missing half of the workbook round trip — `export-targets`\n * pushes rows INTO a workbook; this reads the (possibly user-edited) values\n * back OUT so features can offer \"edit in the workbook, then import your\n * changes\". Values only (formulas come back as their cached value); first\n * sheet by `sheetOrder` unless a sheet id is named. A number shown through a date format reads as\n * its ISO date (a spreadsheet keeps dates as day serials). Reusable — do not fork a per-feature\n * snapshot walker. Callers: the workbook's \"Make this sheet a table\" (features/workbooks/table-link).\n */\n\ninterface CellShape {\n v?: unknown;\n s?: unknown;\n}\n\ninterface SheetShape {\n name?: string;\n /** Frozen panes: `xSplit` columns and `ySplit` rows are pinned. */\n freeze?: { xSplit?: number; ySplit?: number } | null;\n /** Univer marks a hidden column/row `hd: 1` (a table link's Record ID column is one). */\n columnData?: Record<string, { hd?: number } | null | undefined>;\n rowData?: Record<string, { hd?: number } | null | undefined>;\n cellData?: Record<string, Record<string, CellShape | null | undefined>>;\n}\n\ninterface SnapshotShape {\n sheetOrder?: string[];\n sheets?: Record<string, SheetShape>;\n styles?: Record<string, { n?: { pattern?: string } | null } | null>;\n}\n\nexport interface SnapshotRows {\n sheetName: string;\n /** Dense rectangular grid, trailing empty rows/columns trimmed. */\n rows: string[][];\n /** Rows pinned at the top of the sheet (Freeze rows), counted in `rows`. */\n frozenRows: number;\n /** Columns pinned at the left of the sheet (Freeze columns), counted in each row. */\n frozenCols: number;\n}\n\n/** A zero-based, inclusive cell range (a selection). */\nexport interface CellRange {\n startRow: number;\n endRow: number;\n startColumn: number;\n endColumn: number;\n}\n\n/** Sheet ids in tab order. */\nexport function univerSheetIds(snapshot: unknown): string[] {\n if (typeof snapshot !== \"object\" || snapshot === null) return [];\n const shape = snapshot as SnapshotShape;\n const sheets = shape.sheets ?? {};\n const ordered = (shape.sheetOrder ?? []).filter((id) => sheets[id]);\n return ordered.length ? ordered : Object.keys(sheets);\n}\n\ntype Styles = SnapshotShape[\"styles\"];\n\n/** The number-format pattern a cell is shown through, if any. */\nfunction patternOf(cell: CellShape | null | undefined, styles: Styles): string | null {\n const s = cell?.s;\n const style = typeof s === \"string\" ? styles?.[s] : s && typeof s === \"object\" ? (s as { n?: { pattern?: string } }) : null;\n const pattern = style?.n?.pattern;\n return typeof pattern === \"string\" ? pattern : null;\n}\n\nconst DAY_MS = 86_400_000;\nconst SERIAL_EPOCH_MS = Date.UTC(1899, 11, 30);\n\nfunction cellText(cell: CellShape | null | undefined, styles?: Styles): string {\n const value = cell?.v;\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"number\") {\n const pattern = patternOf(cell, styles)?.replace(/\"[^\"]*\"/g, \"\").toLowerCase() ?? \"\";\n if (/[dy]/.test(pattern)) {\n const iso = new Date(Math.round(SERIAL_EPOCH_MS + value * DAY_MS)).toISOString();\n return /h/.test(pattern) ? `${iso.slice(0, 10)} ${iso.slice(11, 16)}` : iso.slice(0, 10);\n }\n }\n return String(value);\n}\n\n/**\n * Extract the first worksheet of a Univer workbook snapshot as a string grid.\n * Returns null when the value is not snapshot-shaped or has no sheets.\n * `skipHidden` leaves out hidden columns and rows: every read-only view (a share page, an agent's\n * read) passes it, so the table link's hidden Record ID column never reaches a reader.\n */\nexport function univerSnapshotToRows(snapshot: unknown, options: { sheetId?: string; skipHidden?: boolean; range?: CellRange } = {}): SnapshotRows | null {\n if (typeof snapshot !== \"object\" || snapshot === null) return null;\n const shape = snapshot as SnapshotShape;\n const sheets = shape.sheets ?? {};\n const styles = shape.styles;\n const firstId = options.sheetId\n ? sheets[options.sheetId]\n ? options.sheetId\n : undefined\n : (shape.sheetOrder?.find((id) => sheets[id]) ?? Object.keys(sheets)[0]);\n if (!firstId) return null;\n const sheet = sheets[firstId];\n const cellData = sheet?.cellData ?? {};\n\n let maxRow = -1;\n let maxCol = -1;\n for (const [rowKey, row] of Object.entries(cellData)) {\n const rowIndex = Number(rowKey);\n if (!Number.isInteger(rowIndex) || !row) continue;\n for (const [colKey, cell] of Object.entries(row)) {\n const colIndex = Number(colKey);\n if (!Number.isInteger(colIndex)) continue;\n if (cellText(cell) === \"\") continue;\n if (rowIndex > maxRow) maxRow = rowIndex;\n if (colIndex > maxCol) maxCol = colIndex;\n }\n }\n const range = options.range;\n if (range) {\n // A selection prints exactly the cells chosen, empty ones included.\n maxRow = range.endRow;\n maxCol = range.endColumn;\n }\n if (maxRow < 0 || maxCol < 0) {\n return { sheetName: sheet?.name ?? \"Sheet1\", rows: [], frozenRows: 0, frozenCols: 0 };\n }\n const firstRow = range?.startRow ?? 0;\n const firstCol = range?.startColumn ?? 0;\n\n const hiddenCol = (c: number) => options.skipHidden === true && sheet?.columnData?.[String(c)]?.hd === 1;\n const hiddenRow = (r: number) => options.skipHidden === true && sheet?.rowData?.[String(r)]?.hd === 1;\n const rows: string[][] = [];\n const ySplit = Math.max(0, sheet?.freeze?.ySplit ?? 0);\n const xSplit = Math.max(0, sheet?.freeze?.xSplit ?? 0);\n let frozenRows = 0;\n let frozenCols = 0;\n for (let r = firstRow; r <= maxRow; r += 1) {\n if (hiddenRow(r)) continue;\n if (r < ySplit) frozenRows += 1;\n const row: string[] = [];\n const source = cellData[String(r)] ?? {};\n let colsFrozenHere = 0;\n for (let c = firstCol; c <= maxCol; c += 1) {\n if (hiddenCol(c)) continue;\n if (c < xSplit) colsFrozenHere += 1;\n row.push(cellText(source[String(c)], styles));\n }\n frozenCols = colsFrozenHere;\n rows.push(row);\n }\n return { sheetName: sheet?.name ?? \"Sheet1\", rows, frozenRows, frozenCols };\n}\n","/**\n * snapshot → SVG: a faithful miniature of a Univer workbook's first sheet or a\n * Univer document's first page — the gallery tile Google draws. Pure (no DOM,\n * no Univer runtime), so it runs in the browser (thumbnail capture), in tests\n * and in node. Reads only what a snapshot stores: cell values + styles +\n * column widths + merges + conditional formats + checkboxes for sheets; the\n * dataStream + text runs + paragraph styles + tables for documents.\n */\n\nexport const THUMB_WIDTH = 320;\nexport const THUMB_HEIGHT = 414;\n\ntype Rgb = { rgb?: string | null } | null | undefined;\ntype CellStyle = {\n bg?: Rgb;\n cl?: Rgb;\n bl?: number;\n it?: number;\n fs?: number;\n ht?: number;\n n?: { pattern?: string } | null;\n bd?: Record<string, unknown> | null;\n};\ntype Cell = { v?: unknown; s?: string | CellStyle | null; t?: number; f?: string };\ntype Sheet = {\n id?: string;\n name?: string;\n cellData?: Record<string, Record<string, Cell>>;\n columnData?: Record<string, { w?: number; hd?: number }>;\n rowData?: Record<string, { h?: number; hd?: number }>;\n defaultColumnWidth?: number;\n defaultRowHeight?: number;\n mergeData?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n showGridlines?: number;\n freeze?: { ySplit?: number; xSplit?: number };\n};\nexport type Workbook = {\n sheetOrder?: string[];\n sheets?: Record<string, Sheet>;\n styles?: Record<string, CellStyle | null>;\n resources?: Array<{ name?: string; data?: string }>;\n};\n\nconst esc = (s: string) =>\n s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n\nfunction color(c: Rgb, fallback: string): string {\n const v = c?.rgb;\n return typeof v === \"string\" && v.length > 0 ? v : fallback;\n}\n\n// ─── number formats ──────────────────────────────────────────────────────────\n\nconst EXCEL_EPOCH = Date.UTC(1899, 11, 30);\nconst MONTHS = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n\nexport function formatCellValue(v: unknown, pattern?: string | null): string {\n if (v === null || v === undefined) return \"\";\n if (typeof v === \"boolean\") return v ? \"TRUE\" : \"FALSE\";\n if (typeof v !== \"number\" || !pattern || pattern === \"General\") return String(v);\n const p = pattern.toLowerCase();\n if (/[dy]/.test(p) && !p.includes(\"$\")) {\n const d = new Date(EXCEL_EPOCH + Math.round(v) * 86400000);\n const mm = d.getUTCMonth();\n const dd = d.getUTCDate();\n const yy = d.getUTCFullYear();\n if (p.includes(\"mmm\")) return `${MONTHS[mm]} ${dd}${p.includes(\"y\") ? `, ${yy}` : \"\"}`;\n return p.includes(\"y\") ? `${mm + 1}/${dd}/${yy}` : `${mm + 1}/${dd}`;\n }\n const decimals = (pattern.split(\".\")[1]?.match(/0/g) ?? []).length;\n if (p.includes(\"%\")) return `${(v * 100).toFixed(decimals)}%`;\n const grouped = Math.abs(v).toLocaleString(\"en-US\", {\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n useGrouping: pattern.includes(\",\"),\n });\n const sign = v < 0 ? \"-\" : \"\";\n return p.includes(\"$\") ? `${sign}$${grouped}` : `${sign}${grouped}`;\n}\n\n// ─── conditional formatting (the rules a preview can evaluate) ───────────────\n\nexport type CfRule = {\n rule?: {\n type?: string;\n subType?: string;\n operator?: string;\n value?: unknown;\n style?: CellStyle;\n };\n ranges?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n};\n\nexport function parseResource<T>(wb: Workbook, name: string): T | null {\n const res = wb.resources?.find((r) => r.name === name);\n if (!res?.data) return null;\n try {\n return JSON.parse(res.data) as T;\n } catch {\n return null;\n }\n}\n\nexport function cfMatch(rule: NonNullable<CfRule[\"rule\"]>, v: unknown): boolean {\n if (rule.type !== \"highlightCell\") return false;\n if (rule.subType === \"number\" && typeof v === \"number\") {\n const x = rule.value;\n const [a = 0, b = 0] = Array.isArray(x) ? (x as number[]) : [Number(x), Number(x)];\n switch (rule.operator) {\n case \"greaterThan\": return v > a;\n case \"greaterThanOrEqual\": return v >= a;\n case \"lessThan\": return v < a;\n case \"lessThanOrEqual\": return v <= a;\n case \"equal\": return v === a;\n case \"notEqual\": return v !== a;\n case \"between\": return v >= a && v <= b;\n default: return false;\n }\n }\n if (rule.subType === \"text\" && v !== undefined && v !== null) {\n const s = String(v).toLowerCase();\n const want = String(rule.value ?? \"\").toLowerCase();\n switch (rule.operator) {\n case \"containsText\": return s.includes(want);\n case \"equal\": return s === want;\n case \"beginsWith\": return s.startsWith(want);\n default: return false;\n }\n }\n return false;\n}\n\n// ─── workbook ────────────────────────────────────────────────────────────────\n\nexport function workbookPreviewSvg(snapshot: unknown): string {\n const wb = (snapshot ?? {}) as Workbook;\n const firstId = wb.sheetOrder?.[0] ?? Object.keys(wb.sheets ?? {})[0];\n const sheet: Sheet = (firstId && wb.sheets?.[firstId]) || {};\n const sheetId = sheet.id ?? firstId ?? \"\";\n const styles = wb.styles ?? {};\n const cfAll = parseResource<Record<string, CfRule[]>>(wb, \"SHEET_CONDITIONAL_FORMATTING_PLUGIN\");\n const cf = (cfAll?.[sheetId] ?? []).filter((r) => r.rule && r.ranges);\n const dvAll = parseResource<Record<string, Array<{ type?: string; ranges?: CfRule[\"ranges\"] }>>>(\n wb,\n \"SHEET_DATA_VALIDATION_PLUGIN\",\n );\n const checkboxRanges = (dvAll?.[sheetId] ?? []).filter((d) => d.type === \"checkbox\").flatMap((d) => d.ranges ?? []);\n const inRanges = (rs: CfRule[\"ranges\"], r: number, c: number) =>\n (rs ?? []).some((x) => r >= x.startRow && r <= x.endRow && c >= x.startColumn && c <= x.endColumn);\n\n const dcw = sheet.defaultColumnWidth ?? 88;\n const drh = sheet.defaultRowHeight ?? 24;\n const colW = (c: number) => (sheet.columnData?.[c]?.hd ? 0 : sheet.columnData?.[c]?.w ?? dcw);\n const rowH = (r: number) => (sheet.rowData?.[r]?.hd ? 0 : sheet.rowData?.[r]?.h ?? drh);\n\n // Show the used width (at least ~5 default columns), scaled to the tile.\n let maxCol = 0;\n for (const row of Object.values(sheet.cellData ?? {})) {\n for (const c of Object.keys(row ?? {})) maxCol = Math.max(maxCol, Number(c));\n }\n let used = 0;\n for (let c = 0; c <= maxCol; c++) used += colW(c);\n // Google's tiles show the top-left of the sheet at a readable size, not the whole width.\n const span = Math.min(Math.max(used + 12, dcw * 5), 640);\n const scale = THUMB_WIDTH / span;\n\n const out: string[] = [];\n out.push(`<rect width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" fill=\"#ffffff\"/>`);\n const gridOn = sheet.showGridlines !== 0;\n const merges = sheet.mergeData ?? [];\n const covered = new Set<string>();\n for (const m of merges) {\n for (let r = m.startRow; r <= m.endRow; r++)\n for (let c = m.startColumn; c <= m.endColumn; c++)\n if (r !== m.startRow || c !== m.startColumn) covered.add(`${r}:${c}`);\n }\n const texts: string[] = [];\n let y = 0;\n for (let r = 0; y * scale < THUMB_HEIGHT && r < 400; r++) {\n const h = rowH(r);\n let x = 0;\n for (let c = 0; x * scale < THUMB_WIDTH && c < 60; c++) {\n const w = colW(c);\n if (w === 0 || h === 0 || covered.has(`${r}:${c}`)) {\n x += w;\n continue;\n }\n const m = merges.find((mm) => mm.startRow === r && mm.startColumn === c);\n let cw = w;\n let ch = h;\n if (m) {\n cw = 0;\n for (let k = m.startColumn; k <= m.endColumn; k++) cw += colW(k);\n ch = 0;\n for (let k = m.startRow; k <= m.endRow; k++) ch += rowH(k);\n }\n const cell = sheet.cellData?.[r]?.[c];\n const base: CellStyle =\n (typeof cell?.s === \"string\" ? styles[cell.s] : (cell?.s as CellStyle | null)) ?? {};\n let st: CellStyle = base;\n for (const rule of cf) {\n if (inRanges(rule.ranges, r, c) && rule.rule && cfMatch(rule.rule, cell?.v)) {\n st = { ...st, ...rule.rule.style };\n break;\n }\n }\n const X = x * scale;\n const Y = y * scale;\n const W = cw * scale;\n const H = ch * scale;\n const bg = st.bg?.rgb;\n if (bg) out.push(`<rect x=\"${X.toFixed(1)}\" y=\"${Y.toFixed(1)}\" width=\"${W.toFixed(1)}\" height=\"${H.toFixed(1)}\" fill=\"${esc(bg)}\"/>`);\n if (gridOn) out.push(`<rect x=\"${X.toFixed(1)}\" y=\"${Y.toFixed(1)}\" width=\"${W.toFixed(1)}\" height=\"${H.toFixed(1)}\" fill=\"none\" stroke=\"#e2e3e3\" stroke-width=\"0.5\"/>`);\n const fs = Math.max((st.fs ?? 10) * 1.333 * scale, 3);\n const midY = Y + H / 2 + fs * 0.35;\n if (inRanges(checkboxRanges, r, c) && r > 0 && (cell?.v === true || cell?.v === false || cell?.v === 1 || cell?.v === 0 || cell?.v === \"TRUE\" || cell?.v === \"FALSE\")) {\n const box = Math.min(H * 0.55, 9);\n const bx = X + W / 2 - box / 2;\n const by = Y + H / 2 - box / 2;\n const on = cell?.v === true || cell?.v === 1 || cell?.v === \"TRUE\";\n out.push(`<rect x=\"${bx.toFixed(1)}\" y=\"${by.toFixed(1)}\" width=\"${box.toFixed(1)}\" height=\"${box.toFixed(1)}\" rx=\"1\" fill=\"${on ? \"#1a73e8\" : \"#ffffff\"}\" stroke=\"${on ? \"#1a73e8\" : \"#5f6368\"}\" stroke-width=\"0.7\"/>`);\n if (on) out.push(`<path d=\"M${(bx + box * 0.2).toFixed(1)} ${(by + box * 0.5).toFixed(1)} l${(box * 0.25).toFixed(1)} ${(box * 0.25).toFixed(1)} l${(box * 0.4).toFixed(1)} ${(-box * 0.45).toFixed(1)}\" stroke=\"#fff\" stroke-width=\"0.9\" fill=\"none\"/>`);\n } else if (cell && cell.v !== undefined && cell.v !== null && cell.v !== \"\") {\n const text = formatCellValue(cell.v, st.n?.pattern);\n const numeric = typeof cell.v === \"number\";\n const ht = st.ht ?? (numeric ? 3 : 1);\n const anchor = ht === 2 ? \"middle\" : ht === 3 ? \"end\" : \"start\";\n const tx = ht === 2 ? X + W / 2 : ht === 3 ? X + W - 2 * scale * 2 : X + 3 * scale;\n const maxChars = Math.max(Math.floor((m ? W : W * (ht === 1 && !numeric ? 3 : 1)) / (fs * 0.55)), 1);\n const shown = text.length > maxChars ? text.slice(0, maxChars) : text;\n texts.push(\n `<text x=\"${tx.toFixed(1)}\" y=\"${midY.toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" text-anchor=\"${anchor}\" fill=\"${esc(color(st.cl, \"#202124\"))}\"${st.bl ? ' font-weight=\"700\"' : \"\"}${st.it ? ' font-style=\"italic\"' : \"\"}>${esc(shown)}</text>`,\n );\n }\n x += w;\n }\n y += h;\n }\n return wrapSvg([...out, ...texts].join(\"\"));\n}\n\n// ─── document ────────────────────────────────────────────────────────────────\n\ntype TextStyle = { fs?: number; bl?: number; it?: number; cl?: Rgb; ff?: string; bg?: Rgb };\ntype DocData = {\n body?: {\n dataStream?: string;\n paragraphs?: Array<{ startIndex: number; paragraphStyle?: { horizontalAlign?: number; spaceAbove?: { v?: number }; spaceBelow?: { v?: number } } }>;\n textRuns?: Array<{ st: number; ed: number; ts?: TextStyle }>;\n tables?: Array<{ startIndex: number; endIndex: number; tableId: string }>;\n };\n documentStyle?: {\n pageSize?: { width?: number; height?: number };\n marginTop?: number;\n marginLeft?: number;\n marginRight?: number;\n };\n};\n\nconst CONTROL = /[\\x1A\\x1B\\x1C\\x1D\\x0E\\x0F\\x1F\\x1E\\b]/g;\n\nexport function documentPreviewSvg(snapshot: unknown): string {\n const doc = (snapshot ?? {}) as DocData;\n const stream = doc.body?.dataStream ?? \"\";\n const pageW = doc.documentStyle?.pageSize?.width ?? 595;\n const scale = THUMB_WIDTH / pageW;\n const ml = (doc.documentStyle?.marginLeft ?? 72) * scale;\n const mr = (doc.documentStyle?.marginRight ?? 72) * scale;\n const mt = (doc.documentStyle?.marginTop ?? 72) * scale;\n const contentW = THUMB_WIDTH - ml - mr;\n const runs = [...(doc.body?.textRuns ?? [])].sort((a, b) => a.st - b.st);\n const tables = doc.body?.tables ?? [];\n const styleAt = (i: number): TextStyle => runs.find((r) => i >= r.st && i < r.ed)?.ts ?? {};\n /** The style most of a paragraph's characters carry (a bold lead-in does not make the line bold). */\n const dominantStyle = (from: number, to: number): TextStyle => {\n const counts = new Map<string, { n: number; ts: TextStyle }>();\n for (let i = from; i < to; i++) {\n if (/\\s/.test(stream[i] ?? \"\")) continue;\n const ts = styleAt(i);\n const k = JSON.stringify(ts);\n const e = counts.get(k) ?? { n: 0, ts };\n e.n++;\n counts.set(k, e);\n }\n let best: { n: number; ts: TextStyle } | null = null;\n for (const e of counts.values()) if (!best || e.n > best.n) best = e;\n return best?.ts ?? {};\n };\n const out: string[] = [`<rect width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" fill=\"#ffffff\"/>`];\n\n let y = mt;\n let start = 0;\n const paragraphs = doc.body?.paragraphs ?? [];\n for (let p = 0; p < paragraphs.length && y < THUMB_HEIGHT; p++) {\n const para = paragraphs[p];\n if (!para) break;\n const end = para.startIndex;\n const table = tables.find((t) => start >= t.startIndex && start < t.endIndex);\n if (table) {\n // Draw the whole table once: rows split on the row token, cells on the cell token.\n const raw = stream.slice(table.startIndex, table.endIndex);\n const rows = raw.split(\"\\x1B\").slice(1).map((row) =>\n row.split(\"\\x1C\").slice(1).map((cell) => cell.replace(/[\\r\\n]/g, \" \").replace(CONTROL, \"\").trim()),\n );\n const cols = Math.max(1, ...rows.map((r) => r.length));\n const cw = contentW / cols;\n // Bold header row when the first cell's text is bold.\n const headerBold = styleAt(table.startIndex + 4).bl === 1;\n for (let r = 0; r < rows.length && y < THUMB_HEIGHT; r++) {\n const rh = 16 * scale * 1.2 + 6 * scale;\n for (let c = 0; c < cols; c++) {\n const cx = ml + c * cw;\n out.push(`<rect x=\"${cx.toFixed(1)}\" y=\"${y.toFixed(1)}\" width=\"${cw.toFixed(1)}\" height=\"${rh.toFixed(1)}\" fill=\"${r === 0 && headerBold ? \"#f1f3f4\" : \"none\"}\" stroke=\"#9aa0a6\" stroke-width=\"0.4\"/>`);\n const fs = 11 * 1.333 * scale;\n const maxChars = Math.max(Math.floor((cw - 6 * scale) / (fs * 0.5)), 1);\n const t = rows[r]?.[c] ?? \"\";\n out.push(`<text x=\"${(cx + 4 * scale).toFixed(1)}\" y=\"${(y + rh / 2 + fs * 0.35).toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" fill=\"#202124\"${r === 0 && headerBold ? ' font-weight=\"700\"' : \"\"}>${esc(t.slice(0, maxChars))}</text>`);\n }\n y += rh;\n }\n // Skip every paragraph inside the table.\n while (p + 1 < paragraphs.length && (paragraphs[p + 1]?.startIndex ?? Infinity) < table.endIndex) p++;\n start = table.endIndex;\n y += 6 * scale;\n continue;\n }\n const text = stream.slice(start, end).replace(CONTROL, \"\");\n const st = dominantStyle(start, end);\n const ps = para.paragraphStyle ?? {};\n const fsPt = st.fs ?? 11;\n const fs = fsPt * 1.333 * scale;\n const lineH = fs * 1.3;\n y += (ps.spaceAbove?.v ?? (fsPt > 13 ? 8 : 0)) * scale;\n const align = ps.horizontalAlign ?? 1;\n const anchor = align === 2 ? \"middle\" : align === 3 ? \"end\" : \"start\";\n const tx = align === 2 ? ml + contentW / 2 : align === 3 ? ml + contentW : ml;\n // Paragraph shading (a filled band) when the run carries a highlight.\n if (!text.trim()) {\n y += lineH * 0.8;\n } else {\n const maxChars = Math.max(Math.floor(contentW / (fs * (st.bl ? 0.56 : 0.5))), 4);\n const words = text.split(/\\s+/);\n const lines: string[] = [];\n let line = \"\";\n for (const w of words) {\n if ((line + \" \" + w).trim().length > maxChars && line) {\n lines.push(line);\n line = w;\n } else line = (line + \" \" + w).trim();\n }\n if (line) lines.push(line);\n for (const l of lines) {\n if (y > THUMB_HEIGHT) break;\n y += lineH;\n if (st.bg?.rgb) out.push(`<rect x=\"${ml.toFixed(1)}\" y=\"${(y - fs).toFixed(1)}\" width=\"${contentW.toFixed(1)}\" height=\"${lineH.toFixed(1)}\" fill=\"${esc(st.bg.rgb)}\"/>`);\n out.push(`<text x=\"${tx.toFixed(1)}\" y=\"${y.toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" text-anchor=\"${anchor}\" fill=\"${esc(color(st.cl, \"#202124\"))}\"${st.bl ? ' font-weight=\"700\"' : \"\"}${st.it ? ' font-style=\"italic\"' : \"\"}${st.ff && /serif|georgia|times|garamond/i.test(st.ff) && !/sans/i.test(st.ff) ? ' font-family=\"Georgia, serif\"' : \"\"}>${esc(l)}</text>`);\n }\n }\n y += (ps.spaceBelow?.v ?? 4) * scale;\n start = end + 1;\n }\n return wrapSvg(out.join(\"\"));\n}\n\nfunction wrapSvg(body: string): string {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" viewBox=\"0 0 ${THUMB_WIDTH} ${THUMB_HEIGHT}\" font-family=\"Arial, Helvetica, sans-serif\">${body}</svg>`;\n}\n\nexport function snapshotPreviewSvg(kind: \"workbook\" | \"document\", snapshot: unknown): string {\n return kind === \"workbook\" ? workbookPreviewSvg(snapshot) : documentPreviewSvg(snapshot);\n}\n","/**\n * features/workbooks/snapshot-grid.ts\n *\n * Snapshot → a formatted, read-only grid model: what a spreadsheet VIEW needs and the plain-string\n * `univer-snapshot-rows` does not carry — number/currency/date formats applied, checkbox cells\n * (data-validation ranges of type checkbox), alignment, bold/italic, fill and text colour, column\n * widths, merges, frozen rows/columns, hidden rows/columns and sheets. Pure (no DOM, no Univer\n * runtime): the signed-out share page draws it. The number formatter is the thumbnail's\n * (`formatCellValue`) so a tile, a share link and the editor read the same.\n */\n\nimport {\n cfMatch,\n formatCellValue,\n parseResource,\n type CfRule,\n type Workbook,\n} from \"./snapshot-preview-svg\";\n\ntype Rgb = { rgb?: string | null } | null | undefined;\ninterface Style {\n bg?: Rgb;\n cl?: Rgb;\n bl?: number;\n it?: number;\n fs?: number;\n ht?: number;\n tb?: number;\n n?: { pattern?: string } | null;\n}\ninterface Cell {\n v?: unknown;\n s?: string | Style | null;\n}\ninterface Sheet {\n id?: string;\n name?: string;\n hidden?: number;\n cellData?: Record<string, Record<string, Cell | null | undefined>>;\n columnData?: Record<string, { w?: number; hd?: number } | null | undefined>;\n rowData?: Record<string, { h?: number; hd?: number } | null | undefined>;\n defaultColumnWidth?: number;\n defaultRowHeight?: number;\n mergeData?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n showGridlines?: number;\n freeze?: { xSplit?: number; ySplit?: number };\n}\n\nexport interface GridCell {\n text: string;\n /** A checkbox cell (a data-validation checkbox range): `checked` says its state. */\n checkbox?: { checked: boolean } | undefined;\n align: \"left\" | \"center\" | \"right\";\n bold: boolean;\n italic: boolean;\n /** Font size in px (the snapshot stores points). */\n fontPx: number;\n bg?: string | undefined;\n color?: string | undefined;\n wrap: boolean;\n rowSpan: number;\n colSpan: number;\n /** Covered by a merge that starts elsewhere: draw nothing. */\n covered: boolean;\n}\n\nexport interface GridSheet {\n id: string;\n name: string;\n /** Visible column indexes (hidden columns left out) with their pixel widths. */\n columns: Array<{ index: number; width: number }>;\n rows: Array<{ index: number; height: number; cells: GridCell[] }>;\n /** How many leading VISIBLE rows / columns stay put while scrolling. */\n frozenRows: number;\n frozenColumns: number;\n gridlines: boolean;\n /** Rows beyond the cap were left out. */\n truncatedFrom: number | null;\n}\n\nexport const GRID_MAX_ROWS = 500;\nexport const GRID_MAX_COLUMNS = 60;\n\nconst PT_TO_PX = 1.333;\nconst isCheckboxValue = (v: unknown) => v === true || v === false || v === 1 || v === 0 || v === \"TRUE\" || v === \"FALSE\";\nconst isOn = (v: unknown) => v === true || v === 1 || v === \"TRUE\";\n\nfunction hasValue(cell: Cell | null | undefined): boolean {\n const v = cell?.v;\n return v !== undefined && v !== null && v !== \"\";\n}\n\n/** Every visible sheet that has something in it, in tab order. Empty and hidden sheets are left out. */\nexport function snapshotToGridSheets(snapshot: unknown): GridSheet[] {\n if (typeof snapshot !== \"object\" || snapshot === null) return [];\n const wb = snapshot as Workbook;\n const sheets = wb.sheets ?? {};\n const order = (wb.sheetOrder ?? []).filter((id) => sheets[id]);\n const ids = order.length > 0 ? order : Object.keys(sheets);\n const out: GridSheet[] = [];\n for (const id of ids) {\n const grid = sheetToGrid(wb, id, sheets[id] as Sheet);\n if (grid) out.push(grid);\n }\n return out;\n}\n\nfunction sheetToGrid(wb: Workbook, id: string, sheet: Sheet): GridSheet | null {\n if (sheet.hidden === 1) return null;\n const cellData = sheet.cellData ?? {};\n let maxRow = -1;\n let maxCol = -1;\n for (const [rk, row] of Object.entries(cellData)) {\n const r = Number(rk);\n if (!Number.isInteger(r) || !row) continue;\n for (const [ck, cell] of Object.entries(row)) {\n const c = Number(ck);\n if (!Number.isInteger(c) || !hasValue(cell)) continue;\n if (r > maxRow) maxRow = r;\n if (c > maxCol) maxCol = c;\n }\n }\n if (maxRow < 0 || maxCol < 0) return null;\n\n const styles = wb.styles ?? {};\n const sheetId = sheet.id ?? id;\n const cfAll = parseResource<Record<string, CfRule[]>>(wb, \"SHEET_CONDITIONAL_FORMATTING_PLUGIN\");\n const cf = (cfAll?.[sheetId] ?? []).filter((r) => r.rule && r.ranges);\n const dvAll = parseResource<Record<string, Array<{ type?: string; ranges?: CfRule[\"ranges\"] }>>>(\n wb,\n \"SHEET_DATA_VALIDATION_PLUGIN\",\n );\n const checkboxRanges = (dvAll?.[sheetId] ?? []).filter((d) => d.type === \"checkbox\").flatMap((d) => d.ranges ?? []);\n const inRanges = (rs: CfRule[\"ranges\"], r: number, c: number) =>\n (rs ?? []).some((x) => r >= x.startRow && r <= x.endRow && c >= x.startColumn && c <= x.endColumn);\n\n const dcw = sheet.defaultColumnWidth ?? 88;\n const drh = sheet.defaultRowHeight ?? 24;\n const lastCol = Math.min(maxCol, GRID_MAX_COLUMNS - 1);\n const columns: GridSheet[\"columns\"] = [];\n for (let c = 0; c <= lastCol; c += 1) {\n const col = sheet.columnData?.[String(c)];\n if (col?.hd === 1) continue;\n columns.push({ index: c, width: col?.w ?? dcw });\n }\n\n const merges = sheet.mergeData ?? [];\n const covered = new Set<string>();\n for (const m of merges) {\n for (let r = m.startRow; r <= m.endRow; r += 1)\n for (let c = m.startColumn; c <= m.endColumn; c += 1) if (r !== m.startRow || c !== m.startColumn) covered.add(`${r}:${c}`);\n }\n\n const rows: GridSheet[\"rows\"] = [];\n const lastRow = Math.min(maxRow, GRID_MAX_ROWS - 1);\n for (let r = 0; r <= lastRow; r += 1) {\n const rd = sheet.rowData?.[String(r)];\n if (rd?.hd === 1) continue;\n const source = cellData[String(r)] ?? {};\n const cells: GridCell[] = columns.map(({ index: c }) => {\n const cell = source[String(c)] ?? undefined;\n const base: Style = (typeof cell?.s === \"string\" ? (styles[cell.s] as Style | null | undefined) : (cell?.s as Style | null | undefined)) ?? {};\n let st: Style = base;\n for (const rule of cf) {\n if (inRanges(rule.ranges, r, c) && rule.rule && cfMatch(rule.rule, cell?.v)) {\n st = { ...st, ...(rule.rule.style as Style | undefined) };\n break;\n }\n }\n const m = merges.find((mm) => mm.startRow === r && mm.startColumn === c);\n const v = cell?.v;\n const box = hasValue(cell) && inRanges(checkboxRanges, r, c) && isCheckboxValue(v);\n const numeric = typeof v === \"number\";\n const ht = st.ht ?? 0;\n return {\n text: box ? \"\" : hasValue(cell) ? formatCellValue(v, st.n?.pattern) : \"\",\n checkbox: box ? { checked: isOn(v) } : undefined,\n align: box || ht === 2 ? \"center\" : ht === 3 || (ht === 0 && numeric) ? \"right\" : \"left\",\n bold: st.bl === 1,\n italic: st.it === 1,\n fontPx: Math.round((st.fs ?? 10) * PT_TO_PX),\n bg: st.bg?.rgb ?? undefined,\n color: st.cl?.rgb ?? undefined,\n wrap: st.tb === 3,\n rowSpan: m ? m.endRow - m.startRow + 1 : 1,\n colSpan: m ? m.endColumn - m.startColumn + 1 : 1,\n covered: covered.has(`${r}:${c}`),\n };\n });\n rows.push({ index: r, height: rd?.h ?? drh, cells });\n }\n\n const ySplit = sheet.freeze?.ySplit ?? 0;\n const xSplit = sheet.freeze?.xSplit ?? 0;\n return {\n id: sheetId,\n name: sheet.name ?? \"Sheet1\",\n columns,\n rows,\n frozenRows: Math.min(rows.filter((r) => r.index < ySplit).length, rows.length),\n frozenColumns: Math.min(columns.filter((c) => c.index < xSplit).length, columns.length),\n gridlines: sheet.showGridlines !== 0,\n truncatedFrom: maxRow > lastRow ? maxRow + 1 : null,\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 colour, hex. Always a light colour 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 colour (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 * A workbook's print settings — Google Sheets' File → Page setup / Print, as pure data and pure\n * pagination (no React, no IO). They live on the workbook (`udt_workbooks.metadata.page_setup`),\n * so Print, Download as PDF and the Page setup dialog all read the same values.\n *\n * Geometry is in 96-dpi CSS pixels, like the rest of the document stack (`PX_PER_INCH`).\n */\n\nimport { PAPER_SIZES, PX_PER_INCH, type PaperSizeName } from \"../core\";\n\nexport const SHEET_SCALES = [\"normal\", \"width\", \"height\", \"page\"] as const;\nexport type SheetScale = (typeof SHEET_SCALES)[number];\nexport const SHEET_MARGIN_PRESETS = [\"normal\", \"narrow\", \"wide\", \"custom\"] as const;\nexport type SheetMarginPreset = (typeof SHEET_MARGIN_PRESETS)[number];\nexport const SHEET_PRINT_SCOPES = [\"sheet\", \"workbook\", \"selection\"] as const;\nexport type SheetPrintScope = (typeof SHEET_PRINT_SCOPES)[number];\nexport type SheetPageOrder = \"down-over\" | \"over-down\";\nexport type SheetAlignH = \"left\" | \"center\" | \"right\";\nexport type SheetAlignV = \"top\" | \"middle\" | \"bottom\";\n\nexport interface SheetPageSetup {\n paper: PaperSizeName;\n orientation: \"portrait\" | \"landscape\";\n scale: SheetScale;\n margins: SheetMarginPreset;\n /** Inches; read only when `margins` is \"custom\". */\n customMargins: { top: number; bottom: number; left: number; right: number };\n scope: SheetPrintScope;\n gridlines: boolean;\n repeatFrozenRows: boolean;\n repeatFrozenColumns: boolean;\n pageOrder: SheetPageOrder;\n alignH: SheetAlignH;\n alignV: SheetAlignV;\n}\n\n/** Google Sheets' defaults: Letter, portrait, 100%, normal margins, current sheet, gridlines on. */\nexport const DEFAULT_SHEET_PAGE_SETUP: SheetPageSetup = {\n paper: \"Letter\",\n orientation: \"portrait\",\n scale: \"normal\",\n margins: \"normal\",\n customMargins: { top: 0.75, bottom: 0.75, left: 0.7, right: 0.7 },\n scope: \"sheet\",\n gridlines: true,\n repeatFrozenRows: false,\n repeatFrozenColumns: false,\n pageOrder: \"down-over\",\n alignH: \"left\",\n alignV: \"top\",\n};\n\n/** Google's three preset margins, in inches. */\nexport const MARGIN_PRESET_INCHES: Record<Exclude<SheetMarginPreset, \"custom\">, { top: number; bottom: number; left: number; right: number }> = {\n normal: { top: 0.75, bottom: 0.75, left: 0.7, right: 0.7 },\n narrow: { top: 0.25, bottom: 0.25, left: 0.25, right: 0.25 },\n wide: { top: 1, bottom: 1, left: 1, right: 1 },\n};\n\nconst isPaper = (v: unknown): v is PaperSizeName => typeof v === \"string\" && v in PAPER_SIZES;\nconst oneOf = <T extends string>(list: readonly T[], v: unknown, fallback: T): T => (typeof v === \"string\" && (list as readonly string[]).includes(v) ? (v as T) : fallback);\nconst inches = (v: unknown, fallback: number) => (typeof v === \"number\" && Number.isFinite(v) && v >= 0 && v <= 5 ? v : fallback);\n\n/** Any stored value → a complete, valid setup. Unknown or broken parts fall back to the default. */\nexport function normalizeSheetPageSetup(raw: unknown): SheetPageSetup {\n const r = (raw && typeof raw === \"object\" ? raw : {}) as Record<string, unknown>;\n const m = (r.customMargins && typeof r.customMargins === \"object\" ? r.customMargins : {}) as Record<string, unknown>;\n const d = DEFAULT_SHEET_PAGE_SETUP;\n return {\n paper: isPaper(r.paper) ? r.paper : d.paper,\n orientation: r.orientation === \"landscape\" ? \"landscape\" : \"portrait\",\n scale: oneOf(SHEET_SCALES, r.scale, d.scale),\n margins: oneOf(SHEET_MARGIN_PRESETS, r.margins, d.margins),\n customMargins: {\n top: inches(m.top, d.customMargins.top),\n bottom: inches(m.bottom, d.customMargins.bottom),\n left: inches(m.left, d.customMargins.left),\n right: inches(m.right, d.customMargins.right),\n },\n scope: oneOf(SHEET_PRINT_SCOPES, r.scope, d.scope),\n gridlines: typeof r.gridlines === \"boolean\" ? r.gridlines : d.gridlines,\n repeatFrozenRows: r.repeatFrozenRows === true,\n repeatFrozenColumns: r.repeatFrozenColumns === true,\n pageOrder: r.pageOrder === \"over-down\" ? \"over-down\" : \"down-over\",\n alignH: oneOf([\"left\", \"center\", \"right\"] as const, r.alignH, d.alignH),\n alignV: oneOf([\"top\", \"middle\", \"bottom\"] as const, r.alignV, d.alignV),\n };\n}\n\n/** The setup stored on a workbook's metadata (`metadata.page_setup`), complete and valid. */\nexport function pageSetupFromMetadata(metadata: unknown): SheetPageSetup {\n return normalizeSheetPageSetup((metadata as { page_setup?: unknown } | null)?.page_setup);\n}\n\nexport interface PrintGeometry {\n /** Paper as printed (orientation applied), px. */\n paperWidth: number;\n paperHeight: number;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /** The printable box inside the margins, px. */\n areaWidth: number;\n areaHeight: number;\n}\n\nexport function printGeometry(setup: SheetPageSetup): PrintGeometry {\n const base = PAPER_SIZES[setup.paper];\n const landscape = setup.orientation === \"landscape\";\n const paperWidth = landscape ? base.height : base.width;\n const paperHeight = landscape ? base.width : base.height;\n const m = setup.margins === \"custom\" ? setup.customMargins : MARGIN_PRESET_INCHES[setup.margins];\n const px = (n: number) => Math.round(n * PX_PER_INCH);\n const geometry = {\n paperWidth,\n paperHeight,\n marginTop: px(m.top),\n marginBottom: px(m.bottom),\n marginLeft: px(m.left),\n marginRight: px(m.right),\n };\n return {\n ...geometry,\n areaWidth: Math.max(48, paperWidth - geometry.marginLeft - geometry.marginRight),\n areaHeight: Math.max(48, paperHeight - geometry.marginTop - geometry.marginBottom),\n };\n}\n\nexport const PRINT_ROW_HEIGHT = 22;\nconst MIN_COL = 48;\nconst MAX_COL = 320;\nconst CHAR_PX = 7;\n\n/** Column widths (px) fitted to the text the column holds. */\nexport function printColumnWidths(rows: readonly (readonly string[])[]): number[] {\n const width = rows.reduce((n, r) => Math.max(n, r.length), 0);\n const out: number[] = [];\n for (let c = 0; c < width; c += 1) {\n let longest = 0;\n for (const r of rows) longest = Math.max(longest, (r[c] ?? \"\").length);\n out.push(Math.min(MAX_COL, Math.max(MIN_COL, longest * CHAR_PX + 16)));\n }\n return out;\n}\n\nexport interface PrintPage {\n /** Grid row indexes drawn on this page, in order (repeated frozen rows first). */\n rows: number[];\n /** Grid column indexes drawn on this page, in order (repeated frozen columns first). */\n cols: number[];\n}\n\nexport interface PrintPlan {\n scale: number;\n geometry: PrintGeometry;\n colWidths: number[];\n pages: PrintPage[];\n}\n\n/** Splits `count` items into bands that fit `capacity(px)`, repeating `frozen` leading items on every band after the first. */\nfunction bands(sizes: readonly number[], capacityPx: number, frozen: number, repeat: boolean): number[][] {\n const total = sizes.length;\n if (total === 0) return [];\n const result: number[][] = [];\n const lead = repeat ? Math.min(frozen, total) : 0;\n const leadPx = sizes.slice(0, lead).reduce((a, b) => a + b, 0);\n let at = 0;\n while (at < total) {\n const first = result.length === 0;\n const carry = !first && lead > 0 ? Array.from({ length: lead }, (_, i) => i) : [];\n let used = first ? 0 : leadPx;\n const band = [...carry];\n // A repeated header never leaves a page with no room for a body item.\n if (!first && leadPx >= capacityPx) used = 0;\n let added = 0;\n while (at < total) {\n const size = sizes[at]!;\n if (used + size > capacityPx && added > 0) break;\n band.push(at);\n used += size;\n added += 1;\n at += 1;\n }\n result.push(band);\n }\n return result;\n}\n\n/** The pages one grid prints on under `setup`: scale, repeated frozen panes, and page order. */\nexport function planSheetPrint(\n rows: readonly (readonly string[])[],\n setup: SheetPageSetup,\n frozen: { rows: number; cols: number } = { rows: 0, cols: 0 },\n): PrintPlan {\n const geometry = printGeometry(setup);\n const colWidths = printColumnWidths(rows);\n const totalW = colWidths.reduce((a, b) => a + b, 0) || 1;\n const totalH = rows.length * PRINT_ROW_HEIGHT || 1;\n const fitW = geometry.areaWidth / totalW;\n const fitH = geometry.areaHeight / totalH;\n const scale =\n setup.scale === \"width\" ? Math.min(1, fitW) : setup.scale === \"height\" ? Math.min(1, fitH) : setup.scale === \"page\" ? Math.min(1, fitW, fitH) : 1;\n const rowBands = bands(\n rows.map(() => PRINT_ROW_HEIGHT),\n geometry.areaHeight / scale,\n frozen.rows,\n setup.repeatFrozenRows,\n );\n const colBands = bands(colWidths, geometry.areaWidth / scale, frozen.cols, setup.repeatFrozenColumns);\n const pages: PrintPage[] = [];\n if (setup.pageOrder === \"down-over\") {\n for (const cols of colBands) for (const r of rowBands) pages.push({ rows: r, cols });\n } else {\n for (const r of rowBands) for (const cols of colBands) pages.push({ rows: r, cols });\n }\n return { scale, geometry, colWidths, pages };\n}\n","/**\n * A workbook's print settings, read and written on the workbook itself:\n * `udt_workbooks.metadata.page_setup` (merged with `mergeJsonColumn`, like the table links beside it).\n */\nimport { mergeJsonColumn } from \"@ai-matrx/data/db\";\n\nimport { getSheetsHost } from \"./ports\";\nimport { normalizeSheetPageSetup, pageSetupFromMetadata, type SheetPageSetup } from \"./sheet-page-setup\";\n\nconst db = () => getSheetsHost().getSupabase();\n\ntype WorkbookMetaRow = { id: string; version: number; metadata: unknown };\n\nexport type PageSetupResult = { ok: true; data: SheetPageSetup } | { ok: false; error: string };\n\nexport async function readSheetPageSetup(workbookId: string): Promise<PageSetupResult> {\n const { data, error } = await db().schema(\"workbench\").from(\"udt_workbooks\").select(\"metadata\").eq(\"id\", workbookId).maybeSingle();\n if (error) return { ok: false, error: error.message };\n return { ok: true, data: pageSetupFromMetadata(data?.metadata) };\n}\n\nexport async function writeSheetPageSetup(workbookId: string, setup: SheetPageSetup): Promise<PageSetupResult> {\n const clean = normalizeSheetPageSetup(setup);\n const result = await mergeJsonColumn<WorkbookMetaRow>({\n fetchCurrent: () => db().schema(\"workbench\").from(\"udt_workbooks\").select(\"id, version, metadata\").eq(\"id\", workbookId).maybeSingle(),\n readColumn: (row) => row.metadata,\n merge: (current) => ({ ...current, page_setup: clean }),\n applyUpdate: ({ value, expectedVersion, nextVersion }) =>\n db()\n .schema(\"workbench\")\n .from(\"udt_workbooks\")\n .update({ metadata: value as never, version: nextVersion })\n .eq(\"id\", workbookId)\n .eq(\"version\", expectedVersion)\n .select(\"id, version, metadata\")\n .maybeSingle(),\n });\n if (result.status === \"saved\") return { ok: true, data: pageSetupFromMetadata(result.row.metadata) };\n if (result.status === \"not_found\") return { ok: false, error: \"This workbook could not be found\" };\n if (result.status === \"conflict\") return { ok: false, error: \"The workbook changed while saving; try again\" };\n const reason: unknown = result.error;\n return { ok: false, error: reason instanceof Error ? reason.message : typeof reason === \"string\" ? reason : \"Something went wrong\" };\n}\n","/**\n * The pages a workbook prints on: the snapshot's cells → paper-sized HTML pages that follow the\n * workbook's print settings (`sheet-page-setup.ts`). Print and Download as PDF both draw these\n * same pages, so what the browser prints is what the PDF holds.\n */\n\nimport { PX_PER_INCH } from \"../core\";\nimport {\n PRINT_ROW_HEIGHT,\n planSheetPrint,\n type PrintGeometry,\n type SheetPageSetup,\n} from \"./sheet-page-setup\";\nimport { univerSheetIds, univerSnapshotToRows, type CellRange } from \"./univer-snapshot-rows\";\n\nexport interface PrintSheet {\n name: string;\n rows: string[][];\n frozenRows: number;\n frozenCols: number;\n}\n\n/** The sheets the setup's \"what to print\" asks for (empty sheets left out). */\nexport function collectPrintSheets(\n snapshot: unknown,\n setup: SheetPageSetup,\n options: { sheetId?: string; selection?: CellRange | null },\n): PrintSheet[] {\n const read = (sheetId: string | undefined, range?: CellRange): PrintSheet | null => {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(sheetId ? { sheetId } : {}), ...(range ? { range } : {}) });\n if (!grid || grid.rows.length === 0) return null;\n return { name: grid.sheetName, rows: grid.rows, frozenRows: grid.frozenRows, frozenCols: grid.frozenCols };\n };\n if (setup.scope === \"workbook\") {\n return univerSheetIds(snapshot)\n .map((id) => read(id))\n .filter((s): s is PrintSheet => s !== null);\n }\n if (setup.scope === \"selection\") {\n const sel = options.selection;\n if (!sel || (sel.startRow === sel.endRow && sel.startColumn === sel.endColumn)) return [];\n const one = read(options.sheetId, sel);\n return one ? [one] : [];\n }\n const one = read(options.sheetId);\n return one ? [one] : [];\n}\n\nconst esc = (s: string) => s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n\nconst JUSTIFY = { left: \"flex-start\", center: \"center\", right: \"flex-end\" } as const;\nconst ALIGN = { top: \"flex-start\", middle: \"center\", bottom: \"flex-end\" } as const;\n\nfunction pageHtml(\n sheet: PrintSheet,\n page: { rows: number[]; cols: number[] },\n scale: number,\n colWidths: number[],\n g: PrintGeometry,\n setup: SheetPageSetup,\n numbering: { sheet: string; at: number; of: number },\n): string {\n const widths = page.cols.map((c) => colWidths[c] ?? 0);\n const tableW = widths.reduce((a, b) => a + b, 0);\n const tableH = page.rows.length * PRINT_ROW_HEIGHT;\n const border = setup.gridlines ? \"1px solid #b7b7b7\" : \"none\";\n const body = page.rows\n .map(\n (r) =>\n `<tr style=\"height:${PRINT_ROW_HEIGHT}px\">${page.cols\n .map((c) => `<td style=\"border:${border}\">${esc(sheet.rows[r]?.[c] ?? \"\")}</td>`)\n .join(\"\")}</tr>`,\n )\n .join(\"\");\n const cols = widths.map((w) => `<col style=\"width:${w}px\">`).join(\"\");\n return `<section data-print-page data-sheet=\"${esc(numbering.sheet)}\" data-page-number=\"${numbering.at}\" data-page-count=\"${numbering.of}\" data-page-rows=\"${page.rows.length}\" data-page-cols=\"${page.cols.length}\" style=\"width:${g.paperWidth}px;height:${g.paperHeight}px;box-sizing:border-box;padding:${g.marginTop}px ${g.marginRight}px ${g.marginBottom}px ${g.marginLeft}px;background:#fff;overflow:hidden;break-after:page;page-break-after:always\">\n<div style=\"width:${g.areaWidth}px;height:${g.areaHeight}px;display:flex;justify-content:${JUSTIFY[setup.alignH]};align-items:${ALIGN[setup.alignV]};overflow:hidden\">\n<div data-print-content style=\"width:${tableW * scale}px;height:${tableH * scale}px;flex:none;overflow:hidden\">\n<table style=\"width:${tableW}px;table-layout:fixed;border-collapse:collapse;transform:scale(${scale});transform-origin:0 0;font:12px/${PRINT_ROW_HEIGHT - 2}px system-ui,sans-serif;color:#111\"><colgroup>${cols}</colgroup><tbody>${body}</tbody></table>\n</div></div></section>`;\n}\n\nexport interface PrintDocument {\n /** Every page, in print order. */\n pagesHtml: string[];\n pageWidth: number;\n pageHeight: number;\n /** `@page` size in inches, for the browser's print engine. */\n pageSizeInches: { width: number; height: number };\n}\n\n/** All the printed pages of the chosen sheets under the setup (empty when there is nothing to print). */\nexport function buildSheetPrintDocument(sheets: readonly PrintSheet[], setup: SheetPageSetup): PrintDocument | null {\n const out: string[] = [];\n let geometry: PrintGeometry | null = null;\n for (const sheet of sheets) {\n const plan = planSheetPrint(sheet.rows, setup, { rows: sheet.frozenRows, cols: sheet.frozenCols });\n geometry = plan.geometry;\n plan.pages.forEach((page, i) => {\n out.push(pageHtml(sheet, page, plan.scale, plan.colWidths, plan.geometry, setup, { sheet: sheet.name, at: i + 1, of: plan.pages.length }));\n });\n }\n if (!geometry || out.length === 0) return null;\n return {\n pagesHtml: out,\n pageWidth: geometry.paperWidth,\n pageHeight: geometry.paperHeight,\n pageSizeInches: { width: geometry.paperWidth / PX_PER_INCH, height: geometry.paperHeight / PX_PER_INCH },\n };\n}\n\n/** The whole printable web page: `@page` set to the paper, one section per page. */\nexport function printDocumentHtml(doc: PrintDocument, title: string): string {\n const { width, height } = doc.pageSizeInches;\n return `<!doctype html><html><head><meta charset=\"utf-8\"><title>${esc(title)}</title>\n<style>@page{size:${width.toFixed(3)}in ${height.toFixed(3)}in;margin:0}html,body{margin:0;padding:0;background:#fff}td{padding:0 6px;overflow:hidden;white-space:nowrap;text-overflow:clip;vertical-align:middle}section:last-child{break-after:auto;page-break-after:auto}</style></head>\n<body data-print-paper=\"${width.toFixed(3)}x${height.toFixed(3)}in\">${doc.pagesHtml.join(\"\\n\")}</body></html>`;\n}\n","/**\n * Outputs of a workbook: CSV/TSV/HTML downloads of the current sheet, and Print / PDF of what its page setup asks for.\n * Both read the same string grid the rest of the workbook code reads\n * (`univerSnapshotToRows`) — one source of what \"the sheet\" contains.\n */\n\nimport { downloadFile } from \"@ai-matrx/kit/download\";\nimport { toDelimitedText } from \"@ai-matrx/alchemy/operate/read\";\nimport { PX_PER_INCH } from \"../core\";\nimport type { SheetPageSetup } from \"./sheet-page-setup\";\nimport { buildSheetPrintDocument, collectPrintSheets, printDocumentHtml } from \"./sheet-print-pages\";\nimport { univerSnapshotToRows, type CellRange } from \"./univer-snapshot-rows\";\n\nexport function sheetGridToCsv(rows: readonly (readonly string[])[]): string {\n const [header, ...body] = rows;\n if (!header) return \"\";\n return toDelimitedText(header, body, { spreadsheetSafe: false });\n}\n\nexport function downloadSheetAsCsv(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const name = `${options.filename.replace(/\\.csv$/i, \"\")}.csv`;\n // BOM so Excel reads UTF-8.\n const blob = new Blob([\"\", sheetGridToCsv(grid.rows)], { type: \"text/csv;charset=utf-8\" });\n downloadFile(name, blob, blob.type);\n return true;\n}\n\n/** Tab-separated values of the current sheet (Google's .tsv download). */\nexport function downloadSheetAsTsv(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const [header, ...body] = grid.rows;\n const text = toDelimitedText(header!, body, { format: \"tsv\", spreadsheetSafe: false });\n const blob = new Blob([\"\\uFEFF\", text], { type: \"text/tab-separated-values;charset=utf-8\" });\n downloadFile(`${options.filename.replace(/\\.tsv$/i, \"\")}.tsv`, blob, blob.type);\n return true;\n}\n\n/** The current sheet as a standalone web page (Google's .html download). */\nexport function downloadSheetAsHtml(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const body = grid.rows.map((r) => `<tr>${r.map((c) => `<td>${esc(c)}</td>`).join(\"\")}</tr>`).join(\"\\n\");\n const html = `<!doctype html><html><head><meta charset=\"utf-8\"><title>${esc(options.filename)} — ${esc(grid.sheetName)}</title>\n<style>body{font:13px system-ui,sans-serif;margin:16px}table{border-collapse:collapse}td{border:1px solid #c0c0c0;padding:2px 6px;vertical-align:top}</style></head>\n<body><table>\n${body}\n</table></body></html>`;\n const blob = new Blob([html], { type: \"text/html;charset=utf-8\" });\n downloadFile(`${options.filename.replace(/\\.html?$/i, \"\")}.html`, blob, blob.type);\n return true;\n}\n\nfunction esc(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\n/** What a print or PDF needs besides the snapshot: the workbook's page setup and the live selection. */\nexport interface SheetPrintOptions {\n sheetId?: string;\n title: string;\n setup: SheetPageSetup;\n /** The cells selected right now (used when the setup prints \"selected cells\"). */\n selection?: CellRange | null;\n}\n\nfunction printDocumentFor(snapshot: unknown, options: SheetPrintOptions) {\n const sheets = collectPrintSheets(snapshot, options.setup, {\n ...(options.sheetId ? { sheetId: options.sheetId } : {}),\n selection: options.selection ?? null,\n });\n return buildSheetPrintDocument(sheets, options.setup);\n}\n\n/** Opens the browser print sheet for what the workbook's page setup asks to print (choose \"Save as PDF\" there). */\nexport function printSheet(snapshot: unknown, options: SheetPrintOptions): boolean {\n const doc = printDocumentFor(snapshot, options);\n if (!doc) return false;\n const html = printDocumentHtml(doc, options.title);\n const frame = document.createElement(\"iframe\");\n frame.style.cssText = \"position:fixed;right:0;bottom:0;width:0;height:0;border:0\";\n document.body.appendChild(frame);\n const fdoc = frame.contentDocument;\n const win = frame.contentWindow;\n if (!fdoc || !win) {\n frame.remove();\n return false;\n }\n fdoc.open();\n fdoc.write(html);\n fdoc.close();\n win.addEventListener(\"afterprint\", () => frame.remove());\n win.focus();\n win.print();\n return true;\n}\n\n/** The sheet's grid as a markdown table (first row is the header row). */\nexport function sheetGridToMarkdownTable(rows: readonly (readonly string[])[]): string {\n if (rows.length === 0) return \"\";\n const width = Math.max(...rows.map((r) => r.length));\n const cell = (v: string | undefined) => (v ?? \"\").replace(/\\|/g, \"\\\\|\").replace(/\\r?\\n/g, \" \");\n const line = (r: readonly string[]) =>\n `| ${Array.from({ length: width }, (_, i) => cell(r[i])).join(\" | \")} |`;\n const [head, ...rest] = rows;\n return [line(head!), `| ${Array.from({ length: width }, () => \"---\").join(\" | \")} |`, ...rest.map(line)].join(\"\\n\");\n}\n\n/**\n * Real PDF download of what the workbook's page setup prints: the same pages Print draws, each one\n * captured and laid on a PDF page of the chosen paper size and orientation. Returns false when empty.\n */\nexport async function downloadSheetAsPdf(snapshot: unknown, options: SheetPrintOptions): Promise<boolean> {\n const doc = printDocumentFor(snapshot, options);\n if (!doc) return false;\n const [{ renderElement, pagesToPdf }, { downloadFile: save }] = await Promise.all([\n import(\"@ai-matrx/alchemy/operate/capture\"),\n import(\"@ai-matrx/kit/download\"),\n ]);\n const host = document.createElement(\"div\");\n host.setAttribute(\"aria-hidden\", \"true\");\n host.style.cssText = \"position:fixed;left:-20000px;top:0\";\n host.innerHTML = `<style>td{padding:0 6px;overflow:hidden;white-space:nowrap;vertical-align:middle}</style>${doc.pagesHtml.join(\"\")}`;\n document.body.appendChild(host);\n try {\n const pages = [];\n for (const el of Array.from(host.querySelectorAll<HTMLElement>(\"[data-print-page]\"))) {\n const image = await renderElement(el, { pixelRatio: 2, backgroundColor: \"#ffffff\", cacheBust: true });\n pages.push({ image, imageType: \"JPEG\" as const, quality: 0.92, placement: \"fill\" as const });\n }\n const mm = (px: number) => Math.round(((px / PX_PER_INCH) * 25.4) * 100) / 100;\n const pdf = await pagesToPdf(pages, {\n orientation: doc.pageWidth > doc.pageHeight ? \"landscape\" : \"portrait\",\n unit: \"mm\",\n format: [mm(Math.min(doc.pageWidth, doc.pageHeight)), mm(Math.max(doc.pageWidth, doc.pageHeight))],\n });\n save(`${options.title.replace(/[\\\\/:*?\"<>|]+/g, \" \").trim() || \"workbook\"}.pdf`, pdf, \"application/pdf\");\n } finally {\n host.remove();\n }\n return true;\n}\n","// features/workbooks/workbook-scope-source.ts\n//\n// Live bridge from the mounted `WorkbookEditor` to the `matrx-user/workbooks`\n// surface emitter on `/workbooks/[id]`.\n//\n// Why a module slot rather than props: the page owns the workbook row and\n// mounts `<SurfaceRuntimeProvider>`, but the sheets / snapshot / save status\n// live inside the editor (Univer refs + local state), one level DOWN. Pushing\n// them up as state would re-render the editor on every keystroke; a\n// registered getter is read once, at Run time, when the user actually\n// launches an agent.\n//\n// Exactly one editor is mounted at a time (one workbook per route), so a\n// single slot keyed by workbookId is enough. The getter returns null when the\n// editor has not booted — callers omit the values, they never fake them.\n\nexport interface WorkbookLiveScope {\n sheets: Array<{ id: string; name: string; index: number }>;\n activeSheetId: string | null;\n activeSheetName: string | null;\n snapshot: Record<string, unknown> | null;\n bootState: \"booting\" | \"ready\" | \"load_error\";\n loadError: string | null;\n saveStatus: string;\n collab: {\n enabled: boolean;\n is_host: boolean;\n self_uid: string;\n remote_peers: number;\n };\n}\n\ninterface Registration {\n workbookId: string;\n read: () => WorkbookLiveScope | null;\n}\n\nlet current: Registration | null = null;\n\n/** Called by `WorkbookEditor` while mounted. Returns an unregister. */\nexport function registerWorkbookScopeSource(\n registration: Registration,\n): () => void {\n current = registration;\n return () => {\n if (current === registration) current = null;\n };\n}\n\n/**\n * Read the live editor state for `workbookId`. Returns null when no editor is\n * mounted, when a different workbook is mounted, or when Univer has not\n * booted yet — never a fabricated shape.\n */\nexport function readWorkbookScopeSource(\n workbookId: string,\n): WorkbookLiveScope | null {\n if (!current || current.workbookId !== workbookId) return null;\n return current.read();\n}\n"]}
|
package/dist/sheets.d.cts
CHANGED
|
@@ -527,7 +527,7 @@ interface PrintDocument {
|
|
|
527
527
|
};
|
|
528
528
|
}
|
|
529
529
|
/** All the printed pages of the chosen sheets under the setup (empty when there is nothing to print). */
|
|
530
|
-
declare function
|
|
530
|
+
declare function buildSheetPrintDocument(sheets: readonly PrintSheet[], setup: SheetPageSetup): PrintDocument | null;
|
|
531
531
|
/** The whole printable web page: `@page` set to the paper, one section per page. */
|
|
532
532
|
declare function printDocumentHtml(doc: PrintDocument, title: string): string;
|
|
533
533
|
|
|
@@ -602,4 +602,4 @@ declare function registerWorkbookScopeSource(registration: Registration): () =>
|
|
|
602
602
|
*/
|
|
603
603
|
declare function readWorkbookScopeSource(workbookId: string): WorkbookLiveScope | null;
|
|
604
604
|
|
|
605
|
-
export { type CellRange, type CfRule, type CreateWorkbookArgs, DEFAULT_SHEET_PAGE_SETUP, GRID_MAX_COLUMNS, GRID_MAX_ROWS, type GridCell, type GridSheet, MARGIN_PRESET_INCHES, PRINT_ROW_HEIGHT, type PageSetupResult, type PrintDocument, type PrintGeometry, type PrintPage, type PrintPlan, type PrintSheet, SHEET_MARGIN_PRESETS, SHEET_PRINT_SCOPES, SHEET_SCALES, type SaveSnapshotArgs, type SheetAlignH, type SheetAlignV, type SheetMarginPreset, type SheetPageOrder, type SheetPageSetup, type SheetPrintOptions, type SheetPrintScope, type SheetScale, type SheetsHostPorts, type SheetsSupabase, type SnapshotRows, THUMB_HEIGHT, THUMB_WIDTH, type Workbook, type WorkbookLiveScope,
|
|
605
|
+
export { type CellRange, type CfRule, type CreateWorkbookArgs, DEFAULT_SHEET_PAGE_SETUP, GRID_MAX_COLUMNS, GRID_MAX_ROWS, type GridCell, type GridSheet, MARGIN_PRESET_INCHES, PRINT_ROW_HEIGHT, type PageSetupResult, type PrintDocument, type PrintGeometry, type PrintPage, type PrintPlan, type PrintSheet, SHEET_MARGIN_PRESETS, SHEET_PRINT_SCOPES, SHEET_SCALES, type SaveSnapshotArgs, type SheetAlignH, type SheetAlignV, type SheetMarginPreset, type SheetPageOrder, type SheetPageSetup, type SheetPrintOptions, type SheetPrintScope, type SheetScale, type SheetsHostPorts, type SheetsSupabase, type SnapshotRows, THUMB_HEIGHT, THUMB_WIDTH, type Workbook, type WorkbookLiveScope, buildSheetPrintDocument, cfMatch, collectPrintSheets, configureSheetsHost, copyWorkbook, createWorkbook, deleteWorkbook, discardFailedWorkbook, documentPreviewSvg, downloadSheetAsCsv, downloadSheetAsHtml, downloadSheetAsPdf, downloadSheetAsTsv, formatCellValue, getLatestSnapshot, getSheetsHost, getWorkbook, listAccessibleWorkbooks, listSnapshots, listTrashedWorkbooks, moveWorkbook, normalizeSheetPageSetup, pageSetupFromMetadata, parseResource, planSheetPrint, printColumnWidths, printDocumentHtml, printGeometry, printSheet, readSheetPageSetup, readWorkbookScopeSource, registerWorkbookScopeSource, renameWorkbook, restoreWorkbook, saveSnapshot, sheetGridToCsv, sheetGridToMarkdownTable, snapshotPreviewSvg, snapshotToGridSheets, univerSheetIds, univerSnapshotToRows, updateWorkbookDescription, workbookPreviewSvg, workbookSourceLabel, writeSheetPageSetup };
|
package/dist/sheets.d.ts
CHANGED
|
@@ -527,7 +527,7 @@ interface PrintDocument {
|
|
|
527
527
|
};
|
|
528
528
|
}
|
|
529
529
|
/** All the printed pages of the chosen sheets under the setup (empty when there is nothing to print). */
|
|
530
|
-
declare function
|
|
530
|
+
declare function buildSheetPrintDocument(sheets: readonly PrintSheet[], setup: SheetPageSetup): PrintDocument | null;
|
|
531
531
|
/** The whole printable web page: `@page` set to the paper, one section per page. */
|
|
532
532
|
declare function printDocumentHtml(doc: PrintDocument, title: string): string;
|
|
533
533
|
|
|
@@ -602,4 +602,4 @@ declare function registerWorkbookScopeSource(registration: Registration): () =>
|
|
|
602
602
|
*/
|
|
603
603
|
declare function readWorkbookScopeSource(workbookId: string): WorkbookLiveScope | null;
|
|
604
604
|
|
|
605
|
-
export { type CellRange, type CfRule, type CreateWorkbookArgs, DEFAULT_SHEET_PAGE_SETUP, GRID_MAX_COLUMNS, GRID_MAX_ROWS, type GridCell, type GridSheet, MARGIN_PRESET_INCHES, PRINT_ROW_HEIGHT, type PageSetupResult, type PrintDocument, type PrintGeometry, type PrintPage, type PrintPlan, type PrintSheet, SHEET_MARGIN_PRESETS, SHEET_PRINT_SCOPES, SHEET_SCALES, type SaveSnapshotArgs, type SheetAlignH, type SheetAlignV, type SheetMarginPreset, type SheetPageOrder, type SheetPageSetup, type SheetPrintOptions, type SheetPrintScope, type SheetScale, type SheetsHostPorts, type SheetsSupabase, type SnapshotRows, THUMB_HEIGHT, THUMB_WIDTH, type Workbook, type WorkbookLiveScope,
|
|
605
|
+
export { type CellRange, type CfRule, type CreateWorkbookArgs, DEFAULT_SHEET_PAGE_SETUP, GRID_MAX_COLUMNS, GRID_MAX_ROWS, type GridCell, type GridSheet, MARGIN_PRESET_INCHES, PRINT_ROW_HEIGHT, type PageSetupResult, type PrintDocument, type PrintGeometry, type PrintPage, type PrintPlan, type PrintSheet, SHEET_MARGIN_PRESETS, SHEET_PRINT_SCOPES, SHEET_SCALES, type SaveSnapshotArgs, type SheetAlignH, type SheetAlignV, type SheetMarginPreset, type SheetPageOrder, type SheetPageSetup, type SheetPrintOptions, type SheetPrintScope, type SheetScale, type SheetsHostPorts, type SheetsSupabase, type SnapshotRows, THUMB_HEIGHT, THUMB_WIDTH, type Workbook, type WorkbookLiveScope, buildSheetPrintDocument, cfMatch, collectPrintSheets, configureSheetsHost, copyWorkbook, createWorkbook, deleteWorkbook, discardFailedWorkbook, documentPreviewSvg, downloadSheetAsCsv, downloadSheetAsHtml, downloadSheetAsPdf, downloadSheetAsTsv, formatCellValue, getLatestSnapshot, getSheetsHost, getWorkbook, listAccessibleWorkbooks, listSnapshots, listTrashedWorkbooks, moveWorkbook, normalizeSheetPageSetup, pageSetupFromMetadata, parseResource, planSheetPrint, printColumnWidths, printDocumentHtml, printGeometry, printSheet, readSheetPageSetup, readWorkbookScopeSource, registerWorkbookScopeSource, renameWorkbook, restoreWorkbook, saveSnapshot, sheetGridToCsv, sheetGridToMarkdownTable, snapshotPreviewSvg, snapshotToGridSheets, univerSheetIds, univerSnapshotToRows, updateWorkbookDescription, workbookPreviewSvg, workbookSourceLabel, writeSheetPageSetup };
|
package/dist/sheets.js
CHANGED
|
@@ -716,7 +716,7 @@ function pageHtml(sheet, page, scale, colWidths, g, setup, numbering) {
|
|
|
716
716
|
<table style="width:${tableW}px;table-layout:fixed;border-collapse:collapse;transform:scale(${scale});transform-origin:0 0;font:12px/${PRINT_ROW_HEIGHT - 2}px system-ui,sans-serif;color:#111"><colgroup>${cols}</colgroup><tbody>${body}</tbody></table>
|
|
717
717
|
</div></div></section>`;
|
|
718
718
|
}
|
|
719
|
-
function
|
|
719
|
+
function buildSheetPrintDocument(sheets, setup) {
|
|
720
720
|
const out = [];
|
|
721
721
|
let geometry = null;
|
|
722
722
|
for (const sheet of sheets) {
|
|
@@ -787,7 +787,7 @@ function printDocumentFor(snapshot, options) {
|
|
|
787
787
|
...options.sheetId ? { sheetId: options.sheetId } : {},
|
|
788
788
|
selection: options.selection ?? null
|
|
789
789
|
});
|
|
790
|
-
return
|
|
790
|
+
return buildSheetPrintDocument(sheets, options.setup);
|
|
791
791
|
}
|
|
792
792
|
function printSheet(snapshot, options) {
|
|
793
793
|
const doc = printDocumentFor(snapshot, options);
|
|
@@ -872,7 +872,7 @@ export {
|
|
|
872
872
|
SHEET_SCALES,
|
|
873
873
|
THUMB_HEIGHT,
|
|
874
874
|
THUMB_WIDTH,
|
|
875
|
-
|
|
875
|
+
buildSheetPrintDocument,
|
|
876
876
|
cfMatch,
|
|
877
877
|
collectPrintSheets,
|
|
878
878
|
configureSheetsHost,
|
package/dist/sheets.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sheets/univer-snapshot-rows.ts","../src/sheets/snapshot-preview-svg.ts","../src/sheets/snapshot-grid.ts","../src/core/document-page-style.ts","../src/sheets/sheet-page-setup.ts","../src/sheets/sheet-page-setup-service.ts","../src/sheets/sheet-print-pages.ts","../src/sheets/sheet-output.ts","../src/sheets/workbook-scope-source.ts"],"sourcesContent":["/**\n * features/workbooks/univer-snapshot-rows.ts\n *\n * Snapshot → rows: read a Univer `IWorkbookData` snapshot back out as a plain\n * string grid. The missing half of the workbook round trip — `export-targets`\n * pushes rows INTO a workbook; this reads the (possibly user-edited) values\n * back OUT so features can offer \"edit in the workbook, then import your\n * changes\". Values only (formulas come back as their cached value); first\n * sheet by `sheetOrder` unless a sheet id is named. A number shown through a date format reads as\n * its ISO date (a spreadsheet keeps dates as day serials). Reusable — do not fork a per-feature\n * snapshot walker. Callers: the workbook's \"Make this sheet a table\" (features/workbooks/table-link).\n */\n\ninterface CellShape {\n v?: unknown;\n s?: unknown;\n}\n\ninterface SheetShape {\n name?: string;\n /** Frozen panes: `xSplit` columns and `ySplit` rows are pinned. */\n freeze?: { xSplit?: number; ySplit?: number } | null;\n /** Univer marks a hidden column/row `hd: 1` (a table link's Record ID column is one). */\n columnData?: Record<string, { hd?: number } | null | undefined>;\n rowData?: Record<string, { hd?: number } | null | undefined>;\n cellData?: Record<string, Record<string, CellShape | null | undefined>>;\n}\n\ninterface SnapshotShape {\n sheetOrder?: string[];\n sheets?: Record<string, SheetShape>;\n styles?: Record<string, { n?: { pattern?: string } | null } | null>;\n}\n\nexport interface SnapshotRows {\n sheetName: string;\n /** Dense rectangular grid, trailing empty rows/columns trimmed. */\n rows: string[][];\n /** Rows pinned at the top of the sheet (Freeze rows), counted in `rows`. */\n frozenRows: number;\n /** Columns pinned at the left of the sheet (Freeze columns), counted in each row. */\n frozenCols: number;\n}\n\n/** A zero-based, inclusive cell range (a selection). */\nexport interface CellRange {\n startRow: number;\n endRow: number;\n startColumn: number;\n endColumn: number;\n}\n\n/** Sheet ids in tab order. */\nexport function univerSheetIds(snapshot: unknown): string[] {\n if (typeof snapshot !== \"object\" || snapshot === null) return [];\n const shape = snapshot as SnapshotShape;\n const sheets = shape.sheets ?? {};\n const ordered = (shape.sheetOrder ?? []).filter((id) => sheets[id]);\n return ordered.length ? ordered : Object.keys(sheets);\n}\n\ntype Styles = SnapshotShape[\"styles\"];\n\n/** The number-format pattern a cell is shown through, if any. */\nfunction patternOf(cell: CellShape | null | undefined, styles: Styles): string | null {\n const s = cell?.s;\n const style = typeof s === \"string\" ? styles?.[s] : s && typeof s === \"object\" ? (s as { n?: { pattern?: string } }) : null;\n const pattern = style?.n?.pattern;\n return typeof pattern === \"string\" ? pattern : null;\n}\n\nconst DAY_MS = 86_400_000;\nconst SERIAL_EPOCH_MS = Date.UTC(1899, 11, 30);\n\nfunction cellText(cell: CellShape | null | undefined, styles?: Styles): string {\n const value = cell?.v;\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"number\") {\n const pattern = patternOf(cell, styles)?.replace(/\"[^\"]*\"/g, \"\").toLowerCase() ?? \"\";\n if (/[dy]/.test(pattern)) {\n const iso = new Date(Math.round(SERIAL_EPOCH_MS + value * DAY_MS)).toISOString();\n return /h/.test(pattern) ? `${iso.slice(0, 10)} ${iso.slice(11, 16)}` : iso.slice(0, 10);\n }\n }\n return String(value);\n}\n\n/**\n * Extract the first worksheet of a Univer workbook snapshot as a string grid.\n * Returns null when the value is not snapshot-shaped or has no sheets.\n * `skipHidden` leaves out hidden columns and rows: every read-only view (a share page, an agent's\n * read) passes it, so the table link's hidden Record ID column never reaches a reader.\n */\nexport function univerSnapshotToRows(snapshot: unknown, options: { sheetId?: string; skipHidden?: boolean; range?: CellRange } = {}): SnapshotRows | null {\n if (typeof snapshot !== \"object\" || snapshot === null) return null;\n const shape = snapshot as SnapshotShape;\n const sheets = shape.sheets ?? {};\n const styles = shape.styles;\n const firstId = options.sheetId\n ? sheets[options.sheetId]\n ? options.sheetId\n : undefined\n : (shape.sheetOrder?.find((id) => sheets[id]) ?? Object.keys(sheets)[0]);\n if (!firstId) return null;\n const sheet = sheets[firstId];\n const cellData = sheet?.cellData ?? {};\n\n let maxRow = -1;\n let maxCol = -1;\n for (const [rowKey, row] of Object.entries(cellData)) {\n const rowIndex = Number(rowKey);\n if (!Number.isInteger(rowIndex) || !row) continue;\n for (const [colKey, cell] of Object.entries(row)) {\n const colIndex = Number(colKey);\n if (!Number.isInteger(colIndex)) continue;\n if (cellText(cell) === \"\") continue;\n if (rowIndex > maxRow) maxRow = rowIndex;\n if (colIndex > maxCol) maxCol = colIndex;\n }\n }\n const range = options.range;\n if (range) {\n // A selection prints exactly the cells chosen, empty ones included.\n maxRow = range.endRow;\n maxCol = range.endColumn;\n }\n if (maxRow < 0 || maxCol < 0) {\n return { sheetName: sheet?.name ?? \"Sheet1\", rows: [], frozenRows: 0, frozenCols: 0 };\n }\n const firstRow = range?.startRow ?? 0;\n const firstCol = range?.startColumn ?? 0;\n\n const hiddenCol = (c: number) => options.skipHidden === true && sheet?.columnData?.[String(c)]?.hd === 1;\n const hiddenRow = (r: number) => options.skipHidden === true && sheet?.rowData?.[String(r)]?.hd === 1;\n const rows: string[][] = [];\n const ySplit = Math.max(0, sheet?.freeze?.ySplit ?? 0);\n const xSplit = Math.max(0, sheet?.freeze?.xSplit ?? 0);\n let frozenRows = 0;\n let frozenCols = 0;\n for (let r = firstRow; r <= maxRow; r += 1) {\n if (hiddenRow(r)) continue;\n if (r < ySplit) frozenRows += 1;\n const row: string[] = [];\n const source = cellData[String(r)] ?? {};\n let colsFrozenHere = 0;\n for (let c = firstCol; c <= maxCol; c += 1) {\n if (hiddenCol(c)) continue;\n if (c < xSplit) colsFrozenHere += 1;\n row.push(cellText(source[String(c)], styles));\n }\n frozenCols = colsFrozenHere;\n rows.push(row);\n }\n return { sheetName: sheet?.name ?? \"Sheet1\", rows, frozenRows, frozenCols };\n}\n","/**\n * snapshot → SVG: a faithful miniature of a Univer workbook's first sheet or a\n * Univer document's first page — the gallery tile Google draws. Pure (no DOM,\n * no Univer runtime), so it runs in the browser (thumbnail capture), in tests\n * and in node. Reads only what a snapshot stores: cell values + styles +\n * column widths + merges + conditional formats + checkboxes for sheets; the\n * dataStream + text runs + paragraph styles + tables for documents.\n */\n\nexport const THUMB_WIDTH = 320;\nexport const THUMB_HEIGHT = 414;\n\ntype Rgb = { rgb?: string | null } | null | undefined;\ntype CellStyle = {\n bg?: Rgb;\n cl?: Rgb;\n bl?: number;\n it?: number;\n fs?: number;\n ht?: number;\n n?: { pattern?: string } | null;\n bd?: Record<string, unknown> | null;\n};\ntype Cell = { v?: unknown; s?: string | CellStyle | null; t?: number; f?: string };\ntype Sheet = {\n id?: string;\n name?: string;\n cellData?: Record<string, Record<string, Cell>>;\n columnData?: Record<string, { w?: number; hd?: number }>;\n rowData?: Record<string, { h?: number; hd?: number }>;\n defaultColumnWidth?: number;\n defaultRowHeight?: number;\n mergeData?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n showGridlines?: number;\n freeze?: { ySplit?: number; xSplit?: number };\n};\nexport type Workbook = {\n sheetOrder?: string[];\n sheets?: Record<string, Sheet>;\n styles?: Record<string, CellStyle | null>;\n resources?: Array<{ name?: string; data?: string }>;\n};\n\nconst esc = (s: string) =>\n s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n\nfunction color(c: Rgb, fallback: string): string {\n const v = c?.rgb;\n return typeof v === \"string\" && v.length > 0 ? v : fallback;\n}\n\n// ─── number formats ──────────────────────────────────────────────────────────\n\nconst EXCEL_EPOCH = Date.UTC(1899, 11, 30);\nconst MONTHS = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n\nexport function formatCellValue(v: unknown, pattern?: string | null): string {\n if (v === null || v === undefined) return \"\";\n if (typeof v === \"boolean\") return v ? \"TRUE\" : \"FALSE\";\n if (typeof v !== \"number\" || !pattern || pattern === \"General\") return String(v);\n const p = pattern.toLowerCase();\n if (/[dy]/.test(p) && !p.includes(\"$\")) {\n const d = new Date(EXCEL_EPOCH + Math.round(v) * 86400000);\n const mm = d.getUTCMonth();\n const dd = d.getUTCDate();\n const yy = d.getUTCFullYear();\n if (p.includes(\"mmm\")) return `${MONTHS[mm]} ${dd}${p.includes(\"y\") ? `, ${yy}` : \"\"}`;\n return p.includes(\"y\") ? `${mm + 1}/${dd}/${yy}` : `${mm + 1}/${dd}`;\n }\n const decimals = (pattern.split(\".\")[1]?.match(/0/g) ?? []).length;\n if (p.includes(\"%\")) return `${(v * 100).toFixed(decimals)}%`;\n const grouped = Math.abs(v).toLocaleString(\"en-US\", {\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n useGrouping: pattern.includes(\",\"),\n });\n const sign = v < 0 ? \"-\" : \"\";\n return p.includes(\"$\") ? `${sign}$${grouped}` : `${sign}${grouped}`;\n}\n\n// ─── conditional formatting (the rules a preview can evaluate) ───────────────\n\nexport type CfRule = {\n rule?: {\n type?: string;\n subType?: string;\n operator?: string;\n value?: unknown;\n style?: CellStyle;\n };\n ranges?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n};\n\nexport function parseResource<T>(wb: Workbook, name: string): T | null {\n const res = wb.resources?.find((r) => r.name === name);\n if (!res?.data) return null;\n try {\n return JSON.parse(res.data) as T;\n } catch {\n return null;\n }\n}\n\nexport function cfMatch(rule: NonNullable<CfRule[\"rule\"]>, v: unknown): boolean {\n if (rule.type !== \"highlightCell\") return false;\n if (rule.subType === \"number\" && typeof v === \"number\") {\n const x = rule.value;\n const [a = 0, b = 0] = Array.isArray(x) ? (x as number[]) : [Number(x), Number(x)];\n switch (rule.operator) {\n case \"greaterThan\": return v > a;\n case \"greaterThanOrEqual\": return v >= a;\n case \"lessThan\": return v < a;\n case \"lessThanOrEqual\": return v <= a;\n case \"equal\": return v === a;\n case \"notEqual\": return v !== a;\n case \"between\": return v >= a && v <= b;\n default: return false;\n }\n }\n if (rule.subType === \"text\" && v !== undefined && v !== null) {\n const s = String(v).toLowerCase();\n const want = String(rule.value ?? \"\").toLowerCase();\n switch (rule.operator) {\n case \"containsText\": return s.includes(want);\n case \"equal\": return s === want;\n case \"beginsWith\": return s.startsWith(want);\n default: return false;\n }\n }\n return false;\n}\n\n// ─── workbook ────────────────────────────────────────────────────────────────\n\nexport function workbookPreviewSvg(snapshot: unknown): string {\n const wb = (snapshot ?? {}) as Workbook;\n const firstId = wb.sheetOrder?.[0] ?? Object.keys(wb.sheets ?? {})[0];\n const sheet: Sheet = (firstId && wb.sheets?.[firstId]) || {};\n const sheetId = sheet.id ?? firstId ?? \"\";\n const styles = wb.styles ?? {};\n const cfAll = parseResource<Record<string, CfRule[]>>(wb, \"SHEET_CONDITIONAL_FORMATTING_PLUGIN\");\n const cf = (cfAll?.[sheetId] ?? []).filter((r) => r.rule && r.ranges);\n const dvAll = parseResource<Record<string, Array<{ type?: string; ranges?: CfRule[\"ranges\"] }>>>(\n wb,\n \"SHEET_DATA_VALIDATION_PLUGIN\",\n );\n const checkboxRanges = (dvAll?.[sheetId] ?? []).filter((d) => d.type === \"checkbox\").flatMap((d) => d.ranges ?? []);\n const inRanges = (rs: CfRule[\"ranges\"], r: number, c: number) =>\n (rs ?? []).some((x) => r >= x.startRow && r <= x.endRow && c >= x.startColumn && c <= x.endColumn);\n\n const dcw = sheet.defaultColumnWidth ?? 88;\n const drh = sheet.defaultRowHeight ?? 24;\n const colW = (c: number) => (sheet.columnData?.[c]?.hd ? 0 : sheet.columnData?.[c]?.w ?? dcw);\n const rowH = (r: number) => (sheet.rowData?.[r]?.hd ? 0 : sheet.rowData?.[r]?.h ?? drh);\n\n // Show the used width (at least ~5 default columns), scaled to the tile.\n let maxCol = 0;\n for (const row of Object.values(sheet.cellData ?? {})) {\n for (const c of Object.keys(row ?? {})) maxCol = Math.max(maxCol, Number(c));\n }\n let used = 0;\n for (let c = 0; c <= maxCol; c++) used += colW(c);\n // Google's tiles show the top-left of the sheet at a readable size, not the whole width.\n const span = Math.min(Math.max(used + 12, dcw * 5), 640);\n const scale = THUMB_WIDTH / span;\n\n const out: string[] = [];\n out.push(`<rect width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" fill=\"#ffffff\"/>`);\n const gridOn = sheet.showGridlines !== 0;\n const merges = sheet.mergeData ?? [];\n const covered = new Set<string>();\n for (const m of merges) {\n for (let r = m.startRow; r <= m.endRow; r++)\n for (let c = m.startColumn; c <= m.endColumn; c++)\n if (r !== m.startRow || c !== m.startColumn) covered.add(`${r}:${c}`);\n }\n const texts: string[] = [];\n let y = 0;\n for (let r = 0; y * scale < THUMB_HEIGHT && r < 400; r++) {\n const h = rowH(r);\n let x = 0;\n for (let c = 0; x * scale < THUMB_WIDTH && c < 60; c++) {\n const w = colW(c);\n if (w === 0 || h === 0 || covered.has(`${r}:${c}`)) {\n x += w;\n continue;\n }\n const m = merges.find((mm) => mm.startRow === r && mm.startColumn === c);\n let cw = w;\n let ch = h;\n if (m) {\n cw = 0;\n for (let k = m.startColumn; k <= m.endColumn; k++) cw += colW(k);\n ch = 0;\n for (let k = m.startRow; k <= m.endRow; k++) ch += rowH(k);\n }\n const cell = sheet.cellData?.[r]?.[c];\n const base: CellStyle =\n (typeof cell?.s === \"string\" ? styles[cell.s] : (cell?.s as CellStyle | null)) ?? {};\n let st: CellStyle = base;\n for (const rule of cf) {\n if (inRanges(rule.ranges, r, c) && rule.rule && cfMatch(rule.rule, cell?.v)) {\n st = { ...st, ...rule.rule.style };\n break;\n }\n }\n const X = x * scale;\n const Y = y * scale;\n const W = cw * scale;\n const H = ch * scale;\n const bg = st.bg?.rgb;\n if (bg) out.push(`<rect x=\"${X.toFixed(1)}\" y=\"${Y.toFixed(1)}\" width=\"${W.toFixed(1)}\" height=\"${H.toFixed(1)}\" fill=\"${esc(bg)}\"/>`);\n if (gridOn) out.push(`<rect x=\"${X.toFixed(1)}\" y=\"${Y.toFixed(1)}\" width=\"${W.toFixed(1)}\" height=\"${H.toFixed(1)}\" fill=\"none\" stroke=\"#e2e3e3\" stroke-width=\"0.5\"/>`);\n const fs = Math.max((st.fs ?? 10) * 1.333 * scale, 3);\n const midY = Y + H / 2 + fs * 0.35;\n if (inRanges(checkboxRanges, r, c) && r > 0 && (cell?.v === true || cell?.v === false || cell?.v === 1 || cell?.v === 0 || cell?.v === \"TRUE\" || cell?.v === \"FALSE\")) {\n const box = Math.min(H * 0.55, 9);\n const bx = X + W / 2 - box / 2;\n const by = Y + H / 2 - box / 2;\n const on = cell?.v === true || cell?.v === 1 || cell?.v === \"TRUE\";\n out.push(`<rect x=\"${bx.toFixed(1)}\" y=\"${by.toFixed(1)}\" width=\"${box.toFixed(1)}\" height=\"${box.toFixed(1)}\" rx=\"1\" fill=\"${on ? \"#1a73e8\" : \"#ffffff\"}\" stroke=\"${on ? \"#1a73e8\" : \"#5f6368\"}\" stroke-width=\"0.7\"/>`);\n if (on) out.push(`<path d=\"M${(bx + box * 0.2).toFixed(1)} ${(by + box * 0.5).toFixed(1)} l${(box * 0.25).toFixed(1)} ${(box * 0.25).toFixed(1)} l${(box * 0.4).toFixed(1)} ${(-box * 0.45).toFixed(1)}\" stroke=\"#fff\" stroke-width=\"0.9\" fill=\"none\"/>`);\n } else if (cell && cell.v !== undefined && cell.v !== null && cell.v !== \"\") {\n const text = formatCellValue(cell.v, st.n?.pattern);\n const numeric = typeof cell.v === \"number\";\n const ht = st.ht ?? (numeric ? 3 : 1);\n const anchor = ht === 2 ? \"middle\" : ht === 3 ? \"end\" : \"start\";\n const tx = ht === 2 ? X + W / 2 : ht === 3 ? X + W - 2 * scale * 2 : X + 3 * scale;\n const maxChars = Math.max(Math.floor((m ? W : W * (ht === 1 && !numeric ? 3 : 1)) / (fs * 0.55)), 1);\n const shown = text.length > maxChars ? text.slice(0, maxChars) : text;\n texts.push(\n `<text x=\"${tx.toFixed(1)}\" y=\"${midY.toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" text-anchor=\"${anchor}\" fill=\"${esc(color(st.cl, \"#202124\"))}\"${st.bl ? ' font-weight=\"700\"' : \"\"}${st.it ? ' font-style=\"italic\"' : \"\"}>${esc(shown)}</text>`,\n );\n }\n x += w;\n }\n y += h;\n }\n return wrapSvg([...out, ...texts].join(\"\"));\n}\n\n// ─── document ────────────────────────────────────────────────────────────────\n\ntype TextStyle = { fs?: number; bl?: number; it?: number; cl?: Rgb; ff?: string; bg?: Rgb };\ntype DocData = {\n body?: {\n dataStream?: string;\n paragraphs?: Array<{ startIndex: number; paragraphStyle?: { horizontalAlign?: number; spaceAbove?: { v?: number }; spaceBelow?: { v?: number } } }>;\n textRuns?: Array<{ st: number; ed: number; ts?: TextStyle }>;\n tables?: Array<{ startIndex: number; endIndex: number; tableId: string }>;\n };\n documentStyle?: {\n pageSize?: { width?: number; height?: number };\n marginTop?: number;\n marginLeft?: number;\n marginRight?: number;\n };\n};\n\nconst CONTROL = /[\\x1A\\x1B\\x1C\\x1D\\x0E\\x0F\\x1F\\x1E\\b]/g;\n\nexport function documentPreviewSvg(snapshot: unknown): string {\n const doc = (snapshot ?? {}) as DocData;\n const stream = doc.body?.dataStream ?? \"\";\n const pageW = doc.documentStyle?.pageSize?.width ?? 595;\n const scale = THUMB_WIDTH / pageW;\n const ml = (doc.documentStyle?.marginLeft ?? 72) * scale;\n const mr = (doc.documentStyle?.marginRight ?? 72) * scale;\n const mt = (doc.documentStyle?.marginTop ?? 72) * scale;\n const contentW = THUMB_WIDTH - ml - mr;\n const runs = [...(doc.body?.textRuns ?? [])].sort((a, b) => a.st - b.st);\n const tables = doc.body?.tables ?? [];\n const styleAt = (i: number): TextStyle => runs.find((r) => i >= r.st && i < r.ed)?.ts ?? {};\n /** The style most of a paragraph's characters carry (a bold lead-in does not make the line bold). */\n const dominantStyle = (from: number, to: number): TextStyle => {\n const counts = new Map<string, { n: number; ts: TextStyle }>();\n for (let i = from; i < to; i++) {\n if (/\\s/.test(stream[i] ?? \"\")) continue;\n const ts = styleAt(i);\n const k = JSON.stringify(ts);\n const e = counts.get(k) ?? { n: 0, ts };\n e.n++;\n counts.set(k, e);\n }\n let best: { n: number; ts: TextStyle } | null = null;\n for (const e of counts.values()) if (!best || e.n > best.n) best = e;\n return best?.ts ?? {};\n };\n const out: string[] = [`<rect width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" fill=\"#ffffff\"/>`];\n\n let y = mt;\n let start = 0;\n const paragraphs = doc.body?.paragraphs ?? [];\n for (let p = 0; p < paragraphs.length && y < THUMB_HEIGHT; p++) {\n const para = paragraphs[p];\n if (!para) break;\n const end = para.startIndex;\n const table = tables.find((t) => start >= t.startIndex && start < t.endIndex);\n if (table) {\n // Draw the whole table once: rows split on the row token, cells on the cell token.\n const raw = stream.slice(table.startIndex, table.endIndex);\n const rows = raw.split(\"\\x1B\").slice(1).map((row) =>\n row.split(\"\\x1C\").slice(1).map((cell) => cell.replace(/[\\r\\n]/g, \" \").replace(CONTROL, \"\").trim()),\n );\n const cols = Math.max(1, ...rows.map((r) => r.length));\n const cw = contentW / cols;\n // Bold header row when the first cell's text is bold.\n const headerBold = styleAt(table.startIndex + 4).bl === 1;\n for (let r = 0; r < rows.length && y < THUMB_HEIGHT; r++) {\n const rh = 16 * scale * 1.2 + 6 * scale;\n for (let c = 0; c < cols; c++) {\n const cx = ml + c * cw;\n out.push(`<rect x=\"${cx.toFixed(1)}\" y=\"${y.toFixed(1)}\" width=\"${cw.toFixed(1)}\" height=\"${rh.toFixed(1)}\" fill=\"${r === 0 && headerBold ? \"#f1f3f4\" : \"none\"}\" stroke=\"#9aa0a6\" stroke-width=\"0.4\"/>`);\n const fs = 11 * 1.333 * scale;\n const maxChars = Math.max(Math.floor((cw - 6 * scale) / (fs * 0.5)), 1);\n const t = rows[r]?.[c] ?? \"\";\n out.push(`<text x=\"${(cx + 4 * scale).toFixed(1)}\" y=\"${(y + rh / 2 + fs * 0.35).toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" fill=\"#202124\"${r === 0 && headerBold ? ' font-weight=\"700\"' : \"\"}>${esc(t.slice(0, maxChars))}</text>`);\n }\n y += rh;\n }\n // Skip every paragraph inside the table.\n while (p + 1 < paragraphs.length && (paragraphs[p + 1]?.startIndex ?? Infinity) < table.endIndex) p++;\n start = table.endIndex;\n y += 6 * scale;\n continue;\n }\n const text = stream.slice(start, end).replace(CONTROL, \"\");\n const st = dominantStyle(start, end);\n const ps = para.paragraphStyle ?? {};\n const fsPt = st.fs ?? 11;\n const fs = fsPt * 1.333 * scale;\n const lineH = fs * 1.3;\n y += (ps.spaceAbove?.v ?? (fsPt > 13 ? 8 : 0)) * scale;\n const align = ps.horizontalAlign ?? 1;\n const anchor = align === 2 ? \"middle\" : align === 3 ? \"end\" : \"start\";\n const tx = align === 2 ? ml + contentW / 2 : align === 3 ? ml + contentW : ml;\n // Paragraph shading (a filled band) when the run carries a highlight.\n if (!text.trim()) {\n y += lineH * 0.8;\n } else {\n const maxChars = Math.max(Math.floor(contentW / (fs * (st.bl ? 0.56 : 0.5))), 4);\n const words = text.split(/\\s+/);\n const lines: string[] = [];\n let line = \"\";\n for (const w of words) {\n if ((line + \" \" + w).trim().length > maxChars && line) {\n lines.push(line);\n line = w;\n } else line = (line + \" \" + w).trim();\n }\n if (line) lines.push(line);\n for (const l of lines) {\n if (y > THUMB_HEIGHT) break;\n y += lineH;\n if (st.bg?.rgb) out.push(`<rect x=\"${ml.toFixed(1)}\" y=\"${(y - fs).toFixed(1)}\" width=\"${contentW.toFixed(1)}\" height=\"${lineH.toFixed(1)}\" fill=\"${esc(st.bg.rgb)}\"/>`);\n out.push(`<text x=\"${tx.toFixed(1)}\" y=\"${y.toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" text-anchor=\"${anchor}\" fill=\"${esc(color(st.cl, \"#202124\"))}\"${st.bl ? ' font-weight=\"700\"' : \"\"}${st.it ? ' font-style=\"italic\"' : \"\"}${st.ff && /serif|georgia|times|garamond/i.test(st.ff) && !/sans/i.test(st.ff) ? ' font-family=\"Georgia, serif\"' : \"\"}>${esc(l)}</text>`);\n }\n }\n y += (ps.spaceBelow?.v ?? 4) * scale;\n start = end + 1;\n }\n return wrapSvg(out.join(\"\"));\n}\n\nfunction wrapSvg(body: string): string {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" viewBox=\"0 0 ${THUMB_WIDTH} ${THUMB_HEIGHT}\" font-family=\"Arial, Helvetica, sans-serif\">${body}</svg>`;\n}\n\nexport function snapshotPreviewSvg(kind: \"workbook\" | \"document\", snapshot: unknown): string {\n return kind === \"workbook\" ? workbookPreviewSvg(snapshot) : documentPreviewSvg(snapshot);\n}\n","/**\n * features/workbooks/snapshot-grid.ts\n *\n * Snapshot → a formatted, read-only grid model: what a spreadsheet VIEW needs and the plain-string\n * `univer-snapshot-rows` does not carry — number/currency/date formats applied, checkbox cells\n * (data-validation ranges of type checkbox), alignment, bold/italic, fill and text colour, column\n * widths, merges, frozen rows/columns, hidden rows/columns and sheets. Pure (no DOM, no Univer\n * runtime): the signed-out share page draws it. The number formatter is the thumbnail's\n * (`formatCellValue`) so a tile, a share link and the editor read the same.\n */\n\nimport {\n cfMatch,\n formatCellValue,\n parseResource,\n type CfRule,\n type Workbook,\n} from \"./snapshot-preview-svg\";\n\ntype Rgb = { rgb?: string | null } | null | undefined;\ninterface Style {\n bg?: Rgb;\n cl?: Rgb;\n bl?: number;\n it?: number;\n fs?: number;\n ht?: number;\n tb?: number;\n n?: { pattern?: string } | null;\n}\ninterface Cell {\n v?: unknown;\n s?: string | Style | null;\n}\ninterface Sheet {\n id?: string;\n name?: string;\n hidden?: number;\n cellData?: Record<string, Record<string, Cell | null | undefined>>;\n columnData?: Record<string, { w?: number; hd?: number } | null | undefined>;\n rowData?: Record<string, { h?: number; hd?: number } | null | undefined>;\n defaultColumnWidth?: number;\n defaultRowHeight?: number;\n mergeData?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n showGridlines?: number;\n freeze?: { xSplit?: number; ySplit?: number };\n}\n\nexport interface GridCell {\n text: string;\n /** A checkbox cell (a data-validation checkbox range): `checked` says its state. */\n checkbox?: { checked: boolean } | undefined;\n align: \"left\" | \"center\" | \"right\";\n bold: boolean;\n italic: boolean;\n /** Font size in px (the snapshot stores points). */\n fontPx: number;\n bg?: string | undefined;\n color?: string | undefined;\n wrap: boolean;\n rowSpan: number;\n colSpan: number;\n /** Covered by a merge that starts elsewhere: draw nothing. */\n covered: boolean;\n}\n\nexport interface GridSheet {\n id: string;\n name: string;\n /** Visible column indexes (hidden columns left out) with their pixel widths. */\n columns: Array<{ index: number; width: number }>;\n rows: Array<{ index: number; height: number; cells: GridCell[] }>;\n /** How many leading VISIBLE rows / columns stay put while scrolling. */\n frozenRows: number;\n frozenColumns: number;\n gridlines: boolean;\n /** Rows beyond the cap were left out. */\n truncatedFrom: number | null;\n}\n\nexport const GRID_MAX_ROWS = 500;\nexport const GRID_MAX_COLUMNS = 60;\n\nconst PT_TO_PX = 1.333;\nconst isCheckboxValue = (v: unknown) => v === true || v === false || v === 1 || v === 0 || v === \"TRUE\" || v === \"FALSE\";\nconst isOn = (v: unknown) => v === true || v === 1 || v === \"TRUE\";\n\nfunction hasValue(cell: Cell | null | undefined): boolean {\n const v = cell?.v;\n return v !== undefined && v !== null && v !== \"\";\n}\n\n/** Every visible sheet that has something in it, in tab order. Empty and hidden sheets are left out. */\nexport function snapshotToGridSheets(snapshot: unknown): GridSheet[] {\n if (typeof snapshot !== \"object\" || snapshot === null) return [];\n const wb = snapshot as Workbook;\n const sheets = wb.sheets ?? {};\n const order = (wb.sheetOrder ?? []).filter((id) => sheets[id]);\n const ids = order.length > 0 ? order : Object.keys(sheets);\n const out: GridSheet[] = [];\n for (const id of ids) {\n const grid = sheetToGrid(wb, id, sheets[id] as Sheet);\n if (grid) out.push(grid);\n }\n return out;\n}\n\nfunction sheetToGrid(wb: Workbook, id: string, sheet: Sheet): GridSheet | null {\n if (sheet.hidden === 1) return null;\n const cellData = sheet.cellData ?? {};\n let maxRow = -1;\n let maxCol = -1;\n for (const [rk, row] of Object.entries(cellData)) {\n const r = Number(rk);\n if (!Number.isInteger(r) || !row) continue;\n for (const [ck, cell] of Object.entries(row)) {\n const c = Number(ck);\n if (!Number.isInteger(c) || !hasValue(cell)) continue;\n if (r > maxRow) maxRow = r;\n if (c > maxCol) maxCol = c;\n }\n }\n if (maxRow < 0 || maxCol < 0) return null;\n\n const styles = wb.styles ?? {};\n const sheetId = sheet.id ?? id;\n const cfAll = parseResource<Record<string, CfRule[]>>(wb, \"SHEET_CONDITIONAL_FORMATTING_PLUGIN\");\n const cf = (cfAll?.[sheetId] ?? []).filter((r) => r.rule && r.ranges);\n const dvAll = parseResource<Record<string, Array<{ type?: string; ranges?: CfRule[\"ranges\"] }>>>(\n wb,\n \"SHEET_DATA_VALIDATION_PLUGIN\",\n );\n const checkboxRanges = (dvAll?.[sheetId] ?? []).filter((d) => d.type === \"checkbox\").flatMap((d) => d.ranges ?? []);\n const inRanges = (rs: CfRule[\"ranges\"], r: number, c: number) =>\n (rs ?? []).some((x) => r >= x.startRow && r <= x.endRow && c >= x.startColumn && c <= x.endColumn);\n\n const dcw = sheet.defaultColumnWidth ?? 88;\n const drh = sheet.defaultRowHeight ?? 24;\n const lastCol = Math.min(maxCol, GRID_MAX_COLUMNS - 1);\n const columns: GridSheet[\"columns\"] = [];\n for (let c = 0; c <= lastCol; c += 1) {\n const col = sheet.columnData?.[String(c)];\n if (col?.hd === 1) continue;\n columns.push({ index: c, width: col?.w ?? dcw });\n }\n\n const merges = sheet.mergeData ?? [];\n const covered = new Set<string>();\n for (const m of merges) {\n for (let r = m.startRow; r <= m.endRow; r += 1)\n for (let c = m.startColumn; c <= m.endColumn; c += 1) if (r !== m.startRow || c !== m.startColumn) covered.add(`${r}:${c}`);\n }\n\n const rows: GridSheet[\"rows\"] = [];\n const lastRow = Math.min(maxRow, GRID_MAX_ROWS - 1);\n for (let r = 0; r <= lastRow; r += 1) {\n const rd = sheet.rowData?.[String(r)];\n if (rd?.hd === 1) continue;\n const source = cellData[String(r)] ?? {};\n const cells: GridCell[] = columns.map(({ index: c }) => {\n const cell = source[String(c)] ?? undefined;\n const base: Style = (typeof cell?.s === \"string\" ? (styles[cell.s] as Style | null | undefined) : (cell?.s as Style | null | undefined)) ?? {};\n let st: Style = base;\n for (const rule of cf) {\n if (inRanges(rule.ranges, r, c) && rule.rule && cfMatch(rule.rule, cell?.v)) {\n st = { ...st, ...(rule.rule.style as Style | undefined) };\n break;\n }\n }\n const m = merges.find((mm) => mm.startRow === r && mm.startColumn === c);\n const v = cell?.v;\n const box = hasValue(cell) && inRanges(checkboxRanges, r, c) && isCheckboxValue(v);\n const numeric = typeof v === \"number\";\n const ht = st.ht ?? 0;\n return {\n text: box ? \"\" : hasValue(cell) ? formatCellValue(v, st.n?.pattern) : \"\",\n checkbox: box ? { checked: isOn(v) } : undefined,\n align: box || ht === 2 ? \"center\" : ht === 3 || (ht === 0 && numeric) ? \"right\" : \"left\",\n bold: st.bl === 1,\n italic: st.it === 1,\n fontPx: Math.round((st.fs ?? 10) * PT_TO_PX),\n bg: st.bg?.rgb ?? undefined,\n color: st.cl?.rgb ?? undefined,\n wrap: st.tb === 3,\n rowSpan: m ? m.endRow - m.startRow + 1 : 1,\n colSpan: m ? m.endColumn - m.startColumn + 1 : 1,\n covered: covered.has(`${r}:${c}`),\n };\n });\n rows.push({ index: r, height: rd?.h ?? drh, cells });\n }\n\n const ySplit = sheet.freeze?.ySplit ?? 0;\n const xSplit = sheet.freeze?.xSplit ?? 0;\n return {\n id: sheetId,\n name: sheet.name ?? \"Sheet1\",\n columns,\n rows,\n frozenRows: Math.min(rows.filter((r) => r.index < ySplit).length, rows.length),\n frozenColumns: Math.min(columns.filter((c) => c.index < xSplit).length, columns.length),\n gridlines: sheet.showGridlines !== 0,\n truncatedFrom: maxRow > lastRow ? maxRow + 1 : null,\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 colour, hex. Always a light colour 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 colour (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 * A workbook's print settings — Google Sheets' File → Page setup / Print, as pure data and pure\n * pagination (no React, no IO). They live on the workbook (`udt_workbooks.metadata.page_setup`),\n * so Print, Download as PDF and the Page setup dialog all read the same values.\n *\n * Geometry is in 96-dpi CSS pixels, like the rest of the document stack (`PX_PER_INCH`).\n */\n\nimport { PAPER_SIZES, PX_PER_INCH, type PaperSizeName } from \"../core\";\n\nexport const SHEET_SCALES = [\"normal\", \"width\", \"height\", \"page\"] as const;\nexport type SheetScale = (typeof SHEET_SCALES)[number];\nexport const SHEET_MARGIN_PRESETS = [\"normal\", \"narrow\", \"wide\", \"custom\"] as const;\nexport type SheetMarginPreset = (typeof SHEET_MARGIN_PRESETS)[number];\nexport const SHEET_PRINT_SCOPES = [\"sheet\", \"workbook\", \"selection\"] as const;\nexport type SheetPrintScope = (typeof SHEET_PRINT_SCOPES)[number];\nexport type SheetPageOrder = \"down-over\" | \"over-down\";\nexport type SheetAlignH = \"left\" | \"center\" | \"right\";\nexport type SheetAlignV = \"top\" | \"middle\" | \"bottom\";\n\nexport interface SheetPageSetup {\n paper: PaperSizeName;\n orientation: \"portrait\" | \"landscape\";\n scale: SheetScale;\n margins: SheetMarginPreset;\n /** Inches; read only when `margins` is \"custom\". */\n customMargins: { top: number; bottom: number; left: number; right: number };\n scope: SheetPrintScope;\n gridlines: boolean;\n repeatFrozenRows: boolean;\n repeatFrozenColumns: boolean;\n pageOrder: SheetPageOrder;\n alignH: SheetAlignH;\n alignV: SheetAlignV;\n}\n\n/** Google Sheets' defaults: Letter, portrait, 100%, normal margins, current sheet, gridlines on. */\nexport const DEFAULT_SHEET_PAGE_SETUP: SheetPageSetup = {\n paper: \"Letter\",\n orientation: \"portrait\",\n scale: \"normal\",\n margins: \"normal\",\n customMargins: { top: 0.75, bottom: 0.75, left: 0.7, right: 0.7 },\n scope: \"sheet\",\n gridlines: true,\n repeatFrozenRows: false,\n repeatFrozenColumns: false,\n pageOrder: \"down-over\",\n alignH: \"left\",\n alignV: \"top\",\n};\n\n/** Google's three preset margins, in inches. */\nexport const MARGIN_PRESET_INCHES: Record<Exclude<SheetMarginPreset, \"custom\">, { top: number; bottom: number; left: number; right: number }> = {\n normal: { top: 0.75, bottom: 0.75, left: 0.7, right: 0.7 },\n narrow: { top: 0.25, bottom: 0.25, left: 0.25, right: 0.25 },\n wide: { top: 1, bottom: 1, left: 1, right: 1 },\n};\n\nconst isPaper = (v: unknown): v is PaperSizeName => typeof v === \"string\" && v in PAPER_SIZES;\nconst oneOf = <T extends string>(list: readonly T[], v: unknown, fallback: T): T => (typeof v === \"string\" && (list as readonly string[]).includes(v) ? (v as T) : fallback);\nconst inches = (v: unknown, fallback: number) => (typeof v === \"number\" && Number.isFinite(v) && v >= 0 && v <= 5 ? v : fallback);\n\n/** Any stored value → a complete, valid setup. Unknown or broken parts fall back to the default. */\nexport function normalizeSheetPageSetup(raw: unknown): SheetPageSetup {\n const r = (raw && typeof raw === \"object\" ? raw : {}) as Record<string, unknown>;\n const m = (r.customMargins && typeof r.customMargins === \"object\" ? r.customMargins : {}) as Record<string, unknown>;\n const d = DEFAULT_SHEET_PAGE_SETUP;\n return {\n paper: isPaper(r.paper) ? r.paper : d.paper,\n orientation: r.orientation === \"landscape\" ? \"landscape\" : \"portrait\",\n scale: oneOf(SHEET_SCALES, r.scale, d.scale),\n margins: oneOf(SHEET_MARGIN_PRESETS, r.margins, d.margins),\n customMargins: {\n top: inches(m.top, d.customMargins.top),\n bottom: inches(m.bottom, d.customMargins.bottom),\n left: inches(m.left, d.customMargins.left),\n right: inches(m.right, d.customMargins.right),\n },\n scope: oneOf(SHEET_PRINT_SCOPES, r.scope, d.scope),\n gridlines: typeof r.gridlines === \"boolean\" ? r.gridlines : d.gridlines,\n repeatFrozenRows: r.repeatFrozenRows === true,\n repeatFrozenColumns: r.repeatFrozenColumns === true,\n pageOrder: r.pageOrder === \"over-down\" ? \"over-down\" : \"down-over\",\n alignH: oneOf([\"left\", \"center\", \"right\"] as const, r.alignH, d.alignH),\n alignV: oneOf([\"top\", \"middle\", \"bottom\"] as const, r.alignV, d.alignV),\n };\n}\n\n/** The setup stored on a workbook's metadata (`metadata.page_setup`), complete and valid. */\nexport function pageSetupFromMetadata(metadata: unknown): SheetPageSetup {\n return normalizeSheetPageSetup((metadata as { page_setup?: unknown } | null)?.page_setup);\n}\n\nexport interface PrintGeometry {\n /** Paper as printed (orientation applied), px. */\n paperWidth: number;\n paperHeight: number;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /** The printable box inside the margins, px. */\n areaWidth: number;\n areaHeight: number;\n}\n\nexport function printGeometry(setup: SheetPageSetup): PrintGeometry {\n const base = PAPER_SIZES[setup.paper];\n const landscape = setup.orientation === \"landscape\";\n const paperWidth = landscape ? base.height : base.width;\n const paperHeight = landscape ? base.width : base.height;\n const m = setup.margins === \"custom\" ? setup.customMargins : MARGIN_PRESET_INCHES[setup.margins];\n const px = (n: number) => Math.round(n * PX_PER_INCH);\n const geometry = {\n paperWidth,\n paperHeight,\n marginTop: px(m.top),\n marginBottom: px(m.bottom),\n marginLeft: px(m.left),\n marginRight: px(m.right),\n };\n return {\n ...geometry,\n areaWidth: Math.max(48, paperWidth - geometry.marginLeft - geometry.marginRight),\n areaHeight: Math.max(48, paperHeight - geometry.marginTop - geometry.marginBottom),\n };\n}\n\nexport const PRINT_ROW_HEIGHT = 22;\nconst MIN_COL = 48;\nconst MAX_COL = 320;\nconst CHAR_PX = 7;\n\n/** Column widths (px) fitted to the text the column holds. */\nexport function printColumnWidths(rows: readonly (readonly string[])[]): number[] {\n const width = rows.reduce((n, r) => Math.max(n, r.length), 0);\n const out: number[] = [];\n for (let c = 0; c < width; c += 1) {\n let longest = 0;\n for (const r of rows) longest = Math.max(longest, (r[c] ?? \"\").length);\n out.push(Math.min(MAX_COL, Math.max(MIN_COL, longest * CHAR_PX + 16)));\n }\n return out;\n}\n\nexport interface PrintPage {\n /** Grid row indexes drawn on this page, in order (repeated frozen rows first). */\n rows: number[];\n /** Grid column indexes drawn on this page, in order (repeated frozen columns first). */\n cols: number[];\n}\n\nexport interface PrintPlan {\n scale: number;\n geometry: PrintGeometry;\n colWidths: number[];\n pages: PrintPage[];\n}\n\n/** Splits `count` items into bands that fit `capacity(px)`, repeating `frozen` leading items on every band after the first. */\nfunction bands(sizes: readonly number[], capacityPx: number, frozen: number, repeat: boolean): number[][] {\n const total = sizes.length;\n if (total === 0) return [];\n const result: number[][] = [];\n const lead = repeat ? Math.min(frozen, total) : 0;\n const leadPx = sizes.slice(0, lead).reduce((a, b) => a + b, 0);\n let at = 0;\n while (at < total) {\n const first = result.length === 0;\n const carry = !first && lead > 0 ? Array.from({ length: lead }, (_, i) => i) : [];\n let used = first ? 0 : leadPx;\n const band = [...carry];\n // A repeated header never leaves a page with no room for a body item.\n if (!first && leadPx >= capacityPx) used = 0;\n let added = 0;\n while (at < total) {\n const size = sizes[at]!;\n if (used + size > capacityPx && added > 0) break;\n band.push(at);\n used += size;\n added += 1;\n at += 1;\n }\n result.push(band);\n }\n return result;\n}\n\n/** The pages one grid prints on under `setup`: scale, repeated frozen panes, and page order. */\nexport function planSheetPrint(\n rows: readonly (readonly string[])[],\n setup: SheetPageSetup,\n frozen: { rows: number; cols: number } = { rows: 0, cols: 0 },\n): PrintPlan {\n const geometry = printGeometry(setup);\n const colWidths = printColumnWidths(rows);\n const totalW = colWidths.reduce((a, b) => a + b, 0) || 1;\n const totalH = rows.length * PRINT_ROW_HEIGHT || 1;\n const fitW = geometry.areaWidth / totalW;\n const fitH = geometry.areaHeight / totalH;\n const scale =\n setup.scale === \"width\" ? Math.min(1, fitW) : setup.scale === \"height\" ? Math.min(1, fitH) : setup.scale === \"page\" ? Math.min(1, fitW, fitH) : 1;\n const rowBands = bands(\n rows.map(() => PRINT_ROW_HEIGHT),\n geometry.areaHeight / scale,\n frozen.rows,\n setup.repeatFrozenRows,\n );\n const colBands = bands(colWidths, geometry.areaWidth / scale, frozen.cols, setup.repeatFrozenColumns);\n const pages: PrintPage[] = [];\n if (setup.pageOrder === \"down-over\") {\n for (const cols of colBands) for (const r of rowBands) pages.push({ rows: r, cols });\n } else {\n for (const r of rowBands) for (const cols of colBands) pages.push({ rows: r, cols });\n }\n return { scale, geometry, colWidths, pages };\n}\n","/**\n * A workbook's print settings, read and written on the workbook itself:\n * `udt_workbooks.metadata.page_setup` (merged with `mergeJsonColumn`, like the table links beside it).\n */\nimport { mergeJsonColumn } from \"@ai-matrx/data/db\";\n\nimport { getSheetsHost } from \"./ports\";\nimport { normalizeSheetPageSetup, pageSetupFromMetadata, type SheetPageSetup } from \"./sheet-page-setup\";\n\nconst db = () => getSheetsHost().getSupabase();\n\ntype WorkbookMetaRow = { id: string; version: number; metadata: unknown };\n\nexport type PageSetupResult = { ok: true; data: SheetPageSetup } | { ok: false; error: string };\n\nexport async function readSheetPageSetup(workbookId: string): Promise<PageSetupResult> {\n const { data, error } = await db().schema(\"workbench\").from(\"udt_workbooks\").select(\"metadata\").eq(\"id\", workbookId).maybeSingle();\n if (error) return { ok: false, error: error.message };\n return { ok: true, data: pageSetupFromMetadata(data?.metadata) };\n}\n\nexport async function writeSheetPageSetup(workbookId: string, setup: SheetPageSetup): Promise<PageSetupResult> {\n const clean = normalizeSheetPageSetup(setup);\n const result = await mergeJsonColumn<WorkbookMetaRow>({\n fetchCurrent: () => db().schema(\"workbench\").from(\"udt_workbooks\").select(\"id, version, metadata\").eq(\"id\", workbookId).maybeSingle(),\n readColumn: (row) => row.metadata,\n merge: (current) => ({ ...current, page_setup: clean }),\n applyUpdate: ({ value, expectedVersion, nextVersion }) =>\n db()\n .schema(\"workbench\")\n .from(\"udt_workbooks\")\n .update({ metadata: value as never, version: nextVersion })\n .eq(\"id\", workbookId)\n .eq(\"version\", expectedVersion)\n .select(\"id, version, metadata\")\n .maybeSingle(),\n });\n if (result.status === \"saved\") return { ok: true, data: pageSetupFromMetadata(result.row.metadata) };\n if (result.status === \"not_found\") return { ok: false, error: \"This workbook could not be found\" };\n if (result.status === \"conflict\") return { ok: false, error: \"The workbook changed while saving; try again\" };\n const reason: unknown = result.error;\n return { ok: false, error: reason instanceof Error ? reason.message : typeof reason === \"string\" ? reason : \"Something went wrong\" };\n}\n","/**\n * The pages a workbook prints on: the snapshot's cells → paper-sized HTML pages that follow the\n * workbook's print settings (`sheet-page-setup.ts`). Print and Download as PDF both draw these\n * same pages, so what the browser prints is what the PDF holds.\n */\n\nimport { PX_PER_INCH } from \"../core\";\nimport {\n PRINT_ROW_HEIGHT,\n planSheetPrint,\n type PrintGeometry,\n type SheetPageSetup,\n} from \"./sheet-page-setup\";\nimport { univerSheetIds, univerSnapshotToRows, type CellRange } from \"./univer-snapshot-rows\";\n\nexport interface PrintSheet {\n name: string;\n rows: string[][];\n frozenRows: number;\n frozenCols: number;\n}\n\n/** The sheets the setup's \"what to print\" asks for (empty sheets left out). */\nexport function collectPrintSheets(\n snapshot: unknown,\n setup: SheetPageSetup,\n options: { sheetId?: string; selection?: CellRange | null },\n): PrintSheet[] {\n const read = (sheetId: string | undefined, range?: CellRange): PrintSheet | null => {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(sheetId ? { sheetId } : {}), ...(range ? { range } : {}) });\n if (!grid || grid.rows.length === 0) return null;\n return { name: grid.sheetName, rows: grid.rows, frozenRows: grid.frozenRows, frozenCols: grid.frozenCols };\n };\n if (setup.scope === \"workbook\") {\n return univerSheetIds(snapshot)\n .map((id) => read(id))\n .filter((s): s is PrintSheet => s !== null);\n }\n if (setup.scope === \"selection\") {\n const sel = options.selection;\n if (!sel || (sel.startRow === sel.endRow && sel.startColumn === sel.endColumn)) return [];\n const one = read(options.sheetId, sel);\n return one ? [one] : [];\n }\n const one = read(options.sheetId);\n return one ? [one] : [];\n}\n\nconst esc = (s: string) => s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n\nconst JUSTIFY = { left: \"flex-start\", center: \"center\", right: \"flex-end\" } as const;\nconst ALIGN = { top: \"flex-start\", middle: \"center\", bottom: \"flex-end\" } as const;\n\nfunction pageHtml(\n sheet: PrintSheet,\n page: { rows: number[]; cols: number[] },\n scale: number,\n colWidths: number[],\n g: PrintGeometry,\n setup: SheetPageSetup,\n numbering: { sheet: string; at: number; of: number },\n): string {\n const widths = page.cols.map((c) => colWidths[c] ?? 0);\n const tableW = widths.reduce((a, b) => a + b, 0);\n const tableH = page.rows.length * PRINT_ROW_HEIGHT;\n const border = setup.gridlines ? \"1px solid #b7b7b7\" : \"none\";\n const body = page.rows\n .map(\n (r) =>\n `<tr style=\"height:${PRINT_ROW_HEIGHT}px\">${page.cols\n .map((c) => `<td style=\"border:${border}\">${esc(sheet.rows[r]?.[c] ?? \"\")}</td>`)\n .join(\"\")}</tr>`,\n )\n .join(\"\");\n const cols = widths.map((w) => `<col style=\"width:${w}px\">`).join(\"\");\n return `<section data-print-page data-sheet=\"${esc(numbering.sheet)}\" data-page-number=\"${numbering.at}\" data-page-count=\"${numbering.of}\" data-page-rows=\"${page.rows.length}\" data-page-cols=\"${page.cols.length}\" style=\"width:${g.paperWidth}px;height:${g.paperHeight}px;box-sizing:border-box;padding:${g.marginTop}px ${g.marginRight}px ${g.marginBottom}px ${g.marginLeft}px;background:#fff;overflow:hidden;break-after:page;page-break-after:always\">\n<div style=\"width:${g.areaWidth}px;height:${g.areaHeight}px;display:flex;justify-content:${JUSTIFY[setup.alignH]};align-items:${ALIGN[setup.alignV]};overflow:hidden\">\n<div data-print-content style=\"width:${tableW * scale}px;height:${tableH * scale}px;flex:none;overflow:hidden\">\n<table style=\"width:${tableW}px;table-layout:fixed;border-collapse:collapse;transform:scale(${scale});transform-origin:0 0;font:12px/${PRINT_ROW_HEIGHT - 2}px system-ui,sans-serif;color:#111\"><colgroup>${cols}</colgroup><tbody>${body}</tbody></table>\n</div></div></section>`;\n}\n\nexport interface PrintDocument {\n /** Every page, in print order. */\n pagesHtml: string[];\n pageWidth: number;\n pageHeight: number;\n /** `@page` size in inches, for the browser's print engine. */\n pageSizeInches: { width: number; height: number };\n}\n\n/** All the printed pages of the chosen sheets under the setup (empty when there is nothing to print). */\nexport function buildPrintDocument(sheets: readonly PrintSheet[], setup: SheetPageSetup): PrintDocument | null {\n const out: string[] = [];\n let geometry: PrintGeometry | null = null;\n for (const sheet of sheets) {\n const plan = planSheetPrint(sheet.rows, setup, { rows: sheet.frozenRows, cols: sheet.frozenCols });\n geometry = plan.geometry;\n plan.pages.forEach((page, i) => {\n out.push(pageHtml(sheet, page, plan.scale, plan.colWidths, plan.geometry, setup, { sheet: sheet.name, at: i + 1, of: plan.pages.length }));\n });\n }\n if (!geometry || out.length === 0) return null;\n return {\n pagesHtml: out,\n pageWidth: geometry.paperWidth,\n pageHeight: geometry.paperHeight,\n pageSizeInches: { width: geometry.paperWidth / PX_PER_INCH, height: geometry.paperHeight / PX_PER_INCH },\n };\n}\n\n/** The whole printable web page: `@page` set to the paper, one section per page. */\nexport function printDocumentHtml(doc: PrintDocument, title: string): string {\n const { width, height } = doc.pageSizeInches;\n return `<!doctype html><html><head><meta charset=\"utf-8\"><title>${esc(title)}</title>\n<style>@page{size:${width.toFixed(3)}in ${height.toFixed(3)}in;margin:0}html,body{margin:0;padding:0;background:#fff}td{padding:0 6px;overflow:hidden;white-space:nowrap;text-overflow:clip;vertical-align:middle}section:last-child{break-after:auto;page-break-after:auto}</style></head>\n<body data-print-paper=\"${width.toFixed(3)}x${height.toFixed(3)}in\">${doc.pagesHtml.join(\"\\n\")}</body></html>`;\n}\n","/**\n * Outputs of a workbook: CSV/TSV/HTML downloads of the current sheet, and Print / PDF of what its page setup asks for.\n * Both read the same string grid the rest of the workbook code reads\n * (`univerSnapshotToRows`) — one source of what \"the sheet\" contains.\n */\n\nimport { downloadFile } from \"@ai-matrx/kit/download\";\nimport { toDelimitedText } from \"@ai-matrx/alchemy/operate/read\";\nimport { PX_PER_INCH } from \"../core\";\nimport type { SheetPageSetup } from \"./sheet-page-setup\";\nimport { buildPrintDocument, collectPrintSheets, printDocumentHtml } from \"./sheet-print-pages\";\nimport { univerSnapshotToRows, type CellRange } from \"./univer-snapshot-rows\";\n\nexport function sheetGridToCsv(rows: readonly (readonly string[])[]): string {\n const [header, ...body] = rows;\n if (!header) return \"\";\n return toDelimitedText(header, body, { spreadsheetSafe: false });\n}\n\nexport function downloadSheetAsCsv(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const name = `${options.filename.replace(/\\.csv$/i, \"\")}.csv`;\n // BOM so Excel reads UTF-8.\n const blob = new Blob([\"\", sheetGridToCsv(grid.rows)], { type: \"text/csv;charset=utf-8\" });\n downloadFile(name, blob, blob.type);\n return true;\n}\n\n/** Tab-separated values of the current sheet (Google's .tsv download). */\nexport function downloadSheetAsTsv(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const [header, ...body] = grid.rows;\n const text = toDelimitedText(header!, body, { format: \"tsv\", spreadsheetSafe: false });\n const blob = new Blob([\"\\uFEFF\", text], { type: \"text/tab-separated-values;charset=utf-8\" });\n downloadFile(`${options.filename.replace(/\\.tsv$/i, \"\")}.tsv`, blob, blob.type);\n return true;\n}\n\n/** The current sheet as a standalone web page (Google's .html download). */\nexport function downloadSheetAsHtml(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const body = grid.rows.map((r) => `<tr>${r.map((c) => `<td>${esc(c)}</td>`).join(\"\")}</tr>`).join(\"\\n\");\n const html = `<!doctype html><html><head><meta charset=\"utf-8\"><title>${esc(options.filename)} — ${esc(grid.sheetName)}</title>\n<style>body{font:13px system-ui,sans-serif;margin:16px}table{border-collapse:collapse}td{border:1px solid #c0c0c0;padding:2px 6px;vertical-align:top}</style></head>\n<body><table>\n${body}\n</table></body></html>`;\n const blob = new Blob([html], { type: \"text/html;charset=utf-8\" });\n downloadFile(`${options.filename.replace(/\\.html?$/i, \"\")}.html`, blob, blob.type);\n return true;\n}\n\nfunction esc(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\n/** What a print or PDF needs besides the snapshot: the workbook's page setup and the live selection. */\nexport interface SheetPrintOptions {\n sheetId?: string;\n title: string;\n setup: SheetPageSetup;\n /** The cells selected right now (used when the setup prints \"selected cells\"). */\n selection?: CellRange | null;\n}\n\nfunction printDocumentFor(snapshot: unknown, options: SheetPrintOptions) {\n const sheets = collectPrintSheets(snapshot, options.setup, {\n ...(options.sheetId ? { sheetId: options.sheetId } : {}),\n selection: options.selection ?? null,\n });\n return buildPrintDocument(sheets, options.setup);\n}\n\n/** Opens the browser print sheet for what the workbook's page setup asks to print (choose \"Save as PDF\" there). */\nexport function printSheet(snapshot: unknown, options: SheetPrintOptions): boolean {\n const doc = printDocumentFor(snapshot, options);\n if (!doc) return false;\n const html = printDocumentHtml(doc, options.title);\n const frame = document.createElement(\"iframe\");\n frame.style.cssText = \"position:fixed;right:0;bottom:0;width:0;height:0;border:0\";\n document.body.appendChild(frame);\n const fdoc = frame.contentDocument;\n const win = frame.contentWindow;\n if (!fdoc || !win) {\n frame.remove();\n return false;\n }\n fdoc.open();\n fdoc.write(html);\n fdoc.close();\n win.addEventListener(\"afterprint\", () => frame.remove());\n win.focus();\n win.print();\n return true;\n}\n\n/** The sheet's grid as a markdown table (first row is the header row). */\nexport function sheetGridToMarkdownTable(rows: readonly (readonly string[])[]): string {\n if (rows.length === 0) return \"\";\n const width = Math.max(...rows.map((r) => r.length));\n const cell = (v: string | undefined) => (v ?? \"\").replace(/\\|/g, \"\\\\|\").replace(/\\r?\\n/g, \" \");\n const line = (r: readonly string[]) =>\n `| ${Array.from({ length: width }, (_, i) => cell(r[i])).join(\" | \")} |`;\n const [head, ...rest] = rows;\n return [line(head!), `| ${Array.from({ length: width }, () => \"---\").join(\" | \")} |`, ...rest.map(line)].join(\"\\n\");\n}\n\n/**\n * Real PDF download of what the workbook's page setup prints: the same pages Print draws, each one\n * captured and laid on a PDF page of the chosen paper size and orientation. Returns false when empty.\n */\nexport async function downloadSheetAsPdf(snapshot: unknown, options: SheetPrintOptions): Promise<boolean> {\n const doc = printDocumentFor(snapshot, options);\n if (!doc) return false;\n const [{ renderElement, pagesToPdf }, { downloadFile: save }] = await Promise.all([\n import(\"@ai-matrx/alchemy/operate/capture\"),\n import(\"@ai-matrx/kit/download\"),\n ]);\n const host = document.createElement(\"div\");\n host.setAttribute(\"aria-hidden\", \"true\");\n host.style.cssText = \"position:fixed;left:-20000px;top:0\";\n host.innerHTML = `<style>td{padding:0 6px;overflow:hidden;white-space:nowrap;vertical-align:middle}</style>${doc.pagesHtml.join(\"\")}`;\n document.body.appendChild(host);\n try {\n const pages = [];\n for (const el of Array.from(host.querySelectorAll<HTMLElement>(\"[data-print-page]\"))) {\n const image = await renderElement(el, { pixelRatio: 2, backgroundColor: \"#ffffff\", cacheBust: true });\n pages.push({ image, imageType: \"JPEG\" as const, quality: 0.92, placement: \"fill\" as const });\n }\n const mm = (px: number) => Math.round(((px / PX_PER_INCH) * 25.4) * 100) / 100;\n const pdf = await pagesToPdf(pages, {\n orientation: doc.pageWidth > doc.pageHeight ? \"landscape\" : \"portrait\",\n unit: \"mm\",\n format: [mm(Math.min(doc.pageWidth, doc.pageHeight)), mm(Math.max(doc.pageWidth, doc.pageHeight))],\n });\n save(`${options.title.replace(/[\\\\/:*?\"<>|]+/g, \" \").trim() || \"workbook\"}.pdf`, pdf, \"application/pdf\");\n } finally {\n host.remove();\n }\n return true;\n}\n","// features/workbooks/workbook-scope-source.ts\n//\n// Live bridge from the mounted `WorkbookEditor` to the `matrx-user/workbooks`\n// surface emitter on `/workbooks/[id]`.\n//\n// Why a module slot rather than props: the page owns the workbook row and\n// mounts `<SurfaceRuntimeProvider>`, but the sheets / snapshot / save status\n// live inside the editor (Univer refs + local state), one level DOWN. Pushing\n// them up as state would re-render the editor on every keystroke; a\n// registered getter is read once, at Run time, when the user actually\n// launches an agent.\n//\n// Exactly one editor is mounted at a time (one workbook per route), so a\n// single slot keyed by workbookId is enough. The getter returns null when the\n// editor has not booted — callers omit the values, they never fake them.\n\nexport interface WorkbookLiveScope {\n sheets: Array<{ id: string; name: string; index: number }>;\n activeSheetId: string | null;\n activeSheetName: string | null;\n snapshot: Record<string, unknown> | null;\n bootState: \"booting\" | \"ready\" | \"load_error\";\n loadError: string | null;\n saveStatus: string;\n collab: {\n enabled: boolean;\n is_host: boolean;\n self_uid: string;\n remote_peers: number;\n };\n}\n\ninterface Registration {\n workbookId: string;\n read: () => WorkbookLiveScope | null;\n}\n\nlet current: Registration | null = null;\n\n/** Called by `WorkbookEditor` while mounted. Returns an unregister. */\nexport function registerWorkbookScopeSource(\n registration: Registration,\n): () => void {\n current = registration;\n return () => {\n if (current === registration) current = null;\n };\n}\n\n/**\n * Read the live editor state for `workbookId`. Returns null when no editor is\n * mounted, when a different workbook is mounted, or when Univer has not\n * booted yet — never a fabricated shape.\n */\nexport function readWorkbookScopeSource(\n workbookId: string,\n): WorkbookLiveScope | null {\n if (!current || current.workbookId !== workbookId) return null;\n return current.read();\n}\n"],"mappings":"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","names":["fs","current","one","esc","esc"]}
|
|
1
|
+
{"version":3,"sources":["../src/sheets/univer-snapshot-rows.ts","../src/sheets/snapshot-preview-svg.ts","../src/sheets/snapshot-grid.ts","../src/core/document-page-style.ts","../src/sheets/sheet-page-setup.ts","../src/sheets/sheet-page-setup-service.ts","../src/sheets/sheet-print-pages.ts","../src/sheets/sheet-output.ts","../src/sheets/workbook-scope-source.ts"],"sourcesContent":["/**\n * features/workbooks/univer-snapshot-rows.ts\n *\n * Snapshot → rows: read a Univer `IWorkbookData` snapshot back out as a plain\n * string grid. The missing half of the workbook round trip — `export-targets`\n * pushes rows INTO a workbook; this reads the (possibly user-edited) values\n * back OUT so features can offer \"edit in the workbook, then import your\n * changes\". Values only (formulas come back as their cached value); first\n * sheet by `sheetOrder` unless a sheet id is named. A number shown through a date format reads as\n * its ISO date (a spreadsheet keeps dates as day serials). Reusable — do not fork a per-feature\n * snapshot walker. Callers: the workbook's \"Make this sheet a table\" (features/workbooks/table-link).\n */\n\ninterface CellShape {\n v?: unknown;\n s?: unknown;\n}\n\ninterface SheetShape {\n name?: string;\n /** Frozen panes: `xSplit` columns and `ySplit` rows are pinned. */\n freeze?: { xSplit?: number; ySplit?: number } | null;\n /** Univer marks a hidden column/row `hd: 1` (a table link's Record ID column is one). */\n columnData?: Record<string, { hd?: number } | null | undefined>;\n rowData?: Record<string, { hd?: number } | null | undefined>;\n cellData?: Record<string, Record<string, CellShape | null | undefined>>;\n}\n\ninterface SnapshotShape {\n sheetOrder?: string[];\n sheets?: Record<string, SheetShape>;\n styles?: Record<string, { n?: { pattern?: string } | null } | null>;\n}\n\nexport interface SnapshotRows {\n sheetName: string;\n /** Dense rectangular grid, trailing empty rows/columns trimmed. */\n rows: string[][];\n /** Rows pinned at the top of the sheet (Freeze rows), counted in `rows`. */\n frozenRows: number;\n /** Columns pinned at the left of the sheet (Freeze columns), counted in each row. */\n frozenCols: number;\n}\n\n/** A zero-based, inclusive cell range (a selection). */\nexport interface CellRange {\n startRow: number;\n endRow: number;\n startColumn: number;\n endColumn: number;\n}\n\n/** Sheet ids in tab order. */\nexport function univerSheetIds(snapshot: unknown): string[] {\n if (typeof snapshot !== \"object\" || snapshot === null) return [];\n const shape = snapshot as SnapshotShape;\n const sheets = shape.sheets ?? {};\n const ordered = (shape.sheetOrder ?? []).filter((id) => sheets[id]);\n return ordered.length ? ordered : Object.keys(sheets);\n}\n\ntype Styles = SnapshotShape[\"styles\"];\n\n/** The number-format pattern a cell is shown through, if any. */\nfunction patternOf(cell: CellShape | null | undefined, styles: Styles): string | null {\n const s = cell?.s;\n const style = typeof s === \"string\" ? styles?.[s] : s && typeof s === \"object\" ? (s as { n?: { pattern?: string } }) : null;\n const pattern = style?.n?.pattern;\n return typeof pattern === \"string\" ? pattern : null;\n}\n\nconst DAY_MS = 86_400_000;\nconst SERIAL_EPOCH_MS = Date.UTC(1899, 11, 30);\n\nfunction cellText(cell: CellShape | null | undefined, styles?: Styles): string {\n const value = cell?.v;\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"number\") {\n const pattern = patternOf(cell, styles)?.replace(/\"[^\"]*\"/g, \"\").toLowerCase() ?? \"\";\n if (/[dy]/.test(pattern)) {\n const iso = new Date(Math.round(SERIAL_EPOCH_MS + value * DAY_MS)).toISOString();\n return /h/.test(pattern) ? `${iso.slice(0, 10)} ${iso.slice(11, 16)}` : iso.slice(0, 10);\n }\n }\n return String(value);\n}\n\n/**\n * Extract the first worksheet of a Univer workbook snapshot as a string grid.\n * Returns null when the value is not snapshot-shaped or has no sheets.\n * `skipHidden` leaves out hidden columns and rows: every read-only view (a share page, an agent's\n * read) passes it, so the table link's hidden Record ID column never reaches a reader.\n */\nexport function univerSnapshotToRows(snapshot: unknown, options: { sheetId?: string; skipHidden?: boolean; range?: CellRange } = {}): SnapshotRows | null {\n if (typeof snapshot !== \"object\" || snapshot === null) return null;\n const shape = snapshot as SnapshotShape;\n const sheets = shape.sheets ?? {};\n const styles = shape.styles;\n const firstId = options.sheetId\n ? sheets[options.sheetId]\n ? options.sheetId\n : undefined\n : (shape.sheetOrder?.find((id) => sheets[id]) ?? Object.keys(sheets)[0]);\n if (!firstId) return null;\n const sheet = sheets[firstId];\n const cellData = sheet?.cellData ?? {};\n\n let maxRow = -1;\n let maxCol = -1;\n for (const [rowKey, row] of Object.entries(cellData)) {\n const rowIndex = Number(rowKey);\n if (!Number.isInteger(rowIndex) || !row) continue;\n for (const [colKey, cell] of Object.entries(row)) {\n const colIndex = Number(colKey);\n if (!Number.isInteger(colIndex)) continue;\n if (cellText(cell) === \"\") continue;\n if (rowIndex > maxRow) maxRow = rowIndex;\n if (colIndex > maxCol) maxCol = colIndex;\n }\n }\n const range = options.range;\n if (range) {\n // A selection prints exactly the cells chosen, empty ones included.\n maxRow = range.endRow;\n maxCol = range.endColumn;\n }\n if (maxRow < 0 || maxCol < 0) {\n return { sheetName: sheet?.name ?? \"Sheet1\", rows: [], frozenRows: 0, frozenCols: 0 };\n }\n const firstRow = range?.startRow ?? 0;\n const firstCol = range?.startColumn ?? 0;\n\n const hiddenCol = (c: number) => options.skipHidden === true && sheet?.columnData?.[String(c)]?.hd === 1;\n const hiddenRow = (r: number) => options.skipHidden === true && sheet?.rowData?.[String(r)]?.hd === 1;\n const rows: string[][] = [];\n const ySplit = Math.max(0, sheet?.freeze?.ySplit ?? 0);\n const xSplit = Math.max(0, sheet?.freeze?.xSplit ?? 0);\n let frozenRows = 0;\n let frozenCols = 0;\n for (let r = firstRow; r <= maxRow; r += 1) {\n if (hiddenRow(r)) continue;\n if (r < ySplit) frozenRows += 1;\n const row: string[] = [];\n const source = cellData[String(r)] ?? {};\n let colsFrozenHere = 0;\n for (let c = firstCol; c <= maxCol; c += 1) {\n if (hiddenCol(c)) continue;\n if (c < xSplit) colsFrozenHere += 1;\n row.push(cellText(source[String(c)], styles));\n }\n frozenCols = colsFrozenHere;\n rows.push(row);\n }\n return { sheetName: sheet?.name ?? \"Sheet1\", rows, frozenRows, frozenCols };\n}\n","/**\n * snapshot → SVG: a faithful miniature of a Univer workbook's first sheet or a\n * Univer document's first page — the gallery tile Google draws. Pure (no DOM,\n * no Univer runtime), so it runs in the browser (thumbnail capture), in tests\n * and in node. Reads only what a snapshot stores: cell values + styles +\n * column widths + merges + conditional formats + checkboxes for sheets; the\n * dataStream + text runs + paragraph styles + tables for documents.\n */\n\nexport const THUMB_WIDTH = 320;\nexport const THUMB_HEIGHT = 414;\n\ntype Rgb = { rgb?: string | null } | null | undefined;\ntype CellStyle = {\n bg?: Rgb;\n cl?: Rgb;\n bl?: number;\n it?: number;\n fs?: number;\n ht?: number;\n n?: { pattern?: string } | null;\n bd?: Record<string, unknown> | null;\n};\ntype Cell = { v?: unknown; s?: string | CellStyle | null; t?: number; f?: string };\ntype Sheet = {\n id?: string;\n name?: string;\n cellData?: Record<string, Record<string, Cell>>;\n columnData?: Record<string, { w?: number; hd?: number }>;\n rowData?: Record<string, { h?: number; hd?: number }>;\n defaultColumnWidth?: number;\n defaultRowHeight?: number;\n mergeData?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n showGridlines?: number;\n freeze?: { ySplit?: number; xSplit?: number };\n};\nexport type Workbook = {\n sheetOrder?: string[];\n sheets?: Record<string, Sheet>;\n styles?: Record<string, CellStyle | null>;\n resources?: Array<{ name?: string; data?: string }>;\n};\n\nconst esc = (s: string) =>\n s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n\nfunction color(c: Rgb, fallback: string): string {\n const v = c?.rgb;\n return typeof v === \"string\" && v.length > 0 ? v : fallback;\n}\n\n// ─── number formats ──────────────────────────────────────────────────────────\n\nconst EXCEL_EPOCH = Date.UTC(1899, 11, 30);\nconst MONTHS = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n\nexport function formatCellValue(v: unknown, pattern?: string | null): string {\n if (v === null || v === undefined) return \"\";\n if (typeof v === \"boolean\") return v ? \"TRUE\" : \"FALSE\";\n if (typeof v !== \"number\" || !pattern || pattern === \"General\") return String(v);\n const p = pattern.toLowerCase();\n if (/[dy]/.test(p) && !p.includes(\"$\")) {\n const d = new Date(EXCEL_EPOCH + Math.round(v) * 86400000);\n const mm = d.getUTCMonth();\n const dd = d.getUTCDate();\n const yy = d.getUTCFullYear();\n if (p.includes(\"mmm\")) return `${MONTHS[mm]} ${dd}${p.includes(\"y\") ? `, ${yy}` : \"\"}`;\n return p.includes(\"y\") ? `${mm + 1}/${dd}/${yy}` : `${mm + 1}/${dd}`;\n }\n const decimals = (pattern.split(\".\")[1]?.match(/0/g) ?? []).length;\n if (p.includes(\"%\")) return `${(v * 100).toFixed(decimals)}%`;\n const grouped = Math.abs(v).toLocaleString(\"en-US\", {\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n useGrouping: pattern.includes(\",\"),\n });\n const sign = v < 0 ? \"-\" : \"\";\n return p.includes(\"$\") ? `${sign}$${grouped}` : `${sign}${grouped}`;\n}\n\n// ─── conditional formatting (the rules a preview can evaluate) ───────────────\n\nexport type CfRule = {\n rule?: {\n type?: string;\n subType?: string;\n operator?: string;\n value?: unknown;\n style?: CellStyle;\n };\n ranges?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n};\n\nexport function parseResource<T>(wb: Workbook, name: string): T | null {\n const res = wb.resources?.find((r) => r.name === name);\n if (!res?.data) return null;\n try {\n return JSON.parse(res.data) as T;\n } catch {\n return null;\n }\n}\n\nexport function cfMatch(rule: NonNullable<CfRule[\"rule\"]>, v: unknown): boolean {\n if (rule.type !== \"highlightCell\") return false;\n if (rule.subType === \"number\" && typeof v === \"number\") {\n const x = rule.value;\n const [a = 0, b = 0] = Array.isArray(x) ? (x as number[]) : [Number(x), Number(x)];\n switch (rule.operator) {\n case \"greaterThan\": return v > a;\n case \"greaterThanOrEqual\": return v >= a;\n case \"lessThan\": return v < a;\n case \"lessThanOrEqual\": return v <= a;\n case \"equal\": return v === a;\n case \"notEqual\": return v !== a;\n case \"between\": return v >= a && v <= b;\n default: return false;\n }\n }\n if (rule.subType === \"text\" && v !== undefined && v !== null) {\n const s = String(v).toLowerCase();\n const want = String(rule.value ?? \"\").toLowerCase();\n switch (rule.operator) {\n case \"containsText\": return s.includes(want);\n case \"equal\": return s === want;\n case \"beginsWith\": return s.startsWith(want);\n default: return false;\n }\n }\n return false;\n}\n\n// ─── workbook ────────────────────────────────────────────────────────────────\n\nexport function workbookPreviewSvg(snapshot: unknown): string {\n const wb = (snapshot ?? {}) as Workbook;\n const firstId = wb.sheetOrder?.[0] ?? Object.keys(wb.sheets ?? {})[0];\n const sheet: Sheet = (firstId && wb.sheets?.[firstId]) || {};\n const sheetId = sheet.id ?? firstId ?? \"\";\n const styles = wb.styles ?? {};\n const cfAll = parseResource<Record<string, CfRule[]>>(wb, \"SHEET_CONDITIONAL_FORMATTING_PLUGIN\");\n const cf = (cfAll?.[sheetId] ?? []).filter((r) => r.rule && r.ranges);\n const dvAll = parseResource<Record<string, Array<{ type?: string; ranges?: CfRule[\"ranges\"] }>>>(\n wb,\n \"SHEET_DATA_VALIDATION_PLUGIN\",\n );\n const checkboxRanges = (dvAll?.[sheetId] ?? []).filter((d) => d.type === \"checkbox\").flatMap((d) => d.ranges ?? []);\n const inRanges = (rs: CfRule[\"ranges\"], r: number, c: number) =>\n (rs ?? []).some((x) => r >= x.startRow && r <= x.endRow && c >= x.startColumn && c <= x.endColumn);\n\n const dcw = sheet.defaultColumnWidth ?? 88;\n const drh = sheet.defaultRowHeight ?? 24;\n const colW = (c: number) => (sheet.columnData?.[c]?.hd ? 0 : sheet.columnData?.[c]?.w ?? dcw);\n const rowH = (r: number) => (sheet.rowData?.[r]?.hd ? 0 : sheet.rowData?.[r]?.h ?? drh);\n\n // Show the used width (at least ~5 default columns), scaled to the tile.\n let maxCol = 0;\n for (const row of Object.values(sheet.cellData ?? {})) {\n for (const c of Object.keys(row ?? {})) maxCol = Math.max(maxCol, Number(c));\n }\n let used = 0;\n for (let c = 0; c <= maxCol; c++) used += colW(c);\n // Google's tiles show the top-left of the sheet at a readable size, not the whole width.\n const span = Math.min(Math.max(used + 12, dcw * 5), 640);\n const scale = THUMB_WIDTH / span;\n\n const out: string[] = [];\n out.push(`<rect width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" fill=\"#ffffff\"/>`);\n const gridOn = sheet.showGridlines !== 0;\n const merges = sheet.mergeData ?? [];\n const covered = new Set<string>();\n for (const m of merges) {\n for (let r = m.startRow; r <= m.endRow; r++)\n for (let c = m.startColumn; c <= m.endColumn; c++)\n if (r !== m.startRow || c !== m.startColumn) covered.add(`${r}:${c}`);\n }\n const texts: string[] = [];\n let y = 0;\n for (let r = 0; y * scale < THUMB_HEIGHT && r < 400; r++) {\n const h = rowH(r);\n let x = 0;\n for (let c = 0; x * scale < THUMB_WIDTH && c < 60; c++) {\n const w = colW(c);\n if (w === 0 || h === 0 || covered.has(`${r}:${c}`)) {\n x += w;\n continue;\n }\n const m = merges.find((mm) => mm.startRow === r && mm.startColumn === c);\n let cw = w;\n let ch = h;\n if (m) {\n cw = 0;\n for (let k = m.startColumn; k <= m.endColumn; k++) cw += colW(k);\n ch = 0;\n for (let k = m.startRow; k <= m.endRow; k++) ch += rowH(k);\n }\n const cell = sheet.cellData?.[r]?.[c];\n const base: CellStyle =\n (typeof cell?.s === \"string\" ? styles[cell.s] : (cell?.s as CellStyle | null)) ?? {};\n let st: CellStyle = base;\n for (const rule of cf) {\n if (inRanges(rule.ranges, r, c) && rule.rule && cfMatch(rule.rule, cell?.v)) {\n st = { ...st, ...rule.rule.style };\n break;\n }\n }\n const X = x * scale;\n const Y = y * scale;\n const W = cw * scale;\n const H = ch * scale;\n const bg = st.bg?.rgb;\n if (bg) out.push(`<rect x=\"${X.toFixed(1)}\" y=\"${Y.toFixed(1)}\" width=\"${W.toFixed(1)}\" height=\"${H.toFixed(1)}\" fill=\"${esc(bg)}\"/>`);\n if (gridOn) out.push(`<rect x=\"${X.toFixed(1)}\" y=\"${Y.toFixed(1)}\" width=\"${W.toFixed(1)}\" height=\"${H.toFixed(1)}\" fill=\"none\" stroke=\"#e2e3e3\" stroke-width=\"0.5\"/>`);\n const fs = Math.max((st.fs ?? 10) * 1.333 * scale, 3);\n const midY = Y + H / 2 + fs * 0.35;\n if (inRanges(checkboxRanges, r, c) && r > 0 && (cell?.v === true || cell?.v === false || cell?.v === 1 || cell?.v === 0 || cell?.v === \"TRUE\" || cell?.v === \"FALSE\")) {\n const box = Math.min(H * 0.55, 9);\n const bx = X + W / 2 - box / 2;\n const by = Y + H / 2 - box / 2;\n const on = cell?.v === true || cell?.v === 1 || cell?.v === \"TRUE\";\n out.push(`<rect x=\"${bx.toFixed(1)}\" y=\"${by.toFixed(1)}\" width=\"${box.toFixed(1)}\" height=\"${box.toFixed(1)}\" rx=\"1\" fill=\"${on ? \"#1a73e8\" : \"#ffffff\"}\" stroke=\"${on ? \"#1a73e8\" : \"#5f6368\"}\" stroke-width=\"0.7\"/>`);\n if (on) out.push(`<path d=\"M${(bx + box * 0.2).toFixed(1)} ${(by + box * 0.5).toFixed(1)} l${(box * 0.25).toFixed(1)} ${(box * 0.25).toFixed(1)} l${(box * 0.4).toFixed(1)} ${(-box * 0.45).toFixed(1)}\" stroke=\"#fff\" stroke-width=\"0.9\" fill=\"none\"/>`);\n } else if (cell && cell.v !== undefined && cell.v !== null && cell.v !== \"\") {\n const text = formatCellValue(cell.v, st.n?.pattern);\n const numeric = typeof cell.v === \"number\";\n const ht = st.ht ?? (numeric ? 3 : 1);\n const anchor = ht === 2 ? \"middle\" : ht === 3 ? \"end\" : \"start\";\n const tx = ht === 2 ? X + W / 2 : ht === 3 ? X + W - 2 * scale * 2 : X + 3 * scale;\n const maxChars = Math.max(Math.floor((m ? W : W * (ht === 1 && !numeric ? 3 : 1)) / (fs * 0.55)), 1);\n const shown = text.length > maxChars ? text.slice(0, maxChars) : text;\n texts.push(\n `<text x=\"${tx.toFixed(1)}\" y=\"${midY.toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" text-anchor=\"${anchor}\" fill=\"${esc(color(st.cl, \"#202124\"))}\"${st.bl ? ' font-weight=\"700\"' : \"\"}${st.it ? ' font-style=\"italic\"' : \"\"}>${esc(shown)}</text>`,\n );\n }\n x += w;\n }\n y += h;\n }\n return wrapSvg([...out, ...texts].join(\"\"));\n}\n\n// ─── document ────────────────────────────────────────────────────────────────\n\ntype TextStyle = { fs?: number; bl?: number; it?: number; cl?: Rgb; ff?: string; bg?: Rgb };\ntype DocData = {\n body?: {\n dataStream?: string;\n paragraphs?: Array<{ startIndex: number; paragraphStyle?: { horizontalAlign?: number; spaceAbove?: { v?: number }; spaceBelow?: { v?: number } } }>;\n textRuns?: Array<{ st: number; ed: number; ts?: TextStyle }>;\n tables?: Array<{ startIndex: number; endIndex: number; tableId: string }>;\n };\n documentStyle?: {\n pageSize?: { width?: number; height?: number };\n marginTop?: number;\n marginLeft?: number;\n marginRight?: number;\n };\n};\n\nconst CONTROL = /[\\x1A\\x1B\\x1C\\x1D\\x0E\\x0F\\x1F\\x1E\\b]/g;\n\nexport function documentPreviewSvg(snapshot: unknown): string {\n const doc = (snapshot ?? {}) as DocData;\n const stream = doc.body?.dataStream ?? \"\";\n const pageW = doc.documentStyle?.pageSize?.width ?? 595;\n const scale = THUMB_WIDTH / pageW;\n const ml = (doc.documentStyle?.marginLeft ?? 72) * scale;\n const mr = (doc.documentStyle?.marginRight ?? 72) * scale;\n const mt = (doc.documentStyle?.marginTop ?? 72) * scale;\n const contentW = THUMB_WIDTH - ml - mr;\n const runs = [...(doc.body?.textRuns ?? [])].sort((a, b) => a.st - b.st);\n const tables = doc.body?.tables ?? [];\n const styleAt = (i: number): TextStyle => runs.find((r) => i >= r.st && i < r.ed)?.ts ?? {};\n /** The style most of a paragraph's characters carry (a bold lead-in does not make the line bold). */\n const dominantStyle = (from: number, to: number): TextStyle => {\n const counts = new Map<string, { n: number; ts: TextStyle }>();\n for (let i = from; i < to; i++) {\n if (/\\s/.test(stream[i] ?? \"\")) continue;\n const ts = styleAt(i);\n const k = JSON.stringify(ts);\n const e = counts.get(k) ?? { n: 0, ts };\n e.n++;\n counts.set(k, e);\n }\n let best: { n: number; ts: TextStyle } | null = null;\n for (const e of counts.values()) if (!best || e.n > best.n) best = e;\n return best?.ts ?? {};\n };\n const out: string[] = [`<rect width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" fill=\"#ffffff\"/>`];\n\n let y = mt;\n let start = 0;\n const paragraphs = doc.body?.paragraphs ?? [];\n for (let p = 0; p < paragraphs.length && y < THUMB_HEIGHT; p++) {\n const para = paragraphs[p];\n if (!para) break;\n const end = para.startIndex;\n const table = tables.find((t) => start >= t.startIndex && start < t.endIndex);\n if (table) {\n // Draw the whole table once: rows split on the row token, cells on the cell token.\n const raw = stream.slice(table.startIndex, table.endIndex);\n const rows = raw.split(\"\\x1B\").slice(1).map((row) =>\n row.split(\"\\x1C\").slice(1).map((cell) => cell.replace(/[\\r\\n]/g, \" \").replace(CONTROL, \"\").trim()),\n );\n const cols = Math.max(1, ...rows.map((r) => r.length));\n const cw = contentW / cols;\n // Bold header row when the first cell's text is bold.\n const headerBold = styleAt(table.startIndex + 4).bl === 1;\n for (let r = 0; r < rows.length && y < THUMB_HEIGHT; r++) {\n const rh = 16 * scale * 1.2 + 6 * scale;\n for (let c = 0; c < cols; c++) {\n const cx = ml + c * cw;\n out.push(`<rect x=\"${cx.toFixed(1)}\" y=\"${y.toFixed(1)}\" width=\"${cw.toFixed(1)}\" height=\"${rh.toFixed(1)}\" fill=\"${r === 0 && headerBold ? \"#f1f3f4\" : \"none\"}\" stroke=\"#9aa0a6\" stroke-width=\"0.4\"/>`);\n const fs = 11 * 1.333 * scale;\n const maxChars = Math.max(Math.floor((cw - 6 * scale) / (fs * 0.5)), 1);\n const t = rows[r]?.[c] ?? \"\";\n out.push(`<text x=\"${(cx + 4 * scale).toFixed(1)}\" y=\"${(y + rh / 2 + fs * 0.35).toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" fill=\"#202124\"${r === 0 && headerBold ? ' font-weight=\"700\"' : \"\"}>${esc(t.slice(0, maxChars))}</text>`);\n }\n y += rh;\n }\n // Skip every paragraph inside the table.\n while (p + 1 < paragraphs.length && (paragraphs[p + 1]?.startIndex ?? Infinity) < table.endIndex) p++;\n start = table.endIndex;\n y += 6 * scale;\n continue;\n }\n const text = stream.slice(start, end).replace(CONTROL, \"\");\n const st = dominantStyle(start, end);\n const ps = para.paragraphStyle ?? {};\n const fsPt = st.fs ?? 11;\n const fs = fsPt * 1.333 * scale;\n const lineH = fs * 1.3;\n y += (ps.spaceAbove?.v ?? (fsPt > 13 ? 8 : 0)) * scale;\n const align = ps.horizontalAlign ?? 1;\n const anchor = align === 2 ? \"middle\" : align === 3 ? \"end\" : \"start\";\n const tx = align === 2 ? ml + contentW / 2 : align === 3 ? ml + contentW : ml;\n // Paragraph shading (a filled band) when the run carries a highlight.\n if (!text.trim()) {\n y += lineH * 0.8;\n } else {\n const maxChars = Math.max(Math.floor(contentW / (fs * (st.bl ? 0.56 : 0.5))), 4);\n const words = text.split(/\\s+/);\n const lines: string[] = [];\n let line = \"\";\n for (const w of words) {\n if ((line + \" \" + w).trim().length > maxChars && line) {\n lines.push(line);\n line = w;\n } else line = (line + \" \" + w).trim();\n }\n if (line) lines.push(line);\n for (const l of lines) {\n if (y > THUMB_HEIGHT) break;\n y += lineH;\n if (st.bg?.rgb) out.push(`<rect x=\"${ml.toFixed(1)}\" y=\"${(y - fs).toFixed(1)}\" width=\"${contentW.toFixed(1)}\" height=\"${lineH.toFixed(1)}\" fill=\"${esc(st.bg.rgb)}\"/>`);\n out.push(`<text x=\"${tx.toFixed(1)}\" y=\"${y.toFixed(1)}\" font-size=\"${fs.toFixed(1)}\" text-anchor=\"${anchor}\" fill=\"${esc(color(st.cl, \"#202124\"))}\"${st.bl ? ' font-weight=\"700\"' : \"\"}${st.it ? ' font-style=\"italic\"' : \"\"}${st.ff && /serif|georgia|times|garamond/i.test(st.ff) && !/sans/i.test(st.ff) ? ' font-family=\"Georgia, serif\"' : \"\"}>${esc(l)}</text>`);\n }\n }\n y += (ps.spaceBelow?.v ?? 4) * scale;\n start = end + 1;\n }\n return wrapSvg(out.join(\"\"));\n}\n\nfunction wrapSvg(body: string): string {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${THUMB_WIDTH}\" height=\"${THUMB_HEIGHT}\" viewBox=\"0 0 ${THUMB_WIDTH} ${THUMB_HEIGHT}\" font-family=\"Arial, Helvetica, sans-serif\">${body}</svg>`;\n}\n\nexport function snapshotPreviewSvg(kind: \"workbook\" | \"document\", snapshot: unknown): string {\n return kind === \"workbook\" ? workbookPreviewSvg(snapshot) : documentPreviewSvg(snapshot);\n}\n","/**\n * features/workbooks/snapshot-grid.ts\n *\n * Snapshot → a formatted, read-only grid model: what a spreadsheet VIEW needs and the plain-string\n * `univer-snapshot-rows` does not carry — number/currency/date formats applied, checkbox cells\n * (data-validation ranges of type checkbox), alignment, bold/italic, fill and text colour, column\n * widths, merges, frozen rows/columns, hidden rows/columns and sheets. Pure (no DOM, no Univer\n * runtime): the signed-out share page draws it. The number formatter is the thumbnail's\n * (`formatCellValue`) so a tile, a share link and the editor read the same.\n */\n\nimport {\n cfMatch,\n formatCellValue,\n parseResource,\n type CfRule,\n type Workbook,\n} from \"./snapshot-preview-svg\";\n\ntype Rgb = { rgb?: string | null } | null | undefined;\ninterface Style {\n bg?: Rgb;\n cl?: Rgb;\n bl?: number;\n it?: number;\n fs?: number;\n ht?: number;\n tb?: number;\n n?: { pattern?: string } | null;\n}\ninterface Cell {\n v?: unknown;\n s?: string | Style | null;\n}\ninterface Sheet {\n id?: string;\n name?: string;\n hidden?: number;\n cellData?: Record<string, Record<string, Cell | null | undefined>>;\n columnData?: Record<string, { w?: number; hd?: number } | null | undefined>;\n rowData?: Record<string, { h?: number; hd?: number } | null | undefined>;\n defaultColumnWidth?: number;\n defaultRowHeight?: number;\n mergeData?: Array<{ startRow: number; endRow: number; startColumn: number; endColumn: number }>;\n showGridlines?: number;\n freeze?: { xSplit?: number; ySplit?: number };\n}\n\nexport interface GridCell {\n text: string;\n /** A checkbox cell (a data-validation checkbox range): `checked` says its state. */\n checkbox?: { checked: boolean } | undefined;\n align: \"left\" | \"center\" | \"right\";\n bold: boolean;\n italic: boolean;\n /** Font size in px (the snapshot stores points). */\n fontPx: number;\n bg?: string | undefined;\n color?: string | undefined;\n wrap: boolean;\n rowSpan: number;\n colSpan: number;\n /** Covered by a merge that starts elsewhere: draw nothing. */\n covered: boolean;\n}\n\nexport interface GridSheet {\n id: string;\n name: string;\n /** Visible column indexes (hidden columns left out) with their pixel widths. */\n columns: Array<{ index: number; width: number }>;\n rows: Array<{ index: number; height: number; cells: GridCell[] }>;\n /** How many leading VISIBLE rows / columns stay put while scrolling. */\n frozenRows: number;\n frozenColumns: number;\n gridlines: boolean;\n /** Rows beyond the cap were left out. */\n truncatedFrom: number | null;\n}\n\nexport const GRID_MAX_ROWS = 500;\nexport const GRID_MAX_COLUMNS = 60;\n\nconst PT_TO_PX = 1.333;\nconst isCheckboxValue = (v: unknown) => v === true || v === false || v === 1 || v === 0 || v === \"TRUE\" || v === \"FALSE\";\nconst isOn = (v: unknown) => v === true || v === 1 || v === \"TRUE\";\n\nfunction hasValue(cell: Cell | null | undefined): boolean {\n const v = cell?.v;\n return v !== undefined && v !== null && v !== \"\";\n}\n\n/** Every visible sheet that has something in it, in tab order. Empty and hidden sheets are left out. */\nexport function snapshotToGridSheets(snapshot: unknown): GridSheet[] {\n if (typeof snapshot !== \"object\" || snapshot === null) return [];\n const wb = snapshot as Workbook;\n const sheets = wb.sheets ?? {};\n const order = (wb.sheetOrder ?? []).filter((id) => sheets[id]);\n const ids = order.length > 0 ? order : Object.keys(sheets);\n const out: GridSheet[] = [];\n for (const id of ids) {\n const grid = sheetToGrid(wb, id, sheets[id] as Sheet);\n if (grid) out.push(grid);\n }\n return out;\n}\n\nfunction sheetToGrid(wb: Workbook, id: string, sheet: Sheet): GridSheet | null {\n if (sheet.hidden === 1) return null;\n const cellData = sheet.cellData ?? {};\n let maxRow = -1;\n let maxCol = -1;\n for (const [rk, row] of Object.entries(cellData)) {\n const r = Number(rk);\n if (!Number.isInteger(r) || !row) continue;\n for (const [ck, cell] of Object.entries(row)) {\n const c = Number(ck);\n if (!Number.isInteger(c) || !hasValue(cell)) continue;\n if (r > maxRow) maxRow = r;\n if (c > maxCol) maxCol = c;\n }\n }\n if (maxRow < 0 || maxCol < 0) return null;\n\n const styles = wb.styles ?? {};\n const sheetId = sheet.id ?? id;\n const cfAll = parseResource<Record<string, CfRule[]>>(wb, \"SHEET_CONDITIONAL_FORMATTING_PLUGIN\");\n const cf = (cfAll?.[sheetId] ?? []).filter((r) => r.rule && r.ranges);\n const dvAll = parseResource<Record<string, Array<{ type?: string; ranges?: CfRule[\"ranges\"] }>>>(\n wb,\n \"SHEET_DATA_VALIDATION_PLUGIN\",\n );\n const checkboxRanges = (dvAll?.[sheetId] ?? []).filter((d) => d.type === \"checkbox\").flatMap((d) => d.ranges ?? []);\n const inRanges = (rs: CfRule[\"ranges\"], r: number, c: number) =>\n (rs ?? []).some((x) => r >= x.startRow && r <= x.endRow && c >= x.startColumn && c <= x.endColumn);\n\n const dcw = sheet.defaultColumnWidth ?? 88;\n const drh = sheet.defaultRowHeight ?? 24;\n const lastCol = Math.min(maxCol, GRID_MAX_COLUMNS - 1);\n const columns: GridSheet[\"columns\"] = [];\n for (let c = 0; c <= lastCol; c += 1) {\n const col = sheet.columnData?.[String(c)];\n if (col?.hd === 1) continue;\n columns.push({ index: c, width: col?.w ?? dcw });\n }\n\n const merges = sheet.mergeData ?? [];\n const covered = new Set<string>();\n for (const m of merges) {\n for (let r = m.startRow; r <= m.endRow; r += 1)\n for (let c = m.startColumn; c <= m.endColumn; c += 1) if (r !== m.startRow || c !== m.startColumn) covered.add(`${r}:${c}`);\n }\n\n const rows: GridSheet[\"rows\"] = [];\n const lastRow = Math.min(maxRow, GRID_MAX_ROWS - 1);\n for (let r = 0; r <= lastRow; r += 1) {\n const rd = sheet.rowData?.[String(r)];\n if (rd?.hd === 1) continue;\n const source = cellData[String(r)] ?? {};\n const cells: GridCell[] = columns.map(({ index: c }) => {\n const cell = source[String(c)] ?? undefined;\n const base: Style = (typeof cell?.s === \"string\" ? (styles[cell.s] as Style | null | undefined) : (cell?.s as Style | null | undefined)) ?? {};\n let st: Style = base;\n for (const rule of cf) {\n if (inRanges(rule.ranges, r, c) && rule.rule && cfMatch(rule.rule, cell?.v)) {\n st = { ...st, ...(rule.rule.style as Style | undefined) };\n break;\n }\n }\n const m = merges.find((mm) => mm.startRow === r && mm.startColumn === c);\n const v = cell?.v;\n const box = hasValue(cell) && inRanges(checkboxRanges, r, c) && isCheckboxValue(v);\n const numeric = typeof v === \"number\";\n const ht = st.ht ?? 0;\n return {\n text: box ? \"\" : hasValue(cell) ? formatCellValue(v, st.n?.pattern) : \"\",\n checkbox: box ? { checked: isOn(v) } : undefined,\n align: box || ht === 2 ? \"center\" : ht === 3 || (ht === 0 && numeric) ? \"right\" : \"left\",\n bold: st.bl === 1,\n italic: st.it === 1,\n fontPx: Math.round((st.fs ?? 10) * PT_TO_PX),\n bg: st.bg?.rgb ?? undefined,\n color: st.cl?.rgb ?? undefined,\n wrap: st.tb === 3,\n rowSpan: m ? m.endRow - m.startRow + 1 : 1,\n colSpan: m ? m.endColumn - m.startColumn + 1 : 1,\n covered: covered.has(`${r}:${c}`),\n };\n });\n rows.push({ index: r, height: rd?.h ?? drh, cells });\n }\n\n const ySplit = sheet.freeze?.ySplit ?? 0;\n const xSplit = sheet.freeze?.xSplit ?? 0;\n return {\n id: sheetId,\n name: sheet.name ?? \"Sheet1\",\n columns,\n rows,\n frozenRows: Math.min(rows.filter((r) => r.index < ySplit).length, rows.length),\n frozenColumns: Math.min(columns.filter((c) => c.index < xSplit).length, columns.length),\n gridlines: sheet.showGridlines !== 0,\n truncatedFrom: maxRow > lastRow ? maxRow + 1 : null,\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 colour, hex. Always a light colour 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 colour (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 * A workbook's print settings — Google Sheets' File → Page setup / Print, as pure data and pure\n * pagination (no React, no IO). They live on the workbook (`udt_workbooks.metadata.page_setup`),\n * so Print, Download as PDF and the Page setup dialog all read the same values.\n *\n * Geometry is in 96-dpi CSS pixels, like the rest of the document stack (`PX_PER_INCH`).\n */\n\nimport { PAPER_SIZES, PX_PER_INCH, type PaperSizeName } from \"../core\";\n\nexport const SHEET_SCALES = [\"normal\", \"width\", \"height\", \"page\"] as const;\nexport type SheetScale = (typeof SHEET_SCALES)[number];\nexport const SHEET_MARGIN_PRESETS = [\"normal\", \"narrow\", \"wide\", \"custom\"] as const;\nexport type SheetMarginPreset = (typeof SHEET_MARGIN_PRESETS)[number];\nexport const SHEET_PRINT_SCOPES = [\"sheet\", \"workbook\", \"selection\"] as const;\nexport type SheetPrintScope = (typeof SHEET_PRINT_SCOPES)[number];\nexport type SheetPageOrder = \"down-over\" | \"over-down\";\nexport type SheetAlignH = \"left\" | \"center\" | \"right\";\nexport type SheetAlignV = \"top\" | \"middle\" | \"bottom\";\n\nexport interface SheetPageSetup {\n paper: PaperSizeName;\n orientation: \"portrait\" | \"landscape\";\n scale: SheetScale;\n margins: SheetMarginPreset;\n /** Inches; read only when `margins` is \"custom\". */\n customMargins: { top: number; bottom: number; left: number; right: number };\n scope: SheetPrintScope;\n gridlines: boolean;\n repeatFrozenRows: boolean;\n repeatFrozenColumns: boolean;\n pageOrder: SheetPageOrder;\n alignH: SheetAlignH;\n alignV: SheetAlignV;\n}\n\n/** Google Sheets' defaults: Letter, portrait, 100%, normal margins, current sheet, gridlines on. */\nexport const DEFAULT_SHEET_PAGE_SETUP: SheetPageSetup = {\n paper: \"Letter\",\n orientation: \"portrait\",\n scale: \"normal\",\n margins: \"normal\",\n customMargins: { top: 0.75, bottom: 0.75, left: 0.7, right: 0.7 },\n scope: \"sheet\",\n gridlines: true,\n repeatFrozenRows: false,\n repeatFrozenColumns: false,\n pageOrder: \"down-over\",\n alignH: \"left\",\n alignV: \"top\",\n};\n\n/** Google's three preset margins, in inches. */\nexport const MARGIN_PRESET_INCHES: Record<Exclude<SheetMarginPreset, \"custom\">, { top: number; bottom: number; left: number; right: number }> = {\n normal: { top: 0.75, bottom: 0.75, left: 0.7, right: 0.7 },\n narrow: { top: 0.25, bottom: 0.25, left: 0.25, right: 0.25 },\n wide: { top: 1, bottom: 1, left: 1, right: 1 },\n};\n\nconst isPaper = (v: unknown): v is PaperSizeName => typeof v === \"string\" && v in PAPER_SIZES;\nconst oneOf = <T extends string>(list: readonly T[], v: unknown, fallback: T): T => (typeof v === \"string\" && (list as readonly string[]).includes(v) ? (v as T) : fallback);\nconst inches = (v: unknown, fallback: number) => (typeof v === \"number\" && Number.isFinite(v) && v >= 0 && v <= 5 ? v : fallback);\n\n/** Any stored value → a complete, valid setup. Unknown or broken parts fall back to the default. */\nexport function normalizeSheetPageSetup(raw: unknown): SheetPageSetup {\n const r = (raw && typeof raw === \"object\" ? raw : {}) as Record<string, unknown>;\n const m = (r.customMargins && typeof r.customMargins === \"object\" ? r.customMargins : {}) as Record<string, unknown>;\n const d = DEFAULT_SHEET_PAGE_SETUP;\n return {\n paper: isPaper(r.paper) ? r.paper : d.paper,\n orientation: r.orientation === \"landscape\" ? \"landscape\" : \"portrait\",\n scale: oneOf(SHEET_SCALES, r.scale, d.scale),\n margins: oneOf(SHEET_MARGIN_PRESETS, r.margins, d.margins),\n customMargins: {\n top: inches(m.top, d.customMargins.top),\n bottom: inches(m.bottom, d.customMargins.bottom),\n left: inches(m.left, d.customMargins.left),\n right: inches(m.right, d.customMargins.right),\n },\n scope: oneOf(SHEET_PRINT_SCOPES, r.scope, d.scope),\n gridlines: typeof r.gridlines === \"boolean\" ? r.gridlines : d.gridlines,\n repeatFrozenRows: r.repeatFrozenRows === true,\n repeatFrozenColumns: r.repeatFrozenColumns === true,\n pageOrder: r.pageOrder === \"over-down\" ? \"over-down\" : \"down-over\",\n alignH: oneOf([\"left\", \"center\", \"right\"] as const, r.alignH, d.alignH),\n alignV: oneOf([\"top\", \"middle\", \"bottom\"] as const, r.alignV, d.alignV),\n };\n}\n\n/** The setup stored on a workbook's metadata (`metadata.page_setup`), complete and valid. */\nexport function pageSetupFromMetadata(metadata: unknown): SheetPageSetup {\n return normalizeSheetPageSetup((metadata as { page_setup?: unknown } | null)?.page_setup);\n}\n\nexport interface PrintGeometry {\n /** Paper as printed (orientation applied), px. */\n paperWidth: number;\n paperHeight: number;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /** The printable box inside the margins, px. */\n areaWidth: number;\n areaHeight: number;\n}\n\nexport function printGeometry(setup: SheetPageSetup): PrintGeometry {\n const base = PAPER_SIZES[setup.paper];\n const landscape = setup.orientation === \"landscape\";\n const paperWidth = landscape ? base.height : base.width;\n const paperHeight = landscape ? base.width : base.height;\n const m = setup.margins === \"custom\" ? setup.customMargins : MARGIN_PRESET_INCHES[setup.margins];\n const px = (n: number) => Math.round(n * PX_PER_INCH);\n const geometry = {\n paperWidth,\n paperHeight,\n marginTop: px(m.top),\n marginBottom: px(m.bottom),\n marginLeft: px(m.left),\n marginRight: px(m.right),\n };\n return {\n ...geometry,\n areaWidth: Math.max(48, paperWidth - geometry.marginLeft - geometry.marginRight),\n areaHeight: Math.max(48, paperHeight - geometry.marginTop - geometry.marginBottom),\n };\n}\n\nexport const PRINT_ROW_HEIGHT = 22;\nconst MIN_COL = 48;\nconst MAX_COL = 320;\nconst CHAR_PX = 7;\n\n/** Column widths (px) fitted to the text the column holds. */\nexport function printColumnWidths(rows: readonly (readonly string[])[]): number[] {\n const width = rows.reduce((n, r) => Math.max(n, r.length), 0);\n const out: number[] = [];\n for (let c = 0; c < width; c += 1) {\n let longest = 0;\n for (const r of rows) longest = Math.max(longest, (r[c] ?? \"\").length);\n out.push(Math.min(MAX_COL, Math.max(MIN_COL, longest * CHAR_PX + 16)));\n }\n return out;\n}\n\nexport interface PrintPage {\n /** Grid row indexes drawn on this page, in order (repeated frozen rows first). */\n rows: number[];\n /** Grid column indexes drawn on this page, in order (repeated frozen columns first). */\n cols: number[];\n}\n\nexport interface PrintPlan {\n scale: number;\n geometry: PrintGeometry;\n colWidths: number[];\n pages: PrintPage[];\n}\n\n/** Splits `count` items into bands that fit `capacity(px)`, repeating `frozen` leading items on every band after the first. */\nfunction bands(sizes: readonly number[], capacityPx: number, frozen: number, repeat: boolean): number[][] {\n const total = sizes.length;\n if (total === 0) return [];\n const result: number[][] = [];\n const lead = repeat ? Math.min(frozen, total) : 0;\n const leadPx = sizes.slice(0, lead).reduce((a, b) => a + b, 0);\n let at = 0;\n while (at < total) {\n const first = result.length === 0;\n const carry = !first && lead > 0 ? Array.from({ length: lead }, (_, i) => i) : [];\n let used = first ? 0 : leadPx;\n const band = [...carry];\n // A repeated header never leaves a page with no room for a body item.\n if (!first && leadPx >= capacityPx) used = 0;\n let added = 0;\n while (at < total) {\n const size = sizes[at]!;\n if (used + size > capacityPx && added > 0) break;\n band.push(at);\n used += size;\n added += 1;\n at += 1;\n }\n result.push(band);\n }\n return result;\n}\n\n/** The pages one grid prints on under `setup`: scale, repeated frozen panes, and page order. */\nexport function planSheetPrint(\n rows: readonly (readonly string[])[],\n setup: SheetPageSetup,\n frozen: { rows: number; cols: number } = { rows: 0, cols: 0 },\n): PrintPlan {\n const geometry = printGeometry(setup);\n const colWidths = printColumnWidths(rows);\n const totalW = colWidths.reduce((a, b) => a + b, 0) || 1;\n const totalH = rows.length * PRINT_ROW_HEIGHT || 1;\n const fitW = geometry.areaWidth / totalW;\n const fitH = geometry.areaHeight / totalH;\n const scale =\n setup.scale === \"width\" ? Math.min(1, fitW) : setup.scale === \"height\" ? Math.min(1, fitH) : setup.scale === \"page\" ? Math.min(1, fitW, fitH) : 1;\n const rowBands = bands(\n rows.map(() => PRINT_ROW_HEIGHT),\n geometry.areaHeight / scale,\n frozen.rows,\n setup.repeatFrozenRows,\n );\n const colBands = bands(colWidths, geometry.areaWidth / scale, frozen.cols, setup.repeatFrozenColumns);\n const pages: PrintPage[] = [];\n if (setup.pageOrder === \"down-over\") {\n for (const cols of colBands) for (const r of rowBands) pages.push({ rows: r, cols });\n } else {\n for (const r of rowBands) for (const cols of colBands) pages.push({ rows: r, cols });\n }\n return { scale, geometry, colWidths, pages };\n}\n","/**\n * A workbook's print settings, read and written on the workbook itself:\n * `udt_workbooks.metadata.page_setup` (merged with `mergeJsonColumn`, like the table links beside it).\n */\nimport { mergeJsonColumn } from \"@ai-matrx/data/db\";\n\nimport { getSheetsHost } from \"./ports\";\nimport { normalizeSheetPageSetup, pageSetupFromMetadata, type SheetPageSetup } from \"./sheet-page-setup\";\n\nconst db = () => getSheetsHost().getSupabase();\n\ntype WorkbookMetaRow = { id: string; version: number; metadata: unknown };\n\nexport type PageSetupResult = { ok: true; data: SheetPageSetup } | { ok: false; error: string };\n\nexport async function readSheetPageSetup(workbookId: string): Promise<PageSetupResult> {\n const { data, error } = await db().schema(\"workbench\").from(\"udt_workbooks\").select(\"metadata\").eq(\"id\", workbookId).maybeSingle();\n if (error) return { ok: false, error: error.message };\n return { ok: true, data: pageSetupFromMetadata(data?.metadata) };\n}\n\nexport async function writeSheetPageSetup(workbookId: string, setup: SheetPageSetup): Promise<PageSetupResult> {\n const clean = normalizeSheetPageSetup(setup);\n const result = await mergeJsonColumn<WorkbookMetaRow>({\n fetchCurrent: () => db().schema(\"workbench\").from(\"udt_workbooks\").select(\"id, version, metadata\").eq(\"id\", workbookId).maybeSingle(),\n readColumn: (row) => row.metadata,\n merge: (current) => ({ ...current, page_setup: clean }),\n applyUpdate: ({ value, expectedVersion, nextVersion }) =>\n db()\n .schema(\"workbench\")\n .from(\"udt_workbooks\")\n .update({ metadata: value as never, version: nextVersion })\n .eq(\"id\", workbookId)\n .eq(\"version\", expectedVersion)\n .select(\"id, version, metadata\")\n .maybeSingle(),\n });\n if (result.status === \"saved\") return { ok: true, data: pageSetupFromMetadata(result.row.metadata) };\n if (result.status === \"not_found\") return { ok: false, error: \"This workbook could not be found\" };\n if (result.status === \"conflict\") return { ok: false, error: \"The workbook changed while saving; try again\" };\n const reason: unknown = result.error;\n return { ok: false, error: reason instanceof Error ? reason.message : typeof reason === \"string\" ? reason : \"Something went wrong\" };\n}\n","/**\n * The pages a workbook prints on: the snapshot's cells → paper-sized HTML pages that follow the\n * workbook's print settings (`sheet-page-setup.ts`). Print and Download as PDF both draw these\n * same pages, so what the browser prints is what the PDF holds.\n */\n\nimport { PX_PER_INCH } from \"../core\";\nimport {\n PRINT_ROW_HEIGHT,\n planSheetPrint,\n type PrintGeometry,\n type SheetPageSetup,\n} from \"./sheet-page-setup\";\nimport { univerSheetIds, univerSnapshotToRows, type CellRange } from \"./univer-snapshot-rows\";\n\nexport interface PrintSheet {\n name: string;\n rows: string[][];\n frozenRows: number;\n frozenCols: number;\n}\n\n/** The sheets the setup's \"what to print\" asks for (empty sheets left out). */\nexport function collectPrintSheets(\n snapshot: unknown,\n setup: SheetPageSetup,\n options: { sheetId?: string; selection?: CellRange | null },\n): PrintSheet[] {\n const read = (sheetId: string | undefined, range?: CellRange): PrintSheet | null => {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(sheetId ? { sheetId } : {}), ...(range ? { range } : {}) });\n if (!grid || grid.rows.length === 0) return null;\n return { name: grid.sheetName, rows: grid.rows, frozenRows: grid.frozenRows, frozenCols: grid.frozenCols };\n };\n if (setup.scope === \"workbook\") {\n return univerSheetIds(snapshot)\n .map((id) => read(id))\n .filter((s): s is PrintSheet => s !== null);\n }\n if (setup.scope === \"selection\") {\n const sel = options.selection;\n if (!sel || (sel.startRow === sel.endRow && sel.startColumn === sel.endColumn)) return [];\n const one = read(options.sheetId, sel);\n return one ? [one] : [];\n }\n const one = read(options.sheetId);\n return one ? [one] : [];\n}\n\nconst esc = (s: string) => s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n\nconst JUSTIFY = { left: \"flex-start\", center: \"center\", right: \"flex-end\" } as const;\nconst ALIGN = { top: \"flex-start\", middle: \"center\", bottom: \"flex-end\" } as const;\n\nfunction pageHtml(\n sheet: PrintSheet,\n page: { rows: number[]; cols: number[] },\n scale: number,\n colWidths: number[],\n g: PrintGeometry,\n setup: SheetPageSetup,\n numbering: { sheet: string; at: number; of: number },\n): string {\n const widths = page.cols.map((c) => colWidths[c] ?? 0);\n const tableW = widths.reduce((a, b) => a + b, 0);\n const tableH = page.rows.length * PRINT_ROW_HEIGHT;\n const border = setup.gridlines ? \"1px solid #b7b7b7\" : \"none\";\n const body = page.rows\n .map(\n (r) =>\n `<tr style=\"height:${PRINT_ROW_HEIGHT}px\">${page.cols\n .map((c) => `<td style=\"border:${border}\">${esc(sheet.rows[r]?.[c] ?? \"\")}</td>`)\n .join(\"\")}</tr>`,\n )\n .join(\"\");\n const cols = widths.map((w) => `<col style=\"width:${w}px\">`).join(\"\");\n return `<section data-print-page data-sheet=\"${esc(numbering.sheet)}\" data-page-number=\"${numbering.at}\" data-page-count=\"${numbering.of}\" data-page-rows=\"${page.rows.length}\" data-page-cols=\"${page.cols.length}\" style=\"width:${g.paperWidth}px;height:${g.paperHeight}px;box-sizing:border-box;padding:${g.marginTop}px ${g.marginRight}px ${g.marginBottom}px ${g.marginLeft}px;background:#fff;overflow:hidden;break-after:page;page-break-after:always\">\n<div style=\"width:${g.areaWidth}px;height:${g.areaHeight}px;display:flex;justify-content:${JUSTIFY[setup.alignH]};align-items:${ALIGN[setup.alignV]};overflow:hidden\">\n<div data-print-content style=\"width:${tableW * scale}px;height:${tableH * scale}px;flex:none;overflow:hidden\">\n<table style=\"width:${tableW}px;table-layout:fixed;border-collapse:collapse;transform:scale(${scale});transform-origin:0 0;font:12px/${PRINT_ROW_HEIGHT - 2}px system-ui,sans-serif;color:#111\"><colgroup>${cols}</colgroup><tbody>${body}</tbody></table>\n</div></div></section>`;\n}\n\nexport interface PrintDocument {\n /** Every page, in print order. */\n pagesHtml: string[];\n pageWidth: number;\n pageHeight: number;\n /** `@page` size in inches, for the browser's print engine. */\n pageSizeInches: { width: number; height: number };\n}\n\n/** All the printed pages of the chosen sheets under the setup (empty when there is nothing to print). */\nexport function buildSheetPrintDocument(sheets: readonly PrintSheet[], setup: SheetPageSetup): PrintDocument | null {\n const out: string[] = [];\n let geometry: PrintGeometry | null = null;\n for (const sheet of sheets) {\n const plan = planSheetPrint(sheet.rows, setup, { rows: sheet.frozenRows, cols: sheet.frozenCols });\n geometry = plan.geometry;\n plan.pages.forEach((page, i) => {\n out.push(pageHtml(sheet, page, plan.scale, plan.colWidths, plan.geometry, setup, { sheet: sheet.name, at: i + 1, of: plan.pages.length }));\n });\n }\n if (!geometry || out.length === 0) return null;\n return {\n pagesHtml: out,\n pageWidth: geometry.paperWidth,\n pageHeight: geometry.paperHeight,\n pageSizeInches: { width: geometry.paperWidth / PX_PER_INCH, height: geometry.paperHeight / PX_PER_INCH },\n };\n}\n\n/** The whole printable web page: `@page` set to the paper, one section per page. */\nexport function printDocumentHtml(doc: PrintDocument, title: string): string {\n const { width, height } = doc.pageSizeInches;\n return `<!doctype html><html><head><meta charset=\"utf-8\"><title>${esc(title)}</title>\n<style>@page{size:${width.toFixed(3)}in ${height.toFixed(3)}in;margin:0}html,body{margin:0;padding:0;background:#fff}td{padding:0 6px;overflow:hidden;white-space:nowrap;text-overflow:clip;vertical-align:middle}section:last-child{break-after:auto;page-break-after:auto}</style></head>\n<body data-print-paper=\"${width.toFixed(3)}x${height.toFixed(3)}in\">${doc.pagesHtml.join(\"\\n\")}</body></html>`;\n}\n","/**\n * Outputs of a workbook: CSV/TSV/HTML downloads of the current sheet, and Print / PDF of what its page setup asks for.\n * Both read the same string grid the rest of the workbook code reads\n * (`univerSnapshotToRows`) — one source of what \"the sheet\" contains.\n */\n\nimport { downloadFile } from \"@ai-matrx/kit/download\";\nimport { toDelimitedText } from \"@ai-matrx/alchemy/operate/read\";\nimport { PX_PER_INCH } from \"../core\";\nimport type { SheetPageSetup } from \"./sheet-page-setup\";\nimport { buildSheetPrintDocument, collectPrintSheets, printDocumentHtml } from \"./sheet-print-pages\";\nimport { univerSnapshotToRows, type CellRange } from \"./univer-snapshot-rows\";\n\nexport function sheetGridToCsv(rows: readonly (readonly string[])[]): string {\n const [header, ...body] = rows;\n if (!header) return \"\";\n return toDelimitedText(header, body, { spreadsheetSafe: false });\n}\n\nexport function downloadSheetAsCsv(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const name = `${options.filename.replace(/\\.csv$/i, \"\")}.csv`;\n // BOM so Excel reads UTF-8.\n const blob = new Blob([\"\", sheetGridToCsv(grid.rows)], { type: \"text/csv;charset=utf-8\" });\n downloadFile(name, blob, blob.type);\n return true;\n}\n\n/** Tab-separated values of the current sheet (Google's .tsv download). */\nexport function downloadSheetAsTsv(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const [header, ...body] = grid.rows;\n const text = toDelimitedText(header!, body, { format: \"tsv\", spreadsheetSafe: false });\n const blob = new Blob([\"\\uFEFF\", text], { type: \"text/tab-separated-values;charset=utf-8\" });\n downloadFile(`${options.filename.replace(/\\.tsv$/i, \"\")}.tsv`, blob, blob.type);\n return true;\n}\n\n/** The current sheet as a standalone web page (Google's .html download). */\nexport function downloadSheetAsHtml(\n snapshot: unknown,\n options: { sheetId?: string; filename: string },\n): boolean {\n const grid = univerSnapshotToRows(snapshot, { skipHidden: true, ...(options.sheetId ? { sheetId: options.sheetId } : {}) });\n if (!grid || grid.rows.length === 0) return false;\n const body = grid.rows.map((r) => `<tr>${r.map((c) => `<td>${esc(c)}</td>`).join(\"\")}</tr>`).join(\"\\n\");\n const html = `<!doctype html><html><head><meta charset=\"utf-8\"><title>${esc(options.filename)} — ${esc(grid.sheetName)}</title>\n<style>body{font:13px system-ui,sans-serif;margin:16px}table{border-collapse:collapse}td{border:1px solid #c0c0c0;padding:2px 6px;vertical-align:top}</style></head>\n<body><table>\n${body}\n</table></body></html>`;\n const blob = new Blob([html], { type: \"text/html;charset=utf-8\" });\n downloadFile(`${options.filename.replace(/\\.html?$/i, \"\")}.html`, blob, blob.type);\n return true;\n}\n\nfunction esc(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\n/** What a print or PDF needs besides the snapshot: the workbook's page setup and the live selection. */\nexport interface SheetPrintOptions {\n sheetId?: string;\n title: string;\n setup: SheetPageSetup;\n /** The cells selected right now (used when the setup prints \"selected cells\"). */\n selection?: CellRange | null;\n}\n\nfunction printDocumentFor(snapshot: unknown, options: SheetPrintOptions) {\n const sheets = collectPrintSheets(snapshot, options.setup, {\n ...(options.sheetId ? { sheetId: options.sheetId } : {}),\n selection: options.selection ?? null,\n });\n return buildSheetPrintDocument(sheets, options.setup);\n}\n\n/** Opens the browser print sheet for what the workbook's page setup asks to print (choose \"Save as PDF\" there). */\nexport function printSheet(snapshot: unknown, options: SheetPrintOptions): boolean {\n const doc = printDocumentFor(snapshot, options);\n if (!doc) return false;\n const html = printDocumentHtml(doc, options.title);\n const frame = document.createElement(\"iframe\");\n frame.style.cssText = \"position:fixed;right:0;bottom:0;width:0;height:0;border:0\";\n document.body.appendChild(frame);\n const fdoc = frame.contentDocument;\n const win = frame.contentWindow;\n if (!fdoc || !win) {\n frame.remove();\n return false;\n }\n fdoc.open();\n fdoc.write(html);\n fdoc.close();\n win.addEventListener(\"afterprint\", () => frame.remove());\n win.focus();\n win.print();\n return true;\n}\n\n/** The sheet's grid as a markdown table (first row is the header row). */\nexport function sheetGridToMarkdownTable(rows: readonly (readonly string[])[]): string {\n if (rows.length === 0) return \"\";\n const width = Math.max(...rows.map((r) => r.length));\n const cell = (v: string | undefined) => (v ?? \"\").replace(/\\|/g, \"\\\\|\").replace(/\\r?\\n/g, \" \");\n const line = (r: readonly string[]) =>\n `| ${Array.from({ length: width }, (_, i) => cell(r[i])).join(\" | \")} |`;\n const [head, ...rest] = rows;\n return [line(head!), `| ${Array.from({ length: width }, () => \"---\").join(\" | \")} |`, ...rest.map(line)].join(\"\\n\");\n}\n\n/**\n * Real PDF download of what the workbook's page setup prints: the same pages Print draws, each one\n * captured and laid on a PDF page of the chosen paper size and orientation. Returns false when empty.\n */\nexport async function downloadSheetAsPdf(snapshot: unknown, options: SheetPrintOptions): Promise<boolean> {\n const doc = printDocumentFor(snapshot, options);\n if (!doc) return false;\n const [{ renderElement, pagesToPdf }, { downloadFile: save }] = await Promise.all([\n import(\"@ai-matrx/alchemy/operate/capture\"),\n import(\"@ai-matrx/kit/download\"),\n ]);\n const host = document.createElement(\"div\");\n host.setAttribute(\"aria-hidden\", \"true\");\n host.style.cssText = \"position:fixed;left:-20000px;top:0\";\n host.innerHTML = `<style>td{padding:0 6px;overflow:hidden;white-space:nowrap;vertical-align:middle}</style>${doc.pagesHtml.join(\"\")}`;\n document.body.appendChild(host);\n try {\n const pages = [];\n for (const el of Array.from(host.querySelectorAll<HTMLElement>(\"[data-print-page]\"))) {\n const image = await renderElement(el, { pixelRatio: 2, backgroundColor: \"#ffffff\", cacheBust: true });\n pages.push({ image, imageType: \"JPEG\" as const, quality: 0.92, placement: \"fill\" as const });\n }\n const mm = (px: number) => Math.round(((px / PX_PER_INCH) * 25.4) * 100) / 100;\n const pdf = await pagesToPdf(pages, {\n orientation: doc.pageWidth > doc.pageHeight ? \"landscape\" : \"portrait\",\n unit: \"mm\",\n format: [mm(Math.min(doc.pageWidth, doc.pageHeight)), mm(Math.max(doc.pageWidth, doc.pageHeight))],\n });\n save(`${options.title.replace(/[\\\\/:*?\"<>|]+/g, \" \").trim() || \"workbook\"}.pdf`, pdf, \"application/pdf\");\n } finally {\n host.remove();\n }\n return true;\n}\n","// features/workbooks/workbook-scope-source.ts\n//\n// Live bridge from the mounted `WorkbookEditor` to the `matrx-user/workbooks`\n// surface emitter on `/workbooks/[id]`.\n//\n// Why a module slot rather than props: the page owns the workbook row and\n// mounts `<SurfaceRuntimeProvider>`, but the sheets / snapshot / save status\n// live inside the editor (Univer refs + local state), one level DOWN. Pushing\n// them up as state would re-render the editor on every keystroke; a\n// registered getter is read once, at Run time, when the user actually\n// launches an agent.\n//\n// Exactly one editor is mounted at a time (one workbook per route), so a\n// single slot keyed by workbookId is enough. The getter returns null when the\n// editor has not booted — callers omit the values, they never fake them.\n\nexport interface WorkbookLiveScope {\n sheets: Array<{ id: string; name: string; index: number }>;\n activeSheetId: string | null;\n activeSheetName: string | null;\n snapshot: Record<string, unknown> | null;\n bootState: \"booting\" | \"ready\" | \"load_error\";\n loadError: string | null;\n saveStatus: string;\n collab: {\n enabled: boolean;\n is_host: boolean;\n self_uid: string;\n remote_peers: number;\n };\n}\n\ninterface Registration {\n workbookId: string;\n read: () => WorkbookLiveScope | null;\n}\n\nlet current: Registration | null = null;\n\n/** Called by `WorkbookEditor` while mounted. Returns an unregister. */\nexport function registerWorkbookScopeSource(\n registration: Registration,\n): () => void {\n current = registration;\n return () => {\n if (current === registration) current = null;\n };\n}\n\n/**\n * Read the live editor state for `workbookId`. Returns null when no editor is\n * mounted, when a different workbook is mounted, or when Univer has not\n * booted yet — never a fabricated shape.\n */\nexport function readWorkbookScopeSource(\n workbookId: string,\n): WorkbookLiveScope | null {\n if (!current || current.workbookId !== workbookId) return null;\n return current.read();\n}\n"],"mappings":"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","names":["fs","current","one","esc","esc"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-matrx/office",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.7",
|
|
4
4
|
"description": "The AI Matrx Office layer: the editors' shared command and menu model, the Google and Microsoft ribbon model, page setup, the Office record types and the configured product hosts. The Univer glue shared by Sheets and Docs. Sheets, Docs and the other products arrive as sections of this one package.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/core.cjs",
|
|
@@ -176,11 +176,11 @@
|
|
|
176
176
|
"@ai-matrx/alchemy": "latest",
|
|
177
177
|
"@ai-matrx/auth": "latest",
|
|
178
178
|
"@ai-matrx/content-ir": "latest",
|
|
179
|
-
"@ai-matrx/kit": "latest",
|
|
180
|
-
"@ai-matrx/data": "latest",
|
|
181
179
|
"@ai-matrx/api": "latest",
|
|
182
|
-
"@ai-matrx/
|
|
180
|
+
"@ai-matrx/data": "latest",
|
|
181
|
+
"@ai-matrx/kit": "latest",
|
|
183
182
|
"@ai-matrx/print": "latest",
|
|
183
|
+
"@ai-matrx/records": "latest",
|
|
184
184
|
"@ai-matrx/rich-content": "latest"
|
|
185
185
|
},
|
|
186
186
|
"peerDependencies": {
|
|
@@ -235,5 +235,5 @@
|
|
|
235
235
|
"test:watch": "vitest",
|
|
236
236
|
"verify:tarball": "node ./scripts/verify-tarball.mjs"
|
|
237
237
|
},
|
|
238
|
-
"gitHead": "
|
|
238
|
+
"gitHead": "039374c6942dab05294f24635ae651f0e94bb0bb"
|
|
239
239
|
}
|