@docen/docx 0.3.0 → 0.3.1
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 +2 -3
- package/dist/blockquote-Ky9xD_Q-.mjs +31 -0
- package/dist/code-block-BgNjhADy.mjs +23 -0
- package/dist/converters/docx.d.mts +1 -109
- package/dist/converters/docx.mjs +1 -623
- package/dist/converters/html.d.mts +1 -13
- package/dist/converters/html.mjs +1 -17
- package/dist/converters/markdown.d.mts +1 -12
- package/dist/converters/markdown.mjs +1 -17
- package/dist/converters/patch.d.mts +1 -52
- package/dist/converters/patch.mjs +1 -36
- package/dist/converters/prepare.d.mts +2 -51
- package/dist/converters/prepare.mjs +2 -76
- package/dist/converters/styles.d.mts +2 -0
- package/dist/converters/styles.mjs +2 -0
- package/dist/core-DEqBHRzE.mjs +406 -0
- package/dist/core-fBMCCj4D.d.mts +97 -0
- package/dist/core.d.mts +1 -1
- package/dist/core.mjs +1 -1
- package/dist/details-Dh8luWb2.mjs +18 -0
- package/dist/dist-B6B3HnVZ.mjs +1838 -0
- package/dist/document-BH1y4qHM.d.mts +6 -0
- package/dist/document-CvTym-FM.mjs +50 -0
- package/dist/docx-C5wyjI-0.d.mts +200 -0
- package/dist/docx-CONyAedl.mjs +1231 -0
- package/dist/editor-Bf3CxQnY.mjs +21 -0
- package/dist/editor-DReY3Rb9.d.mts +21 -0
- package/dist/editor.d.mts +1 -20
- package/dist/editor.mjs +1 -19
- package/dist/emoji-BZ1dJD7d.d.mts +17 -0
- package/dist/emoji-C2OsTWR7.mjs +27 -0
- package/dist/extensions/blockquote.d.mts +23 -0
- package/dist/extensions/blockquote.mjs +3 -0
- package/dist/extensions/code-block.d.mts +19 -0
- package/dist/extensions/code-block.mjs +2 -0
- package/dist/extensions/column-break.d.mts +31 -0
- package/dist/extensions/column-break.mjs +2 -0
- package/dist/extensions/details.d.mts +19 -0
- package/dist/extensions/details.mjs +3 -0
- package/dist/extensions/document.d.mts +2 -0
- package/dist/extensions/document.mjs +2 -0
- package/dist/extensions/emoji.d.mts +2 -0
- package/dist/extensions/emoji.mjs +2 -0
- package/dist/extensions/extensions.d.mts +6 -5
- package/dist/extensions/extensions.mjs +14 -12
- package/dist/extensions/formatting-marks.d.mts +32 -0
- package/dist/extensions/formatting-marks.mjs +2 -0
- package/dist/extensions/heading.mjs +1 -144
- package/dist/extensions/image-group.d.mts +6 -0
- package/dist/extensions/image-group.mjs +2 -0
- package/dist/extensions/image.d.mts +2 -2
- package/dist/extensions/image.mjs +1 -200
- package/dist/extensions/index.d.mts +3 -2
- package/dist/extensions/index.mjs +3 -2
- package/dist/extensions/mention.d.mts +25 -0
- package/dist/extensions/mention.mjs +3 -0
- package/dist/extensions/ordered-list.d.mts +25 -0
- package/dist/extensions/ordered-list.mjs +3 -0
- package/dist/extensions/page-break.d.mts +34 -0
- package/dist/extensions/page-break.mjs +2 -0
- package/dist/extensions/paragraph.d.mts +1 -1
- package/dist/extensions/paragraph.mjs +1 -115
- package/dist/extensions/passthrough.d.mts +2 -0
- package/dist/extensions/passthrough.mjs +2 -0
- package/dist/extensions/section-break.d.mts +27 -0
- package/dist/extensions/section-break.mjs +2 -0
- package/dist/extensions/strike.mjs +1 -49
- package/dist/extensions/table-cell.mjs +1 -111
- package/dist/extensions/table-header.mjs +1 -111
- package/dist/extensions/table-row.mjs +1 -83
- package/dist/extensions/table.mjs +1 -133
- package/dist/extensions/task-item.d.mts +27 -0
- package/dist/extensions/task-item.mjs +3 -0
- package/dist/extensions/text-style.mjs +1 -133
- package/dist/extensions/tiptap.mjs +1 -32
- package/dist/extensions/types.d.mts +7 -5
- package/dist/extensions/utils.d.mts +16 -3
- package/dist/extensions/utils.mjs +2 -289
- package/dist/heading-DAubgJJN.mjs +166 -0
- package/dist/html-DCC_DSHv.d.mts +18 -0
- package/dist/html-DedDWPoO.mjs +66 -0
- package/dist/image-CuEIXoZl.mjs +334 -0
- package/dist/index.d.mts +68 -18
- package/dist/index.mjs +10 -8
- package/dist/markdown-BzJmRsBs.mjs +18 -0
- package/dist/markdown-D0k0sRYS.d.mts +13 -0
- package/dist/mention-C-dTR6MK.mjs +44 -0
- package/dist/ordered-list-V-3xFQmV.mjs +41 -0
- package/dist/paragraph-BrWH-BOV.mjs +147 -0
- package/dist/paragraph-D8mpHo_o.d.mts +8 -0
- package/dist/patch-Cdp5WKJz.d.mts +53 -0
- package/dist/patch-IZ13tXTu.mjs +36 -0
- package/dist/prepare-Bdk8Cjkf.mjs +122 -0
- package/dist/prepare-CPAvcv6q.d.mts +63 -0
- package/dist/strike-hWxShOgb.mjs +50 -0
- package/dist/styles-QSX3RhxK.mjs +285 -0
- package/dist/styles-ugspkrxz.d.mts +85 -0
- package/dist/table-DrA12lxX.mjs +159 -0
- package/dist/table-cell-DmkfYwDc.mjs +112 -0
- package/dist/table-header-Bwr5GKWg.mjs +112 -0
- package/dist/table-row-vew1y7WH.mjs +84 -0
- package/dist/task-item-BnlXGrIG.mjs +37 -0
- package/dist/text-style-tMeBq5XQ.mjs +151 -0
- package/dist/tiptap-D7pl4I5U.mjs +33 -0
- package/dist/utils-BPT4tjcn.mjs +333 -0
- package/package.json +3 -2
- package/dist/core-CFIQVRfx.mjs +0 -88
- package/dist/core-omBKMRtl.d.mts +0 -34
- package/dist/image-Ge1y6uam.d.mts +0 -47
- package/dist/paragraph-fhEXtAN2.d.mts +0 -16
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
//#region src/extensions/utils.ts
|
|
2
|
+
/** Common CSS named colors → hex */
|
|
3
|
+
const CSS_COLORS = {
|
|
4
|
+
black: "#000000",
|
|
5
|
+
white: "#FFFFFF",
|
|
6
|
+
red: "#FF0000",
|
|
7
|
+
green: "#008000",
|
|
8
|
+
blue: "#0000FF",
|
|
9
|
+
yellow: "#FFFF00",
|
|
10
|
+
cyan: "#00FFFF",
|
|
11
|
+
magenta: "#FF00FF",
|
|
12
|
+
gray: "#808080",
|
|
13
|
+
grey: "#808080",
|
|
14
|
+
orange: "#FFA500",
|
|
15
|
+
purple: "#800080",
|
|
16
|
+
pink: "#FFC0CB",
|
|
17
|
+
brown: "#A52A2A",
|
|
18
|
+
lime: "#00FF00",
|
|
19
|
+
navy: "#000080",
|
|
20
|
+
teal: "#008080",
|
|
21
|
+
silver: "#C0C0C0",
|
|
22
|
+
maroon: "#800000",
|
|
23
|
+
olive: "#808000",
|
|
24
|
+
aqua: "#00FFFF",
|
|
25
|
+
fuchsia: "#FF00FF",
|
|
26
|
+
indigo: "#4B0082",
|
|
27
|
+
violet: "#EE82EE",
|
|
28
|
+
coral: "#FF7F50",
|
|
29
|
+
gold: "#FFD700",
|
|
30
|
+
salmon: "#FA8072",
|
|
31
|
+
tomato: "#FF6347"
|
|
32
|
+
};
|
|
33
|
+
/** Normalize a CSS color value to hex (e.g., "red" → "#FF0000", "#ff0000" → "#FF0000").
|
|
34
|
+
* Accepts a string (CSS name/hex or bare OOXML hex), or an OOXML ColorOptions
|
|
35
|
+
* object ({ val, themeColor, themeTint, themeShade }) — the object form
|
|
36
|
+
* resolves to its val (the RGB fallback Word stores alongside themeColor) for
|
|
37
|
+
* CSS rendering. The themeColor/tint/shade are preserved verbatim in the attrs
|
|
38
|
+
* and round-trip back to the DOCX (see text-style/paragraph parseDocx), so
|
|
39
|
+
* theme semantics survive even though only val is rendered here. A pure theme
|
|
40
|
+
* reference with no val (rare — Word usually stores both) would need theme.xml
|
|
41
|
+
* to resolve and is left unset. */
|
|
42
|
+
function normalizeColorToHex(color) {
|
|
43
|
+
if (!color) return void 0;
|
|
44
|
+
if (typeof color === "object") {
|
|
45
|
+
const { val } = color;
|
|
46
|
+
return val ? normalizeColorToHex(val) : void 0;
|
|
47
|
+
}
|
|
48
|
+
if (typeof color !== "string") return void 0;
|
|
49
|
+
if (color === "auto") return void 0;
|
|
50
|
+
if (color.startsWith("#")) return color.length === 4 ? `#${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}`.toUpperCase() : color.toUpperCase();
|
|
51
|
+
if (/^[0-9A-Fa-f]{6}$/.test(color)) return `#${color.toUpperCase()}`;
|
|
52
|
+
if (/^[0-9A-Fa-f]{3}$/.test(color)) return `#${color[0]}${color[0]}${color[1]}${color[1]}${color[2]}${color[2]}`.toUpperCase();
|
|
53
|
+
return CSS_COLORS[color.toLowerCase()] ?? void 0;
|
|
54
|
+
}
|
|
55
|
+
/** Resolve a font value (string or OOXML rFonts { ascii, eastAsia, hAnsi, cs }) to a CSS family name. */
|
|
56
|
+
function resolveFontName(font) {
|
|
57
|
+
if (!font) return null;
|
|
58
|
+
if (typeof font === "string") return font;
|
|
59
|
+
if (typeof font === "object") {
|
|
60
|
+
const f = font;
|
|
61
|
+
return f.ascii || f.hAnsi || f.eastAsia || null;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
/** CSS value (e.g., "18pt") → twip number. 1 pt = 20 twips, 1 px = 15 twips (96 DPI). */
|
|
66
|
+
function cssToTwip(value) {
|
|
67
|
+
if (!value) return void 0;
|
|
68
|
+
const match = value.match(/^([\d.]+)(pt|px|em|cm|in)?$/);
|
|
69
|
+
if (!match) return void 0;
|
|
70
|
+
const num = parseFloat(match[1]);
|
|
71
|
+
switch (match[2] ?? "pt") {
|
|
72
|
+
case "pt": return Math.round(num * 20);
|
|
73
|
+
case "px": return Math.round(num * 15);
|
|
74
|
+
case "in": return Math.round(num * 1440);
|
|
75
|
+
case "cm": return Math.round(num * 567);
|
|
76
|
+
case "em": return Math.round(num * 240);
|
|
77
|
+
default: return Math.round(num * 20);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Twip value → CSS string (e.g., 360 → "18pt"). */
|
|
81
|
+
function twipToCss(value) {
|
|
82
|
+
if (value == null) return null;
|
|
83
|
+
if (typeof value === "string") return value;
|
|
84
|
+
return `${value / 20}pt`;
|
|
85
|
+
}
|
|
86
|
+
const ALIGNMENT_TO_CSS = {
|
|
87
|
+
left: "left",
|
|
88
|
+
center: "center",
|
|
89
|
+
right: "right",
|
|
90
|
+
start: "start",
|
|
91
|
+
end: "end",
|
|
92
|
+
both: "justify",
|
|
93
|
+
distribute: "justify"
|
|
94
|
+
};
|
|
95
|
+
const CSS_TO_ALIGNMENT = {
|
|
96
|
+
left: "left",
|
|
97
|
+
center: "center",
|
|
98
|
+
right: "right",
|
|
99
|
+
start: "start",
|
|
100
|
+
end: "end",
|
|
101
|
+
justify: "both"
|
|
102
|
+
};
|
|
103
|
+
/** OOXML alignment → CSS text-align. */
|
|
104
|
+
function alignmentToCss(alignment) {
|
|
105
|
+
if (!alignment) return null;
|
|
106
|
+
return ALIGNMENT_TO_CSS[alignment] ?? null;
|
|
107
|
+
}
|
|
108
|
+
/** CSS text-align → OOXML alignment. */
|
|
109
|
+
function alignmentFromCss(css) {
|
|
110
|
+
if (!css) return null;
|
|
111
|
+
return CSS_TO_ALIGNMENT[css] ?? null;
|
|
112
|
+
}
|
|
113
|
+
/** Shading.fill → CSS background-color hex. */
|
|
114
|
+
function shadingToCss(shading) {
|
|
115
|
+
if (!shading?.fill) return null;
|
|
116
|
+
return normalizeColorToHex(shading.fill) ?? null;
|
|
117
|
+
}
|
|
118
|
+
/** CSS background-color → ShadingAttributesProperties (fill normalized to hex). */
|
|
119
|
+
function shadingFromCss(css) {
|
|
120
|
+
const hex = normalizeColorToHex(css ?? void 0);
|
|
121
|
+
return hex ? {
|
|
122
|
+
fill: hex,
|
|
123
|
+
type: "clear"
|
|
124
|
+
} : null;
|
|
125
|
+
}
|
|
126
|
+
function lineSpacingToCss(spacing) {
|
|
127
|
+
if (!spacing?.line) return null;
|
|
128
|
+
const rule = spacing.lineRule;
|
|
129
|
+
if (rule === "exact" || rule === "exactly" || rule === "atLeast") return `${spacing.line / 20}pt`;
|
|
130
|
+
return `calc(var(--docen-line-pitch, 1em) * ${Number((spacing.line / 240).toFixed(2))})`;
|
|
131
|
+
}
|
|
132
|
+
function sizeToCss(size) {
|
|
133
|
+
if (size == null) return null;
|
|
134
|
+
return `${size}pt`;
|
|
135
|
+
}
|
|
136
|
+
function sizeFromCss(css) {
|
|
137
|
+
if (!css) return null;
|
|
138
|
+
const m = css.match(/^([\d.]+)(pt|px)?$/);
|
|
139
|
+
if (!m) return null;
|
|
140
|
+
const num = parseFloat(m[1]);
|
|
141
|
+
return (m[2] ?? "pt") === "px" ? num * .75 : num;
|
|
142
|
+
}
|
|
143
|
+
function characterSpacingToCss(spacing) {
|
|
144
|
+
if (spacing == null) return null;
|
|
145
|
+
return `${spacing / 20}pt`;
|
|
146
|
+
}
|
|
147
|
+
function characterSpacingFromCss(css) {
|
|
148
|
+
if (!css) return null;
|
|
149
|
+
const m = css.match(/^(-?[\d.]+)pt$/);
|
|
150
|
+
return m ? Math.round(parseFloat(m[1]) * 20) : null;
|
|
151
|
+
}
|
|
152
|
+
/** Render a BorderOptions to CSS string. OOXML border.size is in eighths of a point. */
|
|
153
|
+
function renderBorderCSS(border) {
|
|
154
|
+
if (!border || !border.style || border.style === "none" || border.style === "nil") return null;
|
|
155
|
+
const size = border.size != null ? `${border.size / 8}pt` : "1pt";
|
|
156
|
+
const cssStyle = {
|
|
157
|
+
single: "solid",
|
|
158
|
+
dashed: "dashed",
|
|
159
|
+
dotted: "dotted",
|
|
160
|
+
double: "double",
|
|
161
|
+
dotDash: "dashed",
|
|
162
|
+
dotDotDash: "dotted"
|
|
163
|
+
}[border.style || "single"] || "solid";
|
|
164
|
+
const hex = border.color && border.color !== "auto" ? normalizeColorToHex(border.color) : null;
|
|
165
|
+
return hex ? `${cssStyle} ${size} ${hex}` : `${cssStyle} ${size}`;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Compute all paragraph-level CSS styles from nested attrs.
|
|
169
|
+
* Shared by Paragraph and Heading extensions for node-level renderHTML.
|
|
170
|
+
* Attrs store office-open native values; mappers here convert to CSS.
|
|
171
|
+
*/
|
|
172
|
+
function renderParagraphStyles(attrs) {
|
|
173
|
+
const a = attrs;
|
|
174
|
+
const styles = [];
|
|
175
|
+
const align = alignmentToCss(a.alignment);
|
|
176
|
+
if (align) styles.push(`text-align:${align}`);
|
|
177
|
+
if (a.indent) {
|
|
178
|
+
const left = twipToCss(a.indent.left);
|
|
179
|
+
if (left) styles.push(`margin-left:${left}`);
|
|
180
|
+
const right = twipToCss(a.indent.right);
|
|
181
|
+
if (right) styles.push(`margin-right:${right}`);
|
|
182
|
+
if (a.indent.firstLine != null) {
|
|
183
|
+
const fl = twipToCss(a.indent.firstLine);
|
|
184
|
+
if (fl) styles.push(`text-indent:${fl}`);
|
|
185
|
+
} else if (a.indent.hanging != null) {
|
|
186
|
+
const h = twipToCss(a.indent.hanging);
|
|
187
|
+
if (h) styles.push(`text-indent:-${h}`);
|
|
188
|
+
} else if (a.indent.firstLineChars != null) styles.push(`text-indent:${a.indent.firstLineChars / 100}em`);
|
|
189
|
+
}
|
|
190
|
+
const markLineHeight = a.run?.size != null ? sizeToCss(a.run.size) : null;
|
|
191
|
+
if (markLineHeight) styles.push(`line-height:${markLineHeight}`);
|
|
192
|
+
if (a.spacing) {
|
|
193
|
+
const before = twipToCss(a.spacing.before);
|
|
194
|
+
if (before) styles.push(`margin-top:${before}`);
|
|
195
|
+
const after = twipToCss(a.spacing.after);
|
|
196
|
+
if (after) styles.push(`margin-bottom:${after}`);
|
|
197
|
+
const lh = lineSpacingToCss(a.spacing);
|
|
198
|
+
if (lh) styles.push(`line-height:${lh}`);
|
|
199
|
+
}
|
|
200
|
+
const bg = shadingToCss(a.shading);
|
|
201
|
+
if (bg) styles.push(`background-color:${bg}`, `color:contrast-color(${bg})`);
|
|
202
|
+
if (a.border) {
|
|
203
|
+
const sides = [
|
|
204
|
+
["top", a.border.top],
|
|
205
|
+
["bottom", a.border.bottom],
|
|
206
|
+
["left", a.border.left],
|
|
207
|
+
["right", a.border.right]
|
|
208
|
+
];
|
|
209
|
+
for (const [side, b] of sides) {
|
|
210
|
+
const css = b ? renderBorderCSS(b) : null;
|
|
211
|
+
if (css) styles.push(`border-${side}:${css}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return styles;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Compute run-level CSS (font/size/color/weight/…) from office-open run attrs.
|
|
218
|
+
* Shared by text-style marks and the styles→CSS generator (stylesToCss).
|
|
219
|
+
*/
|
|
220
|
+
function renderRunStyles(attrs) {
|
|
221
|
+
const a = attrs;
|
|
222
|
+
const styles = [];
|
|
223
|
+
if (a.bold) styles.push("font-weight:bold");
|
|
224
|
+
if (a.italic) styles.push("font-style:italic");
|
|
225
|
+
if (a.smallCaps) styles.push("font-variant:small-caps");
|
|
226
|
+
if (a.allCaps) styles.push("text-transform:uppercase");
|
|
227
|
+
const deco = [];
|
|
228
|
+
if (a.underline) deco.push("underline");
|
|
229
|
+
if (a.strike || a.doubleStrike) deco.push("line-through");
|
|
230
|
+
if (deco.length) styles.push(`text-decoration:${deco.join(" ")}`);
|
|
231
|
+
const font = resolveFontName(a.font);
|
|
232
|
+
if (font) styles.push(`font-family:${font}`);
|
|
233
|
+
const size = sizeToCss(a.size);
|
|
234
|
+
if (size) styles.push(`font-size:${size}`);
|
|
235
|
+
const color = a.color === "auto" ? void 0 : normalizeColorToHex(a.color);
|
|
236
|
+
if (color) styles.push(`color:${color}`);
|
|
237
|
+
const spacing = characterSpacingToCss(a.characterSpacing);
|
|
238
|
+
if (spacing) styles.push(`letter-spacing:${spacing}`);
|
|
239
|
+
if (a.highlight) {
|
|
240
|
+
const hl = normalizeColorToHex(typeof a.highlight === "string" ? a.highlight : null);
|
|
241
|
+
if (hl) styles.push(`background-color:${hl}`, `color:contrast-color(${hl})`);
|
|
242
|
+
}
|
|
243
|
+
return styles;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Compute table cell CSS styles from nested attrs.
|
|
247
|
+
* Shared by TableCell and TableHeader extensions.
|
|
248
|
+
*/
|
|
249
|
+
function renderTableCellStyles(attrs) {
|
|
250
|
+
const a = attrs;
|
|
251
|
+
const styles = [];
|
|
252
|
+
if (a.noWrap) styles.push("white-space:nowrap");
|
|
253
|
+
const bg = shadingToCss(a.shading);
|
|
254
|
+
if (bg) styles.push(`background-color:${bg}`, `color:contrast-color(${bg})`);
|
|
255
|
+
if (a.verticalAlign) styles.push(`vertical-align:${a.verticalAlign}`);
|
|
256
|
+
return styles;
|
|
257
|
+
}
|
|
258
|
+
/** Parse text-align → OOXML alignment. */
|
|
259
|
+
function alignmentFromElement(el) {
|
|
260
|
+
return alignmentFromCss(el.style.textAlign || null);
|
|
261
|
+
}
|
|
262
|
+
/** Parse margin-left/right + text-indent → OOXML indent (twips). */
|
|
263
|
+
function indentFromElement(el) {
|
|
264
|
+
const indent = {};
|
|
265
|
+
const left = cssToTwip(el.style.marginLeft);
|
|
266
|
+
if (left) indent.left = left;
|
|
267
|
+
const right = cssToTwip(el.style.marginRight);
|
|
268
|
+
if (right) indent.right = right;
|
|
269
|
+
const ti = el.style.textIndent;
|
|
270
|
+
if (ti) if (ti.startsWith("-")) {
|
|
271
|
+
const h = cssToTwip(ti.slice(1));
|
|
272
|
+
if (h) indent.hanging = h;
|
|
273
|
+
} else {
|
|
274
|
+
const f = cssToTwip(ti);
|
|
275
|
+
if (f) indent.firstLine = f;
|
|
276
|
+
}
|
|
277
|
+
return Object.keys(indent).length > 0 ? indent : null;
|
|
278
|
+
}
|
|
279
|
+
/** Parse margin-top/bottom + line-height → OOXML spacing (twips). */
|
|
280
|
+
function spacingFromElement(el) {
|
|
281
|
+
const spacing = {};
|
|
282
|
+
const before = cssToTwip(el.style.marginTop);
|
|
283
|
+
if (before) spacing.before = before;
|
|
284
|
+
const after = cssToTwip(el.style.marginBottom);
|
|
285
|
+
if (after) spacing.after = after;
|
|
286
|
+
const lh = el.style.lineHeight;
|
|
287
|
+
if (lh) {
|
|
288
|
+
const m = lh.match(/^([\d.]+)(pt|px)?$/);
|
|
289
|
+
if (m) {
|
|
290
|
+
const num = parseFloat(m[1]);
|
|
291
|
+
if (m[2]) {
|
|
292
|
+
spacing.line = Math.round(num * (m[2] === "px" ? 15 : 20));
|
|
293
|
+
spacing.lineRule = "exact";
|
|
294
|
+
} else {
|
|
295
|
+
spacing.line = Math.round(num * 240);
|
|
296
|
+
spacing.lineRule = "auto";
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return Object.keys(spacing).length > 0 ? spacing : null;
|
|
301
|
+
}
|
|
302
|
+
/** Parse border-* → OOXML BordersOptions. */
|
|
303
|
+
function bordersFromElement(el) {
|
|
304
|
+
const borders = {};
|
|
305
|
+
const sides = [
|
|
306
|
+
["top", el.style.borderTop],
|
|
307
|
+
["bottom", el.style.borderBottom],
|
|
308
|
+
["left", el.style.borderLeft],
|
|
309
|
+
["right", el.style.borderRight]
|
|
310
|
+
];
|
|
311
|
+
for (const [side, css] of sides) {
|
|
312
|
+
if (!css || css === "initial" || css === "none") continue;
|
|
313
|
+
const m = css.match(/^(none|solid|dashed|dotted|double)\s+([\d.]+pt)\s+(.+)$/);
|
|
314
|
+
if (!m) continue;
|
|
315
|
+
borders[side] = {
|
|
316
|
+
style: {
|
|
317
|
+
solid: "single",
|
|
318
|
+
dashed: "dashed",
|
|
319
|
+
dotted: "dotted",
|
|
320
|
+
double: "double"
|
|
321
|
+
}[m[1]] ?? "single",
|
|
322
|
+
size: Math.round(parseFloat(m[2]) * 8),
|
|
323
|
+
color: m[3]
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
return Object.keys(borders).length > 0 ? borders : null;
|
|
327
|
+
}
|
|
328
|
+
/** Parse background-color → OOXML shading. */
|
|
329
|
+
function shadingFromElement(el) {
|
|
330
|
+
return shadingFromCss(el.style.backgroundColor || null);
|
|
331
|
+
}
|
|
332
|
+
//#endregion
|
|
333
|
+
export { twipToCss as S, shadingFromElement as _, characterSpacingFromCss as a, sizeToCss as b, indentFromElement as c, renderBorderCSS as d, renderParagraphStyles as f, shadingFromCss as g, resolveFontName as h, bordersFromElement as i, lineSpacingToCss as l, renderTableCellStyles as m, alignmentFromElement as n, characterSpacingToCss as o, renderRunStyles as p, alignmentToCss as r, cssToTwip as s, alignmentFromCss as t, normalizeColorToHex as u, shadingToCss as v, spacingFromElement as x, sizeFromCss as y };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docen/docx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "DOCX editor and converter powered by @office-open/docx with Tiptap editing layer, supporting bidirectional conversion between DOCX, HTML, and Markdown",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"converter",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@office-open/docx": "0.
|
|
62
|
+
"@office-open/docx": "0.10.0",
|
|
63
63
|
"@tiptap/core": "3.22.5",
|
|
64
64
|
"@tiptap/extension-blockquote": "3.22.5",
|
|
65
65
|
"@tiptap/extension-bold": "3.22.5",
|
|
@@ -98,6 +98,7 @@
|
|
|
98
98
|
"@tiptap/markdown": "3.22.5",
|
|
99
99
|
"@tiptap/pm": "3.22.5",
|
|
100
100
|
"@tiptap/suggestion": "3.22.5",
|
|
101
|
+
"image-meta": "0.2.2",
|
|
101
102
|
"lowlight": "3.3.0"
|
|
102
103
|
},
|
|
103
104
|
"scripts": {
|
package/dist/core-CFIQVRfx.mjs
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { Blockquote, Bold, BulletList, Code, CodeBlockLowlight, Details, DetailsContent, DetailsSummary, Document, Dropcursor, Emoji, Gapcursor, HardBreak, Highlight, HorizontalRule, Italic, Link, ListItem, ListKeymap, Mathematics, Mention, OrderedList, Subscript, Superscript, TaskItem, TaskList, Text, TextAlign as TextAlign$1, TrailingNode, Underline, UndoRedo } from "./extensions/tiptap.mjs";
|
|
2
|
-
import { Heading } from "./extensions/heading.mjs";
|
|
3
|
-
import { Image } from "./extensions/image.mjs";
|
|
4
|
-
import { Paragraph } from "./extensions/paragraph.mjs";
|
|
5
|
-
import { Strike } from "./extensions/strike.mjs";
|
|
6
|
-
import { Table } from "./extensions/table.mjs";
|
|
7
|
-
import { TableCell } from "./extensions/table-cell.mjs";
|
|
8
|
-
import { TableHeader } from "./extensions/table-header.mjs";
|
|
9
|
-
import { TableRow } from "./extensions/table-row.mjs";
|
|
10
|
-
import { TextStyle } from "./extensions/text-style.mjs";
|
|
11
|
-
import { Editor, Extension, Mark, Node } from "@tiptap/core";
|
|
12
|
-
import { all, createLowlight } from "lowlight";
|
|
13
|
-
import { TextAlign } from "@tiptap/extension-text-align";
|
|
14
|
-
//#region src/extensions/extensions.ts
|
|
15
|
-
const tiptapNodeExtensions = [
|
|
16
|
-
Document,
|
|
17
|
-
Paragraph,
|
|
18
|
-
Text,
|
|
19
|
-
HardBreak,
|
|
20
|
-
Blockquote,
|
|
21
|
-
OrderedList,
|
|
22
|
-
BulletList,
|
|
23
|
-
ListItem,
|
|
24
|
-
CodeBlockLowlight.configure({ lowlight: createLowlight(all) }),
|
|
25
|
-
Details,
|
|
26
|
-
DetailsSummary,
|
|
27
|
-
DetailsContent,
|
|
28
|
-
Emoji,
|
|
29
|
-
HorizontalRule,
|
|
30
|
-
Image.configure({ inline: true }),
|
|
31
|
-
Mathematics,
|
|
32
|
-
Mention,
|
|
33
|
-
Table,
|
|
34
|
-
TableRow,
|
|
35
|
-
TableCell,
|
|
36
|
-
TableHeader,
|
|
37
|
-
TaskList,
|
|
38
|
-
TaskItem,
|
|
39
|
-
Heading,
|
|
40
|
-
TextAlign$1.configure({ types: ["heading", "paragraph"] })
|
|
41
|
-
];
|
|
42
|
-
const tiptapMarkExtensions = [
|
|
43
|
-
Bold,
|
|
44
|
-
Code,
|
|
45
|
-
Highlight,
|
|
46
|
-
Italic,
|
|
47
|
-
Link,
|
|
48
|
-
Strike,
|
|
49
|
-
Subscript,
|
|
50
|
-
Superscript,
|
|
51
|
-
TextStyle,
|
|
52
|
-
Underline
|
|
53
|
-
];
|
|
54
|
-
const docxExtensions = [...tiptapNodeExtensions, ...tiptapMarkExtensions];
|
|
55
|
-
const StarterKit = Extension.create({
|
|
56
|
-
name: "docenKit",
|
|
57
|
-
addExtensions() {
|
|
58
|
-
const extensions = [];
|
|
59
|
-
if (this.options.bold !== false) extensions.push(Bold.configure(this.options.bold));
|
|
60
|
-
if (this.options.blockquote !== false) extensions.push(Blockquote.configure(this.options.blockquote));
|
|
61
|
-
if (this.options.bulletList !== false) extensions.push(BulletList.configure(this.options.bulletList));
|
|
62
|
-
if (this.options.code !== false) extensions.push(Code.configure(this.options.code));
|
|
63
|
-
if (this.options.codeBlock !== false) extensions.push(CodeBlockLowlight.configure({
|
|
64
|
-
lowlight: createLowlight(all),
|
|
65
|
-
...this.options.codeBlock
|
|
66
|
-
}));
|
|
67
|
-
if (this.options.document !== false) extensions.push(Document);
|
|
68
|
-
if (this.options.dropcursor !== false) extensions.push(Dropcursor.configure(this.options.dropcursor));
|
|
69
|
-
if (this.options.gapcursor !== false) extensions.push(Gapcursor);
|
|
70
|
-
if (this.options.hardBreak !== false) extensions.push(HardBreak.configure(this.options.hardBreak));
|
|
71
|
-
if (this.options.heading !== false) extensions.push(Heading.configure(this.options.heading));
|
|
72
|
-
if (this.options.undoRedo !== false) extensions.push(UndoRedo.configure(this.options.undoRedo));
|
|
73
|
-
if (this.options.horizontalRule !== false) extensions.push(HorizontalRule.configure(this.options.horizontalRule));
|
|
74
|
-
if (this.options.italic !== false) extensions.push(Italic.configure(this.options.italic));
|
|
75
|
-
if (this.options.listItem !== false) extensions.push(ListItem.configure(this.options.listItem));
|
|
76
|
-
if (this.options.listKeymap !== false) extensions.push(ListKeymap.configure(this.options.listKeymap));
|
|
77
|
-
if (this.options.link !== false) extensions.push(Link.configure(this.options.link));
|
|
78
|
-
if (this.options.orderedList !== false) extensions.push(OrderedList.configure(this.options.orderedList));
|
|
79
|
-
if (this.options.paragraph !== false) extensions.push(Paragraph.configure(this.options.paragraph));
|
|
80
|
-
if (this.options.strike !== false) extensions.push(Strike.configure(this.options.strike));
|
|
81
|
-
if (this.options.text !== false) extensions.push(Text);
|
|
82
|
-
if (this.options.underline !== false) extensions.push(Underline.configure(this.options.underline));
|
|
83
|
-
if (this.options.trailingNode !== false) extensions.push(TrailingNode.configure(this.options.trailingNode));
|
|
84
|
-
return extensions;
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
//#endregion
|
|
88
|
-
export { StarterKit as a, tiptapMarkExtensions as c, Node as i, tiptapNodeExtensions as l, Extension as n, TextAlign as o, Mark as r, docxExtensions as s, Editor as t };
|
package/dist/core-omBKMRtl.d.mts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { AnyExtension, Editor, Extension, Extensions, JSONContent as JSONContent$1, Mark, Node } from "@tiptap/core";
|
|
2
|
-
import { TextAlign } from "@tiptap/extension-text-align";
|
|
3
|
-
|
|
4
|
-
//#region src/extensions/extensions.d.ts
|
|
5
|
-
declare const tiptapNodeExtensions: AnyExtension[];
|
|
6
|
-
declare const tiptapMarkExtensions: AnyExtension[];
|
|
7
|
-
declare const docxExtensions: AnyExtension[];
|
|
8
|
-
interface StarterKitOptions {
|
|
9
|
-
bold?: Record<string, any> | false;
|
|
10
|
-
blockquote?: Record<string, any> | false;
|
|
11
|
-
bulletList?: Record<string, any> | false;
|
|
12
|
-
code?: Record<string, any> | false;
|
|
13
|
-
codeBlock?: Record<string, any> | false;
|
|
14
|
-
document?: false;
|
|
15
|
-
dropcursor?: Record<string, any> | false;
|
|
16
|
-
gapcursor?: false;
|
|
17
|
-
hardBreak?: Record<string, any> | false;
|
|
18
|
-
heading?: Record<string, any> | false;
|
|
19
|
-
undoRedo?: Record<string, any> | false;
|
|
20
|
-
horizontalRule?: Record<string, any> | false;
|
|
21
|
-
italic?: Record<string, any> | false;
|
|
22
|
-
listItem?: Record<string, any> | false;
|
|
23
|
-
listKeymap?: Record<string, any> | false;
|
|
24
|
-
link?: Record<string, any> | false;
|
|
25
|
-
orderedList?: Record<string, any> | false;
|
|
26
|
-
paragraph?: Record<string, any> | false;
|
|
27
|
-
strike?: Record<string, any> | false;
|
|
28
|
-
text?: false;
|
|
29
|
-
underline?: Record<string, any> | false;
|
|
30
|
-
trailingNode?: Record<string, any> | false;
|
|
31
|
-
}
|
|
32
|
-
declare const StarterKit: Extension<StarterKitOptions, any>;
|
|
33
|
-
//#endregion
|
|
34
|
-
export { JSONContent$1 as a, StarterKit as c, docxExtensions as d, tiptapMarkExtensions as f, Extensions as i, StarterKitOptions as l, Editor as n, Mark as o, tiptapNodeExtensions as p, Extension as r, Node as s, AnyExtension as t, TextAlign as u };
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { JSONContent } from "@tiptap/core";
|
|
2
|
-
|
|
3
|
-
//#region src/extensions/image.d.ts
|
|
4
|
-
type CropRect = {
|
|
5
|
-
left?: number;
|
|
6
|
-
top?: number;
|
|
7
|
-
right?: number;
|
|
8
|
-
bottom?: number;
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Custom Image extension with node-level renderHTML + renderDocx/parseDocx.
|
|
12
|
-
*
|
|
13
|
-
* Attrs:
|
|
14
|
-
* - src/alt/title/width/height: Tiptap structural names (kept verbatim so base
|
|
15
|
-
* image commands work).
|
|
16
|
-
* - rotation: editor display only (CSS transform) but also carried through DOCX
|
|
17
|
-
* via transformation.rotation (MediaTransformation.rotation).
|
|
18
|
-
* - floating/outline: nested office-open objects (Floating / OutlineOptions).
|
|
19
|
-
* - crop: nested office-open SourceRectangleOptions (srcRect).
|
|
20
|
-
* - display: editor-only display hint, no OOXML equivalent.
|
|
21
|
-
*
|
|
22
|
-
* DOCX round-trip is near-identity: renderDocx packs attrs into CoreImageOptions;
|
|
23
|
-
* parseDocx unpacks them back. src is a data URL ↔ { type, data } base64.
|
|
24
|
-
* Node-level renderHTML solves the style merge problem (rotation + floating).
|
|
25
|
-
*/
|
|
26
|
-
/**
|
|
27
|
-
* Tiptap JSON image node → CoreImageOptions-shaped object.
|
|
28
|
-
*
|
|
29
|
-
* Returns `{ image: ImageOptions }` (structural wrapper) or null when no
|
|
30
|
-
* embedded image data is available (external URLs need pre-fetching).
|
|
31
|
-
* rotation is carried via transformation.rotation (not dropped).
|
|
32
|
-
*/
|
|
33
|
-
declare function renderDocx(node: JSONContent): Record<string, unknown> | null;
|
|
34
|
-
/**
|
|
35
|
-
* ImageOptions-shaped object → Tiptap attrs.
|
|
36
|
-
*
|
|
37
|
-
* Near-identity unpack: transformation → width/height/rotation, altText → alt/title,
|
|
38
|
-
* floating/srcRect(→crop)/outline passed through verbatim. src is reconstructed by
|
|
39
|
-
* DocxManager from the image data bytes (kept out of parseDocx).
|
|
40
|
-
*/
|
|
41
|
-
declare function parseDocx(imageOpts: Record<string, unknown>): Record<string, unknown>;
|
|
42
|
-
declare function renderCropAttrs(crop: Record<string, unknown> | CropRect): {
|
|
43
|
-
style: string;
|
|
44
|
-
};
|
|
45
|
-
declare const Image: import("@tiptap/core").Node<import("@tiptap/extension-image").ImageOptions, any>;
|
|
46
|
-
//#endregion
|
|
47
|
-
export { renderDocx as i, parseDocx as n, renderCropAttrs as r, Image as t };
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { JSONContent } from "@tiptap/core";
|
|
2
|
-
|
|
3
|
-
//#region src/extensions/paragraph.d.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
|
-
declare function renderDocx(node: JSONContent): Record<string, unknown>;
|
|
13
|
-
declare function parseDocx(opts: Record<string, unknown>): Record<string, unknown>;
|
|
14
|
-
declare const Paragraph: import("@tiptap/core").Node<import("@tiptap/extension-paragraph").ParagraphOptions, any>;
|
|
15
|
-
//#endregion
|
|
16
|
-
export { parseDocx as n, renderDocx as r, Paragraph as t };
|