@coding01/docsjs 0.1.3 → 0.1.6

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/react.cjs CHANGED
@@ -56,6 +56,21 @@ function buildHtmlSnapshot(rawHtml) {
56
56
 
57
57
  // src/lib/docxHtml.ts
58
58
  var import_jszip = __toESM(require("jszip"), 1);
59
+ function createEmptyFeatureCounts() {
60
+ return {
61
+ hyperlinkCount: 0,
62
+ anchorImageCount: 0,
63
+ chartCount: 0,
64
+ smartArtCount: 0,
65
+ ommlCount: 0,
66
+ tableCount: 0,
67
+ footnoteRefCount: 0,
68
+ endnoteRefCount: 0,
69
+ commentRefCount: 0,
70
+ revisionCount: 0,
71
+ pageBreakCount: 0
72
+ };
73
+ }
59
74
  function escapeHtml(text) {
60
75
  return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
61
76
  }
@@ -79,6 +94,9 @@ function getAttr(node, name) {
79
94
  function emuToPx(emu) {
80
95
  return emu * 96 / 914400;
81
96
  }
97
+ function twipToPx(twip) {
98
+ return twip * 96 / 1440;
99
+ }
82
100
  function parseDrawingSizePx(drawing) {
83
101
  const extentNode = queryAllByLocalName(drawing, "extent").find((node) => {
84
102
  const parent = node.parentElement;
@@ -107,9 +125,7 @@ function imageDimensionAttributes(sizePx) {
107
125
  }
108
126
  return attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
109
127
  }
110
- function parseAnchorPositionPx(drawing) {
111
- const anchor = directChildrenByLocalName(drawing, "anchor")[0] ?? null;
112
- if (!anchor) return { leftPx: null, topPx: null };
128
+ function parseAnchorPositionPx(anchor) {
113
129
  let leftPx = null;
114
130
  let topPx = null;
115
131
  const positionH = directChildrenByLocalName(anchor, "positionH")[0] ?? null;
@@ -124,34 +140,80 @@ function parseAnchorPositionPx(drawing) {
124
140
  if (Number.isFinite(top)) topPx = emuToPx(top);
125
141
  return { leftPx, topPx };
126
142
  }
127
- function parseAnchorWrapMode(drawing) {
128
- const anchor = directChildrenByLocalName(drawing, "anchor")[0] ?? null;
129
- if (!anchor) return null;
143
+ function parseAnchorWrapMode(anchor) {
130
144
  if (directChildrenByLocalName(anchor, "wrapSquare")[0]) return "square";
131
145
  if (directChildrenByLocalName(anchor, "wrapTight")[0]) return "tight";
132
146
  if (directChildrenByLocalName(anchor, "wrapTopAndBottom")[0]) return "topAndBottom";
133
147
  if (directChildrenByLocalName(anchor, "wrapNone")[0]) return "none";
134
148
  return null;
135
149
  }
136
- function mergeImageStyle(baseAttrs, anchorPos, wrapMode) {
137
- if (anchorPos.leftPx === null && anchorPos.topPx === null) return baseAttrs;
150
+ function parseAnchorMeta(drawing) {
151
+ const anchor = directChildrenByLocalName(drawing, "anchor")[0] ?? null;
152
+ if (!anchor) return null;
153
+ const positionH = directChildrenByLocalName(anchor, "positionH")[0] ?? null;
154
+ const positionV = directChildrenByLocalName(anchor, "positionV")[0] ?? null;
155
+ const relativeFromH = getAttr(positionH, "relativeFrom");
156
+ const relativeFromV = getAttr(positionV, "relativeFrom");
157
+ const parseDistPx = (name) => {
158
+ const raw = getAttr(anchor, name);
159
+ const emu = raw ? Number.parseInt(raw, 10) : Number.NaN;
160
+ return Number.isFinite(emu) && emu >= 0 ? emuToPx(emu) : null;
161
+ };
162
+ const rawHeight = getAttr(anchor, "relativeHeight");
163
+ const parsedHeight = rawHeight ? Number.parseInt(rawHeight, 10) : Number.NaN;
164
+ const boolAttr = (name, fallback) => {
165
+ const raw = (getAttr(anchor, name) ?? "").toLowerCase();
166
+ if (raw === "1" || raw === "true" || raw === "on") return true;
167
+ if (raw === "0" || raw === "false" || raw === "off") return false;
168
+ return fallback;
169
+ };
170
+ return {
171
+ position: parseAnchorPositionPx(anchor),
172
+ wrapMode: parseAnchorWrapMode(anchor),
173
+ distTPx: parseDistPx("distT"),
174
+ distBPx: parseDistPx("distB"),
175
+ distLPx: parseDistPx("distL"),
176
+ distRPx: parseDistPx("distR"),
177
+ relativeFromH,
178
+ relativeFromV,
179
+ behindDoc: boolAttr("behindDoc", false),
180
+ allowOverlap: boolAttr("allowOverlap", true),
181
+ layoutInCell: boolAttr("layoutInCell", true),
182
+ relativeHeight: Number.isFinite(parsedHeight) ? parsedHeight : null
183
+ };
184
+ }
185
+ function mergeImageStyle(baseAttrs, anchorMeta) {
186
+ if (!anchorMeta) return baseAttrs;
187
+ const { position, wrapMode } = anchorMeta;
188
+ if (position.leftPx === null && position.topPx === null) return baseAttrs;
138
189
  const styleParts = [
139
190
  "position:absolute",
140
- anchorPos.leftPx !== null ? `left:${anchorPos.leftPx.toFixed(2)}px` : "",
141
- anchorPos.topPx !== null ? `top:${anchorPos.topPx.toFixed(2)}px` : "",
142
- "z-index:3"
191
+ position.leftPx !== null ? `left:${position.leftPx.toFixed(2)}px` : "",
192
+ position.topPx !== null ? `top:${position.topPx.toFixed(2)}px` : "",
193
+ `z-index:${anchorMeta.behindDoc ? 0 : anchorMeta.relativeHeight ?? 3}`,
194
+ anchorMeta.distTPx !== null ? `margin-top:${anchorMeta.distTPx.toFixed(2)}px` : "",
195
+ anchorMeta.distBPx !== null ? `margin-bottom:${anchorMeta.distBPx.toFixed(2)}px` : "",
196
+ anchorMeta.distLPx !== null ? `margin-left:${anchorMeta.distLPx.toFixed(2)}px` : "",
197
+ anchorMeta.distRPx !== null ? `margin-right:${anchorMeta.distRPx.toFixed(2)}px` : ""
143
198
  ].filter((x) => x.length > 0);
144
199
  if (wrapMode === "topAndBottom") {
145
- styleParts.push("display:block");
146
- }
200
+ styleParts.push("display:block", "clear:both");
201
+ }
202
+ const anchorAttrs = [
203
+ `data-word-anchor="1"`,
204
+ wrapMode ? `data-word-wrap="${wrapMode}"` : "",
205
+ anchorMeta.relativeFromH ? `data-word-anchor-relh="${escapeHtml(anchorMeta.relativeFromH)}"` : "",
206
+ anchorMeta.relativeFromV ? `data-word-anchor-relv="${escapeHtml(anchorMeta.relativeFromV)}"` : "",
207
+ anchorMeta.behindDoc ? `data-word-anchor-behind="1"` : `data-word-anchor-behind="0"`,
208
+ anchorMeta.allowOverlap ? `data-word-anchor-overlap="1"` : `data-word-anchor-overlap="0"`,
209
+ anchorMeta.layoutInCell ? `data-word-anchor-layout-cell="1"` : `data-word-anchor-layout-cell="0"`
210
+ ].filter((x) => x.length > 0).join(" ");
147
211
  if (!baseAttrs.includes("style=")) {
148
- const wrapAttr = wrapMode ? ` data-word-wrap="${wrapMode}"` : "";
149
- return `${baseAttrs} style="${styleParts.join(";")}" data-word-anchor="1"${wrapAttr}`;
212
+ return `${baseAttrs} style="${styleParts.join(";")}" ${anchorAttrs}`;
150
213
  }
151
214
  return baseAttrs.replace(/style="([^"]*)"/, (_m, styleText) => {
152
215
  const merged = [styleText, ...styleParts].filter((x) => x.length > 0).join(";");
153
- const wrapAttr = wrapMode ? ` data-word-wrap="${wrapMode}"` : "";
154
- return `style="${merged}" data-word-anchor="1"${wrapAttr}`;
216
+ return `style="${merged}" ${anchorAttrs}`;
155
217
  });
156
218
  }
157
219
  function parseDocRelsMap(relsXmlText) {
@@ -177,11 +239,29 @@ function extToMime(ext) {
177
239
  if (lower === "svg") return "image/svg+xml";
178
240
  return "application/octet-stream";
179
241
  }
242
+ function normalizeWordPath(relTarget) {
243
+ const normalized = relTarget.replace(/\\/g, "/").replace(/^\/+/, "");
244
+ if (normalized.startsWith("word/")) return normalized;
245
+ if (normalized.startsWith("../")) return `word/${normalized.replace(/^(\.\.\/)+/, "")}`;
246
+ return `word/${normalized}`;
247
+ }
248
+ function resolveHyperlinkHref(relMap, rid, anchor) {
249
+ if (anchor && anchor.trim()) return `#${encodeURIComponent(anchor.trim())}`;
250
+ if (!rid) return null;
251
+ const relTarget = relMap[rid];
252
+ if (!relTarget) return null;
253
+ const trimmed = relTarget.trim();
254
+ if (!trimmed) return null;
255
+ const lower = trimmed.toLowerCase();
256
+ if (lower.startsWith("http://") || lower.startsWith("https://") || lower.startsWith("mailto:") || lower.startsWith("tel:")) {
257
+ return trimmed;
258
+ }
259
+ return trimmed.startsWith("#") ? trimmed : `#${encodeURIComponent(trimmed)}`;
260
+ }
180
261
  async function imageRidToDataUrl(zip, relMap, rid) {
181
262
  const relTarget = relMap[rid];
182
263
  if (!relTarget) return null;
183
- const normalized = relTarget.replace(/^\/+/, "");
184
- const path = normalized.startsWith("word/") ? normalized : `word/${normalized}`;
264
+ const path = normalizeWordPath(relTarget);
185
265
  const file = zip.file(path);
186
266
  if (!file) return null;
187
267
  const base64 = await file.async("base64");
@@ -189,6 +269,55 @@ async function imageRidToDataUrl(zip, relMap, rid) {
189
269
  const mime = extToMime(ext);
190
270
  return `data:${mime};base64,${base64}`;
191
271
  }
272
+ async function readXmlByRid(zip, relMap, rid) {
273
+ const relTarget = relMap[rid];
274
+ if (!relTarget) return null;
275
+ const path = normalizeWordPath(relTarget);
276
+ const file = zip.file(path);
277
+ return file ? file.async("string") : null;
278
+ }
279
+ function parseChartType(chartDoc) {
280
+ const known = ["barChart", "lineChart", "pieChart", "areaChart", "scatterChart", "radarChart", "doughnutChart"];
281
+ for (const type of known) {
282
+ if (queryByLocalName(chartDoc, type)) return type.replace(/Chart$/, "");
283
+ }
284
+ return "unknown";
285
+ }
286
+ function parseChartSummary(chartXmlText) {
287
+ const chartDoc = parseXml(chartXmlText);
288
+ const title = queryAllByLocalName(chartDoc, "t").map((n) => (n.textContent ?? "").trim()).find((v) => v.length > 0) ?? "Chart";
289
+ const seriesCount = queryAllByLocalName(chartDoc, "ser").length;
290
+ const pointCount = queryAllByLocalName(chartDoc, "pt").length;
291
+ const type = parseChartType(chartDoc);
292
+ return { title, type, seriesCount, pointCount };
293
+ }
294
+ function extractSmartArtText(diagramXmlText) {
295
+ const diagramDoc = parseXml(diagramXmlText);
296
+ return queryAllByLocalName(diagramDoc, "t").map((n) => (n.textContent ?? "").trim()).filter((v) => v.length > 0).slice(0, 12);
297
+ }
298
+ function ommlNodeToText(node) {
299
+ if (node.localName === "t") return node.textContent ?? "";
300
+ if (node.localName === "f") {
301
+ const num = queryByLocalName(node, "num");
302
+ const den = queryByLocalName(node, "den");
303
+ return `(${num ? ommlNodeToText(num) : "?"})/(${den ? ommlNodeToText(den) : "?"})`;
304
+ }
305
+ if (node.localName === "sSup") {
306
+ const e = queryByLocalName(node, "e");
307
+ const sup = queryByLocalName(node, "sup");
308
+ return `${e ? ommlNodeToText(e) : ""}^(${sup ? ommlNodeToText(sup) : ""})`;
309
+ }
310
+ if (node.localName === "sSub") {
311
+ const e = queryByLocalName(node, "e");
312
+ const sub = queryByLocalName(node, "sub");
313
+ return `${e ? ommlNodeToText(e) : ""}_(${sub ? ommlNodeToText(sub) : ""})`;
314
+ }
315
+ if (node.localName === "rad") {
316
+ const e = queryByLocalName(node, "e");
317
+ return `sqrt(${e ? ommlNodeToText(e) : ""})`;
318
+ }
319
+ return Array.from(node.children).map((child) => ommlNodeToText(child)).join("");
320
+ }
192
321
  function runStyleToCss(rPr) {
193
322
  if (!rPr) return "";
194
323
  const declarations = [];
@@ -303,48 +432,73 @@ function renderEndnotesSection(usedIds, endnotesMap) {
303
432
  const items = uniq.map((id) => `<li id="word-endnote-${id}" data-word-endnote-id="${id}">${endnotesMap[id]}</li>`).join("");
304
433
  return `<section data-word-endnotes="1"><hr/><ol>${items}</ol></section>`;
305
434
  }
306
- async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotesMap, usedFootnoteIds, endnotesMap, usedEndnoteIds, commentsMap, usedCommentIds) {
435
+ async function paragraphToHtml(zip, relMap, context, paragraph, paragraphIndex, footnotesMap, usedFootnoteIds, endnotesMap, usedEndnoteIds, commentsMap, usedCommentIds) {
307
436
  const tag = paragraphTag(paragraph);
308
437
  const alignStyle = paragraphAlignStyle(paragraph);
309
438
  const dataAttr = paragraphDataAttr(paragraphIndex);
310
- const runs = queryAllByLocalName(paragraph, "r");
311
- if (runs.length === 0) {
439
+ const hasRenderableNode = queryAllByLocalName(paragraph, "r").length > 0 || queryAllByLocalName(paragraph, "oMath").length > 0 || queryAllByLocalName(paragraph, "oMathPara").length > 0;
440
+ if (!hasRenderableNode) {
312
441
  return `<${tag}${dataAttr}${alignStyle ? ` style="${alignStyle}"` : ""}><br/></${tag}>`;
313
442
  }
314
- const parts = [];
315
- const renderedPageBreakCount = queryAllByLocalName(paragraph, "lastRenderedPageBreak").length;
316
- for (let i = 0; i < renderedPageBreakCount; i += 1) {
317
- parts.push(`<span data-word-page-break="1" style="display:block;break-before:page"></span>`);
443
+ function parseRevisionMeta(node, type) {
444
+ return {
445
+ type,
446
+ id: getAttr(node, "w:id") ?? getAttr(node, "id"),
447
+ author: getAttr(node, "w:author") ?? getAttr(node, "author"),
448
+ date: getAttr(node, "w:date") ?? getAttr(node, "date")
449
+ };
450
+ }
451
+ function inferRevisionMeta(run, fallback) {
452
+ if (fallback) return fallback;
453
+ let cursor = run;
454
+ while (cursor) {
455
+ if (cursor.localName === "ins") return parseRevisionMeta(cursor, "ins");
456
+ if (cursor.localName === "del") return parseRevisionMeta(cursor, "del");
457
+ if (cursor.localName === "p") break;
458
+ cursor = cursor.parentElement;
459
+ }
460
+ return null;
318
461
  }
319
- for (const run of runs) {
462
+ function revisionMetaAttrs(meta) {
463
+ const attrs = [`data-word-revision="${meta.type}"`];
464
+ if (meta.id) attrs.push(`data-word-revision-id="${escapeHtml(meta.id)}"`);
465
+ if (meta.author) attrs.push(`data-word-revision-author="${escapeHtml(meta.author)}"`);
466
+ if (meta.date) attrs.push(`data-word-revision-date="${escapeHtml(meta.date)}"`);
467
+ return attrs.join(" ");
468
+ }
469
+ async function runToHtml(run, revisionFallback) {
470
+ const result = [];
320
471
  const rPr = queryByLocalName(run, "rPr");
321
472
  const css = runStyleToCss(rPr);
322
473
  const footnoteRef = queryByLocalName(run, "footnoteReference");
323
474
  const footnoteId = getAttr(footnoteRef, "w:id") ?? getAttr(footnoteRef, "id");
324
475
  if (footnoteId && footnotesMap[footnoteId]) {
476
+ context.features.footnoteRefCount += 1;
325
477
  usedFootnoteIds.push(footnoteId);
326
- parts.push(
478
+ result.push(
327
479
  `<sup data-word-footnote-ref="${footnoteId}"><a href="#word-footnote-${footnoteId}">[${footnoteId}]</a></sup>`
328
480
  );
329
- continue;
481
+ return result;
330
482
  }
331
483
  const endnoteRef = queryByLocalName(run, "endnoteReference");
332
484
  const endnoteId = getAttr(endnoteRef, "w:id") ?? getAttr(endnoteRef, "id");
333
485
  if (endnoteId && endnotesMap[endnoteId]) {
486
+ context.features.endnoteRefCount += 1;
334
487
  usedEndnoteIds.push(endnoteId);
335
- parts.push(
488
+ result.push(
336
489
  `<sup data-word-endnote-ref="${endnoteId}"><a href="#word-endnote-${endnoteId}">[${endnoteId}]</a></sup>`
337
490
  );
338
- continue;
491
+ return result;
339
492
  }
340
493
  const commentRef = queryByLocalName(run, "commentReference");
341
494
  const commentId = getAttr(commentRef, "w:id") ?? getAttr(commentRef, "id");
342
495
  if (commentId && commentsMap[commentId]) {
496
+ context.features.commentRefCount += 1;
343
497
  usedCommentIds.push(commentId);
344
- parts.push(
498
+ result.push(
345
499
  `<sup data-word-comment-ref="${commentId}"><a href="#word-comment-${commentId}">[c${commentId}]</a></sup>`
346
500
  );
347
- continue;
501
+ return result;
348
502
  }
349
503
  const drawing = queryByLocalName(run, "drawing");
350
504
  if (drawing) {
@@ -355,13 +509,38 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
355
509
  if (src) {
356
510
  const imageSize = parseDrawingSizePx(drawing);
357
511
  const dimensionAttrs = imageDimensionAttributes(imageSize);
358
- const anchorPos = parseAnchorPositionPx(drawing);
359
- const wrapMode = parseAnchorWrapMode(drawing);
360
- const attrs = mergeImageStyle(dimensionAttrs, anchorPos, wrapMode);
361
- parts.push(`<img src="${src}" alt="word-image"${attrs}/>`);
362
- continue;
512
+ const anchorMeta = parseAnchorMeta(drawing);
513
+ const attrs = mergeImageStyle(dimensionAttrs, anchorMeta);
514
+ if (anchorMeta) context.features.anchorImageCount += 1;
515
+ result.push(`<img src="${src}" alt="word-image"${attrs}/>`);
516
+ return result;
517
+ }
518
+ }
519
+ const chartRef = queryByLocalName(drawing, "chart");
520
+ const chartRid = getAttr(chartRef, "r:id") ?? getAttr(chartRef, "id");
521
+ if (chartRid) {
522
+ const chartXmlText = await readXmlByRid(zip, relMap, chartRid);
523
+ if (chartXmlText) {
524
+ const summary = parseChartSummary(chartXmlText);
525
+ context.features.chartCount += 1;
526
+ result.push(
527
+ `<figure data-word-chart="1" data-word-chart-type="${summary.type}" data-word-chart-series="${summary.seriesCount}" data-word-chart-points="${summary.pointCount}"><figcaption>${escapeHtml(summary.title)}</figcaption><div>Chart(${escapeHtml(summary.type)}): series=${summary.seriesCount}, points=${summary.pointCount}</div></figure>`
528
+ );
529
+ return result;
363
530
  }
364
531
  }
532
+ const smartArtRef = queryByLocalName(drawing, "relIds");
533
+ const smartArtRid = getAttr(smartArtRef, "r:dm") ?? getAttr(smartArtRef, "dm");
534
+ if (smartArtRid) {
535
+ const diagramXmlText = await readXmlByRid(zip, relMap, smartArtRid);
536
+ const textItems = diagramXmlText ? extractSmartArtText(diagramXmlText) : [];
537
+ context.features.smartArtCount += 1;
538
+ const preview = textItems.length > 0 ? `: ${escapeHtml(textItems.join(" / "))}` : "";
539
+ result.push(
540
+ `<figure data-word-smartart="1" data-word-smartart-items="${textItems.length}"><figcaption>SmartArt fallback${preview}</figcaption></figure>`
541
+ );
542
+ return result;
543
+ }
365
544
  }
366
545
  const texts = queryAllByLocalName(run, "t").map((t) => t.textContent ?? "").join("");
367
546
  const delTexts = queryAllByLocalName(run, "delText").map((t) => t.textContent ?? "").join("");
@@ -372,40 +551,86 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
372
551
  }).length;
373
552
  const lineBreakCount = Math.max(0, brNodes.length - pageBreakCount);
374
553
  const runText2 = `${escapeHtml(texts || delTexts)}${"<br/>".repeat(lineBreakCount)}`;
375
- if (!runText2) continue;
376
- let revisionType = null;
377
- let cursor = run;
378
- while (cursor) {
379
- if (cursor.localName === "ins") {
380
- revisionType = "ins";
381
- break;
382
- }
383
- if (cursor.localName === "del") {
384
- revisionType = "del";
385
- break;
554
+ if (runText2) {
555
+ const revisionMeta = inferRevisionMeta(run, revisionFallback);
556
+ if (css) {
557
+ const span = `<span style="${css}">${runText2}</span>`;
558
+ if (revisionMeta) {
559
+ context.features.revisionCount += 1;
560
+ const tagName = revisionMeta.type === "ins" ? "ins" : "del";
561
+ result.push(`<${tagName} ${revisionMetaAttrs(revisionMeta)}>${span}</${tagName}>`);
562
+ } else {
563
+ result.push(span);
564
+ }
565
+ } else if (revisionMeta) {
566
+ context.features.revisionCount += 1;
567
+ const tagName = revisionMeta.type === "ins" ? "ins" : "del";
568
+ result.push(`<${tagName} ${revisionMetaAttrs(revisionMeta)}>${runText2}</${tagName}>`);
569
+ } else {
570
+ result.push(runText2);
386
571
  }
387
- if (cursor.localName === "p") break;
388
- cursor = cursor.parentElement;
389
572
  }
390
- if (css) {
391
- const span = `<span style="${css}">${runText2}</span>`;
392
- if (revisionType) {
393
- const tag2 = revisionType === "ins" ? "ins" : "del";
394
- parts.push(`<${tag2} data-word-revision="${revisionType}">${span}</${tag2}>`);
395
- } else {
396
- parts.push(span);
573
+ for (let i = 0; i < pageBreakCount; i += 1) {
574
+ context.features.pageBreakCount += 1;
575
+ result.push(`<span data-word-page-break="1" style="display:block;break-before:page"></span>`);
576
+ }
577
+ return result;
578
+ }
579
+ async function nodeToHtml(node, revisionFallback) {
580
+ if (node.localName === "commentRangeStart") {
581
+ const id = getAttr(node, "w:id") ?? getAttr(node, "id");
582
+ return id ? [`<span data-word-comment-range-start="${id}"></span>`] : [];
583
+ }
584
+ if (node.localName === "commentRangeEnd") {
585
+ const id = getAttr(node, "w:id") ?? getAttr(node, "id");
586
+ return id ? [`<span data-word-comment-range-end="${id}"></span>`] : [];
587
+ }
588
+ if (node.localName === "r") {
589
+ return runToHtml(node, revisionFallback);
590
+ }
591
+ if (node.localName === "hyperlink") {
592
+ const rid = getAttr(node, "r:id") ?? getAttr(node, "id");
593
+ const anchor = getAttr(node, "w:anchor") ?? getAttr(node, "anchor");
594
+ const href = resolveHyperlinkHref(relMap, rid, anchor);
595
+ const nested2 = [];
596
+ for (const child of Array.from(node.children)) {
597
+ nested2.push(...await nodeToHtml(child, revisionFallback));
397
598
  }
398
- } else {
399
- if (revisionType) {
400
- const tag2 = revisionType === "ins" ? "ins" : "del";
401
- parts.push(`<${tag2} data-word-revision="${revisionType}">${runText2}</${tag2}>`);
402
- } else {
403
- parts.push(runText2);
599
+ const content2 = nested2.join("") || escapeHtml(node.textContent ?? "");
600
+ if (!href) return content2 ? [content2] : [];
601
+ context.features.hyperlinkCount += 1;
602
+ return [
603
+ `<a data-word-hyperlink="1" href="${escapeHtml(href)}" rel="noreferrer noopener" target="_blank">${content2}</a>`
604
+ ];
605
+ }
606
+ if (node.localName === "oMath" || node.localName === "oMathPara") {
607
+ const linear = ommlNodeToText(node).trim();
608
+ if (!linear) return [];
609
+ context.features.ommlCount += 1;
610
+ return [`<span data-word-omml="1">${escapeHtml(linear)}</span>`];
611
+ }
612
+ if (node.localName === "ins" || node.localName === "del") {
613
+ const scopedMeta = parseRevisionMeta(node, node.localName === "ins" ? "ins" : "del");
614
+ const nested2 = [];
615
+ for (const child of Array.from(node.children)) {
616
+ nested2.push(...await nodeToHtml(child, scopedMeta));
404
617
  }
618
+ return nested2;
405
619
  }
406
- for (let i = 0; i < pageBreakCount; i += 1) {
407
- parts.push(`<span data-word-page-break="1" style="display:block;break-before:page"></span>`);
620
+ const nested = [];
621
+ for (const child of Array.from(node.children)) {
622
+ nested.push(...await nodeToHtml(child, revisionFallback));
408
623
  }
624
+ return nested;
625
+ }
626
+ const parts = [];
627
+ const renderedPageBreakCount = queryAllByLocalName(paragraph, "lastRenderedPageBreak").length;
628
+ for (let i = 0; i < renderedPageBreakCount; i += 1) {
629
+ context.features.pageBreakCount += 1;
630
+ parts.push(`<span data-word-page-break="1" style="display:block;break-before:page"></span>`);
631
+ }
632
+ for (const child of Array.from(paragraph.children)) {
633
+ parts.push(...await nodeToHtml(child, null));
409
634
  }
410
635
  const content = parts.join("") || "<br/>";
411
636
  return `<${tag}${dataAttr}${alignStyle ? ` style="${alignStyle}"` : ""}>${content}</${tag}>`;
@@ -435,7 +660,102 @@ function parseTcVMerge(tc) {
435
660
  const rawVal = (getAttr(vMerge, "w:val") ?? getAttr(vMerge, "val") ?? "continue").toLowerCase();
436
661
  return rawVal === "restart" ? "restart" : "continue";
437
662
  }
438
- function tableCellHtml(cell, paragraphIndexMap) {
663
+ function parseTblGridWidthsPx(table) {
664
+ const grid = directChildrenByLocalName(table, "tblGrid")[0] ?? null;
665
+ if (!grid) return [];
666
+ return directChildrenByLocalName(grid, "gridCol").map((col) => {
667
+ const raw = getAttr(col, "w:w") ?? getAttr(col, "w");
668
+ const twip = raw ? Number.parseInt(raw, 10) : Number.NaN;
669
+ return Number.isFinite(twip) && twip > 0 ? twipToPx(twip) : 0;
670
+ }).filter((px) => px > 0);
671
+ }
672
+ function borderSizeToPx(size) {
673
+ return size / 6;
674
+ }
675
+ function parseBorderCss(borderNode) {
676
+ if (!borderNode) return null;
677
+ const val = (getAttr(borderNode, "w:val") ?? getAttr(borderNode, "val") ?? "").toLowerCase();
678
+ if (!val || val === "nil" || val === "none") return "none";
679
+ const color = (getAttr(borderNode, "w:color") ?? getAttr(borderNode, "color") ?? "222222").replace(/^#/, "");
680
+ const rawSize = getAttr(borderNode, "w:sz") ?? getAttr(borderNode, "sz");
681
+ const size = rawSize ? Number.parseInt(rawSize, 10) : Number.NaN;
682
+ const px = Number.isFinite(size) && size > 0 ? borderSizeToPx(size) : 1;
683
+ const style = val === "single" ? "solid" : val;
684
+ return `${px.toFixed(2)}px ${style} #${color}`;
685
+ }
686
+ function parseTableStyleProfile(table) {
687
+ const tblPr = directChildrenByLocalName(table, "tblPr")[0] ?? null;
688
+ const tblBorders = tblPr ? directChildrenByLocalName(tblPr, "tblBorders")[0] ?? null : null;
689
+ const layout = tblPr ? directChildrenByLocalName(tblPr, "tblLayout")[0] ?? null : null;
690
+ const spacing = tblPr ? directChildrenByLocalName(tblPr, "tblCellSpacing")[0] ?? null : null;
691
+ const spacingType = (getAttr(spacing, "w:type") ?? getAttr(spacing, "type") ?? "dxa").toLowerCase();
692
+ const spacingRaw = getAttr(spacing, "w:w") ?? getAttr(spacing, "w");
693
+ const spacingVal = spacingRaw ? Number.parseFloat(spacingRaw) : Number.NaN;
694
+ const borderSpacingPx = spacingType === "dxa" && Number.isFinite(spacingVal) && spacingVal > 0 ? twipToPx(spacingVal) : 0;
695
+ const borderCollapse = borderSpacingPx > 0 ? "separate" : "collapse";
696
+ const tableLayout = (getAttr(layout, "w:type") ?? getAttr(layout, "type") ?? "").toLowerCase() === "autofit" ? "auto" : "fixed";
697
+ const top = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "top")[0] ?? null : null);
698
+ const bottom = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "bottom")[0] ?? null : null);
699
+ const left = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "left")[0] ?? null : null);
700
+ const right = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "right")[0] ?? null : null);
701
+ const insideH = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "insideH")[0] ?? null : null);
702
+ const insideV = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "insideV")[0] ?? null : null);
703
+ const borderCss = top ?? right ?? bottom ?? left ?? "1px solid #222";
704
+ return {
705
+ tableLayout,
706
+ borderCollapse,
707
+ borderSpacingPx,
708
+ borderCss,
709
+ insideHCss: insideH,
710
+ insideVCss: insideV
711
+ };
712
+ }
713
+ function parseTableWidthStyle(table, gridWidthsPx) {
714
+ const tblPr = directChildrenByLocalName(table, "tblPr")[0] ?? null;
715
+ const tblW = tblPr ? directChildrenByLocalName(tblPr, "tblW")[0] ?? null : null;
716
+ const type = (getAttr(tblW, "w:type") ?? getAttr(tblW, "type") ?? "").toLowerCase();
717
+ const rawVal = getAttr(tblW, "w:w") ?? getAttr(tblW, "w");
718
+ const numericVal = rawVal ? Number.parseFloat(rawVal) : Number.NaN;
719
+ if (type === "dxa" && Number.isFinite(numericVal) && numericVal > 0) {
720
+ return `width:${twipToPx(numericVal).toFixed(2)}px`;
721
+ }
722
+ if (type === "pct" && Number.isFinite(numericVal) && numericVal > 0) {
723
+ return `width:${(numericVal / 50).toFixed(2)}%`;
724
+ }
725
+ const gridTotal = gridWidthsPx.reduce((sum, item) => sum + item, 0);
726
+ if (gridTotal > 0) return `width:${gridTotal.toFixed(2)}px;max-width:100%`;
727
+ return "width:100%";
728
+ }
729
+ function parseCellWidthStyle(cell, colCursor, colSpan, gridWidthsPx) {
730
+ const tcPr = directChildrenByLocalName(cell, "tcPr")[0] ?? null;
731
+ const tcW = tcPr ? directChildrenByLocalName(tcPr, "tcW")[0] ?? null : null;
732
+ const type = (getAttr(tcW, "w:type") ?? getAttr(tcW, "type") ?? "").toLowerCase();
733
+ const rawVal = getAttr(tcW, "w:w") ?? getAttr(tcW, "w");
734
+ const numericVal = rawVal ? Number.parseFloat(rawVal) : Number.NaN;
735
+ if (type === "dxa" && Number.isFinite(numericVal) && numericVal > 0) {
736
+ return `width:${twipToPx(numericVal).toFixed(2)}px`;
737
+ }
738
+ if (type === "pct" && Number.isFinite(numericVal) && numericVal > 0) {
739
+ return `width:${(numericVal / 50).toFixed(2)}%`;
740
+ }
741
+ const width = gridWidthsPx.slice(colCursor, colCursor + colSpan).reduce((sum, item) => sum + item, 0);
742
+ if (width > 0) return `width:${width.toFixed(2)}px`;
743
+ return "";
744
+ }
745
+ function parseCellBorderStyle(cell, tableStyle) {
746
+ const tcPr = directChildrenByLocalName(cell, "tcPr")[0] ?? null;
747
+ const tcBorders = tcPr ? directChildrenByLocalName(tcPr, "tcBorders")[0] ?? null : null;
748
+ if (!tcBorders) {
749
+ const fallback = tableStyle.insideHCss ?? tableStyle.insideVCss ?? tableStyle.borderCss;
750
+ return `border:${fallback}`;
751
+ }
752
+ const top = parseBorderCss(directChildrenByLocalName(tcBorders, "top")[0] ?? null) ?? tableStyle.insideHCss ?? tableStyle.borderCss;
753
+ const right = parseBorderCss(directChildrenByLocalName(tcBorders, "right")[0] ?? null) ?? tableStyle.insideVCss ?? tableStyle.borderCss;
754
+ const bottom = parseBorderCss(directChildrenByLocalName(tcBorders, "bottom")[0] ?? null) ?? tableStyle.insideHCss ?? tableStyle.borderCss;
755
+ const left = parseBorderCss(directChildrenByLocalName(tcBorders, "left")[0] ?? null) ?? tableStyle.insideVCss ?? tableStyle.borderCss;
756
+ return `border-top:${top};border-right:${right};border-bottom:${bottom};border-left:${left}`;
757
+ }
758
+ function tableCellHtml(cell, paragraphIndexMap, context) {
439
759
  const blocks = [];
440
760
  for (const child of Array.from(cell.children)) {
441
761
  if (child.localName === "tcPr") continue;
@@ -445,7 +765,7 @@ function tableCellHtml(cell, paragraphIndexMap) {
445
765
  continue;
446
766
  }
447
767
  if (child.localName === "tbl") {
448
- blocks.push(tableToHtml(child, paragraphIndexMap));
768
+ blocks.push(tableToHtml(child, paragraphIndexMap, context));
449
769
  continue;
450
770
  }
451
771
  }
@@ -453,8 +773,11 @@ function tableCellHtml(cell, paragraphIndexMap) {
453
773
  const text = queryAllByLocalName(cell, "t").map((t) => t.textContent ?? "").join("").trim();
454
774
  return escapeHtml(text) || "<br/>";
455
775
  }
456
- function tableToHtml(table, paragraphIndexMap) {
776
+ function tableToHtml(table, paragraphIndexMap, context) {
777
+ context.features.tableCount += 1;
457
778
  const rows = directChildrenByLocalName(table, "tr");
779
+ const gridWidthsPx = parseTblGridWidthsPx(table);
780
+ const tableStyle = parseTableStyleProfile(table);
458
781
  const activeByCol = /* @__PURE__ */ new Map();
459
782
  const allOrigins = [];
460
783
  let nextOriginId = 1;
@@ -479,8 +802,10 @@ function tableToHtml(table, paragraphIndexMap) {
479
802
  while (activeByCol.has(colCursor)) {
480
803
  colCursor += 1;
481
804
  }
482
- const html = tableCellHtml(cell, paragraphIndexMap);
805
+ const html = tableCellHtml(cell, paragraphIndexMap, context);
483
806
  const attrs = [];
807
+ const widthStyle = parseCellWidthStyle(cell, colCursor, colSpan, gridWidthsPx);
808
+ const borderStyle = parseCellBorderStyle(cell, tableStyle);
484
809
  if (vMerge === "restart") {
485
810
  const origin = {
486
811
  id: `m${nextOriginId}`,
@@ -498,7 +823,7 @@ function tableToHtml(table, paragraphIndexMap) {
498
823
  }
499
824
  if (colSpan > 1) attrs.push(`colspan="${colSpan}"`);
500
825
  emittedCells.push(
501
- `<td${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""} style="border:1px solid #222;vertical-align:top;">${html}</td>`
826
+ `<td${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""} style="${borderStyle};vertical-align:top;${widthStyle}">${html}</td>`
502
827
  );
503
828
  colCursor += colSpan;
504
829
  }
@@ -517,9 +842,13 @@ function tableToHtml(table, paragraphIndexMap) {
517
842
  const replacement = origin.rowSpan > 1 ? `rowspan="${origin.rowSpan}"` : "";
518
843
  merged = merged.replace(marker, replacement).replace(/\s{2,}/g, " ");
519
844
  }
520
- return `<table style="border-collapse:collapse;table-layout:fixed;width:100%;border:1px solid #222;">${merged}</table>`;
845
+ const tableWidthStyle = parseTableWidthStyle(table, gridWidthsPx);
846
+ const spacing = tableStyle.borderSpacingPx > 0 ? `border-spacing:${tableStyle.borderSpacingPx.toFixed(2)}px;` : "";
847
+ return `<table style="border-collapse:${tableStyle.borderCollapse};${spacing}table-layout:${tableStyle.tableLayout};${tableWidthStyle};border:${tableStyle.borderCss};">${merged}</table>`;
521
848
  }
522
- async function parseDocxToHtmlSnapshot(file) {
849
+ async function parseDocxToHtmlSnapshotWithReport(file) {
850
+ const startedAt = Date.now();
851
+ const context = { features: createEmptyFeatureCounts() };
523
852
  const maybeArrayBuffer = file.arrayBuffer;
524
853
  const buffer = maybeArrayBuffer ? await maybeArrayBuffer.call(file) : await new Response(file).arrayBuffer();
525
854
  const zip = await import_jszip.default.loadAsync(buffer);
@@ -556,6 +885,7 @@ async function parseDocxToHtmlSnapshot(file) {
556
885
  await paragraphToHtml(
557
886
  zip,
558
887
  relMap,
888
+ context,
559
889
  child,
560
890
  paragraphIndex,
561
891
  footnotesMap,
@@ -569,14 +899,20 @@ async function parseDocxToHtmlSnapshot(file) {
569
899
  continue;
570
900
  }
571
901
  if (child.localName === "tbl") {
572
- blockHtml.push(tableToHtml(child, paragraphIndexMap));
902
+ blockHtml.push(tableToHtml(child, paragraphIndexMap, context));
573
903
  continue;
574
904
  }
575
905
  }
576
906
  blockHtml.push(renderFootnotesSection(usedFootnoteIds, footnotesMap));
577
907
  blockHtml.push(renderEndnotesSection(usedEndnoteIds, endnotesMap));
578
908
  blockHtml.push(renderCommentsSection(usedCommentIds, commentsMap));
579
- return buildHtmlSnapshot(blockHtml.join("\n"));
909
+ return {
910
+ htmlSnapshot: buildHtmlSnapshot(blockHtml.join("\n")),
911
+ report: {
912
+ elapsedMs: Date.now() - startedAt,
913
+ features: context.features
914
+ }
915
+ };
580
916
  }
581
917
 
582
918
  // src/lib/pastePipeline.ts
@@ -807,7 +1143,7 @@ function createFallbackWordStyleProfile(sourceFileName = "snapshot") {
807
1143
  paragraphProfiles: []
808
1144
  };
809
1145
  }
810
- function twipToPx(twip) {
1146
+ function twipToPx2(twip) {
811
1147
  return twip / 15;
812
1148
  }
813
1149
  function getAttr2(node, attr) {
@@ -851,10 +1187,10 @@ function parsePageGeometry(documentXml) {
851
1187
  const top = getTwipAttr(pgMar, "w:top") ?? getTwipAttr(pgMar, "top") ?? null;
852
1188
  const bottom = getTwipAttr(pgMar, "w:bottom") ?? getTwipAttr(pgMar, "bottom") ?? null;
853
1189
  return {
854
- contentWidthPx: pageW === null ? null : twipToPx(pageW - left - right),
855
- pageHeightPx: pageH === null ? null : twipToPx(pageH),
856
- marginTopPx: top === null ? null : twipToPx(top),
857
- marginBottomPx: bottom === null ? null : twipToPx(bottom)
1190
+ contentWidthPx: pageW === null ? null : twipToPx2(pageW - left - right),
1191
+ pageHeightPx: pageH === null ? null : twipToPx2(pageH),
1192
+ marginTopPx: top === null ? null : twipToPx2(top),
1193
+ marginBottomPx: bottom === null ? null : twipToPx2(bottom)
858
1194
  };
859
1195
  }
860
1196
  function parseHeadingAlignFromDocument(documentXml) {
@@ -1027,15 +1363,15 @@ function parseParagraphProfiles(documentXml, numberingMap) {
1027
1363
  text,
1028
1364
  isEmpty: text.length === 0,
1029
1365
  align: parseParagraphAlign(paragraph),
1030
- beforePx: before === null ? null : twipToPx(before),
1031
- afterPx: after === null ? null : twipToPx(after),
1366
+ beforePx: before === null ? null : twipToPx2(before),
1367
+ afterPx: after === null ? null : twipToPx2(after),
1032
1368
  lineHeightRatio: line === null || lineHeightRule !== "auto" ? null : line / 240,
1033
- lineHeightPx: line === null || lineHeightRule === "auto" ? null : twipToPx(line),
1369
+ lineHeightPx: line === null || lineHeightRule === "auto" ? null : twipToPx2(line),
1034
1370
  lineHeightRule,
1035
- indentLeftPx: left === null ? null : twipToPx(left),
1036
- indentRightPx: right === null ? null : twipToPx(right),
1037
- firstLinePx: firstLine === null ? null : twipToPx(firstLine),
1038
- hangingPx: hanging === null ? null : twipToPx(hanging),
1371
+ indentLeftPx: left === null ? null : twipToPx2(left),
1372
+ indentRightPx: right === null ? null : twipToPx2(right),
1373
+ firstLinePx: firstLine === null ? null : twipToPx2(firstLine),
1374
+ hangingPx: hanging === null ? null : twipToPx2(hanging),
1039
1375
  listNumId,
1040
1376
  listLevel,
1041
1377
  listFormat: listSpec?.numFmt ?? null,
@@ -1070,19 +1406,19 @@ function parseTableDefaults(stylesXml) {
1070
1406
  return {
1071
1407
  topPx: (() => {
1072
1408
  const v = getTwipAttr(top, "w:w") ?? getTwipAttr(top, "w") ?? null;
1073
- return v === null ? null : twipToPx(v);
1409
+ return v === null ? null : twipToPx2(v);
1074
1410
  })(),
1075
1411
  leftPx: (() => {
1076
1412
  const v = getTwipAttr(left, "w:w") ?? getTwipAttr(left, "w") ?? null;
1077
- return v === null ? null : twipToPx(v);
1413
+ return v === null ? null : twipToPx2(v);
1078
1414
  })(),
1079
1415
  bottomPx: (() => {
1080
1416
  const v = getTwipAttr(bottom, "w:w") ?? getTwipAttr(bottom, "w") ?? null;
1081
- return v === null ? null : twipToPx(v);
1417
+ return v === null ? null : twipToPx2(v);
1082
1418
  })(),
1083
1419
  rightPx: (() => {
1084
1420
  const v = getTwipAttr(right, "w:w") ?? getTwipAttr(right, "w") ?? null;
1085
- return v === null ? null : twipToPx(v);
1421
+ return v === null ? null : twipToPx2(v);
1086
1422
  })()
1087
1423
  };
1088
1424
  }
@@ -1180,9 +1516,9 @@ function parseDefaults(stylesXml) {
1180
1516
  const rawLineRule = (getAttr2(spacing, "w:lineRule") ?? getAttr2(spacing, "lineRule") ?? "auto").toLowerCase();
1181
1517
  const bodyLineHeightRule = rawLineRule === "exact" ? "exact" : rawLineRule === "atleast" ? "atLeast" : "auto";
1182
1518
  const bodyLineHeightRatio = line === null || bodyLineHeightRule !== "auto" ? null : line / 240;
1183
- const bodyLineHeightPx = line === null || bodyLineHeightRule === "auto" ? null : twipToPx(line);
1519
+ const bodyLineHeightPx = line === null || bodyLineHeightRule === "auto" ? null : twipToPx2(line);
1184
1520
  const after = getTwipAttr(spacing, "w:after") ?? getTwipAttr(spacing, "after") ?? null;
1185
- const paragraphAfterPx = after === null ? null : twipToPx(after);
1521
+ const paragraphAfterPx = after === null ? null : twipToPx2(after);
1186
1522
  return { bodyFontPx, bodyLineHeightRatio, bodyLineHeightPx, bodyLineHeightRule, paragraphAfterPx };
1187
1523
  }
1188
1524
  function parseHeading1Style(stylesXml) {
@@ -1707,7 +2043,7 @@ function applyWordRenderModel({ doc, styleProfile, showFormattingMarks }) {
1707
2043
  }
1708
2044
 
1709
2045
  // src/core/DocsWordElement.ts
1710
- var VERSION = "0.1.2";
2046
+ var VERSION = "0.1.5";
1711
2047
  var MESSAGES = {
1712
2048
  zh: {
1713
2049
  readClipboard: "\u4ECE\u7CFB\u7EDF\u526A\u8D34\u677F\u8BFB\u53D6",
@@ -1850,15 +2186,15 @@ var DocsWordElement = class extends HTMLElement {
1850
2186
  }
1851
2187
  async applyDocx(file) {
1852
2188
  try {
1853
- const [snapshot, profile] = await Promise.all([
1854
- parseDocxToHtmlSnapshot(file),
2189
+ const [parseResult, profile] = await Promise.all([
2190
+ parseDocxToHtmlSnapshotWithReport(file),
1855
2191
  parseDocxStyleProfile(file)
1856
2192
  ]);
1857
2193
  this.styleProfile = profile;
1858
- this.htmlSnapshot = snapshot;
2194
+ this.htmlSnapshot = parseResult.htmlSnapshot;
1859
2195
  this.renderSnapshot();
1860
2196
  this.setHint(MESSAGES[this.locale].loadedWord(profile.sourceFileName));
1861
- this.emitChange("upload", profile.sourceFileName);
2197
+ this.emitChange("upload", profile.sourceFileName, parseResult.report);
1862
2198
  } catch (error) {
1863
2199
  this.emitError(error instanceof Error ? error.message : MESSAGES[this.locale].parseFailed);
1864
2200
  }
@@ -1918,8 +2254,10 @@ var DocsWordElement = class extends HTMLElement {
1918
2254
  renderSnapshot() {
1919
2255
  this.frame.srcdoc = this.htmlSnapshot;
1920
2256
  }
1921
- emitChange(source, fileName) {
1922
- this.dispatchEvent(new CustomEvent("docsjs-change", { detail: { htmlSnapshot: this.htmlSnapshot, source, fileName } }));
2257
+ emitChange(source, fileName, parseReport) {
2258
+ this.dispatchEvent(
2259
+ new CustomEvent("docsjs-change", { detail: { htmlSnapshot: this.htmlSnapshot, source, fileName, parseReport } })
2260
+ );
1923
2261
  }
1924
2262
  emitError(message) {
1925
2263
  this.dispatchEvent(new CustomEvent("docsjs-error", { detail: { message } }));
@@ -1955,7 +2293,13 @@ function defineDocsWordElement() {
1955
2293
 
1956
2294
  // src/react/WordFidelityEditorReact.tsx
1957
2295
  defineDocsWordElement();
1958
- function WordFidelityEditorReact({ lang, onChange, onError, onReady, editorRef }) {
2296
+ function WordFidelityEditorReact({
2297
+ lang,
2298
+ onChange,
2299
+ onError,
2300
+ onReady,
2301
+ editorRef
2302
+ }) {
1959
2303
  const ref = (0, import_react.useRef)(null);
1960
2304
  (0, import_react.useEffect)(() => {
1961
2305
  const node = ref.current;
@@ -1983,7 +2327,10 @@ function WordFidelityEditorReact({ lang, onChange, onError, onReady, editorRef }
1983
2327
  editorRef?.(null);
1984
2328
  };
1985
2329
  }, [editorRef, onChange, onError, onReady]);
1986
- return import_react.default.createElement("docs-word-editor", { ref, lang });
2330
+ return import_react.default.createElement("docs-word-editor", {
2331
+ ref,
2332
+ lang
2333
+ });
1987
2334
  }
1988
2335
  // Annotate the CommonJS export names for ESM import in node:
1989
2336
  0 && (module.exports = {