@docen/docx 0.3.1 → 0.3.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/dist/converters/docx.d.mts +199 -1
- package/dist/converters/docx.mjs +1273 -1
- package/dist/converters/html.d.mts +28 -1
- package/dist/converters/html.mjs +103 -1
- package/dist/converters/markdown.d.mts +12 -1
- package/dist/converters/markdown.mjs +17 -1
- package/dist/converters/patch.d.mts +52 -1
- package/dist/converters/patch.mjs +35 -1
- package/dist/converters/prepare.d.mts +62 -1
- package/dist/converters/prepare.mjs +121 -1
- package/dist/converters/styles.d.mts +84 -1
- package/dist/converters/styles.mjs +284 -1
- package/dist/core-C9VunJ8o.d.mts +174 -0
- package/dist/core-DT9IrTzN.mjs +670 -0
- package/dist/core.d.mts +1 -1
- package/dist/core.mjs +1 -1
- package/dist/editor.d.mts +20 -1
- package/dist/editor.mjs +20 -1
- package/dist/extensions/blockquote.d.mts +1 -1
- package/dist/extensions/blockquote.mjs +30 -2
- package/dist/extensions/code-block.d.mts +1 -1
- package/dist/extensions/code-block.mjs +22 -1
- package/dist/extensions/column-break.d.mts +1 -1
- package/dist/extensions/column-break.mjs +1 -1
- package/dist/extensions/details.d.mts +1 -1
- package/dist/extensions/details.mjs +17 -2
- package/dist/extensions/document.mjs +49 -1
- package/dist/extensions/extensions.d.mts +3 -4
- package/dist/extensions/extensions.mjs +13 -14
- package/dist/extensions/formatting-marks.d.mts +7 -1
- package/dist/extensions/formatting-marks.mjs +1 -1
- package/dist/extensions/heading.mjs +165 -1
- package/dist/extensions/image.d.mts +1 -1
- package/dist/extensions/image.mjs +395 -1
- package/dist/extensions/index.d.mts +3 -2
- package/dist/extensions/index.mjs +4 -3
- package/dist/extensions/mention.d.mts +1 -1
- package/dist/extensions/mention.mjs +43 -2
- package/dist/extensions/ordered-list.d.mts +1 -1
- package/dist/extensions/ordered-list.mjs +40 -2
- package/dist/extensions/page-break.d.mts +1 -33
- package/dist/extensions/page-break.mjs +1 -1
- package/dist/extensions/paragraph.mjs +150 -1
- package/dist/extensions/passthrough.d.mts +1 -1
- package/dist/extensions/passthrough.mjs +1 -1
- package/dist/extensions/section-break.d.mts +19 -2
- package/dist/extensions/section-break.mjs +1 -1
- package/dist/extensions/strike.mjs +49 -1
- package/dist/extensions/table-cell.mjs +111 -1
- package/dist/extensions/table-header.mjs +111 -1
- package/dist/extensions/table-row.mjs +83 -1
- package/dist/extensions/table.mjs +159 -1
- package/dist/extensions/task-item.d.mts +1 -1
- package/dist/extensions/task-item.mjs +36 -2
- package/dist/extensions/text-style.mjs +150 -1
- package/dist/extensions/tiptap.d.mts +2 -2
- package/dist/extensions/tiptap.mjs +31 -2
- package/dist/extensions/utils.d.mts +2 -62
- package/dist/extensions/utils.mjs +499 -2
- package/dist/extensions/wpg-group.d.mts +2 -0
- package/dist/extensions/wpg-group.mjs +2 -0
- package/dist/extensions/wps-shape.d.mts +2 -0
- package/dist/extensions/wps-shape.mjs +2 -0
- package/dist/index.d.mts +86 -27
- package/dist/index.mjs +13 -10
- package/dist/{tiptap-TErPjuNJ.d.mts → tiptap-pZsNPsvV.d.mts} +1 -3
- package/dist/utils-D87vukzp.d.mts +128 -0
- package/package.json +39 -40
- package/dist/blockquote-Ky9xD_Q-.mjs +0 -31
- package/dist/code-block-BgNjhADy.mjs +0 -23
- package/dist/core-DEqBHRzE.mjs +0 -406
- package/dist/core-fBMCCj4D.d.mts +0 -97
- package/dist/details-Dh8luWb2.mjs +0 -18
- package/dist/dist-B6B3HnVZ.mjs +0 -1838
- package/dist/document-CvTym-FM.mjs +0 -50
- package/dist/docx-C5wyjI-0.d.mts +0 -200
- package/dist/docx-CONyAedl.mjs +0 -1231
- package/dist/editor-Bf3CxQnY.mjs +0 -21
- package/dist/editor-DReY3Rb9.d.mts +0 -21
- package/dist/emoji-BZ1dJD7d.d.mts +0 -17
- package/dist/emoji-C2OsTWR7.mjs +0 -27
- package/dist/extensions/emoji.d.mts +0 -2
- package/dist/extensions/emoji.mjs +0 -2
- package/dist/extensions/image-group.d.mts +0 -6
- package/dist/extensions/image-group.mjs +0 -2
- package/dist/heading-DAubgJJN.mjs +0 -166
- package/dist/html-DCC_DSHv.d.mts +0 -18
- package/dist/html-DedDWPoO.mjs +0 -66
- package/dist/image-CuEIXoZl.mjs +0 -334
- package/dist/markdown-BzJmRsBs.mjs +0 -18
- package/dist/markdown-D0k0sRYS.d.mts +0 -13
- package/dist/mention-C-dTR6MK.mjs +0 -44
- package/dist/ordered-list-V-3xFQmV.mjs +0 -41
- package/dist/paragraph-BrWH-BOV.mjs +0 -147
- package/dist/patch-Cdp5WKJz.d.mts +0 -53
- package/dist/patch-IZ13tXTu.mjs +0 -36
- package/dist/prepare-Bdk8Cjkf.mjs +0 -122
- package/dist/prepare-CPAvcv6q.d.mts +0 -63
- package/dist/strike-hWxShOgb.mjs +0 -50
- package/dist/styles-QSX3RhxK.mjs +0 -285
- package/dist/styles-ugspkrxz.d.mts +0 -85
- package/dist/table-DrA12lxX.mjs +0 -159
- package/dist/table-cell-DmkfYwDc.mjs +0 -112
- package/dist/table-header-Bwr5GKWg.mjs +0 -112
- package/dist/table-row-vew1y7WH.mjs +0 -84
- package/dist/task-item-BnlXGrIG.mjs +0 -37
- package/dist/text-style-tMeBq5XQ.mjs +0 -151
- package/dist/tiptap-D7pl4I5U.mjs +0 -33
- package/dist/utils-BPT4tjcn.mjs +0 -333
|
@@ -1,2 +1,151 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Paragraph as Paragraph$1 } from "./tiptap.mjs";
|
|
2
|
+
import { alignmentFromElement, bordersFromElement, indentFromElement, renderParagraphStyles, shadingFromElement, spacingFromElement } from "./utils.mjs";
|
|
3
|
+
//#region src/extensions/paragraph.ts
|
|
4
|
+
/**
|
|
5
|
+
* Paragraph extension with nested office-open attrs.
|
|
6
|
+
*
|
|
7
|
+
* Attrs mirror ParagraphPropertiesOptionsBase (alignment/indent/spacing/border/
|
|
8
|
+
* shading/frame as nested objects + scalar OOXML properties). DOCX round-trip is
|
|
9
|
+
* near-identity: renderDocx/parseDocx pass attrs through; CSS conversion happens
|
|
10
|
+
* only in renderHTML via utils mappers.
|
|
11
|
+
*/
|
|
12
|
+
const SECTION_ATTR_KEYS = new Set([
|
|
13
|
+
"sectionProperties",
|
|
14
|
+
"sectionHeaders",
|
|
15
|
+
"sectionFooters"
|
|
16
|
+
]);
|
|
17
|
+
function renderDocx(node) {
|
|
18
|
+
const attrs = node.attrs ?? {};
|
|
19
|
+
const opts = {};
|
|
20
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
21
|
+
if (value === null || value === void 0) continue;
|
|
22
|
+
if (SECTION_ATTR_KEYS.has(key)) continue;
|
|
23
|
+
if (key === "styleId") {
|
|
24
|
+
opts.style = value;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
opts[key] = value;
|
|
28
|
+
}
|
|
29
|
+
return opts;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Structural/semantic keys handled elsewhere (heading ext, list handling, run/text
|
|
33
|
+
* children). NOTE: `run` is intentionally NOT skipped — ParagraphOptions.run (the
|
|
34
|
+
* paragraph's default run properties: font/size/color) is kept as an attr for
|
|
35
|
+
* lossless round-trip (e.g. header/footer paragraphs whose styling lives there).
|
|
36
|
+
*/
|
|
37
|
+
const SKIP_KEYS = new Set([
|
|
38
|
+
"heading",
|
|
39
|
+
"style",
|
|
40
|
+
"bullet",
|
|
41
|
+
"numbering",
|
|
42
|
+
"children",
|
|
43
|
+
"text",
|
|
44
|
+
"thematicBreak"
|
|
45
|
+
]);
|
|
46
|
+
function parseDocx(opts) {
|
|
47
|
+
const resolved = typeof opts === "string" ? { text: opts } : opts;
|
|
48
|
+
const attrs = {};
|
|
49
|
+
if (resolved.style) attrs.styleId = resolved.style;
|
|
50
|
+
for (const [key, value] of Object.entries(resolved)) {
|
|
51
|
+
if (SKIP_KEYS.has(key)) continue;
|
|
52
|
+
attrs[key] = value ?? null;
|
|
53
|
+
}
|
|
54
|
+
return attrs;
|
|
55
|
+
}
|
|
56
|
+
const attrNative = () => ({
|
|
57
|
+
default: null,
|
|
58
|
+
parseHTML: () => null,
|
|
59
|
+
rendered: false
|
|
60
|
+
});
|
|
61
|
+
const Paragraph = Paragraph$1.extend({
|
|
62
|
+
addAttributes() {
|
|
63
|
+
return {
|
|
64
|
+
...this.parent?.(),
|
|
65
|
+
styleId: {
|
|
66
|
+
default: null,
|
|
67
|
+
parseHTML: (el) => {
|
|
68
|
+
const m = (el.getAttribute("class") || "").match(/(?:^|\s)docx-style-(\S+)/);
|
|
69
|
+
return m ? m[1] : null;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
alignment: {
|
|
73
|
+
default: null,
|
|
74
|
+
rendered: false,
|
|
75
|
+
parseHTML: (el) => alignmentFromElement(el)
|
|
76
|
+
},
|
|
77
|
+
indent: {
|
|
78
|
+
default: null,
|
|
79
|
+
rendered: false,
|
|
80
|
+
parseHTML: (el) => indentFromElement(el)
|
|
81
|
+
},
|
|
82
|
+
spacing: {
|
|
83
|
+
default: null,
|
|
84
|
+
rendered: false,
|
|
85
|
+
parseHTML: (el) => spacingFromElement(el)
|
|
86
|
+
},
|
|
87
|
+
shading: {
|
|
88
|
+
default: null,
|
|
89
|
+
rendered: false,
|
|
90
|
+
parseHTML: (el) => shadingFromElement(el)
|
|
91
|
+
},
|
|
92
|
+
border: {
|
|
93
|
+
default: null,
|
|
94
|
+
rendered: false,
|
|
95
|
+
parseHTML: (el) => bordersFromElement(el)
|
|
96
|
+
},
|
|
97
|
+
frame: attrNative(),
|
|
98
|
+
run: attrNative(),
|
|
99
|
+
sectionProperties: attrNative(),
|
|
100
|
+
sectionHeaders: attrNative(),
|
|
101
|
+
sectionFooters: attrNative(),
|
|
102
|
+
keepNext: attrNative(),
|
|
103
|
+
keepLines: attrNative(),
|
|
104
|
+
pageBreakBefore: attrNative(),
|
|
105
|
+
widowControl: attrNative(),
|
|
106
|
+
contextualSpacing: attrNative(),
|
|
107
|
+
bidirectional: attrNative(),
|
|
108
|
+
outlineLevel: attrNative(),
|
|
109
|
+
textDirection: attrNative(),
|
|
110
|
+
textAlignment: attrNative(),
|
|
111
|
+
suppressLineNumbers: attrNative(),
|
|
112
|
+
wordWrap: attrNative(),
|
|
113
|
+
overflowPunctuation: attrNative(),
|
|
114
|
+
autoSpaceEastAsianText: attrNative(),
|
|
115
|
+
suppressOverlap: attrNative(),
|
|
116
|
+
suppressAutoHyphens: attrNative(),
|
|
117
|
+
adjustRightInd: attrNative(),
|
|
118
|
+
snapToGrid: attrNative(),
|
|
119
|
+
mirrorIndents: attrNative(),
|
|
120
|
+
kinsoku: attrNative(),
|
|
121
|
+
topLinePunct: attrNative(),
|
|
122
|
+
autoSpaceDE: attrNative(),
|
|
123
|
+
textboxTightWrap: attrNative(),
|
|
124
|
+
rightTabStop: attrNative(),
|
|
125
|
+
leftTabStop: attrNative(),
|
|
126
|
+
divId: attrNative(),
|
|
127
|
+
tabStops: attrNative(),
|
|
128
|
+
cnfStyle: attrNative()
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
132
|
+
let hasContent = false;
|
|
133
|
+
node.forEach?.((child) => {
|
|
134
|
+
if (child.isText || child.type?.name === "hardBreak" || child.type?.name === "image") hasContent = true;
|
|
135
|
+
});
|
|
136
|
+
const styles = renderParagraphStyles(node.attrs, { empty: !hasContent });
|
|
137
|
+
const attrs = { ...HTMLAttributes };
|
|
138
|
+
const styleId = node.attrs.styleId;
|
|
139
|
+
attrs.class = styleId ? `docx-style-${styleId}` : "docx-default";
|
|
140
|
+
if (styles.length > 0) attrs.style = styles.join(";");
|
|
141
|
+
return [
|
|
142
|
+
"p",
|
|
143
|
+
attrs,
|
|
144
|
+
0
|
|
145
|
+
];
|
|
146
|
+
},
|
|
147
|
+
renderDocx,
|
|
148
|
+
parseDocx
|
|
149
|
+
});
|
|
150
|
+
//#endregion
|
|
2
151
|
export { Paragraph, parseDocx, renderDocx };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { h as Passthrough } from "../core-C9VunJ8o.mjs";
|
|
2
2
|
export { Passthrough };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { h as Passthrough } from "../core-DT9IrTzN.mjs";
|
|
2
2
|
export { Passthrough };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as Extension } from "../core-
|
|
1
|
+
import { r as Extension } from "../core-C9VunJ8o.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/extensions/section-break.d.ts
|
|
4
4
|
/**
|
|
@@ -14,12 +14,29 @@ import { r as Extension } from "../core-fBMCCj4D.mjs";
|
|
|
14
14
|
* The final section's sectPr rides on doc.attrs.sectionProperties (it lives at
|
|
15
15
|
* <w:body>'s end in OOXML). Single-section documents have no section-carrying
|
|
16
16
|
* paragraph at all.
|
|
17
|
+
*
|
|
18
|
+
* Next Page semantics: `setSectionBreak` stamps sectionProperties on the current
|
|
19
|
+
* paragraph (making it the section's last paragraph) AND inserts a fresh empty
|
|
20
|
+
* paragraph after it (the next section's first paragraph), then moves the
|
|
21
|
+
* selection into that new paragraph. The page-plugin's `forcesPageBreakAfter`
|
|
22
|
+
* treats a sectionProperties-bearing paragraph as a page break, so repaginate
|
|
23
|
+
* pushes the new paragraph onto the next page — and the caret follows. This
|
|
24
|
+
* mirrors Word's "Section Break (Next Page)".
|
|
25
|
+
*
|
|
26
|
+
* Split hygiene: pressing Enter inside a section-carrying paragraph must NOT
|
|
27
|
+
* split it. A split would place the new paragraph past the section boundary —
|
|
28
|
+
* forcesPageBreakAfter then pushes it onto the next page (next section), and
|
|
29
|
+
* splitBlock would copy sectionProperties onto it (a second break mark). Word
|
|
30
|
+
* instead inserts a fresh paragraph BEFORE the section's last paragraph, so the
|
|
31
|
+
* new paragraph stays in this section and the stamped paragraph remains last.
|
|
32
|
+
* The Enter shortcut does exactly that; non-section paragraphs fall through to
|
|
33
|
+
* the default Enter unchanged.
|
|
17
34
|
*/
|
|
18
35
|
declare const SectionBreak: Extension<any, any>;
|
|
19
36
|
declare module "@tiptap/core" {
|
|
20
37
|
interface Commands<ReturnType> {
|
|
21
38
|
sectionBreak: {
|
|
22
|
-
/**
|
|
39
|
+
/** Insert a Next Page section break at the current paragraph. */setSectionBreak: () => ReturnType;
|
|
23
40
|
};
|
|
24
41
|
}
|
|
25
42
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { m as SectionBreak } from "../core-DT9IrTzN.mjs";
|
|
2
2
|
export { SectionBreak };
|
|
@@ -1,2 +1,50 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Strike as Strike$1 } from "./tiptap.mjs";
|
|
2
|
+
//#region src/extensions/strike.ts
|
|
3
|
+
/**
|
|
4
|
+
* Strike mark extension with nested office-open attrs.
|
|
5
|
+
*
|
|
6
|
+
* OOXML represents strikethrough on a run via two mutually exclusive booleans:
|
|
7
|
+
* `strike` (single) and `doubleStrike` (double). The mark itself is "single
|
|
8
|
+
* strikethrough"; the `doubleStrike` attr flips it to double. DOCX round-trip
|
|
9
|
+
* is near-identity for the doubleStrike flag; `strike` itself is implied by the
|
|
10
|
+
* mark's presence and handled in renderDocx/parseDocx.
|
|
11
|
+
*
|
|
12
|
+
* Mark attribute-level renderHTML is delegated to the base Strike extension
|
|
13
|
+
* (renders `<s>`); only the DOCX flag needs custom handling.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* attrs → run properties.
|
|
17
|
+
*
|
|
18
|
+
* The mark presence itself means single strikethrough. When `doubleStrike` is
|
|
19
|
+
* set, emit the OOXML double-strike flag instead (the two are mutually
|
|
20
|
+
* exclusive in OOXML). DocxManager calls this with `mark.attrs`.
|
|
21
|
+
*/
|
|
22
|
+
function renderDocx(attrs) {
|
|
23
|
+
return attrs.doubleStrike ? { doubleStrike: true } : { strike: true };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* run properties → attrs.
|
|
27
|
+
*
|
|
28
|
+
* Only the `doubleStrike` flag needs to round-trip; single strike is implied by
|
|
29
|
+
* the mark's existence. `strike` is structural/semantic (the mark) and skipped.
|
|
30
|
+
*/
|
|
31
|
+
function parseDocx(runOpts) {
|
|
32
|
+
return { doubleStrike: runOpts.doubleStrike ?? null };
|
|
33
|
+
}
|
|
34
|
+
const attrNative = () => ({
|
|
35
|
+
default: null,
|
|
36
|
+
parseHTML: () => null,
|
|
37
|
+
rendered: false
|
|
38
|
+
});
|
|
39
|
+
const Strike = Strike$1.extend({
|
|
40
|
+
addAttributes() {
|
|
41
|
+
return {
|
|
42
|
+
...this.parent?.(),
|
|
43
|
+
doubleStrike: attrNative()
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
renderDocx,
|
|
47
|
+
parseDocx
|
|
48
|
+
});
|
|
49
|
+
//#endregion
|
|
2
50
|
export { Strike, parseDocx, renderDocx };
|
|
@@ -1,2 +1,112 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TableCell as TableCell$1 } from "./tiptap.mjs";
|
|
2
|
+
import { bordersFromElement, renderTableCellStyles, shadingFromElement } from "./utils.mjs";
|
|
3
|
+
//#region src/extensions/table-cell.ts
|
|
4
|
+
/**
|
|
5
|
+
* Table cell extension with nested office-open attrs.
|
|
6
|
+
*
|
|
7
|
+
* Attrs mirror TableCellPropertiesOptionsBase (shading/margins/borders/width as
|
|
8
|
+
* nested objects + scalar OOXML properties) plus the inherited Tiptap structural
|
|
9
|
+
* names colspan/rowspan/colwidth/align (rendered: false for the OOXML-named ones).
|
|
10
|
+
* DOCX round-trip is near-identity: renderDocx/parseDocx pass OOXML-native attrs
|
|
11
|
+
* through and only map the Tiptap structural names colspan/rowspan/colwidth to
|
|
12
|
+
* OOXML columnSpan/rowSpan/width. CSS conversion happens solely in renderHTML via
|
|
13
|
+
* utils.renderTableCellStyles (consuming nested shading/verticalAlign/noWrap).
|
|
14
|
+
*/
|
|
15
|
+
/** Tiptap structural attrs expressed via OOXML structural fields, not passed through. */
|
|
16
|
+
const SKIP_KEYS = new Set([
|
|
17
|
+
"colspan",
|
|
18
|
+
"rowspan",
|
|
19
|
+
"colwidth",
|
|
20
|
+
"children"
|
|
21
|
+
]);
|
|
22
|
+
function renderDocx(node) {
|
|
23
|
+
const attrs = node.attrs ?? {};
|
|
24
|
+
const opts = {};
|
|
25
|
+
const colspan = attrs.colspan;
|
|
26
|
+
if (colspan && colspan > 1) opts.columnSpan = colspan;
|
|
27
|
+
const rowspan = attrs.rowspan;
|
|
28
|
+
if (rowspan && rowspan > 1) opts.rowSpan = rowspan;
|
|
29
|
+
const colwidth = attrs.colwidth;
|
|
30
|
+
if (colwidth && colwidth.length > 0) {
|
|
31
|
+
const totalPx = colwidth.reduce((sum, w) => sum + (w || 0), 0);
|
|
32
|
+
if (totalPx > 0) opts.width = {
|
|
33
|
+
size: totalPx * 15,
|
|
34
|
+
type: "dxa"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
38
|
+
if (SKIP_KEYS.has(key)) continue;
|
|
39
|
+
if (value !== null && value !== void 0) opts[key] = value;
|
|
40
|
+
}
|
|
41
|
+
return opts;
|
|
42
|
+
}
|
|
43
|
+
function parseDocx(opts) {
|
|
44
|
+
const resolved = typeof opts === "string" ? { text: opts } : opts;
|
|
45
|
+
const attrs = {};
|
|
46
|
+
if (resolved.columnSpan != null) attrs.colspan = resolved.columnSpan;
|
|
47
|
+
if (resolved.rowSpan != null) attrs.rowspan = resolved.rowSpan;
|
|
48
|
+
if (resolved.width) {
|
|
49
|
+
const twips = resolved.width.size ?? 0;
|
|
50
|
+
if (twips) attrs.colwidth = [Math.round(twips / 15)];
|
|
51
|
+
}
|
|
52
|
+
for (const [key, value] of Object.entries(resolved)) {
|
|
53
|
+
if (key === "columnSpan" || key === "rowSpan" || key === "width" || key === "children") continue;
|
|
54
|
+
attrs[key] = value ?? null;
|
|
55
|
+
}
|
|
56
|
+
return attrs;
|
|
57
|
+
}
|
|
58
|
+
const attrNative = () => ({
|
|
59
|
+
default: null,
|
|
60
|
+
parseHTML: () => null,
|
|
61
|
+
rendered: false
|
|
62
|
+
});
|
|
63
|
+
const TableCell = TableCell$1.extend({
|
|
64
|
+
addAttributes() {
|
|
65
|
+
return {
|
|
66
|
+
...this.parent?.(),
|
|
67
|
+
shading: {
|
|
68
|
+
default: null,
|
|
69
|
+
rendered: false,
|
|
70
|
+
parseHTML: (el) => shadingFromElement(el)
|
|
71
|
+
},
|
|
72
|
+
borders: {
|
|
73
|
+
default: null,
|
|
74
|
+
rendered: false,
|
|
75
|
+
parseHTML: (el) => bordersFromElement(el)
|
|
76
|
+
},
|
|
77
|
+
verticalAlign: {
|
|
78
|
+
default: null,
|
|
79
|
+
rendered: false,
|
|
80
|
+
parseHTML: (el) => el.style.verticalAlign || null
|
|
81
|
+
},
|
|
82
|
+
textDirection: attrNative(),
|
|
83
|
+
width: attrNative(),
|
|
84
|
+
margins: attrNative(),
|
|
85
|
+
noWrap: {
|
|
86
|
+
default: null,
|
|
87
|
+
rendered: false,
|
|
88
|
+
parseHTML: (el) => el.style.whiteSpace === "nowrap" ? true : null
|
|
89
|
+
},
|
|
90
|
+
verticalMerge: attrNative(),
|
|
91
|
+
horizontalMerge: attrNative(),
|
|
92
|
+
fitText: attrNative(),
|
|
93
|
+
hideMark: attrNative(),
|
|
94
|
+
headers: attrNative(),
|
|
95
|
+
cnfStyle: attrNative()
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
99
|
+
const styles = renderTableCellStyles(node.attrs);
|
|
100
|
+
const attrs = { ...HTMLAttributes };
|
|
101
|
+
if (styles.length > 0) attrs.style = styles.join(";");
|
|
102
|
+
return [
|
|
103
|
+
"td",
|
|
104
|
+
attrs,
|
|
105
|
+
0
|
|
106
|
+
];
|
|
107
|
+
},
|
|
108
|
+
renderDocx,
|
|
109
|
+
parseDocx
|
|
110
|
+
});
|
|
111
|
+
//#endregion
|
|
2
112
|
export { TableCell, parseDocx, renderDocx };
|
|
@@ -1,2 +1,112 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TableHeader as TableHeader$1 } from "./tiptap.mjs";
|
|
2
|
+
import { bordersFromElement, renderTableCellStyles, shadingFromElement } from "./utils.mjs";
|
|
3
|
+
//#region src/extensions/table-header.ts
|
|
4
|
+
/**
|
|
5
|
+
* Table header extension with nested office-open attrs (mirrors TableCell).
|
|
6
|
+
*
|
|
7
|
+
* Attrs mirror TableCellPropertiesOptionsBase (shading/margins/borders/width as
|
|
8
|
+
* nested objects + scalar OOXML properties) plus the inherited Tiptap structural
|
|
9
|
+
* names colspan/rowspan/colwidth/align (rendered: false for the OOXML-named ones).
|
|
10
|
+
* DOCX round-trip is near-identity: renderDocx/parseDocx pass OOXML-native attrs
|
|
11
|
+
* through and only map the Tiptap structural names colspan/rowspan/colwidth to
|
|
12
|
+
* OOXML columnSpan/rowSpan/width. CSS conversion happens solely in renderHTML via
|
|
13
|
+
* utils.renderTableCellStyles (consuming nested shading/verticalAlign/noWrap).
|
|
14
|
+
*/
|
|
15
|
+
/** Tiptap structural attrs expressed via OOXML structural fields, not passed through. */
|
|
16
|
+
const SKIP_KEYS = new Set([
|
|
17
|
+
"colspan",
|
|
18
|
+
"rowspan",
|
|
19
|
+
"colwidth",
|
|
20
|
+
"children"
|
|
21
|
+
]);
|
|
22
|
+
function renderDocx(node) {
|
|
23
|
+
const attrs = node.attrs ?? {};
|
|
24
|
+
const opts = {};
|
|
25
|
+
const colspan = attrs.colspan;
|
|
26
|
+
if (colspan && colspan > 1) opts.columnSpan = colspan;
|
|
27
|
+
const rowspan = attrs.rowspan;
|
|
28
|
+
if (rowspan && rowspan > 1) opts.rowSpan = rowspan;
|
|
29
|
+
const colwidth = attrs.colwidth;
|
|
30
|
+
if (colwidth && colwidth.length > 0) {
|
|
31
|
+
const totalPx = colwidth.reduce((sum, w) => sum + (w || 0), 0);
|
|
32
|
+
if (totalPx > 0) opts.width = {
|
|
33
|
+
size: totalPx * 15,
|
|
34
|
+
type: "dxa"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
38
|
+
if (SKIP_KEYS.has(key)) continue;
|
|
39
|
+
if (value !== null && value !== void 0) opts[key] = value;
|
|
40
|
+
}
|
|
41
|
+
return opts;
|
|
42
|
+
}
|
|
43
|
+
function parseDocx(opts) {
|
|
44
|
+
const resolved = typeof opts === "string" ? { text: opts } : opts;
|
|
45
|
+
const attrs = {};
|
|
46
|
+
if (resolved.columnSpan != null) attrs.colspan = resolved.columnSpan;
|
|
47
|
+
if (resolved.rowSpan != null) attrs.rowspan = resolved.rowSpan;
|
|
48
|
+
if (resolved.width) {
|
|
49
|
+
const twips = resolved.width.size ?? 0;
|
|
50
|
+
if (twips) attrs.colwidth = [Math.round(twips / 15)];
|
|
51
|
+
}
|
|
52
|
+
for (const [key, value] of Object.entries(resolved)) {
|
|
53
|
+
if (key === "columnSpan" || key === "rowSpan" || key === "width" || key === "children") continue;
|
|
54
|
+
attrs[key] = value ?? null;
|
|
55
|
+
}
|
|
56
|
+
return attrs;
|
|
57
|
+
}
|
|
58
|
+
const attrNative = () => ({
|
|
59
|
+
default: null,
|
|
60
|
+
parseHTML: () => null,
|
|
61
|
+
rendered: false
|
|
62
|
+
});
|
|
63
|
+
const TableHeader = TableHeader$1.extend({
|
|
64
|
+
addAttributes() {
|
|
65
|
+
return {
|
|
66
|
+
...this.parent?.(),
|
|
67
|
+
shading: {
|
|
68
|
+
default: null,
|
|
69
|
+
rendered: false,
|
|
70
|
+
parseHTML: (el) => shadingFromElement(el)
|
|
71
|
+
},
|
|
72
|
+
borders: {
|
|
73
|
+
default: null,
|
|
74
|
+
rendered: false,
|
|
75
|
+
parseHTML: (el) => bordersFromElement(el)
|
|
76
|
+
},
|
|
77
|
+
verticalAlign: {
|
|
78
|
+
default: null,
|
|
79
|
+
rendered: false,
|
|
80
|
+
parseHTML: (el) => el.style.verticalAlign || null
|
|
81
|
+
},
|
|
82
|
+
textDirection: attrNative(),
|
|
83
|
+
width: attrNative(),
|
|
84
|
+
margins: attrNative(),
|
|
85
|
+
noWrap: {
|
|
86
|
+
default: null,
|
|
87
|
+
rendered: false,
|
|
88
|
+
parseHTML: (el) => el.style.whiteSpace === "nowrap" ? true : null
|
|
89
|
+
},
|
|
90
|
+
verticalMerge: attrNative(),
|
|
91
|
+
horizontalMerge: attrNative(),
|
|
92
|
+
fitText: attrNative(),
|
|
93
|
+
hideMark: attrNative(),
|
|
94
|
+
headers: attrNative(),
|
|
95
|
+
cnfStyle: attrNative()
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
99
|
+
const styles = renderTableCellStyles(node.attrs);
|
|
100
|
+
const attrs = { ...HTMLAttributes };
|
|
101
|
+
if (styles.length > 0) attrs.style = styles.join(";");
|
|
102
|
+
return [
|
|
103
|
+
"th",
|
|
104
|
+
attrs,
|
|
105
|
+
0
|
|
106
|
+
];
|
|
107
|
+
},
|
|
108
|
+
renderDocx,
|
|
109
|
+
parseDocx
|
|
110
|
+
});
|
|
111
|
+
//#endregion
|
|
2
112
|
export { TableHeader, parseDocx, renderDocx };
|
|
@@ -1,2 +1,84 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TableRow as TableRow$1 } from "./tiptap.mjs";
|
|
2
|
+
import { cssToTwip } from "./utils.mjs";
|
|
3
|
+
//#region src/extensions/table-row.ts
|
|
4
|
+
/**
|
|
5
|
+
* Table row extension with nested office-open attrs.
|
|
6
|
+
*
|
|
7
|
+
* Attrs mirror TableRowPropertiesOptionsBase (cantSplit/tableHeader/hidden as
|
|
8
|
+
* booleans; height as a nested { value, rule } object; cellSpacing as a native
|
|
9
|
+
* value; widthBefore/widthAfter as TableWidthProperties; etc.). DOCX round-trip
|
|
10
|
+
* is near-identity: renderDocx/parseDocx pass attrs through (omitting the
|
|
11
|
+
* `cells` structural key that DocxManager owns). CSS conversion happens only
|
|
12
|
+
* in renderHTML.
|
|
13
|
+
*/
|
|
14
|
+
/** Structural keys filled by DocxManager (compileTableNode). */
|
|
15
|
+
const SKIP_KEYS = new Set(["cells"]);
|
|
16
|
+
function renderDocx(node) {
|
|
17
|
+
const attrs = node.attrs ?? {};
|
|
18
|
+
const opts = {};
|
|
19
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
20
|
+
if (SKIP_KEYS.has(key)) continue;
|
|
21
|
+
if (value !== null && value !== void 0) opts[key] = value;
|
|
22
|
+
}
|
|
23
|
+
return opts;
|
|
24
|
+
}
|
|
25
|
+
function parseDocx(opts) {
|
|
26
|
+
const attrs = {};
|
|
27
|
+
for (const [key, value] of Object.entries(opts)) {
|
|
28
|
+
if (SKIP_KEYS.has(key)) continue;
|
|
29
|
+
attrs[key] = value ?? null;
|
|
30
|
+
}
|
|
31
|
+
return attrs;
|
|
32
|
+
}
|
|
33
|
+
const attrNative = () => ({
|
|
34
|
+
default: null,
|
|
35
|
+
parseHTML: () => null,
|
|
36
|
+
rendered: false
|
|
37
|
+
});
|
|
38
|
+
const TableRow = TableRow$1.extend({
|
|
39
|
+
addAttributes() {
|
|
40
|
+
return {
|
|
41
|
+
...this.parent?.(),
|
|
42
|
+
height: {
|
|
43
|
+
default: null,
|
|
44
|
+
rendered: false,
|
|
45
|
+
parseHTML: (el) => {
|
|
46
|
+
const twips = cssToTwip(el.style.height || el.getAttribute("height") || "");
|
|
47
|
+
return twips != null ? {
|
|
48
|
+
value: twips,
|
|
49
|
+
rule: "atLeast"
|
|
50
|
+
} : null;
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
cantSplit: attrNative(),
|
|
54
|
+
tableHeader: attrNative(),
|
|
55
|
+
hidden: attrNative(),
|
|
56
|
+
divId: attrNative(),
|
|
57
|
+
gridBefore: attrNative(),
|
|
58
|
+
gridAfter: attrNative(),
|
|
59
|
+
rowAlignment: attrNative(),
|
|
60
|
+
cnfStyle: attrNative(),
|
|
61
|
+
cellSpacing: attrNative(),
|
|
62
|
+
widthBefore: attrNative(),
|
|
63
|
+
widthAfter: attrNative()
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
67
|
+
const attrs = { ...HTMLAttributes };
|
|
68
|
+
const styles = [];
|
|
69
|
+
if (node.attrs.height && typeof node.attrs.height === "object") {
|
|
70
|
+
const h = node.attrs.height;
|
|
71
|
+
if (h.value != null) styles.push(`height:${h.value / 20}pt`);
|
|
72
|
+
}
|
|
73
|
+
if (styles.length > 0) attrs.style = styles.join(";");
|
|
74
|
+
return [
|
|
75
|
+
"tr",
|
|
76
|
+
attrs,
|
|
77
|
+
0
|
|
78
|
+
];
|
|
79
|
+
},
|
|
80
|
+
renderDocx,
|
|
81
|
+
parseDocx
|
|
82
|
+
});
|
|
83
|
+
//#endregion
|
|
2
84
|
export { TableRow, parseDocx, renderDocx };
|