docx-diff-editor 1.0.45 → 1.0.46
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/index.js +170 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +170 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -453,6 +453,170 @@ var TIMEOUTS = {
|
|
|
453
453
|
CLEANUP_DELAY: 100
|
|
454
454
|
};
|
|
455
455
|
|
|
456
|
+
// src/services/runPropertiesSync.ts
|
|
457
|
+
var PT_TO_TWIPS = 20;
|
|
458
|
+
function ptToTwips(ptValue) {
|
|
459
|
+
return Math.round(ptValue * PT_TO_TWIPS);
|
|
460
|
+
}
|
|
461
|
+
function stripHashFromColor(color) {
|
|
462
|
+
return color.replace(/^#/, "");
|
|
463
|
+
}
|
|
464
|
+
function parseFontSizeToPoints(fontSize) {
|
|
465
|
+
if (typeof fontSize === "number") {
|
|
466
|
+
return fontSize;
|
|
467
|
+
}
|
|
468
|
+
const value = parseFloat(fontSize);
|
|
469
|
+
if (isNaN(value)) {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
if (fontSize.toLowerCase().includes("px")) {
|
|
473
|
+
return value * 0.75;
|
|
474
|
+
}
|
|
475
|
+
return value;
|
|
476
|
+
}
|
|
477
|
+
function cleanFontFamily(fontFamily) {
|
|
478
|
+
return fontFamily.split(",")[0].trim().replace(/^["']|["']$/g, "");
|
|
479
|
+
}
|
|
480
|
+
function marksToRunProperties(marks) {
|
|
481
|
+
const runProperties = {};
|
|
482
|
+
if (!marks || !Array.isArray(marks)) {
|
|
483
|
+
return runProperties;
|
|
484
|
+
}
|
|
485
|
+
for (const mark of marks) {
|
|
486
|
+
const type = mark.type;
|
|
487
|
+
const attrs = mark.attrs || {};
|
|
488
|
+
switch (type) {
|
|
489
|
+
// Boolean marks: bold, italic, strike
|
|
490
|
+
case "bold":
|
|
491
|
+
case "italic":
|
|
492
|
+
case "strike": {
|
|
493
|
+
const isNegated = attrs.value === "0" || attrs.value === false;
|
|
494
|
+
runProperties[type] = !isNegated;
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
// Underline with optional type and color
|
|
498
|
+
case "underline": {
|
|
499
|
+
const underlineAttrs = {};
|
|
500
|
+
if (attrs.underlineType) {
|
|
501
|
+
underlineAttrs["w:val"] = String(attrs.underlineType);
|
|
502
|
+
} else {
|
|
503
|
+
underlineAttrs["w:val"] = "single";
|
|
504
|
+
}
|
|
505
|
+
if (attrs.underlineColor) {
|
|
506
|
+
underlineAttrs["w:color"] = stripHashFromColor(String(attrs.underlineColor));
|
|
507
|
+
}
|
|
508
|
+
if (Object.keys(underlineAttrs).length > 0) {
|
|
509
|
+
runProperties.underline = underlineAttrs;
|
|
510
|
+
}
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
// Highlight (background color)
|
|
514
|
+
case "highlight": {
|
|
515
|
+
if (attrs.color) {
|
|
516
|
+
const color = String(attrs.color).toLowerCase();
|
|
517
|
+
if (color === "transparent") {
|
|
518
|
+
runProperties.highlight = { "w:val": "none" };
|
|
519
|
+
} else {
|
|
520
|
+
runProperties.highlight = { "w:val": color };
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
// textStyle contains multiple style attributes
|
|
526
|
+
case "textStyle": {
|
|
527
|
+
if (attrs.color != null) {
|
|
528
|
+
runProperties.color = {
|
|
529
|
+
val: stripHashFromColor(String(attrs.color))
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
if (attrs.fontSize != null) {
|
|
533
|
+
const points = parseFontSizeToPoints(attrs.fontSize);
|
|
534
|
+
if (points !== null) {
|
|
535
|
+
runProperties.fontSize = points * 2;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
if (attrs.fontFamily != null) {
|
|
539
|
+
const cleanedFont = cleanFontFamily(String(attrs.fontFamily));
|
|
540
|
+
runProperties.fontFamily = {
|
|
541
|
+
ascii: cleanedFont,
|
|
542
|
+
eastAsia: cleanedFont,
|
|
543
|
+
hAnsi: cleanedFont,
|
|
544
|
+
cs: cleanedFont
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
if (attrs.letterSpacing != null) {
|
|
548
|
+
const ptValue = parseFloat(String(attrs.letterSpacing));
|
|
549
|
+
if (!isNaN(ptValue)) {
|
|
550
|
+
runProperties.letterSpacing = ptToTwips(ptValue);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (attrs.textTransform != null) {
|
|
554
|
+
runProperties.textTransform = String(attrs.textTransform);
|
|
555
|
+
}
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
return runProperties;
|
|
561
|
+
}
|
|
562
|
+
function collectMarksRecursively(node, allMarks) {
|
|
563
|
+
if (node.type === "text" && node.marks && Array.isArray(node.marks)) {
|
|
564
|
+
allMarks.push(...node.marks);
|
|
565
|
+
}
|
|
566
|
+
if (node.content && Array.isArray(node.content)) {
|
|
567
|
+
for (const child of node.content) {
|
|
568
|
+
collectMarksRecursively(child, allMarks);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function collectMarksFromRunChildren(runNode) {
|
|
573
|
+
const allMarks = [];
|
|
574
|
+
if (!runNode.content || !Array.isArray(runNode.content)) {
|
|
575
|
+
return allMarks;
|
|
576
|
+
}
|
|
577
|
+
for (const child of runNode.content) {
|
|
578
|
+
collectMarksRecursively(child, allMarks);
|
|
579
|
+
}
|
|
580
|
+
const marksByType = /* @__PURE__ */ new Map();
|
|
581
|
+
for (const mark of allMarks) {
|
|
582
|
+
marksByType.set(mark.type, mark);
|
|
583
|
+
}
|
|
584
|
+
return Array.from(marksByType.values());
|
|
585
|
+
}
|
|
586
|
+
function normalizeNode(node) {
|
|
587
|
+
if (node.type === "run") {
|
|
588
|
+
const marks = collectMarksFromRunChildren(node);
|
|
589
|
+
if (marks.length > 0) {
|
|
590
|
+
const runPropsFromMarks = marksToRunProperties(marks);
|
|
591
|
+
const existingRunProps = node.attrs?.runProperties || {};
|
|
592
|
+
const mergedRunProps = {
|
|
593
|
+
...existingRunProps,
|
|
594
|
+
...runPropsFromMarks
|
|
595
|
+
};
|
|
596
|
+
return {
|
|
597
|
+
...node,
|
|
598
|
+
attrs: {
|
|
599
|
+
...node.attrs,
|
|
600
|
+
runProperties: mergedRunProps
|
|
601
|
+
},
|
|
602
|
+
// Also recursively process children (though runs usually just have text)
|
|
603
|
+
content: node.content?.map(normalizeNode)
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
if (node.content && Array.isArray(node.content)) {
|
|
608
|
+
return {
|
|
609
|
+
...node,
|
|
610
|
+
content: node.content.map(normalizeNode)
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
return node;
|
|
614
|
+
}
|
|
615
|
+
function normalizeRunProperties(doc) {
|
|
616
|
+
const cloned = JSON.parse(JSON.stringify(doc));
|
|
617
|
+
return normalizeNode(cloned);
|
|
618
|
+
}
|
|
619
|
+
|
|
456
620
|
// src/services/contentResolver.ts
|
|
457
621
|
function detectContentType(content) {
|
|
458
622
|
if (content instanceof File) {
|
|
@@ -519,7 +683,8 @@ async function parseHtmlToJson(html, SuperDoc) {
|
|
|
519
683
|
try {
|
|
520
684
|
const json = editor.getJSON();
|
|
521
685
|
if (json?.content?.length > 0) {
|
|
522
|
-
|
|
686
|
+
const normalizedJson = normalizeRunProperties(json);
|
|
687
|
+
onSuccess(normalizedJson);
|
|
523
688
|
} else {
|
|
524
689
|
onFail();
|
|
525
690
|
}
|
|
@@ -556,9 +721,10 @@ async function parseHtmlToJson(html, SuperDoc) {
|
|
|
556
721
|
throw new Error("No active editor found");
|
|
557
722
|
}
|
|
558
723
|
const json = editor.getJSON();
|
|
724
|
+
const normalizedJson = normalizeRunProperties(json);
|
|
559
725
|
resolved = true;
|
|
560
726
|
cleanup();
|
|
561
|
-
resolve(
|
|
727
|
+
resolve(normalizedJson);
|
|
562
728
|
} catch (err) {
|
|
563
729
|
resolved = true;
|
|
564
730
|
cleanup();
|
|
@@ -2861,9 +3027,10 @@ var DocxDiffEditor = react.forwardRef(
|
|
|
2861
3027
|
}
|
|
2862
3028
|
newJson = content;
|
|
2863
3029
|
}
|
|
3030
|
+
const normalizedNewJson = normalizeRunProperties(newJson);
|
|
2864
3031
|
const structuralResult = mergeWithStructuralAwareness(
|
|
2865
3032
|
sourceJson,
|
|
2866
|
-
|
|
3033
|
+
normalizedNewJson,
|
|
2867
3034
|
author
|
|
2868
3035
|
);
|
|
2869
3036
|
const merged = structuralResult.mergedDoc;
|