@ai-matrx/office 0.3.1 → 0.5.2
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 +47 -2
- package/dist/chunk-2UBGQUXW.cjs +37 -0
- package/dist/chunk-2UBGQUXW.cjs.map +1 -0
- package/dist/chunk-5T2M6LSI.js +529 -0
- package/dist/chunk-5T2M6LSI.js.map +1 -0
- package/dist/chunk-BWMAYLW4.cjs +272 -0
- package/dist/chunk-BWMAYLW4.cjs.map +1 -0
- package/dist/chunk-IDEA5UXK.js +272 -0
- package/dist/chunk-IDEA5UXK.js.map +1 -0
- package/dist/chunk-MPKXXZZV.js +37 -0
- package/dist/chunk-MPKXXZZV.js.map +1 -0
- package/dist/chunk-O6FTSXHE.cjs +463 -0
- package/dist/chunk-O6FTSXHE.cjs.map +1 -0
- package/dist/chunk-PI473GES.js +463 -0
- package/dist/chunk-PI473GES.js.map +1 -0
- package/dist/chunk-QZE7HBZB.cjs +529 -0
- package/dist/chunk-QZE7HBZB.cjs.map +1 -0
- package/dist/chunk-WKBWRG7N.js +209 -0
- package/dist/chunk-WKBWRG7N.js.map +1 -0
- package/dist/chunk-ZDZCCOUB.cjs +209 -0
- package/dist/chunk-ZDZCCOUB.cjs.map +1 -0
- package/dist/core.d.cts +5 -1
- package/dist/core.d.ts +5 -1
- package/dist/docs-io.cjs +496 -0
- package/dist/docs-io.cjs.map +1 -0
- package/dist/docs-io.d.cts +147 -0
- package/dist/docs-io.d.ts +147 -0
- package/dist/docs-io.js +496 -0
- package/dist/docs-io.js.map +1 -0
- package/dist/docs-tools.cjs +217 -0
- package/dist/docs-tools.cjs.map +1 -0
- package/dist/docs-tools.d.cts +150 -0
- package/dist/docs-tools.d.ts +150 -0
- package/dist/docs-tools.js +217 -0
- package/dist/docs-tools.js.map +1 -0
- package/dist/docs.cjs +657 -0
- package/dist/docs.cjs.map +1 -0
- package/dist/docs.d.cts +582 -0
- package/dist/docs.d.ts +582 -0
- package/dist/docs.js +657 -0
- package/dist/docs.js.map +1 -0
- package/dist/matrxImagePorts-JDFYE4QI.cjs +59 -0
- package/dist/matrxImagePorts-JDFYE4QI.cjs.map +1 -0
- package/dist/matrxImagePorts-VPBBUADM.js +59 -0
- package/dist/matrxImagePorts-VPBBUADM.js.map +1 -0
- package/dist/sheets-xlsx.cjs +525 -0
- package/dist/sheets-xlsx.cjs.map +1 -0
- package/dist/sheets-xlsx.d.cts +153 -0
- package/dist/sheets-xlsx.d.ts +153 -0
- package/dist/sheets-xlsx.js +525 -0
- package/dist/sheets-xlsx.js.map +1 -0
- package/dist/sheets.cjs +921 -0
- package/dist/sheets.cjs.map +1 -0
- package/dist/sheets.d.cts +605 -0
- package/dist/sheets.d.ts +605 -0
- package/dist/sheets.js +921 -0
- package/dist/sheets.js.map +1 -0
- package/dist/univer-collab.cjs +4 -77
- package/dist/univer-collab.cjs.map +1 -1
- package/dist/univer-collab.d.cts +8 -15
- package/dist/univer-collab.d.ts +8 -15
- package/dist/univer-collab.js +4 -77
- package/dist/univer-collab.js.map +1 -1
- package/dist/univer-realtime.cjs +102 -0
- package/dist/univer-realtime.cjs.map +1 -0
- package/dist/univer-realtime.d.cts +15 -0
- package/dist/univer-realtime.d.ts +15 -0
- package/dist/univer-realtime.js +80 -0
- package/dist/univer-realtime.js.map +1 -0
- package/dist/xlsx-to-univer-AQAXU3TC.cjs +7 -0
- package/dist/xlsx-to-univer-AQAXU3TC.cjs.map +1 -0
- package/dist/xlsx-to-univer-OPMMBWEW.js +7 -0
- package/dist/xlsx-to-univer-OPMMBWEW.js.map +1 -0
- package/package.json +75 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,54 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.2
|
|
4
|
+
|
|
5
|
+
No API change. The docs file-import test runs under jsdom (`jsdom` is now a dev dependency, so the isolated publish run can start its worker).
|
|
6
|
+
|
|
7
|
+
## 0.5.1
|
|
8
|
+
|
|
9
|
+
Fix: two-person Docs co-editing. Each seat mounts its own Univer unit, and a mutation carries the SENDER's unit id; replayed unchanged, the receiver threw "DocumentDataModel not found for unitId" and typed text never arrived in either direction.
|
|
10
|
+
|
|
11
|
+
- `DocumentModel` re-addresses every replay (peer edits and same-browser views) to the receiving view's own unit. `DocumentViewPort` gains optional `unitId()` (falls back to the id of `snapshot()`).
|
|
12
|
+
- A failed apply is never only a console line: `DocumentModelDeps.onApplyFailed(documentId, mutationId, error)` lets the app say so, and the model re-syncs the views from the saved version (unless this tab has unsaved edits).
|
|
13
|
+
- `WorkbookCollabSession` gets the same: optional `unitId()` re-addresses a peer's mutation, and `onApplyFailed(mutationId, error)` reports a refused apply.
|
|
14
|
+
|
|
15
|
+
## 0.5.0
|
|
16
|
+
|
|
17
|
+
W1-G4. The Docs model, service and io move in from matrx-frontend `features/documents`.
|
|
18
|
+
|
|
19
|
+
- New `./docs` entry (pure, SSR-import-safe): the document service (`createDocument`, `getLatestDocumentSnapshot`, `saveDocumentSnapshot`, `copyDocument`, ...), the open-document model (`DocumentModel`, load / one save / realtime / conflict), the `document_body` write contract (`documentBodyWriteHandler`, `planBodyEdit`; the handler type is structural, the package imports no chat), the snapshot sanitizer, symbol sets, `fitZoomRatio` and the documents hub display helpers.
|
|
20
|
+
- New `./docs/io` entry (heavy; load on demand): `markdownToUniverDoc`, `univerDocToMarkdown`, the file import `importDocumentFile` (.docx / .md / .txt / .html) and the open-format downloads (`exportOpenFormat`, `downloadOpenFormat`: EPUB, ODT, RTF).
|
|
21
|
+
- New `./docs/tools` entry: the pure insert plans (building blocks, table of contents, bookmarks) and the Univer edit operations that apply them.
|
|
22
|
+
- New host port `configureDocsHost({ getSupabase, requestRaw })`. An unconfigured port throws naming itself.
|
|
23
|
+
- Depends on `@ai-matrx/{content-ir,rich-content}` (markdown engine) and `@univerjs/docs` (dynamic import in the edit operations).
|
|
24
|
+
|
|
25
|
+
### Consumer action
|
|
26
|
+
|
|
27
|
+
Call `configureDocsHost(...)` once at start-up, in a client module. Replace `@/features/documents/{document-service,document-model/documentModel,doc-symbols,document-body-text,agent-context/documentWriteValidation,utils/*}` imports with `@ai-matrx/office/docs`; `markdown-to-univer-doc`, `univer-doc-to-markdown`, `import-document-file`, `export-open-formats` with `@ai-matrx/office/docs/io`; `doc-tools-core`, `doc-edit-ops` with `@ai-matrx/office/docs/tools`.
|
|
28
|
+
|
|
3
29
|
## 0.3.1
|
|
4
30
|
|
|
5
|
-
|
|
6
|
-
|
|
31
|
+
SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
|
|
32
|
+
so they may include breaking API changes. Consumer action is UNKNOWN: read the diff before upgrading.
|
|
33
|
+
Diff: `git diff ed06946f4d 696913bd94 -- apps/shared/office/src`
|
|
34
|
+
|
|
35
|
+
Changed shipped source files (1):
|
|
36
|
+
- `apps/shared/office/src/univer/collab/WorkbookCollabSession.ts`
|
|
37
|
+
|
|
38
|
+
## 0.4.0
|
|
39
|
+
|
|
40
|
+
W1-G2b. The Sheets model and io move in from matrx-frontend `features/workbooks`.
|
|
41
|
+
|
|
42
|
+
- New `./sheets` entry (pure, SSR-import-safe): the workbook service (`createWorkbook`, `getLatestSnapshot`, `saveSnapshot`, `listSnapshots`, `copyWorkbook`, ...), `univerSnapshotToRows`, `snapshotToGridSheets`, the snapshot miniature (`snapshotPreviewSvg`, `workbookPreviewSvg`, `documentPreviewSvg`, `formatCellValue`; moved from `features/templates/files/thumbnail`), sheet page setup (`sheet-page-setup`, its service) and print pages, the sheet output (CSV, print, PDF) and `registerWorkbookScopeSource` / `readWorkbookScopeSource`.
|
|
43
|
+
- New `./sheets/xlsx` entry (heavy; load on demand): `buildXlsxFromUniver`, `xlsxToUniverWorkbook`, the xlsx resource helpers, and the one file-import path `importWorkbookFile` / `unsupportedFileReason`.
|
|
44
|
+
- New host port `configureSheetsHost({ getSupabase, ensureOrgId, uploadOriginalFile })`. An unconfigured port throws naming itself.
|
|
45
|
+
- `./univer/collab` is now the collab session only (the Yjs import). `useWorkbookRealtime` moved to its own entry, `./univer/realtime`, so a static import of the hook never loads Yjs into the editor chunk (module graph of the hook: 67 modules -> 25; no `yjs` / `y-protocols`).
|
|
46
|
+
- `/core` adds `WorkbookSnapshotOrigin` and `DocumentSnapshotOrigin`.
|
|
47
|
+
- Depends on `@ai-matrx/{api,auth,alchemy,print,records}`; `@supabase/supabase-js` is a type-only peer.
|
|
48
|
+
|
|
49
|
+
### Consumer action
|
|
50
|
+
|
|
51
|
+
Call `configureSheetsHost(...)` once at start-up. Replace `@/features/workbooks/{workbook-service,univer-snapshot-rows,snapshot-grid,sheet-*,workbook-scope-source}` imports with `@ai-matrx/office/sheets`, and `xlsx-shared`, `univer-to-xlsx`, `xlsx-to-univer`, `import-workbook-file` with `@ai-matrx/office/sheets/xlsx`. Import `useWorkbookRealtime` from `@ai-matrx/office/univer/realtime` (not `univer/collab`).
|
|
7
52
|
|
|
8
53
|
## 0.3.0
|
|
9
54
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/core/document-page-style.ts
|
|
2
|
+
var TRADITIONAL = 1;
|
|
3
|
+
var PORTRAIT = 0;
|
|
4
|
+
var PX_PER_INCH = 96;
|
|
5
|
+
var DEFAULT_DOCUMENT_PAGE_STYLE = {
|
|
6
|
+
pageSize: { width: 816, height: 1056 },
|
|
7
|
+
documentFlavor: TRADITIONAL,
|
|
8
|
+
pageOrient: PORTRAIT,
|
|
9
|
+
marginTop: PX_PER_INCH,
|
|
10
|
+
marginBottom: PX_PER_INCH,
|
|
11
|
+
marginLeft: PX_PER_INCH,
|
|
12
|
+
marginRight: PX_PER_INCH,
|
|
13
|
+
// Univer applies no paragraph spacing to a paginated page by itself; without this every paragraph
|
|
14
|
+
// runs into the next (Google Docs' own default: 1.15 lines, 10px after).
|
|
15
|
+
defaultParagraphStyle: { spaceAbove: { v: 0 }, spaceBelow: { v: 10 }, lineSpacing: 1.15 }
|
|
16
|
+
};
|
|
17
|
+
function defaultDocumentPageStyle() {
|
|
18
|
+
return {
|
|
19
|
+
...DEFAULT_DOCUMENT_PAGE_STYLE,
|
|
20
|
+
pageSize: { ...DEFAULT_DOCUMENT_PAGE_STYLE.pageSize },
|
|
21
|
+
defaultParagraphStyle: { ...DEFAULT_DOCUMENT_PAGE_STYLE.defaultParagraphStyle }
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function isLegacySqueezedPageStyle(style) {
|
|
25
|
+
const size = _optionalChain([style, 'optionalAccess', _ => _.pageSize]);
|
|
26
|
+
return !!size && size.width === 595 && size.height === 842 && _optionalChain([style, 'optionalAccess', _2 => _2.marginLeft]) === 90 && _optionalChain([style, 'optionalAccess', _3 => _3.marginRight]) === 90 && _optionalChain([style, 'optionalAccess', _4 => _4.marginTop]) === 72 && _optionalChain([style, 'optionalAccess', _5 => _5.marginBottom]) === 72;
|
|
27
|
+
}
|
|
28
|
+
var PAGE_COLORS = ["#ffffff", "#fff8e7", "#f3f3f3", "#e8f0fe", "#e6f4ea", "#fef7e0"];
|
|
29
|
+
var DEFAULT_PAGE_COLOR = PAGE_COLORS[0];
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
exports.PX_PER_INCH = PX_PER_INCH; exports.DEFAULT_DOCUMENT_PAGE_STYLE = DEFAULT_DOCUMENT_PAGE_STYLE; exports.defaultDocumentPageStyle = defaultDocumentPageStyle; exports.isLegacySqueezedPageStyle = isLegacySqueezedPageStyle;
|
|
37
|
+
//# sourceMappingURL=chunk-2UBGQUXW.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/aidream/aidream/apps/shared/office/dist/chunk-2UBGQUXW.cjs","../src/core/document-page-style.ts"],"names":[],"mappings":"AAAA;ACiBA,IAAM,YAAA,EAAc,CAAA;AAEpB,IAAM,SAAA,EAAW,CAAA;AAMV,IAAM,YAAA,EAAc,EAAA;AAgBpB,IAAM,4BAAA,EAA6C;AAAA,EACxD,QAAA,EAAU,EAAE,KAAA,EAAO,GAAA,EAAK,MAAA,EAAQ,KAAK,CAAA;AAAA,EACrC,cAAA,EAAgB,WAAA;AAAA,EAChB,UAAA,EAAY,QAAA;AAAA,EACZ,SAAA,EAAW,WAAA;AAAA,EACX,YAAA,EAAc,WAAA;AAAA,EACd,UAAA,EAAY,WAAA;AAAA,EACZ,WAAA,EAAa,WAAA;AAAA;AAAA;AAAA,EAGb,qBAAA,EAAuB,EAAE,UAAA,EAAY,EAAE,CAAA,EAAG,EAAE,CAAA,EAAG,UAAA,EAAY,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,WAAA,EAAa,KAAK;AAC1F,CAAA;AAGO,SAAS,wBAAA,CAAA,EAA0C;AACxD,EAAA,OAAO;AAAA,IACL,GAAG,2BAAA;AAAA,IACH,QAAA,EAAU,EAAE,GAAG,2BAAA,CAA4B,SAAU,CAAA;AAAA,IACrD,qBAAA,EAAuB,EAAE,GAAG,2BAAA,CAA4B,sBAAuB;AAAA,EACjF,CAAA;AACF;AAOO,SAAS,yBAAA,CAA0B,KAAA,EAA2C;AACnF,EAAA,MAAM,KAAA,kBAAO,KAAA,2BAAO,UAAA;AACpB,EAAA,OACE,CAAC,CAAC,KAAA,GACF,IAAA,CAAK,MAAA,IAAU,IAAA,GACf,IAAA,CAAK,OAAA,IAAW,IAAA,mBAChB,KAAA,6BAAO,aAAA,IAAe,GAAA,mBACtB,KAAA,6BAAO,cAAA,IAAgB,GAAA,mBACvB,KAAA,6BAAO,YAAA,IAAc,GAAA,mBACrB,KAAA,6BAAO,eAAA,IAAiB,EAAA;AAE5B;AAeO,IAAM,YAAA,EAAc,CAAC,SAAA,EAAW,SAAA,EAAW,SAAA,EAAW,SAAA,EAAW,SAAA,EAAW,SAAS,CAAA;AACrF,IAAM,mBAAA,EAAqB,WAAA,CAAY,CAAC,CAAA;ADlE/C;AACA;AACE;AACA;AACA;AACA;AACF,iOAAC","file":"/home/runner/work/aidream/aidream/apps/shared/office/dist/chunk-2UBGQUXW.cjs","sourcesContent":[null,"/**\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"]}
|
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
// src/sheets/xlsx-to-univer.ts
|
|
2
|
+
import { readWorkbook } from "@ai-matrx/alchemy/operate/read";
|
|
3
|
+
import { writeWorkbookBytes } from "@ai-matrx/alchemy/operate/formats/xlsx";
|
|
4
|
+
|
|
5
|
+
// src/sheets/xlsx-to-univer-excel.ts
|
|
6
|
+
import { loadExcelJs } from "@ai-matrx/print/xlsx-styled";
|
|
7
|
+
|
|
8
|
+
// src/sheets/xlsx-shared.ts
|
|
9
|
+
var RESOURCE = {
|
|
10
|
+
validation: "SHEET_DATA_VALIDATION_PLUGIN",
|
|
11
|
+
conditional: "SHEET_CONDITIONAL_FORMATTING_PLUGIN",
|
|
12
|
+
filter: "SHEET_FILTER_PLUGIN",
|
|
13
|
+
note: "SHEET_NOTE_PLUGIN",
|
|
14
|
+
comments: "SHEET_UNIVER_THREAD_COMMENT_PLUGIN",
|
|
15
|
+
drawing: "SHEET_DRAWING_PLUGIN",
|
|
16
|
+
table: "SHEET_TABLE_PLUGIN"
|
|
17
|
+
};
|
|
18
|
+
function readResource(resources, name) {
|
|
19
|
+
const raw = resources?.find((r) => r.name === name)?.data;
|
|
20
|
+
if (!raw) return void 0;
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(raw);
|
|
23
|
+
} catch {
|
|
24
|
+
return void 0;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function writeResource(resources, name, value) {
|
|
28
|
+
const i = resources.findIndex((r) => r.name === name);
|
|
29
|
+
const entry = { name, data: JSON.stringify(value) };
|
|
30
|
+
if (i >= 0) resources[i] = entry;
|
|
31
|
+
else resources.push(entry);
|
|
32
|
+
}
|
|
33
|
+
var colPxToChars = (px) => Math.max(0, Math.round(px / 7 * 100) / 100);
|
|
34
|
+
var colCharsToPx = (chars) => Math.round(chars * 7);
|
|
35
|
+
var rowPxToPt = (px) => Math.round(px * 0.75 * 100) / 100;
|
|
36
|
+
var rowPtToPx = (pt) => Math.round(pt / 0.75 * 100) / 100;
|
|
37
|
+
function colorToArgb(input) {
|
|
38
|
+
if (!input) return void 0;
|
|
39
|
+
const s = input.trim();
|
|
40
|
+
const hex = /^#?([0-9a-f]{6})$/i.exec(s);
|
|
41
|
+
if (hex) return `FF${hex[1].toUpperCase()}`;
|
|
42
|
+
const short = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(s);
|
|
43
|
+
if (short) return `FF${short[1]}${short[1]}${short[2]}${short[2]}${short[3]}${short[3]}`.toUpperCase();
|
|
44
|
+
const rgb = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i.exec(s);
|
|
45
|
+
if (rgb) {
|
|
46
|
+
const h = (n) => Number(n).toString(16).padStart(2, "0");
|
|
47
|
+
return `FF${h(rgb[1])}${h(rgb[2])}${h(rgb[3])}`.toUpperCase();
|
|
48
|
+
}
|
|
49
|
+
return void 0;
|
|
50
|
+
}
|
|
51
|
+
function argbToColor(argb) {
|
|
52
|
+
if (!argb) return void 0;
|
|
53
|
+
const v = argb.replace(/^#/, "");
|
|
54
|
+
if (v.length === 8) return `#${v.slice(2).toLowerCase()}`;
|
|
55
|
+
if (v.length === 6) return `#${v.toLowerCase()}`;
|
|
56
|
+
return void 0;
|
|
57
|
+
}
|
|
58
|
+
var BORDER_OUT = {
|
|
59
|
+
1: "thin",
|
|
60
|
+
2: "hair",
|
|
61
|
+
3: "dotted",
|
|
62
|
+
4: "dashed",
|
|
63
|
+
5: "dashDot",
|
|
64
|
+
6: "dashDotDot",
|
|
65
|
+
7: "double",
|
|
66
|
+
8: "medium",
|
|
67
|
+
9: "mediumDashed",
|
|
68
|
+
10: "mediumDashDot",
|
|
69
|
+
11: "mediumDashDotDot",
|
|
70
|
+
12: "slantDashDot",
|
|
71
|
+
13: "thick"
|
|
72
|
+
};
|
|
73
|
+
var borderToExcel = (n) => n === void 0 ? void 0 : BORDER_OUT[n];
|
|
74
|
+
var borderFromExcel = (name) => {
|
|
75
|
+
if (!name) return void 0;
|
|
76
|
+
const hit = Object.entries(BORDER_OUT).find(([, v]) => v === name);
|
|
77
|
+
return hit ? Number(hit[0]) : void 0;
|
|
78
|
+
};
|
|
79
|
+
var H_ALIGN_OUT = { 1: "left", 2: "center", 3: "right", 4: "justify", 5: "justify", 6: "distributed" };
|
|
80
|
+
var V_ALIGN_OUT = { 1: "top", 2: "middle", 3: "bottom" };
|
|
81
|
+
var H_ALIGN_IN = { left: 1, center: 2, right: 3, justify: 4, fill: 1, centerContinuous: 2, distributed: 6 };
|
|
82
|
+
var V_ALIGN_IN = { top: 1, middle: 2, bottom: 3, distributed: 2, justify: 2 };
|
|
83
|
+
function a1(row, col) {
|
|
84
|
+
let n = col + 1;
|
|
85
|
+
let letters = "";
|
|
86
|
+
while (n > 0) {
|
|
87
|
+
const m = (n - 1) % 26;
|
|
88
|
+
letters = String.fromCharCode(65 + m) + letters;
|
|
89
|
+
n = Math.floor((n - 1) / 26);
|
|
90
|
+
}
|
|
91
|
+
return `${letters}${row + 1}`;
|
|
92
|
+
}
|
|
93
|
+
var rangeToA1 = (r) => r.startRow === r.endRow && r.startColumn === r.endColumn ? a1(r.startRow, r.startColumn) : `${a1(r.startRow, r.startColumn)}:${a1(r.endRow, r.endColumn)}`;
|
|
94
|
+
function parseA1Range(ref) {
|
|
95
|
+
const m = /^\$?([A-Z]+)\$?(\d+)(?::\$?([A-Z]+)\$?(\d+))?$/i.exec(ref.trim());
|
|
96
|
+
if (!m) return null;
|
|
97
|
+
const col = (s) => [...s.toUpperCase()].reduce((acc, ch) => acc * 26 + ch.charCodeAt(0) - 64, 0) - 1;
|
|
98
|
+
const sc = col(m[1]);
|
|
99
|
+
const sr = Number(m[2]) - 1;
|
|
100
|
+
return { startRow: sr, startColumn: sc, endRow: m[4] ? Number(m[4]) - 1 : sr, endColumn: m[3] ? col(m[3]) : sc };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/sheets/xlsx-to-univer-excel.ts
|
|
104
|
+
var THEME = ["FFFFFF", "000000", "E7E6E6", "44546A", "4472C4", "ED7D31", "A5A5A5", "FFC000", "5B9BD5", "70AD47"];
|
|
105
|
+
var colorOf = (c) => c?.argb ? argbToColor(c.argb) : typeof c?.theme === "number" && THEME[c.theme] ? `#${THEME[c.theme].toLowerCase()}` : void 0;
|
|
106
|
+
var rid = (prefix) => `${prefix}${Math.random().toString(36).slice(2, 10)}`;
|
|
107
|
+
var sheetId = (name) => `${name.replace(/[^A-Za-z0-9_-]+/g, "-").slice(0, 32) || "sheet"}-${Math.random().toString(36).slice(2, 8)}`;
|
|
108
|
+
async function importXlsxWithExcelJs(file, options = {}) {
|
|
109
|
+
const ExcelJS = await loadExcelJs();
|
|
110
|
+
const wb = new ExcelJS.Workbook();
|
|
111
|
+
await wb.xlsx.load(await file.arrayBuffer());
|
|
112
|
+
const dropped = /* @__PURE__ */ new Set();
|
|
113
|
+
const styles = {};
|
|
114
|
+
const styleIds = /* @__PURE__ */ new Map();
|
|
115
|
+
const styleId = (st) => {
|
|
116
|
+
const key = JSON.stringify(st);
|
|
117
|
+
let id = styleIds.get(key);
|
|
118
|
+
if (!id) {
|
|
119
|
+
id = `s${styleIds.size + 1}`;
|
|
120
|
+
styleIds.set(key, id);
|
|
121
|
+
styles[id] = st;
|
|
122
|
+
}
|
|
123
|
+
return id;
|
|
124
|
+
};
|
|
125
|
+
const sheets = {};
|
|
126
|
+
const sheetOrder = [];
|
|
127
|
+
const resources = [];
|
|
128
|
+
const validation = {};
|
|
129
|
+
const conditional = {};
|
|
130
|
+
const filters = {};
|
|
131
|
+
const notes = {};
|
|
132
|
+
const drawings = {};
|
|
133
|
+
const unitId = `wb-${rid("")}`;
|
|
134
|
+
for (const ws of wb.worksheets) {
|
|
135
|
+
const id = sheetId(ws.name);
|
|
136
|
+
sheetOrder.push(id);
|
|
137
|
+
const cellData = {};
|
|
138
|
+
let maxR = 0;
|
|
139
|
+
let maxC = 0;
|
|
140
|
+
const sheetNotes = {};
|
|
141
|
+
ws.eachRow({ includeEmpty: false }, (row, rowNumber) => {
|
|
142
|
+
row.eachCell({ includeEmpty: false }, (cell, colNumber) => {
|
|
143
|
+
const r = rowNumber - 1;
|
|
144
|
+
const c = colNumber - 1;
|
|
145
|
+
const out = toCell(cell, styleId);
|
|
146
|
+
if (out) {
|
|
147
|
+
(cellData[r] ??= {})[c] = out;
|
|
148
|
+
maxR = Math.max(maxR, r);
|
|
149
|
+
maxC = Math.max(maxC, c);
|
|
150
|
+
}
|
|
151
|
+
const note = cell.note;
|
|
152
|
+
const text = typeof note === "string" ? note : note?.texts?.map((t) => t.text).join("");
|
|
153
|
+
if (text) {
|
|
154
|
+
(sheetNotes[r] ??= {})[c] = { id: rid("n"), row: r, col: c, width: 160, height: 72, note: text, show: false };
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
if (Object.keys(sheetNotes).length) notes[id] = sheetNotes;
|
|
159
|
+
const sheet = {
|
|
160
|
+
id,
|
|
161
|
+
name: ws.name.slice(0, 31),
|
|
162
|
+
cellData,
|
|
163
|
+
rowCount: Math.max(maxR + 1, ws.rowCount, 100),
|
|
164
|
+
columnCount: Math.max(maxC + 1, ws.columnCount, 26)
|
|
165
|
+
};
|
|
166
|
+
const tab = colorOf(ws.properties?.tabColor);
|
|
167
|
+
if (tab) sheet.tabColor = tab;
|
|
168
|
+
const merges = ws.model.merges;
|
|
169
|
+
const mergeData = (merges ?? []).map((m) => parseA1Range(m)).filter((m) => !!m);
|
|
170
|
+
if (mergeData.length) {
|
|
171
|
+
sheet.mergeData = mergeData;
|
|
172
|
+
sheet.rowCount = Math.max(sheet.rowCount, ...mergeData.map((m) => m.endRow + 1));
|
|
173
|
+
sheet.columnCount = Math.max(sheet.columnCount, ...mergeData.map((m) => m.endColumn + 1));
|
|
174
|
+
}
|
|
175
|
+
const columnData = {};
|
|
176
|
+
for (let c = 1; c <= Math.min(ws.columnCount, 2e3); c++) {
|
|
177
|
+
const col = ws.getColumn(c);
|
|
178
|
+
if (typeof col.width === "number" || col.hidden) {
|
|
179
|
+
columnData[c - 1] = {
|
|
180
|
+
...typeof col.width === "number" ? { w: colCharsToPx(col.width) } : {},
|
|
181
|
+
...col.hidden ? { hd: 1 } : {}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (Object.keys(columnData).length) sheet.columnData = columnData;
|
|
186
|
+
const rowData = {};
|
|
187
|
+
ws.eachRow({ includeEmpty: true }, (row, n) => {
|
|
188
|
+
if (typeof row.height === "number" || row.hidden) {
|
|
189
|
+
rowData[n - 1] = {
|
|
190
|
+
...typeof row.height === "number" ? { h: rowPtToPx(row.height), hd: row.hidden ? 1 : 0 } : { hd: 1 }
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
if (Object.keys(rowData).length) sheet.rowData = rowData;
|
|
195
|
+
const view = ws.views?.[0];
|
|
196
|
+
if (view?.state === "frozen" && (view.xSplit || view.ySplit)) {
|
|
197
|
+
sheet.freeze = {
|
|
198
|
+
xSplit: view.xSplit ?? 0,
|
|
199
|
+
ySplit: view.ySplit ?? 0,
|
|
200
|
+
startColumn: view.xSplit ?? 0,
|
|
201
|
+
startRow: view.ySplit ?? 0
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
const dvModel = ws.dataValidations?.model;
|
|
205
|
+
const rules = dataValidationRules(dvModel ?? {});
|
|
206
|
+
if (rules.length) validation[id] = rules;
|
|
207
|
+
const cf = conditionalRules(ws.conditionalFormattings ?? [], dropped);
|
|
208
|
+
if (cf.length) conditional[id] = cf;
|
|
209
|
+
const af = ws.autoFilter;
|
|
210
|
+
if (af) {
|
|
211
|
+
const range = typeof af === "string" ? parseA1Range(af) : af.from && af.to ? {
|
|
212
|
+
startRow: af.from.row - 1,
|
|
213
|
+
startColumn: af.from.column - 1,
|
|
214
|
+
endRow: af.to.row - 1,
|
|
215
|
+
endColumn: af.to.column - 1
|
|
216
|
+
} : null;
|
|
217
|
+
if (range) filters[id] = { ref: range, filterColumns: [] };
|
|
218
|
+
}
|
|
219
|
+
const images = ws.getImages();
|
|
220
|
+
if (images.length) {
|
|
221
|
+
if (!options.uploadImage) {
|
|
222
|
+
dropped.add("Pictures in the file were not imported");
|
|
223
|
+
} else {
|
|
224
|
+
const data = {};
|
|
225
|
+
const order = [];
|
|
226
|
+
for (const img of images) {
|
|
227
|
+
try {
|
|
228
|
+
const media = wb.getImage(Number(img.imageId));
|
|
229
|
+
const bytes = new Uint8Array(media.buffer);
|
|
230
|
+
const fileId = await options.uploadImage(bytes, String(media.extension ?? "png"));
|
|
231
|
+
const tl = img.range.tl;
|
|
232
|
+
const ext = img.range.ext;
|
|
233
|
+
const br = img.range.br;
|
|
234
|
+
const width = ext?.width ?? ((br?.nativeCol ?? tl.nativeCol + 3) - tl.nativeCol) * 88;
|
|
235
|
+
const height = ext?.height ?? ((br?.nativeRow ?? tl.nativeRow + 6) - tl.nativeRow) * 24;
|
|
236
|
+
const drawingId = rid("img");
|
|
237
|
+
const column = Math.floor(tl.nativeCol ?? tl.col);
|
|
238
|
+
const rowIdx = Math.floor(tl.nativeRow ?? tl.row);
|
|
239
|
+
data[drawingId] = {
|
|
240
|
+
unitId,
|
|
241
|
+
subUnitId: id,
|
|
242
|
+
drawingId,
|
|
243
|
+
drawingType: 0,
|
|
244
|
+
imageSourceType: "URL",
|
|
245
|
+
source: `matrx-file:${fileId}`,
|
|
246
|
+
transform: { left: column * 88, top: rowIdx * 24, width, height, angle: 0 },
|
|
247
|
+
sheetTransform: {
|
|
248
|
+
from: { column, columnOffset: 0, row: rowIdx, rowOffset: 0 },
|
|
249
|
+
to: { column: column + Math.max(1, Math.round(width / 88)), columnOffset: 0, row: rowIdx + Math.max(1, Math.round(height / 24)), rowOffset: 0 }
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
order.push(drawingId);
|
|
253
|
+
} catch {
|
|
254
|
+
dropped.add("Some pictures could not be stored and were left out");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (order.length) drawings[id] = { data, order };
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if ((ws.getTables?.() ?? []).length) dropped.add("Excel tables became plain ranges (their data and styling are kept)");
|
|
261
|
+
sheets[id] = sheet;
|
|
262
|
+
}
|
|
263
|
+
if (Object.keys(validation).length) writeResource(resources, RESOURCE.validation, validation);
|
|
264
|
+
if (Object.keys(conditional).length) writeResource(resources, RESOURCE.conditional, conditional);
|
|
265
|
+
if (Object.keys(filters).length) writeResource(resources, RESOURCE.filter, filters);
|
|
266
|
+
if (Object.keys(notes).length) writeResource(resources, RESOURCE.note, notes);
|
|
267
|
+
if (Object.keys(drawings).length) writeResource(resources, RESOURCE.drawing, drawings);
|
|
268
|
+
for (const d of dropped) options.onDropped?.(d);
|
|
269
|
+
return {
|
|
270
|
+
id: unitId,
|
|
271
|
+
sheetOrder,
|
|
272
|
+
name: file.name.replace(/\.[^.]+$/, ""),
|
|
273
|
+
appVersion: "1",
|
|
274
|
+
locale: "enUS",
|
|
275
|
+
styles,
|
|
276
|
+
sheets,
|
|
277
|
+
resources
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function toStyle(cell) {
|
|
281
|
+
const st = {};
|
|
282
|
+
const f = cell.font;
|
|
283
|
+
if (f) {
|
|
284
|
+
if (f.name) st.ff = f.name;
|
|
285
|
+
if (f.size) st.fs = f.size;
|
|
286
|
+
if (f.bold) st.bl = 1;
|
|
287
|
+
if (f.italic) st.it = 1;
|
|
288
|
+
if (f.underline) st.ul = { s: 1 };
|
|
289
|
+
if (f.strike) st.st = { s: 1 };
|
|
290
|
+
const cl = colorOf(f.color);
|
|
291
|
+
if (cl) st.cl = { rgb: cl };
|
|
292
|
+
}
|
|
293
|
+
const fill = cell.fill;
|
|
294
|
+
if (fill?.type === "pattern" && fill.pattern === "solid") {
|
|
295
|
+
const bg = colorOf(fill.fgColor);
|
|
296
|
+
if (bg) st.bg = { rgb: bg };
|
|
297
|
+
}
|
|
298
|
+
const al = cell.alignment;
|
|
299
|
+
if (al) {
|
|
300
|
+
if (al.horizontal && H_ALIGN_IN[al.horizontal]) st.ht = H_ALIGN_IN[al.horizontal];
|
|
301
|
+
if (al.vertical && V_ALIGN_IN[al.vertical]) st.vt = V_ALIGN_IN[al.vertical];
|
|
302
|
+
if (al.wrapText) st.tb = 3;
|
|
303
|
+
}
|
|
304
|
+
const bd = cell.border;
|
|
305
|
+
if (bd) {
|
|
306
|
+
const out = {};
|
|
307
|
+
for (const [side, key] of [["top", "t"], ["bottom", "b"], ["left", "l"], ["right", "r"]]) {
|
|
308
|
+
const s = borderFromExcel(bd[side]?.style);
|
|
309
|
+
if (s) out[key] = { s, cl: { rgb: colorOf(bd[side]?.color) ?? "#000000" } };
|
|
310
|
+
}
|
|
311
|
+
if (Object.keys(out).length) st.bd = out;
|
|
312
|
+
}
|
|
313
|
+
if (cell.numFmt && cell.numFmt !== "General") st.n = { pattern: cell.numFmt };
|
|
314
|
+
return Object.keys(st).length ? st : void 0;
|
|
315
|
+
}
|
|
316
|
+
var EXCEL_EPOCH_OFFSET_DAYS = 25569;
|
|
317
|
+
function toCell(cell, styleId) {
|
|
318
|
+
const out = {};
|
|
319
|
+
let st = toStyle(cell);
|
|
320
|
+
const v = cell.value;
|
|
321
|
+
const setNumber = (n) => {
|
|
322
|
+
out.v = n;
|
|
323
|
+
out.t = 2;
|
|
324
|
+
};
|
|
325
|
+
const apply = (value) => {
|
|
326
|
+
if (value instanceof Date) {
|
|
327
|
+
setNumber(value.getTime() / 864e5 + EXCEL_EPOCH_OFFSET_DAYS);
|
|
328
|
+
st = { ...st ?? {}, n: st?.n ?? { pattern: "yyyy-mm-dd" } };
|
|
329
|
+
} else if (typeof value === "number") setNumber(value);
|
|
330
|
+
else if (typeof value === "boolean") {
|
|
331
|
+
out.v = value ? 1 : 0;
|
|
332
|
+
out.t = 3;
|
|
333
|
+
} else if (typeof value === "string") {
|
|
334
|
+
out.v = value;
|
|
335
|
+
out.t = 1;
|
|
336
|
+
} else if (value && typeof value === "object" && "error" in value) {
|
|
337
|
+
out.v = String(value.error);
|
|
338
|
+
out.t = 1;
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
if (v && typeof v === "object" && !(v instanceof Date)) {
|
|
342
|
+
const o = v;
|
|
343
|
+
if ("formula" in o || "sharedFormula" in o) {
|
|
344
|
+
const f = o.formula ?? o.sharedFormula;
|
|
345
|
+
if (f) out.f = `=${String(f).replace(/^=/, "")}`;
|
|
346
|
+
apply(o.result);
|
|
347
|
+
} else if (Array.isArray(o.richText)) {
|
|
348
|
+
apply(o.richText.map((r) => r.text).join(""));
|
|
349
|
+
} else if ("hyperlink" in o) {
|
|
350
|
+
const text = String(typeof o.text === "object" ? (o.text?.richText ?? []).map((r) => r.text).join("") : o.text ?? o.hyperlink);
|
|
351
|
+
out.v = text;
|
|
352
|
+
out.t = 1;
|
|
353
|
+
out.p = linkDoc(text, String(o.hyperlink));
|
|
354
|
+
} else apply(o);
|
|
355
|
+
} else {
|
|
356
|
+
apply(v);
|
|
357
|
+
}
|
|
358
|
+
if (st) out.s = styleId(st);
|
|
359
|
+
return out.v === void 0 && out.f === void 0 && !out.s ? null : out;
|
|
360
|
+
}
|
|
361
|
+
function linkDoc(text, url) {
|
|
362
|
+
return {
|
|
363
|
+
id: "d",
|
|
364
|
+
documentStyle: {},
|
|
365
|
+
body: {
|
|
366
|
+
dataStream: `${text}\r
|
|
367
|
+
`,
|
|
368
|
+
textRuns: [],
|
|
369
|
+
paragraphs: [{ startIndex: text.length }],
|
|
370
|
+
customRanges: [
|
|
371
|
+
{ startIndex: 0, endIndex: Math.max(0, text.length - 1), rangeId: rid("link"), rangeType: 0, properties: { url } }
|
|
372
|
+
]
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
function dataValidationRules(model) {
|
|
377
|
+
const groups = /* @__PURE__ */ new Map();
|
|
378
|
+
for (const [ref, dv] of Object.entries(model)) {
|
|
379
|
+
const pos = parseA1Range(ref);
|
|
380
|
+
if (!pos) continue;
|
|
381
|
+
const type = String(dv.type);
|
|
382
|
+
const rule = {
|
|
383
|
+
allowBlank: dv.allowBlank !== false,
|
|
384
|
+
showErrorMessage: dv.showErrorMessage !== false,
|
|
385
|
+
...dv.error ? { error: dv.error } : {},
|
|
386
|
+
...dv.errorTitle ? { errorTitle: dv.errorTitle } : {},
|
|
387
|
+
...dv.prompt ? { prompt: dv.prompt, showInputMessage: true } : {}
|
|
388
|
+
};
|
|
389
|
+
const f = dv.formulae ?? [];
|
|
390
|
+
if (type === "list") {
|
|
391
|
+
const raw = String(f[0] ?? "");
|
|
392
|
+
const literal = /^"(.*)"$/.exec(raw);
|
|
393
|
+
Object.assign(rule, { type: "list", formula1: literal ? literal[1] : raw, formula2: "", showDropDown: true });
|
|
394
|
+
} else if (["whole", "decimal", "date", "time", "textLength"].includes(type)) {
|
|
395
|
+
Object.assign(rule, { type, operator: dv.operator ?? "between", formula1: String(f[0] ?? ""), formula2: f[1] !== void 0 ? String(f[1]) : "" });
|
|
396
|
+
} else if (type === "custom") {
|
|
397
|
+
Object.assign(rule, { type: "custom", formula1: String(f[0] ?? "") });
|
|
398
|
+
} else continue;
|
|
399
|
+
const key = JSON.stringify(rule);
|
|
400
|
+
const g = groups.get(key) ?? { rule, cells: [] };
|
|
401
|
+
g.cells.push([pos.startRow, pos.startColumn]);
|
|
402
|
+
groups.set(key, g);
|
|
403
|
+
}
|
|
404
|
+
return [...groups.values()].map(({ rule, cells }) => ({ uid: rid("dv"), ...rule, ranges: compressCells(cells) }));
|
|
405
|
+
}
|
|
406
|
+
function compressCells(cells) {
|
|
407
|
+
const sorted = [...cells].sort((a, b) => a[1] - b[1] || a[0] - b[0]);
|
|
408
|
+
const out = [];
|
|
409
|
+
for (const [r, c] of sorted) {
|
|
410
|
+
const last = out[out.length - 1];
|
|
411
|
+
if (last && last.startColumn === c && last.endColumn === c && last.endRow === r - 1) last.endRow = r;
|
|
412
|
+
else out.push({ startRow: r, endRow: r, startColumn: c, endColumn: c });
|
|
413
|
+
}
|
|
414
|
+
return out;
|
|
415
|
+
}
|
|
416
|
+
function dxfToStyle(style) {
|
|
417
|
+
const out = {};
|
|
418
|
+
const fg = colorOf(style?.font?.color);
|
|
419
|
+
if (fg) out.cl = { rgb: fg };
|
|
420
|
+
if (style?.font?.bold) out.bl = 1;
|
|
421
|
+
if (style?.font?.italic) out.it = 1;
|
|
422
|
+
const bg = colorOf(style?.fill?.bgColor) ?? colorOf(style?.fill?.fgColor);
|
|
423
|
+
if (bg) out.bg = { rgb: bg };
|
|
424
|
+
return out;
|
|
425
|
+
}
|
|
426
|
+
function conditionalRules(formats, dropped) {
|
|
427
|
+
const out = [];
|
|
428
|
+
for (const cf of formats) {
|
|
429
|
+
const ranges = String(cf.ref ?? "").split(/\s+/).map((r) => parseA1Range(r)).filter((r) => !!r);
|
|
430
|
+
if (!ranges.length) continue;
|
|
431
|
+
for (const rule of cf.rules ?? []) {
|
|
432
|
+
let mapped = null;
|
|
433
|
+
const style = dxfToStyle(rule.style);
|
|
434
|
+
if (rule.type === "cellIs") {
|
|
435
|
+
const nums = (rule.formulae ?? []).map(Number);
|
|
436
|
+
const between = rule.operator === "between" || rule.operator === "notBetween";
|
|
437
|
+
mapped = { type: "highlightCell", subType: "number", operator: rule.operator, value: between ? nums.slice(0, 2) : nums[0], style };
|
|
438
|
+
} else if (rule.type === "containsText") {
|
|
439
|
+
mapped = { type: "highlightCell", subType: "text", operator: "containsText", value: String(rule.text ?? ""), style };
|
|
440
|
+
} else if (rule.type === "expression") {
|
|
441
|
+
mapped = { type: "highlightCell", subType: "formula", value: `=${String((rule.formulae ?? [])[0] ?? "")}`, style };
|
|
442
|
+
} else if (rule.type === "colorScale") {
|
|
443
|
+
mapped = {
|
|
444
|
+
type: "colorScale",
|
|
445
|
+
config: (rule.cfvo ?? []).map((v, i) => ({
|
|
446
|
+
index: i,
|
|
447
|
+
color: colorOf(rule.color?.[i]) ?? "#ffffff",
|
|
448
|
+
value: { type: v.type, ...v.value !== void 0 ? { value: v.value } : {} }
|
|
449
|
+
}))
|
|
450
|
+
};
|
|
451
|
+
} else if (rule.type === "dataBar") {
|
|
452
|
+
const [min, max] = rule.cfvo ?? [];
|
|
453
|
+
mapped = {
|
|
454
|
+
type: "dataBar",
|
|
455
|
+
isShowValue: true,
|
|
456
|
+
config: {
|
|
457
|
+
min: { type: min?.type ?? "min" },
|
|
458
|
+
max: { type: max?.type ?? "max" },
|
|
459
|
+
isGradient: rule.gradient !== false,
|
|
460
|
+
positiveColor: colorOf(rule.color) ?? "#638ec6",
|
|
461
|
+
nativeColor: "#ff0000"
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
if (!mapped) {
|
|
466
|
+
dropped.add("Some conditional formats (icon sets, top/bottom, date rules) were not imported");
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
out.push({ cfId: rid("cf"), ranges, stopIfTrue: Boolean(rule.stopIfTrue), rule: mapped });
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return out;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// src/sheets/xlsx-to-univer.ts
|
|
476
|
+
async function legacyToXlsxBytes(file) {
|
|
477
|
+
const wb = await readWorkbook(file, { dates: true, formulas: true });
|
|
478
|
+
const json = {
|
|
479
|
+
sheets: wb.sheets.map((ws) => {
|
|
480
|
+
const range = ws.range ?? { s: { r: 0, c: 0 }, e: { r: -1, c: -1 } };
|
|
481
|
+
const rows = [];
|
|
482
|
+
for (let r = 0; r <= range.e.r; r++) {
|
|
483
|
+
const row = [];
|
|
484
|
+
for (let c = 0; c <= range.e.c; c++) {
|
|
485
|
+
const cell = ws.cell(r, c);
|
|
486
|
+
if (!cell || cell.v === void 0 || cell.v === null) {
|
|
487
|
+
row.push(null);
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
const v = cell.v instanceof Date ? cell.v.toISOString().slice(0, 10) : cell.v;
|
|
491
|
+
if (cell.f) row.push({ v: typeof v === "boolean" || typeof v === "number" ? v : String(v), f: cell.f.replace(/^=/, "") });
|
|
492
|
+
else row.push(v);
|
|
493
|
+
}
|
|
494
|
+
rows.push(row);
|
|
495
|
+
}
|
|
496
|
+
return { name: ws.name.slice(0, 31) || "Sheet1", rows, merges: ws.merges };
|
|
497
|
+
})
|
|
498
|
+
};
|
|
499
|
+
const bytes = await writeWorkbookBytes(json);
|
|
500
|
+
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
501
|
+
}
|
|
502
|
+
async function xlsxToUniverWorkbook(file, options = {}) {
|
|
503
|
+
if (/\.xlsx$/i.test(file.name)) return importXlsxWithExcelJs(file, options);
|
|
504
|
+
const data = await legacyToXlsxBytes(file);
|
|
505
|
+
return importXlsxWithExcelJs({ name: file.name, arrayBuffer: async () => data }, options);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export {
|
|
509
|
+
RESOURCE,
|
|
510
|
+
readResource,
|
|
511
|
+
writeResource,
|
|
512
|
+
colPxToChars,
|
|
513
|
+
colCharsToPx,
|
|
514
|
+
rowPxToPt,
|
|
515
|
+
rowPtToPx,
|
|
516
|
+
colorToArgb,
|
|
517
|
+
argbToColor,
|
|
518
|
+
borderToExcel,
|
|
519
|
+
borderFromExcel,
|
|
520
|
+
H_ALIGN_OUT,
|
|
521
|
+
V_ALIGN_OUT,
|
|
522
|
+
H_ALIGN_IN,
|
|
523
|
+
V_ALIGN_IN,
|
|
524
|
+
a1,
|
|
525
|
+
rangeToA1,
|
|
526
|
+
parseA1Range,
|
|
527
|
+
xlsxToUniverWorkbook
|
|
528
|
+
};
|
|
529
|
+
//# sourceMappingURL=chunk-5T2M6LSI.js.map
|