@docen/docx 0.3.0

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.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +156 -0
  3. package/dist/converters/docx.d.mts +110 -0
  4. package/dist/converters/docx.mjs +624 -0
  5. package/dist/converters/html.d.mts +14 -0
  6. package/dist/converters/html.mjs +18 -0
  7. package/dist/converters/markdown.d.mts +13 -0
  8. package/dist/converters/markdown.mjs +18 -0
  9. package/dist/converters/patch.d.mts +53 -0
  10. package/dist/converters/patch.mjs +37 -0
  11. package/dist/converters/prepare.d.mts +51 -0
  12. package/dist/converters/prepare.mjs +76 -0
  13. package/dist/core-CFIQVRfx.mjs +88 -0
  14. package/dist/core-omBKMRtl.d.mts +34 -0
  15. package/dist/core.d.mts +2 -0
  16. package/dist/core.mjs +2 -0
  17. package/dist/editor.d.mts +21 -0
  18. package/dist/editor.mjs +20 -0
  19. package/dist/extensions/extensions.d.mts +12 -0
  20. package/dist/extensions/extensions.mjs +12 -0
  21. package/dist/extensions/heading.d.mts +2 -0
  22. package/dist/extensions/heading.mjs +145 -0
  23. package/dist/extensions/image.d.mts +2 -0
  24. package/dist/extensions/image.mjs +201 -0
  25. package/dist/extensions/index.d.mts +2 -0
  26. package/dist/extensions/index.mjs +2 -0
  27. package/dist/extensions/paragraph.d.mts +2 -0
  28. package/dist/extensions/paragraph.mjs +116 -0
  29. package/dist/extensions/strike.d.mts +2 -0
  30. package/dist/extensions/strike.mjs +50 -0
  31. package/dist/extensions/table-cell.d.mts +2 -0
  32. package/dist/extensions/table-cell.mjs +112 -0
  33. package/dist/extensions/table-header.d.mts +2 -0
  34. package/dist/extensions/table-header.mjs +112 -0
  35. package/dist/extensions/table-row.d.mts +2 -0
  36. package/dist/extensions/table-row.mjs +84 -0
  37. package/dist/extensions/table.d.mts +2 -0
  38. package/dist/extensions/table.mjs +134 -0
  39. package/dist/extensions/text-style.d.mts +2 -0
  40. package/dist/extensions/text-style.mjs +134 -0
  41. package/dist/extensions/tiptap.d.mts +2 -0
  42. package/dist/extensions/tiptap.mjs +33 -0
  43. package/dist/extensions/types.d.mts +30 -0
  44. package/dist/extensions/utils.d.mts +49 -0
  45. package/dist/extensions/utils.mjs +289 -0
  46. package/dist/heading-BvqBD2zX.d.mts +8 -0
  47. package/dist/image-Ge1y6uam.d.mts +47 -0
  48. package/dist/index.d.mts +213 -0
  49. package/dist/index.mjs +8 -0
  50. package/dist/paragraph-fhEXtAN2.d.mts +16 -0
  51. package/dist/strike-BgWGvjKr.d.mts +33 -0
  52. package/dist/table-BFkfeRp9.d.mts +9 -0
  53. package/dist/table-cell-D_FV4D2h.d.mts +8 -0
  54. package/dist/table-header-KGQ2aEkP.d.mts +8 -0
  55. package/dist/table-row-kgzYkZlW.d.mts +9 -0
  56. package/dist/text-style-BHdtXkMb.d.mts +8 -0
  57. package/dist/tiptap-TErPjuNJ.d.mts +33 -0
  58. package/package.json +106 -0
