@beyondwork/docx-react-component 1.0.36 → 1.0.38
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/README.md +103 -13
- package/package.json +1 -1
- package/src/api/package-version.ts +13 -0
- package/src/api/public-types.ts +402 -1
- package/src/core/commands/index.ts +18 -1
- package/src/core/commands/section-layout-commands.ts +58 -0
- package/src/core/commands/table-grid.ts +431 -0
- package/src/core/commands/table-structure-commands.ts +815 -55
- package/src/core/selection/mapping.ts +6 -0
- package/src/io/docx-session.ts +24 -9
- package/src/io/export/build-app-properties-xml.ts +88 -0
- package/src/io/export/serialize-comments.ts +6 -1
- package/src/io/export/serialize-footnotes.ts +10 -9
- package/src/io/export/serialize-headers-footers.ts +11 -10
- package/src/io/export/serialize-main-document.ts +328 -50
- package/src/io/export/serialize-numbering.ts +114 -24
- package/src/io/export/serialize-tables.ts +87 -11
- package/src/io/export/table-properties-xml.ts +174 -20
- package/src/io/export/twip.ts +66 -0
- package/src/io/normalize/normalize-text.ts +20 -0
- package/src/io/ooxml/parse-footnotes.ts +62 -1
- package/src/io/ooxml/parse-headers-footers.ts +62 -1
- package/src/io/ooxml/parse-main-document.ts +158 -1
- package/src/io/ooxml/parse-tables.ts +249 -0
- package/src/legal/bookmarks.ts +78 -0
- package/src/model/canonical-document.ts +45 -0
- package/src/review/store/scope-tag-diff.ts +130 -0
- package/src/runtime/document-layout.ts +4 -2
- package/src/runtime/document-navigation.ts +2 -306
- package/src/runtime/document-runtime.ts +287 -11
- package/src/runtime/layout/default-page-format.ts +96 -0
- package/src/runtime/layout/docx-font-loader.ts +143 -0
- package/src/runtime/layout/index.ts +233 -0
- package/src/runtime/layout/inert-layout-facet.ts +59 -0
- package/src/runtime/layout/layout-engine-instance.ts +628 -0
- package/src/runtime/layout/layout-invalidation.ts +257 -0
- package/src/runtime/layout/layout-measurement-provider.ts +175 -0
- package/src/runtime/layout/margin-preset-catalog.ts +178 -0
- package/src/runtime/layout/measurement-backend-canvas.ts +307 -0
- package/src/runtime/layout/measurement-backend-empirical.ts +208 -0
- package/src/runtime/layout/page-format-catalog.ts +233 -0
- package/src/runtime/layout/page-fragment-mapper.ts +179 -0
- package/src/runtime/layout/page-graph.ts +452 -0
- package/src/runtime/layout/page-layout-snapshot-adapter.ts +70 -0
- package/src/runtime/layout/page-story-resolver.ts +195 -0
- package/src/runtime/layout/paginated-layout-engine.ts +921 -0
- package/src/runtime/layout/project-block-fragments.ts +91 -0
- package/src/runtime/layout/public-facet.ts +1398 -0
- package/src/runtime/layout/resolved-formatting-document.ts +317 -0
- package/src/runtime/layout/resolved-formatting-state.ts +430 -0
- package/src/runtime/layout/table-render-plan.ts +229 -0
- package/src/runtime/render/block-fragment-projection.ts +35 -0
- package/src/runtime/render/decoration-resolver.ts +189 -0
- package/src/runtime/render/index.ts +57 -0
- package/src/runtime/render/pending-op-delta-reader.ts +129 -0
- package/src/runtime/render/render-frame-types.ts +317 -0
- package/src/runtime/render/render-kernel.ts +755 -0
- package/src/runtime/scope-tag-registry.ts +95 -0
- package/src/runtime/surface-projection.ts +1 -0
- package/src/runtime/text-ack-range.ts +49 -0
- package/src/runtime/view-state.ts +67 -0
- package/src/runtime/workflow-markup.ts +1 -5
- package/src/runtime/workflow-rail-segments.ts +280 -0
- package/src/ui/WordReviewEditor.tsx +99 -15
- package/src/ui/editor-runtime-boundary.ts +10 -1
- package/src/ui/editor-shell-view.tsx +6 -0
- package/src/ui/editor-surface-controller.tsx +3 -0
- package/src/ui/headless/chrome-registry.ts +501 -0
- package/src/ui/headless/scoped-chrome-policy.ts +183 -0
- package/src/ui/headless/selection-tool-context.ts +2 -0
- package/src/ui/headless/selection-tool-resolver.ts +36 -17
- package/src/ui/headless/selection-tool-types.ts +10 -0
- package/src/ui-tailwind/chrome/chrome-preset-model.ts +23 -2
- package/src/ui-tailwind/chrome/role-action-sets.ts +74 -0
- package/src/ui-tailwind/chrome/tw-detach-handle.tsx +147 -0
- package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +163 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +57 -92
- package/src/ui-tailwind/chrome/tw-selection-tool-placement.ts +149 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +15 -4
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +274 -138
- package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +90 -0
- package/src/ui-tailwind/chrome-overlay/index.ts +22 -0
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +86 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +178 -0
- package/src/ui-tailwind/chrome-overlay/tw-workspace-view-switcher.tsx +95 -0
- package/src/ui-tailwind/editor-surface/fast-text-edit-lane.ts +337 -0
- package/src/ui-tailwind/editor-surface/local-edit-session-state.ts +100 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +27 -1
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +20 -2
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +93 -23
- package/src/ui-tailwind/editor-surface/predicted-position-map.ts +78 -0
- package/src/ui-tailwind/editor-surface/predicted-tag-preflight.ts +63 -0
- package/src/ui-tailwind/editor-surface/predicted-tx-gate.ts +39 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +176 -6
- package/src/ui-tailwind/index.ts +33 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +2 -2
- package/src/ui-tailwind/review/tw-rail-card.tsx +150 -0
- package/src/ui-tailwind/review/tw-review-rail-footer.tsx +52 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +166 -11
- package/src/ui-tailwind/review/tw-workflow-tab.tsx +108 -0
- package/src/ui-tailwind/theme/editor-theme.css +505 -144
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +559 -0
- package/src/ui-tailwind/toolbar/tw-scope-posture-menu.tsx +182 -0
- package/src/ui-tailwind/toolbar/tw-shell-header.tsx +162 -0
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +2 -2
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +304 -166
- package/src/ui-tailwind/tw-review-workspace.tsx +163 -2
|
@@ -51,6 +51,12 @@ export interface TransactionMapping {
|
|
|
51
51
|
affectsComments?: boolean;
|
|
52
52
|
affectsRevisions?: boolean;
|
|
53
53
|
affectsOpaqueFragments?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Review-tag touches performed during this transaction. Used by the
|
|
56
|
+
* predicted-text lane's reconciler to classify acks as `adjusted` vs
|
|
57
|
+
* `structural-divergence` without re-walking the document.
|
|
58
|
+
*/
|
|
59
|
+
scopeTagTouches?: readonly import("../../api/public-types.ts").ScopeTagTouch[];
|
|
54
60
|
[key: string]: unknown;
|
|
55
61
|
};
|
|
56
62
|
}
|
package/src/io/docx-session.ts
CHANGED
|
@@ -67,6 +67,7 @@ import {
|
|
|
67
67
|
createBrokenRelationshipIssue,
|
|
68
68
|
createMissingPartIssue,
|
|
69
69
|
} from "./opc/corrupt-package.ts";
|
|
70
|
+
import { buildAppPropertiesXml } from "./export/build-app-properties-xml.ts";
|
|
70
71
|
import { createExportSession } from "./export/export-session.ts";
|
|
71
72
|
import { serializeMainDocument } from "./export/serialize-main-document.ts";
|
|
72
73
|
import {
|
|
@@ -2909,10 +2910,31 @@ function serializeCanonicalDocumentForExport(document: CanonicalDocumentEnvelope
|
|
|
2909
2910
|
});
|
|
2910
2911
|
}
|
|
2911
2912
|
|
|
2913
|
+
/**
|
|
2914
|
+
* Read a Node-style environment variable without referencing the Node-only
|
|
2915
|
+
* `process` global in the production build (which excludes @types/node).
|
|
2916
|
+
* Returns `undefined` in browser environments or when the var is unset.
|
|
2917
|
+
*/
|
|
2918
|
+
function readNodeEnvVar(name: string): string | undefined {
|
|
2919
|
+
const proc = (globalThis as unknown as {
|
|
2920
|
+
process?: { env?: Record<string, string | undefined> };
|
|
2921
|
+
}).process;
|
|
2922
|
+
return proc?.env?.[name];
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2912
2925
|
function canReuseSourceBytesForCurrentDocument(
|
|
2913
2926
|
state: ImportedDocxState,
|
|
2914
2927
|
document: CanonicalDocumentEnvelope,
|
|
2915
2928
|
): boolean {
|
|
2929
|
+
// The validator-loop CI harness (§1 / §7) needs to exercise the full
|
|
2930
|
+
// serializer pipeline — including A.1 / A.2 / A.3 / A.6 / A.7 / A.8 /
|
|
2931
|
+
// A.9 fixes — so it sets DOCX_VALIDATOR_FORCE_REGEN=1 to disable the
|
|
2932
|
+
// fast-path byte-reuse. Never set this flag in production; it forces a
|
|
2933
|
+
// full XML regeneration on every export and is only used by the CCEP
|
|
2934
|
+
// validator harness to prove our serializer's correctness.
|
|
2935
|
+
if (readNodeEnvVar("DOCX_VALIDATOR_FORCE_REGEN") === "1") {
|
|
2936
|
+
return false;
|
|
2937
|
+
}
|
|
2916
2938
|
if (requiresHostMetadataNormalization(state.sourcePackage, state.sourceDocumentPartPath)) {
|
|
2917
2939
|
return false;
|
|
2918
2940
|
}
|
|
@@ -3108,15 +3130,8 @@ function buildCorePropertiesXml(document: CanonicalDocumentEnvelope): string {
|
|
|
3108
3130
|
].join("\n");
|
|
3109
3131
|
}
|
|
3110
3132
|
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>`,
|
|
3114
|
-
`<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">`,
|
|
3115
|
-
` <Application>React OOXML Office</Application>`,
|
|
3116
|
-
` <AppVersion>1.0</AppVersion>`,
|
|
3117
|
-
`</Properties>`,
|
|
3118
|
-
].join("\n");
|
|
3119
|
-
}
|
|
3133
|
+
// buildAppPropertiesXml moved to src/io/export/build-app-properties-xml.ts
|
|
3134
|
+
// per close-render-fidelity §2 A.5. Re-import as `buildAppPropertiesXmlFn`.
|
|
3120
3135
|
|
|
3121
3136
|
function xmlNode(tagName: string, value: string | undefined): string | undefined {
|
|
3122
3137
|
if (typeof value !== "string" || value.length === 0) {
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* build-app-properties-xml — synthesises `/docProps/app.xml` for the export.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `buildCorePropertiesXml` (in `docx-session.ts`) but targets the
|
|
5
|
+
* `extended-properties` namespace. Emitted once per export when the source
|
|
6
|
+
* package does not already carry a valid app.xml part with the correct
|
|
7
|
+
* content type.
|
|
8
|
+
*
|
|
9
|
+
* Required by:
|
|
10
|
+
* docs/plans/close-render-fidelity.md §2 A.5
|
|
11
|
+
*
|
|
12
|
+
* Schema shape (ECMA-376 Part 1, Office Extended properties):
|
|
13
|
+
* <Properties xmlns="…/extended-properties" xmlns:vt="…/docPropsVTypes">
|
|
14
|
+
* <Application>@beyondwork/docx-react-component/<pkg.version></Application>
|
|
15
|
+
* <AppVersion>1.0</AppVersion>
|
|
16
|
+
* <Pages>0</Pages>
|
|
17
|
+
* <Words>0</Words>
|
|
18
|
+
* <Characters>0</Characters>
|
|
19
|
+
* <Lines>0</Lines>
|
|
20
|
+
* <Paragraphs>0</Paragraphs>
|
|
21
|
+
* </Properties>
|
|
22
|
+
*
|
|
23
|
+
* Zero counts are acceptable per the ECMA schema — Word-authoritative counts
|
|
24
|
+
* are recomputed at open time by the hosting application. A future §4 pass
|
|
25
|
+
* can replace these with canonical-derived counts without changing the XML
|
|
26
|
+
* shape.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { PACKAGE_VERSION } from "../../api/package-version.ts";
|
|
30
|
+
|
|
31
|
+
export const APP_PROPERTIES_NAMESPACE =
|
|
32
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
|
|
33
|
+
export const APP_PROPERTIES_VT_NAMESPACE =
|
|
34
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
|
|
35
|
+
|
|
36
|
+
export interface AppPropertiesStats {
|
|
37
|
+
/** Rendered page count; zero is a valid placeholder. */
|
|
38
|
+
pages?: number;
|
|
39
|
+
/** Word count. */
|
|
40
|
+
words?: number;
|
|
41
|
+
/** Character count. */
|
|
42
|
+
characters?: number;
|
|
43
|
+
/** Line count. */
|
|
44
|
+
lines?: number;
|
|
45
|
+
/** Paragraph count. */
|
|
46
|
+
paragraphs?: number;
|
|
47
|
+
/** App-version string override; defaults to the package version. */
|
|
48
|
+
appVersion?: string;
|
|
49
|
+
/** Application identifier override; defaults to package.json name@version. */
|
|
50
|
+
application?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function buildAppPropertiesXml(
|
|
54
|
+
stats: AppPropertiesStats = {},
|
|
55
|
+
): string {
|
|
56
|
+
const application = stats.application ?? defaultApplicationLabel();
|
|
57
|
+
const appVersion = stats.appVersion ?? PACKAGE_VERSION;
|
|
58
|
+
const pages = stats.pages ?? 0;
|
|
59
|
+
const words = stats.words ?? 0;
|
|
60
|
+
const characters = stats.characters ?? 0;
|
|
61
|
+
const lines = stats.lines ?? 0;
|
|
62
|
+
const paragraphs = stats.paragraphs ?? 0;
|
|
63
|
+
|
|
64
|
+
return [
|
|
65
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>`,
|
|
66
|
+
`<Properties xmlns="${APP_PROPERTIES_NAMESPACE}" xmlns:vt="${APP_PROPERTIES_VT_NAMESPACE}">`,
|
|
67
|
+
` <Application>${escapeXml(application)}</Application>`,
|
|
68
|
+
` <AppVersion>${escapeXml(appVersion)}</AppVersion>`,
|
|
69
|
+
` <Pages>${Math.max(0, Math.round(pages))}</Pages>`,
|
|
70
|
+
` <Words>${Math.max(0, Math.round(words))}</Words>`,
|
|
71
|
+
` <Characters>${Math.max(0, Math.round(characters))}</Characters>`,
|
|
72
|
+
` <Lines>${Math.max(0, Math.round(lines))}</Lines>`,
|
|
73
|
+
` <Paragraphs>${Math.max(0, Math.round(paragraphs))}</Paragraphs>`,
|
|
74
|
+
`</Properties>`,
|
|
75
|
+
].join("\n");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function defaultApplicationLabel(): string {
|
|
79
|
+
return `@beyondwork/docx-react-component/${PACKAGE_VERSION}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function escapeXml(value: string): string {
|
|
83
|
+
return value
|
|
84
|
+
.replace(/&/gu, "&")
|
|
85
|
+
.replace(/</gu, "<")
|
|
86
|
+
.replace(/>/gu, ">")
|
|
87
|
+
.replace(/"/gu, """);
|
|
88
|
+
}
|
|
@@ -64,8 +64,13 @@ export interface SerializedCommentDocumentResult {
|
|
|
64
64
|
skippedCommentIds: string[];
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
// A.8: emit root attributes in deterministic order (xmlns:* alphabetised,
|
|
68
|
+
// then mc:Ignorable, then other attrs). The sort above happens to produce
|
|
69
|
+
// the same token order `mc < w < w14` + `mc:Ignorable` — keep the literal
|
|
70
|
+
// in sync with renderDeterministicRootAttributes so regenerated docs and
|
|
71
|
+
// comments.xml samples match byte-for-byte when snapshots compare them.
|
|
67
72
|
const DEFAULT_COMMENTS_ROOT_TAG =
|
|
68
|
-
`<w:comments xmlns:
|
|
73
|
+
`<w:comments xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" mc:Ignorable="w14">`;
|
|
69
74
|
const DEFAULT_COMMENTS_EXTENDED_ROOT_TAG =
|
|
70
75
|
`<w15:commentsEx xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml">`;
|
|
71
76
|
const DEFAULT_COMMENTS_IDS_ROOT_TAG =
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
serializeTablePropertiesXml,
|
|
17
17
|
serializeTableRowPropertiesXml,
|
|
18
18
|
} from "./table-properties-xml.ts";
|
|
19
|
+
import { twip } from "./twip.ts";
|
|
19
20
|
|
|
20
21
|
export const WORD_FOOTNOTES_CONTENT_TYPE =
|
|
21
22
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml";
|
|
@@ -142,7 +143,7 @@ function serializeTable(table: TableNode): string {
|
|
|
142
143
|
if (table.gridColumns.length > 0) {
|
|
143
144
|
xml += "<w:tblGrid>";
|
|
144
145
|
for (const width of table.gridColumns) {
|
|
145
|
-
xml += `<w:gridCol w:w="${width}"/>`;
|
|
146
|
+
xml += `<w:gridCol w:w="${twip(width)}"/>`;
|
|
146
147
|
}
|
|
147
148
|
xml += "</w:tblGrid>";
|
|
148
149
|
}
|
|
@@ -194,9 +195,9 @@ function buildParagraphPropertiesXml(paragraph: ParagraphNode): string {
|
|
|
194
195
|
}
|
|
195
196
|
if (paragraph.spacing) {
|
|
196
197
|
const attrs: string[] = [];
|
|
197
|
-
if (paragraph.spacing.before !== undefined) attrs.push(`w:before="${paragraph.spacing.before}"`);
|
|
198
|
-
if (paragraph.spacing.after !== undefined) attrs.push(`w:after="${paragraph.spacing.after}"`);
|
|
199
|
-
if (paragraph.spacing.line !== undefined) attrs.push(`w:line="${paragraph.spacing.line}"`);
|
|
198
|
+
if (paragraph.spacing.before !== undefined) attrs.push(`w:before="${twip(paragraph.spacing.before)}"`);
|
|
199
|
+
if (paragraph.spacing.after !== undefined) attrs.push(`w:after="${twip(paragraph.spacing.after)}"`);
|
|
200
|
+
if (paragraph.spacing.line !== undefined) attrs.push(`w:line="${twip(paragraph.spacing.line)}"`);
|
|
200
201
|
if (paragraph.spacing.lineRule) attrs.push(`w:lineRule="${escapeAttribute(paragraph.spacing.lineRule)}"`);
|
|
201
202
|
if (attrs.length > 0) {
|
|
202
203
|
parts.push(`<w:spacing ${attrs.join(" ")}/>`);
|
|
@@ -204,10 +205,10 @@ function buildParagraphPropertiesXml(paragraph: ParagraphNode): string {
|
|
|
204
205
|
}
|
|
205
206
|
if (paragraph.indentation) {
|
|
206
207
|
const attrs: string[] = [];
|
|
207
|
-
if (paragraph.indentation.left !== undefined) attrs.push(`w:left="${paragraph.indentation.left}"`);
|
|
208
|
-
if (paragraph.indentation.right !== undefined) attrs.push(`w:right="${paragraph.indentation.right}"`);
|
|
209
|
-
if (paragraph.indentation.firstLine !== undefined) attrs.push(`w:firstLine="${paragraph.indentation.firstLine}"`);
|
|
210
|
-
if (paragraph.indentation.hanging !== undefined) attrs.push(`w:hanging="${paragraph.indentation.hanging}"`);
|
|
208
|
+
if (paragraph.indentation.left !== undefined) attrs.push(`w:left="${twip(paragraph.indentation.left)}"`);
|
|
209
|
+
if (paragraph.indentation.right !== undefined) attrs.push(`w:right="${twip(paragraph.indentation.right)}"`);
|
|
210
|
+
if (paragraph.indentation.firstLine !== undefined) attrs.push(`w:firstLine="${twip(paragraph.indentation.firstLine)}"`);
|
|
211
|
+
if (paragraph.indentation.hanging !== undefined) attrs.push(`w:hanging="${twip(paragraph.indentation.hanging)}"`);
|
|
211
212
|
if (attrs.length > 0) {
|
|
212
213
|
parts.push(`<w:ind ${attrs.join(" ")}/>`);
|
|
213
214
|
}
|
|
@@ -330,7 +331,7 @@ function buildRunPropertiesXml(marks: TextMark[] | undefined): string {
|
|
|
330
331
|
);
|
|
331
332
|
break;
|
|
332
333
|
case "fontSize":
|
|
333
|
-
parts.push(`<w:sz w:val="${mark.val}"/>`);
|
|
334
|
+
parts.push(`<w:sz w:val="${twip(mark.val)}"/>`);
|
|
334
335
|
break;
|
|
335
336
|
case "textColor":
|
|
336
337
|
parts.push(`<w:color w:val="${escapeAttribute(mark.color)}"/>`);
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
serializeTablePropertiesXml,
|
|
17
17
|
serializeTableRowPropertiesXml,
|
|
18
18
|
} from "./table-properties-xml.ts";
|
|
19
|
+
import { twip } from "./twip.ts";
|
|
19
20
|
|
|
20
21
|
export const WORD_HEADER_CONTENT_TYPE =
|
|
21
22
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml";
|
|
@@ -132,7 +133,7 @@ function serializeTable(table: TableNode): string {
|
|
|
132
133
|
if (table.gridColumns.length > 0) {
|
|
133
134
|
xml += "<w:tblGrid>";
|
|
134
135
|
for (const width of table.gridColumns) {
|
|
135
|
-
xml += `<w:gridCol w:w="${width}"/>`;
|
|
136
|
+
xml += `<w:gridCol w:w="${twip(width)}"/>`;
|
|
136
137
|
}
|
|
137
138
|
xml += "</w:tblGrid>";
|
|
138
139
|
}
|
|
@@ -182,19 +183,19 @@ function buildParagraphPropertiesXml(paragraph: ParagraphNode): string {
|
|
|
182
183
|
if (paragraph.spacing) {
|
|
183
184
|
const s = paragraph.spacing;
|
|
184
185
|
const attrs: string[] = [];
|
|
185
|
-
if (s.before !== undefined) attrs.push(`w:before="${s.before}"`);
|
|
186
|
-
if (s.after !== undefined) attrs.push(`w:after="${s.after}"`);
|
|
187
|
-
if (s.line !== undefined) attrs.push(`w:line="${s.line}"`);
|
|
186
|
+
if (s.before !== undefined) attrs.push(`w:before="${twip(s.before)}"`);
|
|
187
|
+
if (s.after !== undefined) attrs.push(`w:after="${twip(s.after)}"`);
|
|
188
|
+
if (s.line !== undefined) attrs.push(`w:line="${twip(s.line)}"`);
|
|
188
189
|
if (s.lineRule) attrs.push(`w:lineRule="${escapeAttribute(s.lineRule)}"`);
|
|
189
190
|
if (attrs.length > 0) parts.push(`<w:spacing ${attrs.join(" ")}/>`);
|
|
190
191
|
}
|
|
191
192
|
if (paragraph.indentation) {
|
|
192
193
|
const ind = paragraph.indentation;
|
|
193
194
|
const attrs: string[] = [];
|
|
194
|
-
if (ind.left !== undefined) attrs.push(`w:left="${ind.left}"`);
|
|
195
|
-
if (ind.right !== undefined) attrs.push(`w:right="${ind.right}"`);
|
|
196
|
-
if (ind.firstLine !== undefined) attrs.push(`w:firstLine="${ind.firstLine}"`);
|
|
197
|
-
if (ind.hanging !== undefined) attrs.push(`w:hanging="${ind.hanging}"`);
|
|
195
|
+
if (ind.left !== undefined) attrs.push(`w:left="${twip(ind.left)}"`);
|
|
196
|
+
if (ind.right !== undefined) attrs.push(`w:right="${twip(ind.right)}"`);
|
|
197
|
+
if (ind.firstLine !== undefined) attrs.push(`w:firstLine="${twip(ind.firstLine)}"`);
|
|
198
|
+
if (ind.hanging !== undefined) attrs.push(`w:hanging="${twip(ind.hanging)}"`);
|
|
198
199
|
if (attrs.length > 0) parts.push(`<w:ind ${attrs.join(" ")}/>`);
|
|
199
200
|
}
|
|
200
201
|
if (paragraph.alignment) {
|
|
@@ -203,7 +204,7 @@ function buildParagraphPropertiesXml(paragraph: ParagraphNode): string {
|
|
|
203
204
|
if (paragraph.tabStops && paragraph.tabStops.length > 0) {
|
|
204
205
|
const tabsXml = paragraph.tabStops.map((tab) => {
|
|
205
206
|
const leaderAttr = tab.leader ? ` w:leader="${escapeAttribute(tab.leader)}"` : "";
|
|
206
|
-
return `<w:tab w:val="${tab.align}" w:pos="${tab.position}"${leaderAttr}/>`;
|
|
207
|
+
return `<w:tab w:val="${tab.align}" w:pos="${twip(tab.position)}"${leaderAttr}/>`;
|
|
207
208
|
}).join("");
|
|
208
209
|
parts.push(`<w:tabs>${tabsXml}</w:tabs>`);
|
|
209
210
|
}
|
|
@@ -303,7 +304,7 @@ function buildRunPropertiesXml(marks: TextMark[] | undefined): string {
|
|
|
303
304
|
parts.push(`<w:rFonts w:ascii="${escapeAttribute(mark.val)}" w:hAnsi="${escapeAttribute(mark.val)}"/>`);
|
|
304
305
|
break;
|
|
305
306
|
case "fontSize":
|
|
306
|
-
parts.push(`<w:sz w:val="${mark.val}"/>`);
|
|
307
|
+
parts.push(`<w:sz w:val="${twip(mark.val)}"/>`);
|
|
307
308
|
break;
|
|
308
309
|
case "textColor":
|
|
309
310
|
parts.push(`<w:color w:val="${escapeAttribute(mark.color)}"/>`);
|