@@ -0,0 +1,201 @@
1
+ import { Image as Image$1 } from "./tiptap.mjs";
2
+ //#region src/extensions/image.ts
3
+ /**
4
+ * Custom Image extension with node-level renderHTML + renderDocx/parseDocx.
5
+ *
6
+ * Attrs:
7
+ * - src/alt/title/width/height: Tiptap structural names (kept verbatim so base
8
+ * image commands work).
9
+ * - rotation: editor display only (CSS transform) but also carried through DOCX
10
+ * via transformation.rotation (MediaTransformation.rotation).
11
+ * - floating/outline: nested office-open objects (Floating / OutlineOptions).
12
+ * - crop: nested office-open SourceRectangleOptions (srcRect).
13
+ * - display: editor-only display hint, no OOXML equivalent.
14
+ *
15
+ * DOCX round-trip is near-identity: renderDocx packs attrs into CoreImageOptions;
16
+ * parseDocx unpacks them back. src is a data URL ↔ { type, data } base64.
17
+ * Node-level renderHTML solves the style merge problem (rotation + floating).
18
+ */
19
+ /**
20
+ * Tiptap JSON image node → CoreImageOptions-shaped object.
21
+ *
22
+ * Returns `{ image: ImageOptions }` (structural wrapper) or null when no
23
+ * embedded image data is available (external URLs need pre-fetching).
24
+ * rotation is carried via transformation.rotation (not dropped).
25
+ */
26
+ function renderDocx(node) {
27
+ const attrs = node.attrs ?? {};
28
+ const imageOpts = {};
29
+ const src = attrs.src;
30
+ if (src?.startsWith("data:image/")) {
31
+ const match = src.match(/^data:image\/([\w.+-]+);base64,(.+)$/);
32
+ if (match) {
33
+ imageOpts.type = match[1] === "jpeg" ? "jpg" : match[1];
34
+ const binary = atob(match[2]);
35
+ const bytes = new Uint8Array(binary.length);
36
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
37
+ imageOpts.data = bytes;
38
+ }
39
+ }
40
+ if (!imageOpts.data) return null;
41
+ const transformation = {
42
+ width: attrs.width ?? 600,
43
+ height: attrs.height ?? 400
44
+ };
45
+ const rotation = attrs.rotation;
46
+ if (rotation != null) transformation.rotation = rotation;
47
+ imageOpts.transformation = transformation;
48
+ const altText = {};
49
+ if (attrs.alt) altText.name = attrs.alt;
50
+ if (attrs.title) altText.description = attrs.title;
51
+ if (Object.keys(altText).length > 0) imageOpts.altText = altText;
52
+ if (attrs.floating) imageOpts.floating = attrs.floating;
53
+ if (attrs.crop) imageOpts.srcRect = attrs.crop;
54
+ if (attrs.outline) imageOpts.outline = attrs.outline;
55
+ return { image: imageOpts };
56
+ }
57
+ /**
58
+ * ImageOptions-shaped object → Tiptap attrs.
59
+ *
60
+ * Near-identity unpack: transformation → width/height/rotation, altText → alt/title,
61
+ * floating/srcRect(→crop)/outline passed through verbatim. src is reconstructed by
62
+ * DocxManager from the image data bytes (kept out of parseDocx).
63
+ */
64
+ function parseDocx(imageOpts) {
65
+ const opts = imageOpts ?? {};
66
+ const attrs = {};
67
+ const transformation = opts.transformation;
68
+ if (transformation) {
69
+ if (typeof transformation.width === "number") attrs.width = transformation.width;
70
+ if (typeof transformation.height === "number") attrs.height = transformation.height;
71
+ if (typeof transformation.rotation === "number") attrs.rotation = transformation.rotation;
72
+ }
73
+ const altText = opts.altText;
74
+ if (altText) {
75
+ if (altText.name) attrs.alt = altText.name;
76
+ if (altText.description) attrs.title = altText.description;
77
+ }
78
+ if (opts.floating) attrs.floating = opts.floating;
79
+ if (opts.srcRect) attrs.crop = opts.srcRect;
80
+ if (opts.outline) attrs.outline = opts.outline;
81
+ return attrs;
82
+ }
83
+ function renderCropAttrs(crop) {
84
+ const c = crop;
85
+ const leftPct = (c.left || 0) / 1e5;
86
+ const topPct = (c.top || 0) / 1e5;
87
+ const rightPct = (c.right || 0) / 1e5;
88
+ const bottomPct = (c.bottom || 0) / 1e5;
89
+ const visibleWidthPct = 1 - leftPct - rightPct;
90
+ const visibleHeightPct = 1 - topPct - bottomPct;
91
+ const posX = visibleWidthPct > 0 ? leftPct / visibleWidthPct * 100 : 0;
92
+ const posY = visibleHeightPct > 0 ? topPct / visibleHeightPct * 100 : 0;
93
+ return { style: `object-fit:cover;object-position:${posX.toFixed(2)}% ${posY.toFixed(2)}%` };
94
+ }
95
+ function renderImageStyles(attrs) {
96
+ const styles = [];
97
+ if (attrs.display) styles.push(`display:${attrs.display}`);
98
+ if (attrs.rotation) styles.push(`transform:rotate(${attrs.rotation}deg)`);
99
+ const f = attrs.floating;
100
+ if (f) {
101
+ styles.push(f.behindDocument ? "z-index:-1" : "z-index:1");
102
+ const wrapType = f.wrap?.type ?? 0;
103
+ if (wrapType === 0) styles.push("position:absolute");
104
+ else if (wrapType === 1) {
105
+ const align = f.horizontalPosition?.align;
106
+ if (align === "left" || align === "inside") styles.push("float:left");
107
+ else if (align === "right" || align === "outside") styles.push("float:right");
108
+ else styles.push("float:left");
109
+ } else if (wrapType === 2) {
110
+ styles.push("float:left");
111
+ styles.push("shape-outside:margin-box");
112
+ } else if (wrapType === 3) {
113
+ styles.push("display:block");
114
+ styles.push("clear:both");
115
+ } else styles.push("display:inline-block");
116
+ const m = f.margins;
117
+ if (m) {
118
+ if (m.top) styles.push(`margin-top:${(m.top * 96 / 1440).toFixed(1)}pt`);
119
+ if (m.bottom) styles.push(`margin-bottom:${(m.bottom * 96 / 1440).toFixed(1)}pt`);
120
+ if (m.left) styles.push(`margin-left:${(m.left * 96 / 1440).toFixed(1)}pt`);
121
+ if (m.right) styles.push(`margin-right:${(m.right * 96 / 1440).toFixed(1)}pt`);
122
+ }
123
+ }
124
+ if (attrs.crop) {
125
+ const cropAttrs = renderCropAttrs(attrs.crop);
126
+ styles.push(cropAttrs.style);
127
+ }
128
+ return styles;
129
+ }
130
+ const Image = Image$1.extend({
131
+ addAttributes() {
132
+ return {
133
+ ...this.parent?.(),
134
+ display: {
135
+ default: null,
136
+ rendered: false,
137
+ parseHTML: () => this.options.inline ? "inline-block" : null
138
+ },
139
+ rotation: {
140
+ default: null,
141
+ rendered: false,
142
+ parseHTML: (element) => {
143
+ const match = (element.getAttribute("style") || "").match(/transform:\s*rotate\(([\d.]+)deg\)/);
144
+ return match ? parseFloat(match[1]) : null;
145
+ }
146
+ },
147
+ floating: {
148
+ default: null,
149
+ rendered: false,
150
+ parseHTML: (element) => {
151
+ const raw = element.getAttribute("data-floating");
152
+ if (!raw) return null;
153
+ try {
154
+ return JSON.parse(raw);
155
+ } catch {
156
+ return null;
157
+ }
158
+ }
159
+ },
160
+ outline: {
161
+ default: null,
162
+ rendered: false,
163
+ parseHTML: (element) => {
164
+ const raw = element.getAttribute("data-outline");
165
+ if (!raw) return null;
166
+ try {
167
+ return JSON.parse(raw);
168
+ } catch {
169
+ return null;
170
+ }
171
+ }
172
+ },
173
+ crop: {
174
+ default: null,
175
+ rendered: false,
176
+ parseHTML: (element) => {
177
+ const raw = element.getAttribute("data-crop");
178
+ if (!raw) return null;
179
+ try {
180
+ return JSON.parse(raw);
181
+ } catch {
182
+ return null;
183
+ }
184
+ }
185
+ }
186
+ };
187
+ },
188
+ renderHTML({ node, HTMLAttributes }) {
189
+ const styles = renderImageStyles(node.attrs);
190
+ const attrs = { ...HTMLAttributes };
191
+ if (styles.length > 0) attrs.style = styles.join(";");
192
+ if (node.attrs.floating) attrs["data-floating"] = JSON.stringify(node.attrs.floating);
193
+ if (node.attrs.outline) attrs["data-outline"] = JSON.stringify(node.attrs.outline);
194
+ if (node.attrs.crop) attrs["data-crop"] = JSON.stringify(node.attrs.crop);
195
+ return ["img", attrs];
196
+ },
197
+ renderDocx,
198
+ parseDocx
199
+ });
200
+ //#endregion
201
+ export { Image, parseDocx, renderCropAttrs, renderDocx };
@@ -0,0 +1,2 @@
1
+ import { c as StarterKit, d as docxExtensions, f as tiptapMarkExtensions, l as StarterKitOptions, p as tiptapNodeExtensions } from "../core-omBKMRtl.mjs";
2
+ export { StarterKit, type StarterKitOptions, docxExtensions, tiptapMarkExtensions, tiptapNodeExtensions };
@@ -0,0 +1,2 @@
1
+ import { a as StarterKit, c as tiptapMarkExtensions, l as tiptapNodeExtensions, s as docxExtensions } from "../core-CFIQVRfx.mjs";
2
+ export { StarterKit, docxExtensions, tiptapMarkExtensions, tiptapNodeExtensions };
@@ -0,0 +1,2 @@
1
+ import { n as parseDocx, r as renderDocx, t as Paragraph } from "../paragraph-fhEXtAN2.mjs";
2
+ export { Paragraph, parseDocx, renderDocx };
@@ -0,0 +1,116 @@
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
+ function renderDocx(node) {
13
+ const attrs = node.attrs ?? {};
14
+ const opts = {};
15
+ for (const [key, value] of Object.entries(attrs)) if (value !== null && value !== void 0) opts[key] = value;
16
+ return opts;
17
+ }
18
+ /** Structural/semantic keys expressed elsewhere (heading ext, list handling, run children). */
19
+ const SKIP_KEYS = new Set([
20
+ "heading",
21
+ "style",
22
+ "bullet",
23
+ "numbering",
24
+ "run",
25
+ "children",
26
+ "text",
27
+ "thematicBreak"
28
+ ]);
29
+ function parseDocx(opts) {
30
+ const resolved = typeof opts === "string" ? { text: opts } : opts;
31
+ const attrs = {};
32
+ for (const [key, value] of Object.entries(resolved)) {
33
+ if (SKIP_KEYS.has(key)) continue;
34
+ attrs[key] = value ?? null;
35
+ }
36
+ return attrs;
37
+ }
38
+ const attrNative = () => ({
39
+ default: null,
40
+ parseHTML: () => null,
41
+ rendered: false
42
+ });
43
+ const Paragraph = Paragraph$1.extend({
44
+ addAttributes() {
45
+ return {
46
+ ...this.parent?.(),
47
+ alignment: {
48
+ default: null,
49
+ rendered: false,
50
+ parseHTML: (el) => alignmentFromElement(el)
51
+ },
52
+ indent: {
53
+ default: null,
54
+ rendered: false,
55
+ parseHTML: (el) => indentFromElement(el)
56
+ },
57
+ spacing: {
58
+ default: null,
59
+ rendered: false,
60
+ parseHTML: (el) => spacingFromElement(el)
61
+ },
62
+ shading: {
63
+ default: null,
64
+ rendered: false,
65
+ parseHTML: (el) => shadingFromElement(el)
66
+ },
67
+ border: {
68
+ default: null,
69
+ rendered: false,
70
+ parseHTML: (el) => bordersFromElement(el)
71
+ },
72
+ frame: attrNative(),
73
+ keepNext: attrNative(),
74
+ keepLines: attrNative(),
75
+ pageBreakBefore: attrNative(),
76
+ widowControl: attrNative(),
77
+ contextualSpacing: attrNative(),
78
+ bidirectional: attrNative(),
79
+ outlineLevel: attrNative(),
80
+ textDirection: attrNative(),
81
+ textAlignment: attrNative(),
82
+ suppressLineNumbers: attrNative(),
83
+ wordWrap: attrNative(),
84
+ overflowPunctuation: attrNative(),
85
+ autoSpaceEastAsianText: attrNative(),
86
+ suppressOverlap: attrNative(),
87
+ suppressAutoHyphens: attrNative(),
88
+ adjustRightInd: attrNative(),
89
+ snapToGrid: attrNative(),
90
+ mirrorIndents: attrNative(),
91
+ kinsoku: attrNative(),
92
+ topLinePunct: attrNative(),
93
+ autoSpaceDE: attrNative(),
94
+ textboxTightWrap: attrNative(),
95
+ rightTabStop: attrNative(),
96
+ leftTabStop: attrNative(),
97
+ divId: attrNative(),
98
+ tabStops: attrNative(),
99
+ cnfStyle: attrNative()
100
+ };
101
+ },
102
+ renderHTML({ node, HTMLAttributes }) {
103
+ const styles = renderParagraphStyles(node.attrs);
104
+ const attrs = { ...HTMLAttributes };
105
+ if (styles.length > 0) attrs.style = styles.join(";");
106
+ return [
107
+ "p",
108
+ attrs,
109
+ 0
110
+ ];
111
+ },
112
+ renderDocx,
113
+ parseDocx
114
+ });
115
+ //#endregion
116
+ export { Paragraph, parseDocx, renderDocx };
@@ -0,0 +1,2 @@
1
+ import { n as parseDocx, r as renderDocx, t as Strike } from "../strike-BgWGvjKr.mjs";
2
+ export { Strike, parseDocx, renderDocx };
@@ -0,0 +1,50 @@
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
50
+ export { Strike, parseDocx, renderDocx };
@@ -0,0 +1,2 @@
1
+ import { n as parseDocx, r as renderDocx, t as TableCell } from "../table-cell-D_FV4D2h.mjs";
2
+ export { TableCell, parseDocx, renderDocx };
@@ -0,0 +1,112 @@
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
112
+ export { TableCell, parseDocx, renderDocx };
@@ -0,0 +1,2 @@
1
+ import { n as parseDocx, r as renderDocx, t as TableHeader } from "../table-header-KGQ2aEkP.mjs";
2
+ export { TableHeader, parseDocx, renderDocx };
@@ -0,0 +1,112 @@
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
112
+ export { TableHeader, parseDocx, renderDocx };
@@ -0,0 +1,2 @@
1
+ import { n as parseDocx, r as renderDocx, t as TableRow } from "../table-row-kgzYkZlW.mjs";
2
+ export { TableRow, parseDocx, renderDocx };