superdoc 2.18.0-next.9 → 2.18.1-next.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/dist/chunks/{create-super-doc-ui-qTSa0PbD.es.js → create-super-doc-ui-C_NS0Kbv.es.js} +1003 -911
- package/dist/chunks/{create-super-doc-ui-D9JWPXRh.cjs → create-super-doc-ui-DteEHfc7.cjs} +1046 -942
- package/dist/collaboration-upgrade-engine.cjs +1 -1
- package/dist/collaboration-upgrade-engine.es.js +1 -1
- package/dist/document-api/src/diff/diff.types.d.ts +1 -1
- package/dist/document-api/src/images/images.types.d.ts +2 -0
- package/dist/document-api/src/types/clipboard.d.ts +24 -1
- package/dist/layout-engine/contracts/src/index.d.ts +4 -0
- package/dist/public/ui-react.cjs +1 -1
- package/dist/public/ui-react.es.js +1 -1
- package/dist/public/ui-vue.cjs +1 -1
- package/dist/public/ui-vue.es.js +1 -1
- package/dist/public/ui.cjs +1 -1
- package/dist/public/ui.es.js +1 -1
- package/dist/style.css +22 -22
- package/dist/style.layered.css +22 -22
- package/dist/superdoc/src/core/SuperDoc.d.ts +10 -3
- package/dist/superdoc/src/core/types/index.d.ts +37 -0
- package/dist/superdoc/src/internal/toolbar/built-in/LinkInput.vue.d.ts +4 -4
- package/dist/superdoc/src/public/index.d.cts +10 -0
- package/dist/superdoc/src/public/index.d.ts +5 -0
- package/dist/superdoc/src/public/ui/create-super-doc-ui.d.ts +9 -1
- package/dist/superdoc/src/public/ui/types.d.ts +3 -5
- package/dist/superdoc.cjs +232 -104
- package/dist/superdoc.es.js +232 -104
- package/dist-cdn/style.layered.css +1 -1
- package/dist-cdn/superdoc.min.css +1 -1
- package/dist-cdn/superdoc.min.js +37 -37
- package/package.json +2 -2
|
@@ -510,398 +510,291 @@ var decodeLayoutStoryDataset = (raw) => {
|
|
|
510
510
|
`${DOM_CLASS_NAMES.BLOCK_SDT}${DATA_ATTRS.SDT_ID}`;
|
|
511
511
|
`${DATA_ATTRS.DRAGGABLE}`;
|
|
512
512
|
//#endregion
|
|
513
|
-
//#region
|
|
513
|
+
//#region src/public/ui/equality.ts
|
|
514
514
|
/**
|
|
515
|
-
*
|
|
515
|
+
* Shallow equality used by the controller to suppress redundant slice
|
|
516
|
+
* notifications. v2-native, dependency-free.
|
|
517
|
+
*/
|
|
518
|
+
/**
|
|
519
|
+
* Returns `true` when `a` and `b` are the same reference, or are objects with
|
|
520
|
+
* the same own-enumerable keys and `Object.is`-equal values one level deep.
|
|
521
|
+
* Arrays compare by index. Primitives compare with `Object.is`.
|
|
522
|
+
*/
|
|
523
|
+
function shallowEqual(a, b) {
|
|
524
|
+
if (Object.is(a, b)) return true;
|
|
525
|
+
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
|
|
526
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
527
|
+
const aKeys = Object.keys(a);
|
|
528
|
+
const bKeys = Object.keys(b);
|
|
529
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
530
|
+
for (const key of aKeys) {
|
|
531
|
+
if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
|
|
532
|
+
if (!Object.is(a[key], b[key])) return false;
|
|
533
|
+
}
|
|
534
|
+
return true;
|
|
535
|
+
}
|
|
536
|
+
//#endregion
|
|
537
|
+
//#region src/public/ui/format-painter-helpers.js
|
|
538
|
+
/**
|
|
539
|
+
* Maps SDRunProps field names to InlineRunPatch field names.
|
|
540
|
+
* SDRunProps (read-side) and InlineRunPatch (write-side) use different keys
|
|
541
|
+
* for the same properties; direct assignment between them is forbidden.
|
|
516
542
|
*
|
|
517
|
-
*
|
|
518
|
-
*
|
|
519
|
-
|
|
520
|
-
|
|
543
|
+
* @param {Record<string, unknown>} props - SDRunProps object from doc.getNodeById
|
|
544
|
+
* @returns {Record<string, unknown>} InlineRunPatch ready for doc.format.apply
|
|
545
|
+
*/
|
|
546
|
+
function sdRunPropsToInlineRunPatch(props) {
|
|
547
|
+
if (!props || typeof props !== "object") return {};
|
|
548
|
+
const patch = {};
|
|
549
|
+
if (props.fonts) patch.rFonts = {
|
|
550
|
+
ascii: props.fonts.ascii,
|
|
551
|
+
hAnsi: props.fonts.hAnsi,
|
|
552
|
+
eastAsia: props.fonts.eastAsia,
|
|
553
|
+
cs: props.fonts.cs,
|
|
554
|
+
asciiTheme: props.fonts.asciiTheme,
|
|
555
|
+
hAnsiTheme: props.fonts.hAnsiTheme,
|
|
556
|
+
eastAsiaTheme: props.fonts.eastAsiaTheme,
|
|
557
|
+
csTheme: props.fonts.csTheme,
|
|
558
|
+
hint: props.fonts.hint
|
|
559
|
+
};
|
|
560
|
+
if (props.fontFamily != null) patch.fontFamily = props.fontFamily;
|
|
561
|
+
if (props.lang) patch.lang = {
|
|
562
|
+
val: props.lang.val,
|
|
563
|
+
eastAsia: props.lang.eastAsia,
|
|
564
|
+
bidi: props.lang.bidi
|
|
565
|
+
};
|
|
566
|
+
if (props.fontSize != null) patch.fontSize = props.fontSize;
|
|
567
|
+
if (props.fontSizeCs != null) patch.fontSizeCs = props.fontSizeCs;
|
|
568
|
+
const color = projectColorRefToInlineColor(props.color);
|
|
569
|
+
if (color != null) patch.color = color;
|
|
570
|
+
if (props.highlight != null) patch.highlight = props.highlight;
|
|
571
|
+
const shading = projectShadingToInlinePatch(props.shading);
|
|
572
|
+
if (shading) patch.shading = shading;
|
|
573
|
+
if (props.cs != null) patch.cs = props.cs;
|
|
574
|
+
if (props.rtl != null) patch.rtl = props.rtl;
|
|
575
|
+
if (props.bold != null) patch.bold = props.bold;
|
|
576
|
+
if (props.boldCs != null) patch.bCs = props.boldCs;
|
|
577
|
+
if (props.italic != null) patch.italic = props.italic;
|
|
578
|
+
if (props.italicCs != null) patch.iCs = props.italicCs;
|
|
579
|
+
const underline = projectUnderlineToInlinePatch(props.underline);
|
|
580
|
+
if (underline !== void 0) patch.underline = underline;
|
|
581
|
+
if (props.strikethrough != null) patch.strike = props.strikethrough;
|
|
582
|
+
if (props.doubleStrikethrough != null) patch.dstrike = props.doubleStrikethrough;
|
|
583
|
+
if (props.caps != null) patch.caps = props.caps;
|
|
584
|
+
if (props.smallCaps != null) patch.smallCaps = props.smallCaps;
|
|
585
|
+
if (props.outline != null) patch.outline = props.outline;
|
|
586
|
+
if (props.shadow != null) patch.shadow = props.shadow;
|
|
587
|
+
if (props.emboss != null) patch.emboss = props.emboss;
|
|
588
|
+
if (props.imprint != null) patch.imprint = props.imprint;
|
|
589
|
+
if (props.verticalAlign != null) patch.vertAlign = props.verticalAlign;
|
|
590
|
+
if (props.characterSpacing != null) patch.letterSpacing = props.characterSpacing;
|
|
591
|
+
if (props.characterScale != null) patch.charScale = props.characterScale;
|
|
592
|
+
if (props.kern != null) patch.kerning = props.kern;
|
|
593
|
+
if (props.baselineShift != null) patch.position = props.baselineShift;
|
|
594
|
+
if (props.fitTextWidth != null) patch.fitText = { val: props.fitTextWidth };
|
|
595
|
+
if (props.vanish != null) patch.vanish = props.vanish;
|
|
596
|
+
if (props.webHidden != null) patch.webHidden = props.webHidden;
|
|
597
|
+
if (props.specVanish != null) patch.specVanish = props.specVanish;
|
|
598
|
+
const border = projectBorderToInlinePatch(props.border);
|
|
599
|
+
if (border) patch.border = border;
|
|
600
|
+
return patch;
|
|
601
|
+
}
|
|
602
|
+
function projectColorRefToInlineColor(color) {
|
|
603
|
+
if (!color) return void 0;
|
|
604
|
+
if (typeof color === "string") return color;
|
|
605
|
+
if (color.model === "rgb") return color.value;
|
|
606
|
+
if (color.model === "auto") return "auto";
|
|
607
|
+
}
|
|
608
|
+
function projectUnderlineToInlinePatch(underline) {
|
|
609
|
+
if (underline == null) return void 0;
|
|
610
|
+
const patch = {};
|
|
611
|
+
if (underline.style != null) patch.style = underline.style;
|
|
612
|
+
if (underline.color?.model === "rgb") patch.color = underline.color.value;
|
|
613
|
+
if (underline.color?.model === "theme") patch.themeColor = underline.color.theme;
|
|
614
|
+
return Object.keys(patch).length > 0 ? patch : true;
|
|
615
|
+
}
|
|
616
|
+
function projectShadingToInlinePatch(shading) {
|
|
617
|
+
if (!shading) return void 0;
|
|
618
|
+
const patch = {};
|
|
619
|
+
const fill = projectColorRefToInlineColor(shading.fill);
|
|
620
|
+
if (fill != null) patch.fill = fill;
|
|
621
|
+
const color = projectColorRefToInlineColor(shading.color);
|
|
622
|
+
if (color != null) patch.color = color;
|
|
623
|
+
if (shading.pattern != null) patch.val = shading.pattern;
|
|
624
|
+
return Object.keys(patch).length > 0 ? patch : void 0;
|
|
625
|
+
}
|
|
626
|
+
function projectBorderToInlinePatch(border) {
|
|
627
|
+
if (!border) return void 0;
|
|
628
|
+
const patch = {};
|
|
629
|
+
if (border.style != null) patch.val = border.style;
|
|
630
|
+
if (border.width != null) patch.sz = border.width;
|
|
631
|
+
if (border.space != null) patch.space = border.space;
|
|
632
|
+
const color = projectColorRefToInlineColor(border.color);
|
|
633
|
+
if (color != null) patch.color = color;
|
|
634
|
+
return Object.keys(patch).length > 0 ? patch : void 0;
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Serializes a selection to a stable string key used to detect whether
|
|
638
|
+
* the target selection is the same as the source (skip apply in that case).
|
|
521
639
|
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
640
|
+
* Falls back to the plain text target when the host has not populated an
|
|
641
|
+
* explicit `selectionTarget` yet.
|
|
642
|
+
*
|
|
643
|
+
* @param {{ selectionTarget?: unknown; target?: unknown } | null | undefined} selection
|
|
644
|
+
* @returns {string}
|
|
524
645
|
*/
|
|
525
|
-
function
|
|
526
|
-
const
|
|
527
|
-
if (
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
646
|
+
function selectionKey(selection) {
|
|
647
|
+
const target = selection?.selectionTarget ?? selection?.target;
|
|
648
|
+
if (!selection || !target) return "";
|
|
649
|
+
try {
|
|
650
|
+
return JSON.stringify(target);
|
|
651
|
+
} catch {
|
|
652
|
+
return String(target);
|
|
653
|
+
}
|
|
531
654
|
}
|
|
532
655
|
//#endregion
|
|
533
|
-
//#region
|
|
656
|
+
//#region src/helpers/v2-review-mutation-impact.js
|
|
534
657
|
/**
|
|
535
|
-
*
|
|
658
|
+
* Classify the tracked-change identities carried by a v2 mutation event.
|
|
536
659
|
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
* `
|
|
660
|
+
* Receipt entities are the durable invalidation contract between the document
|
|
661
|
+
* kernel and derived review UI. Direct receipts carry entity refs; mutation
|
|
662
|
+
* plans carry the same identities through `trackedChanges` and per-step ids.
|
|
540
663
|
*/
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
}
|
|
577
|
-
|
|
664
|
+
function getV2TrackedChangeMutationImpact(event) {
|
|
665
|
+
if (event?.type !== "mutation:committed") return null;
|
|
666
|
+
const payload = event.origin === "history" ? event.result : event.receipt;
|
|
667
|
+
if (!payload || typeof payload !== "object") return null;
|
|
668
|
+
const upsertIds = /* @__PURE__ */ new Set();
|
|
669
|
+
const removedIds = /* @__PURE__ */ new Set();
|
|
670
|
+
/** @type {Array<{ from: string, to: string }>} */
|
|
671
|
+
const remappedPairs = [];
|
|
672
|
+
const collectEntity = (entry, into) => {
|
|
673
|
+
if (entry?.kind !== "entity" || entry.entityType !== "trackedChange") return;
|
|
674
|
+
if (typeof entry.entityId === "string" && entry.entityId.length > 0) into.add(entry.entityId);
|
|
675
|
+
};
|
|
676
|
+
const readEntityId = (entry) => {
|
|
677
|
+
if (entry?.kind !== "entity" || entry.entityType !== "trackedChange") return null;
|
|
678
|
+
return typeof entry.entityId === "string" && entry.entityId.length > 0 ? entry.entityId : null;
|
|
679
|
+
};
|
|
680
|
+
if (Array.isArray(payload.inserted)) payload.inserted.forEach((entry) => collectEntity(entry, upsertIds));
|
|
681
|
+
if (Array.isArray(payload.updated)) payload.updated.forEach((entry) => collectEntity(entry, upsertIds));
|
|
682
|
+
if (Array.isArray(payload.trackedChangeRefs)) payload.trackedChangeRefs.forEach((entry) => collectEntity(entry, upsertIds));
|
|
683
|
+
if (Array.isArray(payload.trackedChanges)) payload.trackedChanges.forEach((entry) => collectEntity(entry, upsertIds));
|
|
684
|
+
if (Array.isArray(payload.steps)) for (const step of payload.steps) {
|
|
685
|
+
if (!Array.isArray(step?.trackedChangeIds)) continue;
|
|
686
|
+
for (const id of step.trackedChangeIds) if (typeof id === "string" && id.length > 0) upsertIds.add(id);
|
|
687
|
+
}
|
|
688
|
+
if (Array.isArray(payload.removed)) payload.removed.forEach((entry) => collectEntity(entry, removedIds));
|
|
689
|
+
if (Array.isArray(payload.invalidatedRefs)) payload.invalidatedRefs.forEach((entry) => collectEntity(entry, removedIds));
|
|
690
|
+
if (Array.isArray(payload.remappedRefs)) for (const mapping of payload.remappedRefs) {
|
|
691
|
+
const fromId = readEntityId(mapping?.from);
|
|
692
|
+
const toId = readEntityId(mapping?.to);
|
|
693
|
+
if (fromId) removedIds.add(fromId);
|
|
694
|
+
if (toId) upsertIds.add(toId);
|
|
695
|
+
if (fromId && toId && fromId !== toId) remappedPairs.push({
|
|
696
|
+
from: fromId,
|
|
697
|
+
to: toId
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
for (const id of removedIds) upsertIds.delete(id);
|
|
701
|
+
const allResolved = readAllResolvedFact(event, payload);
|
|
702
|
+
if (upsertIds.size === 0 && removedIds.size === 0 && !allResolved) return null;
|
|
703
|
+
return {
|
|
704
|
+
upsertIds,
|
|
705
|
+
removedIds,
|
|
706
|
+
remappedPairs,
|
|
707
|
+
reconcileMode: "targeted",
|
|
708
|
+
...allResolved ? { allResolved } : {}
|
|
709
|
+
};
|
|
710
|
+
}
|
|
578
711
|
/**
|
|
579
|
-
*
|
|
712
|
+
* Comment ids retired by a committed v2 mutation.
|
|
580
713
|
*
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
* -
|
|
585
|
-
*
|
|
586
|
-
* family;
|
|
587
|
-
* - `deferred` families make no support claim (`contract: 'none'`, no
|
|
588
|
-
* diagnostic).
|
|
589
|
-
*/
|
|
590
|
-
var DRAWING_SUPPORT_TAXONOMY = {
|
|
591
|
-
inlineBitmap: {
|
|
592
|
-
family: "inlineBitmap",
|
|
593
|
-
support: "supported",
|
|
594
|
-
description: "wp:inline pic:pic with internal media and browser-safe MIME (PNG/JPEG; WebP/SVG once the host media resolver lands).",
|
|
595
|
-
contract: "ImageRun"
|
|
596
|
-
},
|
|
597
|
-
anchoredBitmap: {
|
|
598
|
-
family: "anchoredBitmap",
|
|
599
|
-
support: "supported",
|
|
600
|
-
description: "wp:anchor bitmap with anchor/wrap expressible by ImageAnchor/ImageWrap. Never silently inlined.",
|
|
601
|
-
contract: "ImageBlock"
|
|
602
|
-
},
|
|
603
|
-
imageChildInGroup: {
|
|
604
|
-
family: "imageChildInGroup",
|
|
605
|
-
support: "supported",
|
|
606
|
-
description: "Bitmap child of a supported DrawingML group/drawing wrapper. Supported only when the parent is.",
|
|
607
|
-
contract: "ImageDrawing"
|
|
608
|
-
},
|
|
609
|
-
vectorShape: {
|
|
610
|
-
family: "vectorShape",
|
|
611
|
-
support: "supported",
|
|
612
|
-
description: "Block/floating DrawingML preset/custom shape with the supported geometry/style subset.",
|
|
613
|
-
contract: "DrawingBlock",
|
|
614
|
-
drawingKind: "vectorShape"
|
|
615
|
-
},
|
|
616
|
-
shapeGroup: {
|
|
617
|
-
family: "shapeGroup",
|
|
618
|
-
support: "supported",
|
|
619
|
-
description: "DrawingML group whose rendered children are supported vector/image children.",
|
|
620
|
-
contract: "DrawingBlock",
|
|
621
|
-
drawingKind: "shapeGroup"
|
|
622
|
-
},
|
|
623
|
-
chart: {
|
|
624
|
-
family: "chart",
|
|
625
|
-
support: "supported",
|
|
626
|
-
description: "DrawingML chart projected into a ChartDrawing with parsed cached chart XML data. Complete Word chart fidelity remains deferred to chartFidelity.",
|
|
627
|
-
contract: "DrawingBlock",
|
|
628
|
-
drawingKind: "chart"
|
|
629
|
-
},
|
|
630
|
-
alternateContent: {
|
|
631
|
-
family: "alternateContent",
|
|
632
|
-
support: "supported",
|
|
633
|
-
description: "mc:AlternateContent traversal/select policy. Selected Choice/Fallback maps to its family contract; unselected branches preserved for save/reopen.",
|
|
634
|
-
contract: "selected-choice"
|
|
635
|
-
},
|
|
636
|
-
externalImage: {
|
|
637
|
-
family: "externalImage",
|
|
638
|
-
support: "fail-closed",
|
|
639
|
-
description: "External image relationship (r:link / TargetMode=\"External\"). Not fetched.",
|
|
640
|
-
contract: "none",
|
|
641
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.externalImageDeferred
|
|
642
|
-
},
|
|
643
|
-
missingRelationship: {
|
|
644
|
-
family: "missingRelationship",
|
|
645
|
-
support: "fail-closed",
|
|
646
|
-
description: "Drawing references a relationship id absent from the owner part .rels.",
|
|
647
|
-
contract: "none",
|
|
648
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.missingRelationship
|
|
649
|
-
},
|
|
650
|
-
missingMediaPart: {
|
|
651
|
-
family: "missingMediaPart",
|
|
652
|
-
support: "fail-closed",
|
|
653
|
-
description: "Relationship resolves but the target media part bytes are missing or empty.",
|
|
654
|
-
contract: "none",
|
|
655
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.missingMediaPart
|
|
656
|
-
},
|
|
657
|
-
wrongRelationshipType: {
|
|
658
|
-
family: "wrongRelationshipType",
|
|
659
|
-
support: "fail-closed",
|
|
660
|
-
description: "Relationship exists but is not an image relationship type.",
|
|
661
|
-
contract: "none",
|
|
662
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsupportedRelationshipType
|
|
663
|
-
},
|
|
664
|
-
unsupportedMime: {
|
|
665
|
-
family: "unsupportedMime",
|
|
666
|
-
support: "fail-closed",
|
|
667
|
-
description: "Media MIME outside the supported allowlist (incl. GIF/BMP/ICO).",
|
|
668
|
-
contract: "none",
|
|
669
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsupportedMime
|
|
670
|
-
},
|
|
671
|
-
oversizedMediaPart: {
|
|
672
|
-
family: "oversizedMediaPart",
|
|
673
|
-
support: "fail-closed",
|
|
674
|
-
description: "Media part exceeds the host byte-size policy before bytes are materialized.",
|
|
675
|
-
contract: "none",
|
|
676
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.imageTooLarge
|
|
677
|
-
},
|
|
678
|
-
unsafeSvg: {
|
|
679
|
-
family: "unsafeSvg",
|
|
680
|
-
support: "fail-closed",
|
|
681
|
-
description: "SVG content rejected by the SVG safety policy.",
|
|
682
|
-
contract: "none",
|
|
683
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsafeSvg
|
|
684
|
-
},
|
|
685
|
-
metafileOrTiff: {
|
|
686
|
-
family: "metafileOrTiff",
|
|
687
|
-
support: "fail-closed",
|
|
688
|
-
description: "EMF/WMF/TIFF and other non-browser-native formats with no approved conversion path.",
|
|
689
|
-
contract: "none",
|
|
690
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsupportedFormat
|
|
691
|
-
},
|
|
692
|
-
embeddedObject: {
|
|
693
|
-
family: "embeddedObject",
|
|
694
|
-
support: "fail-closed",
|
|
695
|
-
description: "OLE / ActiveX / embedded package object.",
|
|
696
|
-
contract: "none",
|
|
697
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.embeddedObjectNotSupported
|
|
698
|
-
},
|
|
699
|
-
smartArtOrDiagram: {
|
|
700
|
-
family: "smartArtOrDiagram",
|
|
701
|
-
support: "fail-closed",
|
|
702
|
-
description: "SmartArt / diagram / unknown external graphic-data object.",
|
|
703
|
-
contract: "none",
|
|
704
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsupportedObject
|
|
705
|
-
},
|
|
706
|
-
vml: {
|
|
707
|
-
family: "vml",
|
|
708
|
-
support: "fail-closed",
|
|
709
|
-
description: "VML structure outside any supported image-like subset (default fail-closed policy).",
|
|
710
|
-
contract: "none",
|
|
711
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.vmlUnsupported
|
|
712
|
-
},
|
|
713
|
-
vmlImageLike: {
|
|
714
|
-
family: "vmlImageLike",
|
|
715
|
-
support: "fail-closed",
|
|
716
|
-
description: "Simple VML image references (v:imagedata) / watermark image metadata. Fail-closed unless a later change promotes a named subset with deterministic fixtures and exact oracles.",
|
|
717
|
-
contract: "none",
|
|
718
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.vmlImageUnsupported
|
|
719
|
-
},
|
|
720
|
-
unsupportedGeometryCommand: {
|
|
721
|
-
family: "unsupportedGeometryCommand",
|
|
722
|
-
support: "fail-closed",
|
|
723
|
-
description: "Custom geometry command the extractor does not implement, e.g. arcTo.",
|
|
724
|
-
contract: "none",
|
|
725
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsupportedGeometryCommand
|
|
726
|
-
},
|
|
727
|
-
unsupportedAnchorFields: {
|
|
728
|
-
family: "unsupportedAnchorFields",
|
|
729
|
-
support: "fail-closed",
|
|
730
|
-
description: "Anchor fields required for honest placement are unsupported (char-relative, alignment modes, etc.).",
|
|
731
|
-
contract: "none",
|
|
732
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.anchorUnsupported
|
|
733
|
-
},
|
|
734
|
-
unsupportedWrapFields: {
|
|
735
|
-
family: "unsupportedWrapFields",
|
|
736
|
-
support: "fail-closed",
|
|
737
|
-
description: "Wrap fields required for honest placement are unsupported (arbitrary wrap polygons, etc.).",
|
|
738
|
-
contract: "none",
|
|
739
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.wrapUnsupported
|
|
740
|
-
},
|
|
741
|
-
alternateContentNoSupportedChoice: {
|
|
742
|
-
family: "alternateContentNoSupportedChoice",
|
|
743
|
-
support: "fail-closed",
|
|
744
|
-
description: "mc:AlternateContent with no supported choice and no usable fallback.",
|
|
745
|
-
contract: "none",
|
|
746
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.altContentNoSupportedChoice
|
|
747
|
-
},
|
|
748
|
-
groupChildUnsupported: {
|
|
749
|
-
family: "groupChildUnsupported",
|
|
750
|
-
support: "fail-closed",
|
|
751
|
-
description: "Unsupported child inside an otherwise-supported group. Supported siblings are not dropped.",
|
|
752
|
-
contract: "none",
|
|
753
|
-
diagnostic: DRAWING_DIAGNOSTIC_CODES.groupChildUnsupported
|
|
754
|
-
},
|
|
755
|
-
objectEditing: {
|
|
756
|
-
family: "objectEditing",
|
|
757
|
-
support: "deferred",
|
|
758
|
-
description: "Editing/mutation of anchored/vector objects.",
|
|
759
|
-
contract: "none"
|
|
760
|
-
},
|
|
761
|
-
customWrapPolygon: {
|
|
762
|
-
family: "customWrapPolygon",
|
|
763
|
-
support: "deferred",
|
|
764
|
-
description: "Full Word-compatible text wrapping for arbitrary custom wrap polygons.",
|
|
765
|
-
contract: "none"
|
|
766
|
-
},
|
|
767
|
-
chartFidelity: {
|
|
768
|
-
family: "chartFidelity",
|
|
769
|
-
support: "deferred",
|
|
770
|
-
description: "Complete chart fidelity (a dedicated chart effort owns the parsed subset).",
|
|
771
|
-
contract: "none"
|
|
772
|
-
},
|
|
773
|
-
vmlFidelity: {
|
|
774
|
-
family: "vmlFidelity",
|
|
775
|
-
support: "deferred",
|
|
776
|
-
description: "Complete VML fidelity.",
|
|
777
|
-
contract: "none"
|
|
778
|
-
},
|
|
779
|
-
decorativeAccessibilityUi: {
|
|
780
|
-
family: "decorativeAccessibilityUi",
|
|
781
|
-
support: "deferred",
|
|
782
|
-
description: "Full accessibility UI for decorative image semantics beyond preserving source data.",
|
|
783
|
-
contract: "none"
|
|
784
|
-
}
|
|
785
|
-
};
|
|
786
|
-
Object.keys(DRAWING_SUPPORT_TAXONOMY);
|
|
787
|
-
Object.freeze([
|
|
788
|
-
"multiple-sections",
|
|
789
|
-
"furniture-page-tokens",
|
|
790
|
-
"non-balanceable-multi-column-sections",
|
|
791
|
-
"body-anchored-objects",
|
|
792
|
-
"non-flowing-page-relative-body-anchors",
|
|
793
|
-
"footnotes",
|
|
794
|
-
"page-references",
|
|
795
|
-
"cross-references",
|
|
796
|
-
"keep-constraints",
|
|
797
|
-
"tables",
|
|
798
|
-
"furniture-anchored-objects"
|
|
799
|
-
]);
|
|
800
|
-
var INCREMENTAL_DEPENDENCY_CERTIFICATE_CLASSES = Object.freeze([
|
|
801
|
-
"checkpoint-geometry",
|
|
802
|
-
"section-numbering",
|
|
803
|
-
"font-style-inputs",
|
|
804
|
-
"notes",
|
|
805
|
-
"furniture",
|
|
806
|
-
"flowing-anchors",
|
|
807
|
-
"non-flowing-page-anchors",
|
|
808
|
-
"convergence",
|
|
809
|
-
"source-topology"
|
|
810
|
-
]);
|
|
811
|
-
new Set(INCREMENTAL_DEPENDENCY_CERTIFICATE_CLASSES);
|
|
812
|
-
//#endregion
|
|
813
|
-
//#region src/helpers/v2-review-mutation-impact.js
|
|
814
|
-
/**
|
|
815
|
-
* Classify the tracked-change identities carried by a v2 mutation event.
|
|
816
|
-
*
|
|
817
|
-
* Receipt entities are the durable invalidation contract between the document
|
|
818
|
-
* kernel and derived review UI. Direct receipts carry entity refs; mutation
|
|
819
|
-
* plans carry the same identities through `trackedChanges` and per-step ids.
|
|
714
|
+
* AIDEV-NOTE: History commits put invalidated comment ids on `result`; cut and
|
|
715
|
+
* other command receipts use `receipt`. Same origin split as
|
|
716
|
+
* getV2TrackedChangeMutationImpact. Reading the wrong field, or treating a
|
|
717
|
+
* tracked-change entity as a comment, leaves a sidebar card after cut or
|
|
718
|
+
* undo/redo.
|
|
820
719
|
*/
|
|
821
|
-
function
|
|
822
|
-
if (event?.type !== "mutation:committed") return null;
|
|
823
|
-
const payload = event.origin === "history" ? event.result : event.receipt;
|
|
824
|
-
if (!payload || typeof payload !== "object") return null;
|
|
825
|
-
const upsertIds = /* @__PURE__ */ new Set();
|
|
720
|
+
function collectV2InvalidatedCommentIds(event) {
|
|
826
721
|
const removedIds = /* @__PURE__ */ new Set();
|
|
827
|
-
|
|
828
|
-
const
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
722
|
+
if (event?.type !== "mutation:committed") return removedIds;
|
|
723
|
+
const payload = event.origin === "history" ? event.result : event.receipt;
|
|
724
|
+
if (!Array.isArray(payload?.invalidatedRefs)) return removedIds;
|
|
725
|
+
for (const ref of payload.invalidatedRefs) if (ref?.kind === "entity" && ref.entityType === "comment" && typeof ref.entityId === "string" && ref.entityId) removedIds.add(ref.entityId);
|
|
726
|
+
return removedIds;
|
|
727
|
+
}
|
|
728
|
+
function applyV2CommentInvalidationFromMutation({ event, commentsStore, superdoc, documentId } = {}) {
|
|
729
|
+
const removedIds = collectV2InvalidatedCommentIds(event);
|
|
730
|
+
if (removedIds.size === 0) return {
|
|
731
|
+
ok: true,
|
|
732
|
+
removedIds: []
|
|
836
733
|
};
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
}
|
|
845
|
-
if (Array.isArray(payload.removed)) payload.removed.forEach((entry) => collectEntity(entry, removedIds));
|
|
846
|
-
if (Array.isArray(payload.invalidatedRefs)) payload.invalidatedRefs.forEach((entry) => collectEntity(entry, removedIds));
|
|
847
|
-
if (Array.isArray(payload.remappedRefs)) for (const mapping of payload.remappedRefs) {
|
|
848
|
-
const fromId = readEntityId(mapping?.from);
|
|
849
|
-
const toId = readEntityId(mapping?.to);
|
|
850
|
-
if (fromId) removedIds.add(fromId);
|
|
851
|
-
if (toId) upsertIds.add(toId);
|
|
852
|
-
if (fromId && toId && fromId !== toId) remappedPairs.push({
|
|
853
|
-
from: fromId,
|
|
854
|
-
to: toId
|
|
855
|
-
});
|
|
856
|
-
}
|
|
857
|
-
for (const id of removedIds) upsertIds.delete(id);
|
|
858
|
-
const allResolved = readAllResolvedFact(event, payload);
|
|
859
|
-
if (upsertIds.size === 0 && removedIds.size === 0 && !allResolved) return null;
|
|
860
|
-
return {
|
|
861
|
-
upsertIds,
|
|
862
|
-
removedIds,
|
|
863
|
-
remappedPairs,
|
|
864
|
-
reconcileMode: "targeted",
|
|
865
|
-
...allResolved ? { allResolved } : {}
|
|
734
|
+
return commentsStore?.dropCommentsFromMutationImpact?.({
|
|
735
|
+
superdoc,
|
|
736
|
+
documentId,
|
|
737
|
+
removedIds
|
|
738
|
+
}) ?? {
|
|
739
|
+
ok: true,
|
|
740
|
+
removedIds: []
|
|
866
741
|
};
|
|
867
742
|
}
|
|
743
|
+
function readAllResolvedFact(event, receipt) {
|
|
744
|
+
const fact = event?.trackedChangeAllResolved;
|
|
745
|
+
if (event?.origin === "history" || !fact || fact.schemaVersion !== 1 || fact.targetKind !== "all" || fact.decision !== "accept" && fact.decision !== "reject" || fact.remainingLogicalCount !== 0 || typeof fact.catalogRevision !== "string" || !fact.catalogRevision || typeof fact.sourceCoverageRevision !== "string" || !fact.sourceCoverageRevision || !Number.isSafeInteger(fact.logicalTargetCount) || fact.logicalTargetCount <= 0 || !Number.isSafeInteger(fact.physicalCarrierCount) || fact.physicalCarrierCount < fact.logicalTargetCount || typeof fact.txId !== "string" || fact.txId !== receipt.txId || typeof fact.documentEpoch !== "string" || !Number.isSafeInteger(fact.commitSequence) || typeof fact.packagePreviousRevision !== "string" || typeof fact.packageNextRevision !== "string" || fact.packagePreviousRevision === fact.packageNextRevision) return null;
|
|
746
|
+
return fact;
|
|
747
|
+
}
|
|
748
|
+
//#endregion
|
|
749
|
+
//#region src/helpers/v2-typing-mutation-event.js
|
|
868
750
|
/**
|
|
869
|
-
*
|
|
751
|
+
* Command kinds whose committed mutations belong to the sustained typing
|
|
752
|
+
* cadence class (insert / replace / plain paste / Backspace / Delete).
|
|
753
|
+
*
|
|
754
|
+
* The SuperDoc shell debounces per-keystroke review-row hydration for these
|
|
755
|
+
* kinds instead of refreshing comments + tracked changes on every commit —
|
|
756
|
+
* hydrating immediately per keystroke was a measured worker-read storm during
|
|
757
|
+
* typing and backspace bursts. The `text.*` aliases cover integrations that
|
|
758
|
+
* forward Document API style command ids rather than editable-input kinds.
|
|
759
|
+
*/
|
|
760
|
+
var V2_TYPING_COMMAND_KINDS = /* @__PURE__ */ new Set([
|
|
761
|
+
"insert-text",
|
|
762
|
+
"replace-text",
|
|
763
|
+
"plain-text-paste",
|
|
764
|
+
"delete-backward",
|
|
765
|
+
"delete-forward",
|
|
766
|
+
"text.insert",
|
|
767
|
+
"text.replace",
|
|
768
|
+
"text.pastePlain",
|
|
769
|
+
"text.deleteBackward",
|
|
770
|
+
"text.deleteForward",
|
|
771
|
+
"structural.enter",
|
|
772
|
+
"structural:enter-split-paragraph",
|
|
773
|
+
"structural:enter-insert-paragraph-before",
|
|
774
|
+
"structural:enter-insert-paragraph-after",
|
|
775
|
+
"structural:shift-enter-line-break",
|
|
776
|
+
"structural:backspace-boundary-merge-with-previous",
|
|
777
|
+
"structural:delete-boundary-merge-with-next",
|
|
778
|
+
"backspace:boundary-merge-with-previous",
|
|
779
|
+
"backspace:list-remove",
|
|
780
|
+
"backspace:list-outdent"
|
|
781
|
+
]);
|
|
782
|
+
/**
|
|
783
|
+
* True when a forwarded v2 host event is a committed editable-input mutation
|
|
784
|
+
* of the sustained-typing class, i.e. review-row hydration for it should be
|
|
785
|
+
* debounced rather than fired immediately.
|
|
870
786
|
*
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
787
|
+
* Events without a forwarded `editableCommandKind` (programmatic Document API
|
|
788
|
+
* mutations, history commits, unclassified structural commands) return false
|
|
789
|
+
* so they keep hydrating immediately.
|
|
790
|
+
*
|
|
791
|
+
* @param {{ type?: string, origin?: string, editableCommandKind?: string } | null | undefined} event
|
|
792
|
+
* @returns {boolean}
|
|
876
793
|
*/
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
if (!Array.isArray(payload?.invalidatedRefs)) return removedIds;
|
|
882
|
-
for (const ref of payload.invalidatedRefs) if (ref?.kind === "entity" && ref.entityType === "comment" && typeof ref.entityId === "string" && ref.entityId) removedIds.add(ref.entityId);
|
|
883
|
-
return removedIds;
|
|
884
|
-
}
|
|
885
|
-
function applyV2CommentInvalidationFromMutation({ event, commentsStore, superdoc, documentId } = {}) {
|
|
886
|
-
const removedIds = collectV2InvalidatedCommentIds(event);
|
|
887
|
-
if (removedIds.size === 0) return {
|
|
888
|
-
ok: true,
|
|
889
|
-
removedIds: []
|
|
890
|
-
};
|
|
891
|
-
return commentsStore?.dropCommentsFromMutationImpact?.({
|
|
892
|
-
superdoc,
|
|
893
|
-
documentId,
|
|
894
|
-
removedIds
|
|
895
|
-
}) ?? {
|
|
896
|
-
ok: true,
|
|
897
|
-
removedIds: []
|
|
898
|
-
};
|
|
899
|
-
}
|
|
900
|
-
function readAllResolvedFact(event, receipt) {
|
|
901
|
-
const fact = event?.trackedChangeAllResolved;
|
|
902
|
-
if (event?.origin === "history" || !fact || fact.schemaVersion !== 1 || fact.targetKind !== "all" || fact.decision !== "accept" && fact.decision !== "reject" || fact.remainingLogicalCount !== 0 || typeof fact.catalogRevision !== "string" || !fact.catalogRevision || typeof fact.sourceCoverageRevision !== "string" || !fact.sourceCoverageRevision || !Number.isSafeInteger(fact.logicalTargetCount) || fact.logicalTargetCount <= 0 || !Number.isSafeInteger(fact.physicalCarrierCount) || fact.physicalCarrierCount < fact.logicalTargetCount || typeof fact.txId !== "string" || fact.txId !== receipt.txId || typeof fact.documentEpoch !== "string" || !Number.isSafeInteger(fact.commitSequence) || typeof fact.packagePreviousRevision !== "string" || typeof fact.packageNextRevision !== "string" || fact.packagePreviousRevision === fact.packageNextRevision) return null;
|
|
903
|
-
return fact;
|
|
904
|
-
}
|
|
794
|
+
var isV2EditableTextMutationEvent = (event) => {
|
|
795
|
+
if (event?.type !== "mutation:committed" || event.origin !== "command") return false;
|
|
796
|
+
return V2_TYPING_COMMAND_KINDS.has(event.editableCommandKind);
|
|
797
|
+
};
|
|
905
798
|
//#endregion
|
|
906
799
|
//#region src/public/ui/reasons.ts
|
|
907
800
|
/**
|
|
@@ -1430,603 +1323,717 @@ var COMMAND_CATALOG = [
|
|
|
1430
1323
|
key: "highlight",
|
|
1431
1324
|
kind: "value-string"
|
|
1432
1325
|
},
|
|
1433
|
-
normalizePayload: normalizeColorPayload
|
|
1326
|
+
normalizePayload: normalizeColorPayload
|
|
1327
|
+
},
|
|
1328
|
+
{
|
|
1329
|
+
id: "link",
|
|
1330
|
+
family: "links",
|
|
1331
|
+
disposition: "routed",
|
|
1332
|
+
mutates: true,
|
|
1333
|
+
docRoute: "hyperlinks.wrap",
|
|
1334
|
+
activeMark: "link",
|
|
1335
|
+
link: { kind: "link" }
|
|
1336
|
+
},
|
|
1337
|
+
{
|
|
1338
|
+
id: "text-align",
|
|
1339
|
+
family: "paragraph",
|
|
1340
|
+
disposition: "routed",
|
|
1341
|
+
mutates: true,
|
|
1342
|
+
docRoute: "format.paragraph.setAlignment",
|
|
1343
|
+
blockParagraph: { kind: "alignment" },
|
|
1344
|
+
normalizePayload: normalizeAlignmentPayload
|
|
1345
|
+
},
|
|
1346
|
+
{
|
|
1347
|
+
id: "line-height",
|
|
1348
|
+
family: "paragraph",
|
|
1349
|
+
disposition: "routed",
|
|
1350
|
+
mutates: true,
|
|
1351
|
+
docRoute: "format.paragraph.setSpacing",
|
|
1352
|
+
blockParagraph: { kind: "spacing-line" },
|
|
1353
|
+
normalizePayload: normalizeLineHeightPayload
|
|
1354
|
+
},
|
|
1355
|
+
{
|
|
1356
|
+
id: "linked-style",
|
|
1357
|
+
family: "paragraph",
|
|
1358
|
+
disposition: "routed",
|
|
1359
|
+
mutates: true,
|
|
1360
|
+
docRoute: "styles.paragraph.setStyle",
|
|
1361
|
+
blockParagraph: { kind: "style" },
|
|
1362
|
+
normalizePayload: normalizeStyleIdPayload
|
|
1363
|
+
},
|
|
1364
|
+
{
|
|
1365
|
+
id: "bullet-list",
|
|
1366
|
+
family: "lists",
|
|
1367
|
+
disposition: "routed",
|
|
1368
|
+
mutates: true,
|
|
1369
|
+
docRoute: "lists.apply",
|
|
1370
|
+
list: {
|
|
1371
|
+
mode: "toggle-seed",
|
|
1372
|
+
seed: "bullet"
|
|
1373
|
+
}
|
|
1374
|
+
},
|
|
1375
|
+
{
|
|
1376
|
+
id: "numbered-list",
|
|
1377
|
+
family: "lists",
|
|
1378
|
+
disposition: "routed",
|
|
1379
|
+
mutates: true,
|
|
1380
|
+
docRoute: "lists.apply",
|
|
1381
|
+
list: {
|
|
1382
|
+
mode: "toggle-seed",
|
|
1383
|
+
seed: "ordered"
|
|
1384
|
+
}
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
id: "indent-increase",
|
|
1388
|
+
family: "lists/indent",
|
|
1389
|
+
disposition: "routed",
|
|
1390
|
+
mutates: true,
|
|
1391
|
+
docRoute: "lists.indent",
|
|
1392
|
+
list: { mode: "indent" }
|
|
1393
|
+
},
|
|
1394
|
+
{
|
|
1395
|
+
id: "indent-decrease",
|
|
1396
|
+
family: "lists/indent",
|
|
1397
|
+
disposition: "routed",
|
|
1398
|
+
mutates: true,
|
|
1399
|
+
docRoute: "lists.outdent",
|
|
1400
|
+
list: { mode: "outdent" }
|
|
1401
|
+
},
|
|
1402
|
+
{
|
|
1403
|
+
id: "direction-ltr",
|
|
1404
|
+
family: "direction",
|
|
1405
|
+
disposition: "routed",
|
|
1406
|
+
mutates: true,
|
|
1407
|
+
docRoute: "format.paragraph.setDirection",
|
|
1408
|
+
blockParagraph: {
|
|
1409
|
+
kind: "direction",
|
|
1410
|
+
fixedValue: "ltr"
|
|
1411
|
+
}
|
|
1412
|
+
},
|
|
1413
|
+
{
|
|
1414
|
+
id: "direction-rtl",
|
|
1415
|
+
family: "direction",
|
|
1416
|
+
disposition: "routed",
|
|
1417
|
+
mutates: true,
|
|
1418
|
+
docRoute: "format.paragraph.setDirection",
|
|
1419
|
+
blockParagraph: {
|
|
1420
|
+
kind: "direction",
|
|
1421
|
+
fixedValue: "rtl"
|
|
1422
|
+
}
|
|
1423
|
+
},
|
|
1424
|
+
{
|
|
1425
|
+
id: "clear-formatting",
|
|
1426
|
+
family: "formatting",
|
|
1427
|
+
disposition: "routed",
|
|
1428
|
+
mutates: true,
|
|
1429
|
+
docRoute: "format.apply",
|
|
1430
|
+
inline: {
|
|
1431
|
+
key: "*",
|
|
1432
|
+
kind: "clear"
|
|
1433
|
+
}
|
|
1434
|
+
},
|
|
1435
|
+
{
|
|
1436
|
+
id: "image",
|
|
1437
|
+
family: "media",
|
|
1438
|
+
disposition: "routed",
|
|
1439
|
+
mutates: true,
|
|
1440
|
+
docRoute: "create.image",
|
|
1441
|
+
create: { kind: "image" }
|
|
1442
|
+
},
|
|
1443
|
+
{
|
|
1444
|
+
id: "table-of-contents-insert",
|
|
1445
|
+
family: "TOC",
|
|
1446
|
+
disposition: "routed",
|
|
1447
|
+
mutates: true,
|
|
1448
|
+
docRoute: "create.tableOfContents",
|
|
1449
|
+
create: { kind: "toc" }
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
id: "table-insert",
|
|
1453
|
+
family: "tables",
|
|
1454
|
+
disposition: "routed",
|
|
1455
|
+
mutates: true,
|
|
1456
|
+
docRoute: "create.table",
|
|
1457
|
+
create: { kind: "table" }
|
|
1458
|
+
},
|
|
1459
|
+
{
|
|
1460
|
+
id: "table-add-row-before",
|
|
1461
|
+
family: "tables",
|
|
1462
|
+
disposition: "routed",
|
|
1463
|
+
mutates: true,
|
|
1464
|
+
docRoute: "tables.insertRow",
|
|
1465
|
+
table: {
|
|
1466
|
+
action: "insert-row-before",
|
|
1467
|
+
op: "insertRow"
|
|
1468
|
+
},
|
|
1469
|
+
reason: TABLE_CONTEXT
|
|
1470
|
+
},
|
|
1471
|
+
{
|
|
1472
|
+
id: "table-add-row-after",
|
|
1473
|
+
family: "tables",
|
|
1474
|
+
disposition: "routed",
|
|
1475
|
+
mutates: true,
|
|
1476
|
+
docRoute: "tables.insertRow",
|
|
1477
|
+
table: {
|
|
1478
|
+
action: "insert-row-after",
|
|
1479
|
+
op: "insertRow"
|
|
1480
|
+
},
|
|
1481
|
+
reason: TABLE_CONTEXT
|
|
1482
|
+
},
|
|
1483
|
+
{
|
|
1484
|
+
id: "table-delete-row",
|
|
1485
|
+
family: "tables",
|
|
1486
|
+
disposition: "routed",
|
|
1487
|
+
mutates: true,
|
|
1488
|
+
docRoute: "tables.deleteRow",
|
|
1489
|
+
table: {
|
|
1490
|
+
action: "delete-row",
|
|
1491
|
+
op: "deleteRow"
|
|
1492
|
+
},
|
|
1493
|
+
reason: TABLE_CONTEXT
|
|
1494
|
+
},
|
|
1495
|
+
{
|
|
1496
|
+
id: "table-add-column-before",
|
|
1497
|
+
family: "tables",
|
|
1498
|
+
disposition: "routed",
|
|
1499
|
+
mutates: true,
|
|
1500
|
+
docRoute: "tables.insertColumn",
|
|
1501
|
+
table: {
|
|
1502
|
+
action: "insert-column-before",
|
|
1503
|
+
op: "insertColumn"
|
|
1504
|
+
},
|
|
1505
|
+
reason: TABLE_CONTEXT
|
|
1506
|
+
},
|
|
1507
|
+
{
|
|
1508
|
+
id: "table-add-column-after",
|
|
1509
|
+
family: "tables",
|
|
1510
|
+
disposition: "routed",
|
|
1511
|
+
mutates: true,
|
|
1512
|
+
docRoute: "tables.insertColumn",
|
|
1513
|
+
table: {
|
|
1514
|
+
action: "insert-column-after",
|
|
1515
|
+
op: "insertColumn"
|
|
1516
|
+
},
|
|
1517
|
+
reason: TABLE_CONTEXT
|
|
1518
|
+
},
|
|
1519
|
+
{
|
|
1520
|
+
id: "table-delete-column",
|
|
1521
|
+
family: "tables",
|
|
1522
|
+
disposition: "routed",
|
|
1523
|
+
mutates: true,
|
|
1524
|
+
docRoute: "tables.deleteColumn",
|
|
1525
|
+
table: {
|
|
1526
|
+
action: "delete-column",
|
|
1527
|
+
op: "deleteColumn"
|
|
1528
|
+
},
|
|
1529
|
+
reason: TABLE_CONTEXT
|
|
1530
|
+
},
|
|
1531
|
+
{
|
|
1532
|
+
id: "table-delete",
|
|
1533
|
+
family: "tables",
|
|
1534
|
+
disposition: "routed",
|
|
1535
|
+
mutates: true,
|
|
1536
|
+
docRoute: "tables.delete",
|
|
1537
|
+
table: {
|
|
1538
|
+
action: "delete-table",
|
|
1539
|
+
op: "delete"
|
|
1540
|
+
},
|
|
1541
|
+
reason: TABLE_CONTEXT
|
|
1434
1542
|
},
|
|
1435
1543
|
{
|
|
1436
|
-
id: "
|
|
1437
|
-
family: "
|
|
1544
|
+
id: "table-merge-cells",
|
|
1545
|
+
family: "tables",
|
|
1438
1546
|
disposition: "routed",
|
|
1439
1547
|
mutates: true,
|
|
1440
|
-
docRoute: "
|
|
1441
|
-
|
|
1442
|
-
|
|
1548
|
+
docRoute: "tables.mergeCells",
|
|
1549
|
+
table: {
|
|
1550
|
+
action: "merge-cells",
|
|
1551
|
+
op: "mergeCells"
|
|
1552
|
+
},
|
|
1553
|
+
reason: TABLE_CONTEXT
|
|
1443
1554
|
},
|
|
1444
1555
|
{
|
|
1445
|
-
id: "
|
|
1446
|
-
family: "
|
|
1556
|
+
id: "table-split-cell",
|
|
1557
|
+
family: "tables",
|
|
1447
1558
|
disposition: "routed",
|
|
1448
1559
|
mutates: true,
|
|
1449
|
-
docRoute: "
|
|
1450
|
-
|
|
1451
|
-
|
|
1560
|
+
docRoute: "tables.splitCell",
|
|
1561
|
+
table: {
|
|
1562
|
+
action: "split-cell",
|
|
1563
|
+
op: "splitCell",
|
|
1564
|
+
requiresCell: true
|
|
1565
|
+
},
|
|
1566
|
+
reason: TABLE_CONTEXT
|
|
1452
1567
|
},
|
|
1453
1568
|
{
|
|
1454
|
-
id: "
|
|
1455
|
-
family: "
|
|
1569
|
+
id: "table-remove-borders",
|
|
1570
|
+
family: "tables",
|
|
1456
1571
|
disposition: "routed",
|
|
1457
1572
|
mutates: true,
|
|
1458
|
-
docRoute: "
|
|
1459
|
-
|
|
1460
|
-
|
|
1573
|
+
docRoute: "tables.setBorders",
|
|
1574
|
+
table: {
|
|
1575
|
+
action: "remove-borders",
|
|
1576
|
+
op: "setBorders"
|
|
1577
|
+
},
|
|
1578
|
+
reason: TABLE_CONTEXT
|
|
1461
1579
|
},
|
|
1462
1580
|
{
|
|
1463
|
-
id: "
|
|
1464
|
-
family: "
|
|
1581
|
+
id: "ruler",
|
|
1582
|
+
family: "UI chrome",
|
|
1465
1583
|
disposition: "routed",
|
|
1466
|
-
mutates:
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
normalizePayload: normalizeStyleIdPayload
|
|
1584
|
+
mutates: false,
|
|
1585
|
+
instanceRoute: "toggleRuler",
|
|
1586
|
+
valueFrom: "ruler"
|
|
1470
1587
|
},
|
|
1471
1588
|
{
|
|
1472
|
-
id: "
|
|
1473
|
-
family: "
|
|
1589
|
+
id: "formatting-marks",
|
|
1590
|
+
family: "UI chrome",
|
|
1474
1591
|
disposition: "routed",
|
|
1475
|
-
mutates:
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
mode: "toggle-seed",
|
|
1479
|
-
seed: "bullet"
|
|
1480
|
-
}
|
|
1592
|
+
mutates: false,
|
|
1593
|
+
instanceRoute: "toggleFormattingMarks",
|
|
1594
|
+
valueFrom: "formattingMarks"
|
|
1481
1595
|
},
|
|
1482
1596
|
{
|
|
1483
|
-
id: "
|
|
1484
|
-
family: "
|
|
1597
|
+
id: "copy-format",
|
|
1598
|
+
family: "formatting",
|
|
1485
1599
|
disposition: "routed",
|
|
1486
|
-
mutates:
|
|
1487
|
-
docRoute: "lists.apply",
|
|
1488
|
-
list: {
|
|
1489
|
-
mode: "toggle-seed",
|
|
1490
|
-
seed: "ordered"
|
|
1491
|
-
}
|
|
1600
|
+
mutates: false
|
|
1492
1601
|
},
|
|
1493
1602
|
{
|
|
1494
|
-
id: "
|
|
1495
|
-
family: "
|
|
1496
|
-
disposition: "
|
|
1603
|
+
id: "table-fix",
|
|
1604
|
+
family: "tables",
|
|
1605
|
+
disposition: "unsupported",
|
|
1497
1606
|
mutates: true,
|
|
1498
|
-
|
|
1499
|
-
|
|
1607
|
+
reason: UNSUPPORTED
|
|
1608
|
+
}
|
|
1609
|
+
];
|
|
1610
|
+
var CATALOG_BY_ID = new Map(COMMAND_CATALOG.map((descriptor) => [descriptor.id, descriptor]));
|
|
1611
|
+
/** All built-in command ids known to the controller (routed + deferred + unsupported). */
|
|
1612
|
+
var ALL_BUILT_IN_COMMAND_IDS = COMMAND_CATALOG.map((d) => d.id);
|
|
1613
|
+
/** Resolve a command descriptor by id, or `null` when the id is unknown. */
|
|
1614
|
+
function getCommandDescriptor(id) {
|
|
1615
|
+
return CATALOG_BY_ID.get(id) ?? null;
|
|
1616
|
+
}
|
|
1617
|
+
//#endregion
|
|
1618
|
+
//#region src/public/ui/entity-at.ts
|
|
1619
|
+
function parseCommaSeparatedIds(value) {
|
|
1620
|
+
return value.split(",").map((id) => id.trim()).filter(Boolean);
|
|
1621
|
+
}
|
|
1622
|
+
/**
|
|
1623
|
+
* Collect every public-id candidate a painted run can carry for a tracked
|
|
1624
|
+
* change, deduped, in priority order: the canonical
|
|
1625
|
+
* `data-track-change-preferred-target-id` first (when the painter stamps one),
|
|
1626
|
+
* then the `data-track-change-ids` list, then the singular
|
|
1627
|
+
* `data-track-change-id`. The caller validates these against the live
|
|
1628
|
+
* tracked-changes slice and keeps whichever is the public id, so it does not
|
|
1629
|
+
* matter which attribute carries it — an imported/raw alias on one attribute
|
|
1630
|
+
* never hides the public id on another (a union, not a prefer-one-attribute).
|
|
1631
|
+
*/
|
|
1632
|
+
function getTrackChangeIds(node) {
|
|
1633
|
+
const out = [];
|
|
1634
|
+
const add = (id) => {
|
|
1635
|
+
if (id && !out.includes(id)) out.push(id);
|
|
1636
|
+
};
|
|
1637
|
+
add(node.getAttribute("data-track-change-preferred-target-id"));
|
|
1638
|
+
const list = node.getAttribute("data-track-change-ids");
|
|
1639
|
+
if (list) for (const id of parseCommaSeparatedIds(list)) add(id);
|
|
1640
|
+
add(node.getAttribute("data-track-change-id"));
|
|
1641
|
+
return out;
|
|
1642
|
+
}
|
|
1643
|
+
/**
|
|
1644
|
+
* Read painted entities off `el` and every ancestor up to the document root, or
|
|
1645
|
+
* up to and INCLUDING `stopAt` when given. Innermost-first ordering: a tracked
|
|
1646
|
+
* change inside a comment highlight returns `[{ trackedChange }, { comment }]`,
|
|
1647
|
+
* matching what a switch on `hits[0]` expects when picking the most specific
|
|
1648
|
+
* entity.
|
|
1649
|
+
*
|
|
1650
|
+
* `stopAt` bounds the walk to the visible host: its own attributes are read, but
|
|
1651
|
+
* the walk never climbs into an app wrapper ABOVE it, so wrapper data-* cannot
|
|
1652
|
+
* leak into the hits. Omitting it keeps the original walk-to-document-root.
|
|
1653
|
+
*
|
|
1654
|
+
* Returns `[]` for null / non-Element starts. Uses duck-typed `getAttribute`
|
|
1655
|
+
* access so it works under any DOM implementation (happy-dom, jsdom, real
|
|
1656
|
+
* browser) without an `instanceof` check that could fail across realms.
|
|
1657
|
+
*/
|
|
1658
|
+
function collectEntityHitsFromChain(start, stopAt) {
|
|
1659
|
+
if (!start || typeof start.getAttribute !== "function") return [];
|
|
1660
|
+
const hits = [];
|
|
1661
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1662
|
+
let pendingStory = [];
|
|
1663
|
+
let nearestStoryKey = null;
|
|
1664
|
+
let nearestLayoutStory = null;
|
|
1665
|
+
let el = start;
|
|
1666
|
+
while (el) {
|
|
1667
|
+
const node = el;
|
|
1668
|
+
nearestStoryKey ??= node.getAttribute("data-story-key");
|
|
1669
|
+
const trackChangeIds = getTrackChangeIds(node);
|
|
1670
|
+
const storyKey = trackChangeIds.length > 0 ? node.getAttribute("data-story-key") : null;
|
|
1671
|
+
for (const trackChangeId of trackChangeIds) {
|
|
1672
|
+
const key = `trackedChange:${trackChangeId}`;
|
|
1673
|
+
if (!seen.has(key)) {
|
|
1674
|
+
seen.add(key);
|
|
1675
|
+
const hit = {
|
|
1676
|
+
type: "trackedChange",
|
|
1677
|
+
id: trackChangeId
|
|
1678
|
+
};
|
|
1679
|
+
if (storyKey) hit.storyKey = storyKey;
|
|
1680
|
+
hits.push(hit);
|
|
1681
|
+
pendingStory.push(hit);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
const layoutStory = node.getAttribute("data-layout-story");
|
|
1685
|
+
nearestLayoutStory ??= layoutStory;
|
|
1686
|
+
if (layoutStory && pendingStory.length > 0) {
|
|
1687
|
+
for (const hit of pendingStory) hit.story = layoutStory;
|
|
1688
|
+
pendingStory = [];
|
|
1689
|
+
}
|
|
1690
|
+
const citationId = node.getAttribute("data-citation-id");
|
|
1691
|
+
if (citationId) {
|
|
1692
|
+
const key = `citation:${citationId}`;
|
|
1693
|
+
if (!seen.has(key)) {
|
|
1694
|
+
seen.add(key);
|
|
1695
|
+
hits.push({
|
|
1696
|
+
type: "citation",
|
|
1697
|
+
id: citationId
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
const commentIds = node.getAttribute("data-comment-ids");
|
|
1702
|
+
if (commentIds) for (const id of parseCommaSeparatedIds(commentIds)) {
|
|
1703
|
+
const key = `comment:${id}`;
|
|
1704
|
+
if (!seen.has(key)) {
|
|
1705
|
+
seen.add(key);
|
|
1706
|
+
hits.push({
|
|
1707
|
+
type: "comment",
|
|
1708
|
+
id
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
const sdtType = node.getAttribute("data-sdt-type");
|
|
1713
|
+
const sdtId = node.getAttribute("data-sdt-id");
|
|
1714
|
+
if (sdtId && sdtType === "structuredContent") {
|
|
1715
|
+
const key = `contentControl:${sdtId}`;
|
|
1716
|
+
if (!seen.has(key)) {
|
|
1717
|
+
seen.add(key);
|
|
1718
|
+
const scopeAttr = node.getAttribute("data-sdt-scope");
|
|
1719
|
+
const tag = node.getAttribute("data-sdt-tag");
|
|
1720
|
+
const hit = {
|
|
1721
|
+
type: "contentControl",
|
|
1722
|
+
id: sdtId
|
|
1723
|
+
};
|
|
1724
|
+
if (nearestStoryKey) hit.storyKey = nearestStoryKey;
|
|
1725
|
+
if (nearestLayoutStory) hit.story = nearestLayoutStory;
|
|
1726
|
+
else pendingStory.push(hit);
|
|
1727
|
+
if (scopeAttr === "block" || scopeAttr === "inline") hit.scope = scopeAttr;
|
|
1728
|
+
if (tag) hit.tag = tag;
|
|
1729
|
+
hits.push(hit);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
if (stopAt && el === stopAt) break;
|
|
1733
|
+
el = el.parentElement;
|
|
1734
|
+
}
|
|
1735
|
+
return hits;
|
|
1736
|
+
}
|
|
1737
|
+
//#endregion
|
|
1738
|
+
//#region ../layout-engine/contracts/src/direction-context.ts
|
|
1739
|
+
/**
|
|
1740
|
+
* Read a paragraph's inline base direction from its attributes.
|
|
1741
|
+
*
|
|
1742
|
+
* Prefers the resolved {@link ParagraphDirectionContext} (SD-2776) when
|
|
1743
|
+
* present. Falls back to `paragraphProperties.rightToLeft` for PM-node /
|
|
1744
|
+
* editor paths that store direction on the raw OOXML properties rather
|
|
1745
|
+
* than the typed direction context.
|
|
1746
|
+
*
|
|
1747
|
+
* Consumers should call this instead of inspecting attrs ad hoc so the
|
|
1748
|
+
* direction source check stays in one place.
|
|
1749
|
+
*/
|
|
1750
|
+
function getParagraphInlineDirection(attrs) {
|
|
1751
|
+
const fromContext = attrs?.directionContext?.inlineDirection;
|
|
1752
|
+
if (fromContext != null) return fromContext;
|
|
1753
|
+
const ppRtl = attrs?.paragraphProperties?.rightToLeft;
|
|
1754
|
+
if (ppRtl === true) return "rtl";
|
|
1755
|
+
if (ppRtl === false) return "ltr";
|
|
1756
|
+
}
|
|
1757
|
+
//#endregion
|
|
1758
|
+
//#region ../layout-engine/contracts/src/drawing-taxonomy.ts
|
|
1759
|
+
/**
|
|
1760
|
+
* Frozen canonical diagnostic codes for drawing rendering.
|
|
1761
|
+
*
|
|
1762
|
+
* New extractor/adapter diagnostics MUST use these exact strings. Family-
|
|
1763
|
+
* specific codes are required — do not collapse everything to
|
|
1764
|
+
* `render.unsupported-inline-ooxml` (plan §4).
|
|
1765
|
+
*/
|
|
1766
|
+
var DRAWING_DIAGNOSTIC_CODES = {
|
|
1767
|
+
/** External image relationship (`r:link` / `TargetMode="External"`). Not fetched. */
|
|
1768
|
+
externalImageDeferred: "render.media.external-image-deferred",
|
|
1769
|
+
/** Drawing references a relationship id that does not exist on the owner part. */
|
|
1770
|
+
missingRelationship: "render.drawing.missing-relationship",
|
|
1771
|
+
/** Relationship resolves but the target media part bytes are missing/empty. */
|
|
1772
|
+
missingMediaPart: "render.media.missing-part",
|
|
1773
|
+
/** Relationship exists but is not an image relationship type. */
|
|
1774
|
+
unsupportedRelationshipType: "render.drawing.unsupported-relationship-type",
|
|
1775
|
+
/** Media MIME is not in the supported allowlist. */
|
|
1776
|
+
unsupportedMime: "render.media.unsupported-mime",
|
|
1777
|
+
/** Media part exceeds the host byte-size policy before bytes are materialized. */
|
|
1778
|
+
imageTooLarge: "render.media.image-too-large",
|
|
1779
|
+
/** SVG content rejected by the SVG safety policy. */
|
|
1780
|
+
unsafeSvg: "render.media.unsafe-svg",
|
|
1781
|
+
/** Metafile / TIFF (EMF, WMF, TIFF) with no approved conversion path. */
|
|
1782
|
+
unsupportedFormat: "render.media.unsupported-format",
|
|
1783
|
+
/** OLE / ActiveX / embedded package object. */
|
|
1784
|
+
embeddedObjectNotSupported: "render.embedded-object-not-supported",
|
|
1785
|
+
/** SmartArt / diagram / unknown external graphic-data object. */
|
|
1786
|
+
unsupportedObject: "render.drawing.unsupported-object",
|
|
1787
|
+
/** VML structure outside any supported image-like subset. */
|
|
1788
|
+
vmlUnsupported: "render.drawing.vml-unsupported",
|
|
1789
|
+
/** VML image-like content that could not be promoted to a supported image. */
|
|
1790
|
+
vmlImageUnsupported: "render.drawing.vml-image-unsupported",
|
|
1791
|
+
/** Custom geometry command the extractor does not implement (e.g. `arcTo`). */
|
|
1792
|
+
unsupportedGeometryCommand: "render.drawing.unsupported-geometry-command",
|
|
1793
|
+
/** Anchor fields required for honest placement are unsupported. */
|
|
1794
|
+
anchorUnsupported: "render.drawing.anchor-unsupported",
|
|
1795
|
+
/** Wrap fields required for honest placement are unsupported. */
|
|
1796
|
+
wrapUnsupported: "render.drawing.wrap-unsupported",
|
|
1797
|
+
/** `mc:AlternateContent` had no supported choice and no usable fallback. */
|
|
1798
|
+
altContentNoSupportedChoice: "render.drawing.altcontent-no-supported-choice",
|
|
1799
|
+
/** A child of an otherwise-supported group is unsupported. */
|
|
1800
|
+
groupChildUnsupported: "render.drawing.group-child-unsupported"
|
|
1801
|
+
};
|
|
1802
|
+
DRAWING_DIAGNOSTIC_CODES.missingRelationship, DRAWING_DIAGNOSTIC_CODES.unsupportedRelationshipType, DRAWING_DIAGNOSTIC_CODES.unsupportedRelationshipType, DRAWING_DIAGNOSTIC_CODES.imageTooLarge, DRAWING_DIAGNOSTIC_CODES.missingMediaPart, DRAWING_DIAGNOSTIC_CODES.unsupportedObject, DRAWING_DIAGNOSTIC_CODES.vmlUnsupported;
|
|
1803
|
+
/**
|
|
1804
|
+
* The frozen drawing support taxonomy.
|
|
1805
|
+
*
|
|
1806
|
+
* Invariants (enforced by `drawing-taxonomy.test.ts`):
|
|
1807
|
+
* - every `supported` family has a real contract target (`!== 'none'`);
|
|
1808
|
+
* - every `DrawingBlock`-targeted family declares a `drawingKind`;
|
|
1809
|
+
* - every `fail-closed` family declares a canonical `diagnostic`;
|
|
1810
|
+
* - every canonical diagnostic code is referenced by at least one fail-closed
|
|
1811
|
+
* family;
|
|
1812
|
+
* - `deferred` families make no support claim (`contract: 'none'`, no
|
|
1813
|
+
* diagnostic).
|
|
1814
|
+
*/
|
|
1815
|
+
var DRAWING_SUPPORT_TAXONOMY = {
|
|
1816
|
+
inlineBitmap: {
|
|
1817
|
+
family: "inlineBitmap",
|
|
1818
|
+
support: "supported",
|
|
1819
|
+
description: "wp:inline pic:pic with internal media and browser-safe MIME (PNG/JPEG; WebP/SVG once the host media resolver lands).",
|
|
1820
|
+
contract: "ImageRun"
|
|
1500
1821
|
},
|
|
1501
|
-
{
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
docRoute: "lists.outdent",
|
|
1507
|
-
list: { mode: "outdent" }
|
|
1822
|
+
anchoredBitmap: {
|
|
1823
|
+
family: "anchoredBitmap",
|
|
1824
|
+
support: "supported",
|
|
1825
|
+
description: "wp:anchor bitmap with anchor/wrap expressible by ImageAnchor/ImageWrap. Never silently inlined.",
|
|
1826
|
+
contract: "ImageBlock"
|
|
1508
1827
|
},
|
|
1509
|
-
{
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
docRoute: "format.paragraph.setDirection",
|
|
1515
|
-
blockParagraph: {
|
|
1516
|
-
kind: "direction",
|
|
1517
|
-
fixedValue: "ltr"
|
|
1518
|
-
}
|
|
1828
|
+
imageChildInGroup: {
|
|
1829
|
+
family: "imageChildInGroup",
|
|
1830
|
+
support: "supported",
|
|
1831
|
+
description: "Bitmap child of a supported DrawingML group/drawing wrapper. Supported only when the parent is.",
|
|
1832
|
+
contract: "ImageDrawing"
|
|
1519
1833
|
},
|
|
1520
|
-
{
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
blockParagraph: {
|
|
1527
|
-
kind: "direction",
|
|
1528
|
-
fixedValue: "rtl"
|
|
1529
|
-
}
|
|
1834
|
+
vectorShape: {
|
|
1835
|
+
family: "vectorShape",
|
|
1836
|
+
support: "supported",
|
|
1837
|
+
description: "Block/floating DrawingML preset/custom shape with the supported geometry/style subset.",
|
|
1838
|
+
contract: "DrawingBlock",
|
|
1839
|
+
drawingKind: "vectorShape"
|
|
1530
1840
|
},
|
|
1531
|
-
{
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
inline: {
|
|
1538
|
-
key: "*",
|
|
1539
|
-
kind: "clear"
|
|
1540
|
-
}
|
|
1841
|
+
shapeGroup: {
|
|
1842
|
+
family: "shapeGroup",
|
|
1843
|
+
support: "supported",
|
|
1844
|
+
description: "DrawingML group whose rendered children are supported vector/image children.",
|
|
1845
|
+
contract: "DrawingBlock",
|
|
1846
|
+
drawingKind: "shapeGroup"
|
|
1541
1847
|
},
|
|
1542
|
-
{
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
create: { kind: "image" }
|
|
1848
|
+
chart: {
|
|
1849
|
+
family: "chart",
|
|
1850
|
+
support: "supported",
|
|
1851
|
+
description: "DrawingML chart projected into a ChartDrawing with parsed cached chart XML data. Complete Word chart fidelity remains deferred to chartFidelity.",
|
|
1852
|
+
contract: "DrawingBlock",
|
|
1853
|
+
drawingKind: "chart"
|
|
1549
1854
|
},
|
|
1550
|
-
{
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
docRoute: "create.tableOfContents",
|
|
1556
|
-
create: { kind: "toc" }
|
|
1855
|
+
alternateContent: {
|
|
1856
|
+
family: "alternateContent",
|
|
1857
|
+
support: "supported",
|
|
1858
|
+
description: "mc:AlternateContent traversal/select policy. Selected Choice/Fallback maps to its family contract; unselected branches preserved for save/reopen.",
|
|
1859
|
+
contract: "selected-choice"
|
|
1557
1860
|
},
|
|
1558
|
-
{
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
create: { kind: "table" }
|
|
1861
|
+
externalImage: {
|
|
1862
|
+
family: "externalImage",
|
|
1863
|
+
support: "fail-closed",
|
|
1864
|
+
description: "External image relationship (r:link / TargetMode=\"External\"). Not fetched.",
|
|
1865
|
+
contract: "none",
|
|
1866
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.externalImageDeferred
|
|
1565
1867
|
},
|
|
1566
|
-
{
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
table: {
|
|
1573
|
-
action: "insert-row-before",
|
|
1574
|
-
op: "insertRow"
|
|
1575
|
-
},
|
|
1576
|
-
reason: TABLE_CONTEXT
|
|
1868
|
+
missingRelationship: {
|
|
1869
|
+
family: "missingRelationship",
|
|
1870
|
+
support: "fail-closed",
|
|
1871
|
+
description: "Drawing references a relationship id absent from the owner part .rels.",
|
|
1872
|
+
contract: "none",
|
|
1873
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.missingRelationship
|
|
1577
1874
|
},
|
|
1578
|
-
{
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
table: {
|
|
1585
|
-
action: "insert-row-after",
|
|
1586
|
-
op: "insertRow"
|
|
1587
|
-
},
|
|
1588
|
-
reason: TABLE_CONTEXT
|
|
1875
|
+
missingMediaPart: {
|
|
1876
|
+
family: "missingMediaPart",
|
|
1877
|
+
support: "fail-closed",
|
|
1878
|
+
description: "Relationship resolves but the target media part bytes are missing or empty.",
|
|
1879
|
+
contract: "none",
|
|
1880
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.missingMediaPart
|
|
1589
1881
|
},
|
|
1590
|
-
{
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
table: {
|
|
1597
|
-
action: "delete-row",
|
|
1598
|
-
op: "deleteRow"
|
|
1599
|
-
},
|
|
1600
|
-
reason: TABLE_CONTEXT
|
|
1882
|
+
wrongRelationshipType: {
|
|
1883
|
+
family: "wrongRelationshipType",
|
|
1884
|
+
support: "fail-closed",
|
|
1885
|
+
description: "Relationship exists but is not an image relationship type.",
|
|
1886
|
+
contract: "none",
|
|
1887
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsupportedRelationshipType
|
|
1601
1888
|
},
|
|
1602
|
-
{
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
table: {
|
|
1609
|
-
action: "insert-column-before",
|
|
1610
|
-
op: "insertColumn"
|
|
1611
|
-
},
|
|
1612
|
-
reason: TABLE_CONTEXT
|
|
1889
|
+
unsupportedMime: {
|
|
1890
|
+
family: "unsupportedMime",
|
|
1891
|
+
support: "fail-closed",
|
|
1892
|
+
description: "Media MIME outside the supported allowlist (incl. GIF/BMP/ICO).",
|
|
1893
|
+
contract: "none",
|
|
1894
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsupportedMime
|
|
1613
1895
|
},
|
|
1614
|
-
{
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
table: {
|
|
1621
|
-
action: "insert-column-after",
|
|
1622
|
-
op: "insertColumn"
|
|
1623
|
-
},
|
|
1624
|
-
reason: TABLE_CONTEXT
|
|
1896
|
+
oversizedMediaPart: {
|
|
1897
|
+
family: "oversizedMediaPart",
|
|
1898
|
+
support: "fail-closed",
|
|
1899
|
+
description: "Media part exceeds the host byte-size policy before bytes are materialized.",
|
|
1900
|
+
contract: "none",
|
|
1901
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.imageTooLarge
|
|
1625
1902
|
},
|
|
1626
|
-
{
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
table: {
|
|
1633
|
-
action: "delete-column",
|
|
1634
|
-
op: "deleteColumn"
|
|
1635
|
-
},
|
|
1636
|
-
reason: TABLE_CONTEXT
|
|
1903
|
+
unsafeSvg: {
|
|
1904
|
+
family: "unsafeSvg",
|
|
1905
|
+
support: "fail-closed",
|
|
1906
|
+
description: "SVG content rejected by the SVG safety policy.",
|
|
1907
|
+
contract: "none",
|
|
1908
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsafeSvg
|
|
1637
1909
|
},
|
|
1638
|
-
{
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
table: {
|
|
1645
|
-
action: "delete-table",
|
|
1646
|
-
op: "delete"
|
|
1647
|
-
},
|
|
1648
|
-
reason: TABLE_CONTEXT
|
|
1910
|
+
metafileOrTiff: {
|
|
1911
|
+
family: "metafileOrTiff",
|
|
1912
|
+
support: "fail-closed",
|
|
1913
|
+
description: "EMF/WMF/TIFF and other non-browser-native formats with no approved conversion path.",
|
|
1914
|
+
contract: "none",
|
|
1915
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsupportedFormat
|
|
1649
1916
|
},
|
|
1650
|
-
{
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
table: {
|
|
1657
|
-
action: "merge-cells",
|
|
1658
|
-
op: "mergeCells"
|
|
1659
|
-
},
|
|
1660
|
-
reason: TABLE_CONTEXT
|
|
1917
|
+
embeddedObject: {
|
|
1918
|
+
family: "embeddedObject",
|
|
1919
|
+
support: "fail-closed",
|
|
1920
|
+
description: "OLE / ActiveX / embedded package object.",
|
|
1921
|
+
contract: "none",
|
|
1922
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.embeddedObjectNotSupported
|
|
1661
1923
|
},
|
|
1662
|
-
{
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
table: {
|
|
1669
|
-
action: "split-cell",
|
|
1670
|
-
op: "splitCell",
|
|
1671
|
-
requiresCell: true
|
|
1672
|
-
},
|
|
1673
|
-
reason: TABLE_CONTEXT
|
|
1924
|
+
smartArtOrDiagram: {
|
|
1925
|
+
family: "smartArtOrDiagram",
|
|
1926
|
+
support: "fail-closed",
|
|
1927
|
+
description: "SmartArt / diagram / unknown external graphic-data object.",
|
|
1928
|
+
contract: "none",
|
|
1929
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsupportedObject
|
|
1674
1930
|
},
|
|
1675
|
-
{
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
table: {
|
|
1682
|
-
action: "remove-borders",
|
|
1683
|
-
op: "setBorders"
|
|
1684
|
-
},
|
|
1685
|
-
reason: TABLE_CONTEXT
|
|
1931
|
+
vml: {
|
|
1932
|
+
family: "vml",
|
|
1933
|
+
support: "fail-closed",
|
|
1934
|
+
description: "VML structure outside any supported image-like subset (default fail-closed policy).",
|
|
1935
|
+
contract: "none",
|
|
1936
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.vmlUnsupported
|
|
1686
1937
|
},
|
|
1687
|
-
{
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
valueFrom: "ruler"
|
|
1938
|
+
vmlImageLike: {
|
|
1939
|
+
family: "vmlImageLike",
|
|
1940
|
+
support: "fail-closed",
|
|
1941
|
+
description: "Simple VML image references (v:imagedata) / watermark image metadata. Fail-closed unless a later change promotes a named subset with deterministic fixtures and exact oracles.",
|
|
1942
|
+
contract: "none",
|
|
1943
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.vmlImageUnsupported
|
|
1694
1944
|
},
|
|
1695
|
-
{
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
valueFrom: "formattingMarks"
|
|
1945
|
+
unsupportedGeometryCommand: {
|
|
1946
|
+
family: "unsupportedGeometryCommand",
|
|
1947
|
+
support: "fail-closed",
|
|
1948
|
+
description: "Custom geometry command the extractor does not implement, e.g. arcTo.",
|
|
1949
|
+
contract: "none",
|
|
1950
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.unsupportedGeometryCommand
|
|
1702
1951
|
},
|
|
1703
|
-
{
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1952
|
+
unsupportedAnchorFields: {
|
|
1953
|
+
family: "unsupportedAnchorFields",
|
|
1954
|
+
support: "fail-closed",
|
|
1955
|
+
description: "Anchor fields required for honest placement are unsupported (char-relative, alignment modes, etc.).",
|
|
1956
|
+
contract: "none",
|
|
1957
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.anchorUnsupported
|
|
1708
1958
|
},
|
|
1709
|
-
{
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
}
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
if (!props || typeof props !== "object") return {};
|
|
1760
|
-
const patch = {};
|
|
1761
|
-
if (props.fonts) patch.rFonts = {
|
|
1762
|
-
ascii: props.fonts.ascii,
|
|
1763
|
-
hAnsi: props.fonts.hAnsi,
|
|
1764
|
-
eastAsia: props.fonts.eastAsia,
|
|
1765
|
-
cs: props.fonts.cs,
|
|
1766
|
-
asciiTheme: props.fonts.asciiTheme,
|
|
1767
|
-
hAnsiTheme: props.fonts.hAnsiTheme,
|
|
1768
|
-
eastAsiaTheme: props.fonts.eastAsiaTheme,
|
|
1769
|
-
csTheme: props.fonts.csTheme,
|
|
1770
|
-
hint: props.fonts.hint
|
|
1771
|
-
};
|
|
1772
|
-
if (props.fontFamily != null) patch.fontFamily = props.fontFamily;
|
|
1773
|
-
if (props.lang) patch.lang = {
|
|
1774
|
-
val: props.lang.val,
|
|
1775
|
-
eastAsia: props.lang.eastAsia,
|
|
1776
|
-
bidi: props.lang.bidi
|
|
1777
|
-
};
|
|
1778
|
-
if (props.fontSize != null) patch.fontSize = props.fontSize;
|
|
1779
|
-
if (props.fontSizeCs != null) patch.fontSizeCs = props.fontSizeCs;
|
|
1780
|
-
const color = projectColorRefToInlineColor(props.color);
|
|
1781
|
-
if (color != null) patch.color = color;
|
|
1782
|
-
if (props.highlight != null) patch.highlight = props.highlight;
|
|
1783
|
-
const shading = projectShadingToInlinePatch(props.shading);
|
|
1784
|
-
if (shading) patch.shading = shading;
|
|
1785
|
-
if (props.cs != null) patch.cs = props.cs;
|
|
1786
|
-
if (props.rtl != null) patch.rtl = props.rtl;
|
|
1787
|
-
if (props.bold != null) patch.bold = props.bold;
|
|
1788
|
-
if (props.boldCs != null) patch.bCs = props.boldCs;
|
|
1789
|
-
if (props.italic != null) patch.italic = props.italic;
|
|
1790
|
-
if (props.italicCs != null) patch.iCs = props.italicCs;
|
|
1791
|
-
const underline = projectUnderlineToInlinePatch(props.underline);
|
|
1792
|
-
if (underline !== void 0) patch.underline = underline;
|
|
1793
|
-
if (props.strikethrough != null) patch.strike = props.strikethrough;
|
|
1794
|
-
if (props.doubleStrikethrough != null) patch.dstrike = props.doubleStrikethrough;
|
|
1795
|
-
if (props.caps != null) patch.caps = props.caps;
|
|
1796
|
-
if (props.smallCaps != null) patch.smallCaps = props.smallCaps;
|
|
1797
|
-
if (props.outline != null) patch.outline = props.outline;
|
|
1798
|
-
if (props.shadow != null) patch.shadow = props.shadow;
|
|
1799
|
-
if (props.emboss != null) patch.emboss = props.emboss;
|
|
1800
|
-
if (props.imprint != null) patch.imprint = props.imprint;
|
|
1801
|
-
if (props.verticalAlign != null) patch.vertAlign = props.verticalAlign;
|
|
1802
|
-
if (props.characterSpacing != null) patch.letterSpacing = props.characterSpacing;
|
|
1803
|
-
if (props.characterScale != null) patch.charScale = props.characterScale;
|
|
1804
|
-
if (props.kern != null) patch.kerning = props.kern;
|
|
1805
|
-
if (props.baselineShift != null) patch.position = props.baselineShift;
|
|
1806
|
-
if (props.fitTextWidth != null) patch.fitText = { val: props.fitTextWidth };
|
|
1807
|
-
if (props.vanish != null) patch.vanish = props.vanish;
|
|
1808
|
-
if (props.webHidden != null) patch.webHidden = props.webHidden;
|
|
1809
|
-
if (props.specVanish != null) patch.specVanish = props.specVanish;
|
|
1810
|
-
const border = projectBorderToInlinePatch(props.border);
|
|
1811
|
-
if (border) patch.border = border;
|
|
1812
|
-
return patch;
|
|
1813
|
-
}
|
|
1814
|
-
function projectColorRefToInlineColor(color) {
|
|
1815
|
-
if (!color) return void 0;
|
|
1816
|
-
if (typeof color === "string") return color;
|
|
1817
|
-
if (color.model === "rgb") return color.value;
|
|
1818
|
-
if (color.model === "auto") return "auto";
|
|
1819
|
-
}
|
|
1820
|
-
function projectUnderlineToInlinePatch(underline) {
|
|
1821
|
-
if (underline == null) return void 0;
|
|
1822
|
-
const patch = {};
|
|
1823
|
-
if (underline.style != null) patch.style = underline.style;
|
|
1824
|
-
if (underline.color?.model === "rgb") patch.color = underline.color.value;
|
|
1825
|
-
if (underline.color?.model === "theme") patch.themeColor = underline.color.theme;
|
|
1826
|
-
return Object.keys(patch).length > 0 ? patch : true;
|
|
1827
|
-
}
|
|
1828
|
-
function projectShadingToInlinePatch(shading) {
|
|
1829
|
-
if (!shading) return void 0;
|
|
1830
|
-
const patch = {};
|
|
1831
|
-
const fill = projectColorRefToInlineColor(shading.fill);
|
|
1832
|
-
if (fill != null) patch.fill = fill;
|
|
1833
|
-
const color = projectColorRefToInlineColor(shading.color);
|
|
1834
|
-
if (color != null) patch.color = color;
|
|
1835
|
-
if (shading.pattern != null) patch.val = shading.pattern;
|
|
1836
|
-
return Object.keys(patch).length > 0 ? patch : void 0;
|
|
1837
|
-
}
|
|
1838
|
-
function projectBorderToInlinePatch(border) {
|
|
1839
|
-
if (!border) return void 0;
|
|
1840
|
-
const patch = {};
|
|
1841
|
-
if (border.style != null) patch.val = border.style;
|
|
1842
|
-
if (border.width != null) patch.sz = border.width;
|
|
1843
|
-
if (border.space != null) patch.space = border.space;
|
|
1844
|
-
const color = projectColorRefToInlineColor(border.color);
|
|
1845
|
-
if (color != null) patch.color = color;
|
|
1846
|
-
return Object.keys(patch).length > 0 ? patch : void 0;
|
|
1847
|
-
}
|
|
1848
|
-
/**
|
|
1849
|
-
* Serializes a selection to a stable string key used to detect whether
|
|
1850
|
-
* the target selection is the same as the source (skip apply in that case).
|
|
1851
|
-
*
|
|
1852
|
-
* Falls back to the plain text target when the host has not populated an
|
|
1853
|
-
* explicit `selectionTarget` yet.
|
|
1854
|
-
*
|
|
1855
|
-
* @param {{ selectionTarget?: unknown; target?: unknown } | null | undefined} selection
|
|
1856
|
-
* @returns {string}
|
|
1857
|
-
*/
|
|
1858
|
-
function selectionKey(selection) {
|
|
1859
|
-
const target = selection?.selectionTarget ?? selection?.target;
|
|
1860
|
-
if (!selection || !target) return "";
|
|
1861
|
-
try {
|
|
1862
|
-
return JSON.stringify(target);
|
|
1863
|
-
} catch {
|
|
1864
|
-
return String(target);
|
|
1959
|
+
unsupportedWrapFields: {
|
|
1960
|
+
family: "unsupportedWrapFields",
|
|
1961
|
+
support: "fail-closed",
|
|
1962
|
+
description: "Wrap fields required for honest placement are unsupported (arbitrary wrap polygons, etc.).",
|
|
1963
|
+
contract: "none",
|
|
1964
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.wrapUnsupported
|
|
1965
|
+
},
|
|
1966
|
+
alternateContentNoSupportedChoice: {
|
|
1967
|
+
family: "alternateContentNoSupportedChoice",
|
|
1968
|
+
support: "fail-closed",
|
|
1969
|
+
description: "mc:AlternateContent with no supported choice and no usable fallback.",
|
|
1970
|
+
contract: "none",
|
|
1971
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.altContentNoSupportedChoice
|
|
1972
|
+
},
|
|
1973
|
+
groupChildUnsupported: {
|
|
1974
|
+
family: "groupChildUnsupported",
|
|
1975
|
+
support: "fail-closed",
|
|
1976
|
+
description: "Unsupported child inside an otherwise-supported group. Supported siblings are not dropped.",
|
|
1977
|
+
contract: "none",
|
|
1978
|
+
diagnostic: DRAWING_DIAGNOSTIC_CODES.groupChildUnsupported
|
|
1979
|
+
},
|
|
1980
|
+
objectEditing: {
|
|
1981
|
+
family: "objectEditing",
|
|
1982
|
+
support: "deferred",
|
|
1983
|
+
description: "Editing/mutation of anchored/vector objects.",
|
|
1984
|
+
contract: "none"
|
|
1985
|
+
},
|
|
1986
|
+
customWrapPolygon: {
|
|
1987
|
+
family: "customWrapPolygon",
|
|
1988
|
+
support: "deferred",
|
|
1989
|
+
description: "Full Word-compatible text wrapping for arbitrary custom wrap polygons.",
|
|
1990
|
+
contract: "none"
|
|
1991
|
+
},
|
|
1992
|
+
chartFidelity: {
|
|
1993
|
+
family: "chartFidelity",
|
|
1994
|
+
support: "deferred",
|
|
1995
|
+
description: "Complete chart fidelity (a dedicated chart effort owns the parsed subset).",
|
|
1996
|
+
contract: "none"
|
|
1997
|
+
},
|
|
1998
|
+
vmlFidelity: {
|
|
1999
|
+
family: "vmlFidelity",
|
|
2000
|
+
support: "deferred",
|
|
2001
|
+
description: "Complete VML fidelity.",
|
|
2002
|
+
contract: "none"
|
|
2003
|
+
},
|
|
2004
|
+
decorativeAccessibilityUi: {
|
|
2005
|
+
family: "decorativeAccessibilityUi",
|
|
2006
|
+
support: "deferred",
|
|
2007
|
+
description: "Full accessibility UI for decorative image semantics beyond preserving source data.",
|
|
2008
|
+
contract: "none"
|
|
1865
2009
|
}
|
|
1866
|
-
}
|
|
1867
|
-
//#endregion
|
|
1868
|
-
//#region src/helpers/v2-typing-mutation-event.js
|
|
1869
|
-
/**
|
|
1870
|
-
* Command kinds whose committed mutations belong to the sustained typing
|
|
1871
|
-
* cadence class (insert / replace / plain paste / Backspace / Delete).
|
|
1872
|
-
*
|
|
1873
|
-
* The SuperDoc shell debounces per-keystroke review-row hydration for these
|
|
1874
|
-
* kinds instead of refreshing comments + tracked changes on every commit —
|
|
1875
|
-
* hydrating immediately per keystroke was a measured worker-read storm during
|
|
1876
|
-
* typing and backspace bursts. The `text.*` aliases cover integrations that
|
|
1877
|
-
* forward Document API style command ids rather than editable-input kinds.
|
|
1878
|
-
*/
|
|
1879
|
-
var V2_TYPING_COMMAND_KINDS = /* @__PURE__ */ new Set([
|
|
1880
|
-
"insert-text",
|
|
1881
|
-
"replace-text",
|
|
1882
|
-
"plain-text-paste",
|
|
1883
|
-
"delete-backward",
|
|
1884
|
-
"delete-forward",
|
|
1885
|
-
"text.insert",
|
|
1886
|
-
"text.replace",
|
|
1887
|
-
"text.pastePlain",
|
|
1888
|
-
"text.deleteBackward",
|
|
1889
|
-
"text.deleteForward",
|
|
1890
|
-
"structural.enter",
|
|
1891
|
-
"structural:enter-split-paragraph",
|
|
1892
|
-
"structural:enter-insert-paragraph-before",
|
|
1893
|
-
"structural:enter-insert-paragraph-after",
|
|
1894
|
-
"structural:shift-enter-line-break",
|
|
1895
|
-
"structural:backspace-boundary-merge-with-previous",
|
|
1896
|
-
"structural:delete-boundary-merge-with-next",
|
|
1897
|
-
"backspace:boundary-merge-with-previous",
|
|
1898
|
-
"backspace:list-remove",
|
|
1899
|
-
"backspace:list-outdent"
|
|
1900
|
-
]);
|
|
1901
|
-
/**
|
|
1902
|
-
* True when a forwarded v2 host event is a committed editable-input mutation
|
|
1903
|
-
* of the sustained-typing class, i.e. review-row hydration for it should be
|
|
1904
|
-
* debounced rather than fired immediately.
|
|
1905
|
-
*
|
|
1906
|
-
* Events without a forwarded `editableCommandKind` (programmatic Document API
|
|
1907
|
-
* mutations, history commits, unclassified structural commands) return false
|
|
1908
|
-
* so they keep hydrating immediately.
|
|
1909
|
-
*
|
|
1910
|
-
* @param {{ type?: string, origin?: string, editableCommandKind?: string } | null | undefined} event
|
|
1911
|
-
* @returns {boolean}
|
|
1912
|
-
*/
|
|
1913
|
-
var isV2EditableTextMutationEvent = (event) => {
|
|
1914
|
-
if (event?.type !== "mutation:committed" || event.origin !== "command") return false;
|
|
1915
|
-
return V2_TYPING_COMMAND_KINDS.has(event.editableCommandKind);
|
|
1916
2010
|
};
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
/**
|
|
1944
|
-
* Read painted entities off `el` and every ancestor up to the document root, or
|
|
1945
|
-
* up to and INCLUDING `stopAt` when given. Innermost-first ordering: a tracked
|
|
1946
|
-
* change inside a comment highlight returns `[{ trackedChange }, { comment }]`,
|
|
1947
|
-
* matching what a switch on `hits[0]` expects when picking the most specific
|
|
1948
|
-
* entity.
|
|
1949
|
-
*
|
|
1950
|
-
* `stopAt` bounds the walk to the visible host: its own attributes are read, but
|
|
1951
|
-
* the walk never climbs into an app wrapper ABOVE it, so wrapper data-* cannot
|
|
1952
|
-
* leak into the hits. Omitting it keeps the original walk-to-document-root.
|
|
1953
|
-
*
|
|
1954
|
-
* Returns `[]` for null / non-Element starts. Uses duck-typed `getAttribute`
|
|
1955
|
-
* access so it works under any DOM implementation (happy-dom, jsdom, real
|
|
1956
|
-
* browser) without an `instanceof` check that could fail across realms.
|
|
1957
|
-
*/
|
|
1958
|
-
function collectEntityHitsFromChain(start, stopAt) {
|
|
1959
|
-
if (!start || typeof start.getAttribute !== "function") return [];
|
|
1960
|
-
const hits = [];
|
|
1961
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1962
|
-
let pendingStory = [];
|
|
1963
|
-
let el = start;
|
|
1964
|
-
while (el) {
|
|
1965
|
-
const node = el;
|
|
1966
|
-
const trackChangeIds = getTrackChangeIds(node);
|
|
1967
|
-
const storyKey = trackChangeIds.length > 0 ? node.getAttribute("data-story-key") : null;
|
|
1968
|
-
for (const trackChangeId of trackChangeIds) {
|
|
1969
|
-
const key = `trackedChange:${trackChangeId}`;
|
|
1970
|
-
if (!seen.has(key)) {
|
|
1971
|
-
seen.add(key);
|
|
1972
|
-
const hit = {
|
|
1973
|
-
type: "trackedChange",
|
|
1974
|
-
id: trackChangeId
|
|
1975
|
-
};
|
|
1976
|
-
if (storyKey) hit.storyKey = storyKey;
|
|
1977
|
-
hits.push(hit);
|
|
1978
|
-
pendingStory.push(hit);
|
|
1979
|
-
}
|
|
1980
|
-
}
|
|
1981
|
-
const layoutStory = node.getAttribute("data-layout-story");
|
|
1982
|
-
if (layoutStory && pendingStory.length > 0) {
|
|
1983
|
-
for (const hit of pendingStory) hit.story = layoutStory;
|
|
1984
|
-
pendingStory = [];
|
|
1985
|
-
}
|
|
1986
|
-
const citationId = node.getAttribute("data-citation-id");
|
|
1987
|
-
if (citationId) {
|
|
1988
|
-
const key = `citation:${citationId}`;
|
|
1989
|
-
if (!seen.has(key)) {
|
|
1990
|
-
seen.add(key);
|
|
1991
|
-
hits.push({
|
|
1992
|
-
type: "citation",
|
|
1993
|
-
id: citationId
|
|
1994
|
-
});
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
const commentIds = node.getAttribute("data-comment-ids");
|
|
1998
|
-
if (commentIds) for (const id of parseCommaSeparatedIds(commentIds)) {
|
|
1999
|
-
const key = `comment:${id}`;
|
|
2000
|
-
if (!seen.has(key)) {
|
|
2001
|
-
seen.add(key);
|
|
2002
|
-
hits.push({
|
|
2003
|
-
type: "comment",
|
|
2004
|
-
id
|
|
2005
|
-
});
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
2008
|
-
const sdtType = node.getAttribute("data-sdt-type");
|
|
2009
|
-
const sdtId = node.getAttribute("data-sdt-id");
|
|
2010
|
-
if (sdtId && sdtType === "structuredContent") {
|
|
2011
|
-
const key = `contentControl:${sdtId}`;
|
|
2012
|
-
if (!seen.has(key)) {
|
|
2013
|
-
seen.add(key);
|
|
2014
|
-
const scopeAttr = node.getAttribute("data-sdt-scope");
|
|
2015
|
-
const tag = node.getAttribute("data-sdt-tag");
|
|
2016
|
-
const hit = {
|
|
2017
|
-
type: "contentControl",
|
|
2018
|
-
id: sdtId
|
|
2019
|
-
};
|
|
2020
|
-
if (scopeAttr === "block" || scopeAttr === "inline") hit.scope = scopeAttr;
|
|
2021
|
-
if (tag) hit.tag = tag;
|
|
2022
|
-
hits.push(hit);
|
|
2023
|
-
}
|
|
2024
|
-
}
|
|
2025
|
-
if (stopAt && el === stopAt) break;
|
|
2026
|
-
el = el.parentElement;
|
|
2027
|
-
}
|
|
2028
|
-
return hits;
|
|
2029
|
-
}
|
|
2011
|
+
Object.keys(DRAWING_SUPPORT_TAXONOMY);
|
|
2012
|
+
Object.freeze([
|
|
2013
|
+
"multiple-sections",
|
|
2014
|
+
"furniture-page-tokens",
|
|
2015
|
+
"non-balanceable-multi-column-sections",
|
|
2016
|
+
"body-anchored-objects",
|
|
2017
|
+
"non-flowing-page-relative-body-anchors",
|
|
2018
|
+
"footnotes",
|
|
2019
|
+
"page-references",
|
|
2020
|
+
"cross-references",
|
|
2021
|
+
"keep-constraints",
|
|
2022
|
+
"tables",
|
|
2023
|
+
"furniture-anchored-objects"
|
|
2024
|
+
]);
|
|
2025
|
+
var INCREMENTAL_DEPENDENCY_CERTIFICATE_CLASSES = Object.freeze([
|
|
2026
|
+
"checkpoint-geometry",
|
|
2027
|
+
"section-numbering",
|
|
2028
|
+
"font-style-inputs",
|
|
2029
|
+
"notes",
|
|
2030
|
+
"furniture",
|
|
2031
|
+
"flowing-anchors",
|
|
2032
|
+
"non-flowing-page-anchors",
|
|
2033
|
+
"convergence",
|
|
2034
|
+
"source-topology"
|
|
2035
|
+
]);
|
|
2036
|
+
new Set(INCREMENTAL_DEPENDENCY_CERTIFICATE_CLASSES);
|
|
2030
2037
|
//#endregion
|
|
2031
2038
|
//#region ../document-api/src/format/inline-run-patch.ts
|
|
2032
2039
|
var schemaBooleanOrNull = () => ({ oneOf: [{ type: "boolean" }, { type: "null" }] });
|
|
@@ -2295,6 +2302,19 @@ INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "mark").map((entry)
|
|
|
2295
2302
|
* `false` when the surface is unavailable (view mode, a pre-ready editor, or a
|
|
2296
2303
|
* host that has not exposed a Document API facade) rather than throwing.
|
|
2297
2304
|
*/
|
|
2305
|
+
var firstPartyCommandMutations = /* @__PURE__ */ new WeakMap();
|
|
2306
|
+
var firstPartyCommandExecutors = /* @__PURE__ */ new WeakMap();
|
|
2307
|
+
function registerFirstPartyCommandMutation(superdoc, host, mutation) {
|
|
2308
|
+
let hosts = firstPartyCommandMutations.get(superdoc);
|
|
2309
|
+
if (!hosts) {
|
|
2310
|
+
hosts = /* @__PURE__ */ new WeakMap();
|
|
2311
|
+
firstPartyCommandMutations.set(superdoc, hosts);
|
|
2312
|
+
}
|
|
2313
|
+
hosts.set(host, mutation);
|
|
2314
|
+
}
|
|
2315
|
+
function executeFirstPartyCommandAsync(ui, id, payload) {
|
|
2316
|
+
return firstPartyCommandExecutors.get(ui)?.(id, payload) ?? ui.commands.executeAsync(id, payload);
|
|
2317
|
+
}
|
|
2298
2318
|
function uiBenchNowMs() {
|
|
2299
2319
|
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
2300
2320
|
}
|
|
@@ -2686,6 +2706,11 @@ function layoutStoryDatasetToStoryLocator(raw) {
|
|
|
2686
2706
|
storyType: "headerFooterPart",
|
|
2687
2707
|
refId: decoded.id
|
|
2688
2708
|
} : void 0;
|
|
2709
|
+
case "textbox": return decoded.id ? {
|
|
2710
|
+
kind: "story",
|
|
2711
|
+
storyType: "textbox",
|
|
2712
|
+
textboxId: decoded.id
|
|
2713
|
+
} : void 0;
|
|
2689
2714
|
default: return;
|
|
2690
2715
|
}
|
|
2691
2716
|
}
|
|
@@ -3915,6 +3940,7 @@ function createSuperDocUI(options) {
|
|
|
3915
3940
|
keyboardSelecting: false
|
|
3916
3941
|
};
|
|
3917
3942
|
let painterCaptureEpoch = 0;
|
|
3943
|
+
let painterCommandDoc = null;
|
|
3918
3944
|
const painterModeListeners = /* @__PURE__ */ new Set();
|
|
3919
3945
|
let frozenProjectedValues = {};
|
|
3920
3946
|
let frozenProjectedValuesKey = "";
|
|
@@ -3964,8 +3990,10 @@ function createSuperDocUI(options) {
|
|
|
3964
3990
|
},
|
|
3965
3991
|
contextAt
|
|
3966
3992
|
};
|
|
3993
|
+
let firstPartyCommandDoc;
|
|
3967
3994
|
/** Read the live browser Document API facade (or null). */
|
|
3968
3995
|
const getDoc = () => {
|
|
3996
|
+
if (firstPartyCommandDoc !== void 0) return firstPartyCommandDoc;
|
|
3969
3997
|
const doc = getEditor()?.doc;
|
|
3970
3998
|
return doc && typeof doc === "object" ? doc : null;
|
|
3971
3999
|
};
|
|
@@ -3996,6 +4024,25 @@ function createSuperDocUI(options) {
|
|
|
3996
4024
|
const host = getEditor()?.host;
|
|
3997
4025
|
return host && typeof host === "object" ? host : null;
|
|
3998
4026
|
};
|
|
4027
|
+
const createFirstPartyCommandDoc = () => {
|
|
4028
|
+
const editor = getEditor();
|
|
4029
|
+
const doc = editor?.doc;
|
|
4030
|
+
if (editor?.editorVersion !== 2) return doc;
|
|
4031
|
+
const host = getHost();
|
|
4032
|
+
const mutation = host ? firstPartyCommandMutations.get(superdoc)?.get(host) : null;
|
|
4033
|
+
if (!doc || !host || !mutation) return null;
|
|
4034
|
+
const wrap = (source, prefix) => new Proxy(source, { get(target, key, receiver) {
|
|
4035
|
+
const value = Reflect.get(target, key, receiver);
|
|
4036
|
+
if (typeof key !== "string") return value;
|
|
4037
|
+
const memberPath = prefix ? `${prefix}.${key}` : key;
|
|
4038
|
+
if (typeof value === "function" && mutation.supports(memberPath)) return (...args) => {
|
|
4039
|
+
if (getEditor() !== editor || getHost() !== host || editor.doc !== doc) return false;
|
|
4040
|
+
return mutation.run(memberPath, args);
|
|
4041
|
+
};
|
|
4042
|
+
return value && (typeof value === "object" || typeof value === "function") ? wrap(value, memberPath) : value;
|
|
4043
|
+
} });
|
|
4044
|
+
return wrap(doc, "");
|
|
4045
|
+
};
|
|
3999
4046
|
const resolveActiveHeaderFooterSlot = (story) => {
|
|
4000
4047
|
if (story.storyType !== "headerFooterPart" || typeof story.refId !== "string") return null;
|
|
4001
4048
|
const editor = getEditor();
|
|
@@ -7994,7 +8041,10 @@ function createSuperDocUI(options) {
|
|
|
7994
8041
|
function executeListToggleCommand(kind, payload) {
|
|
7995
8042
|
const lists = getEditCommands()?.lists;
|
|
7996
8043
|
const apply = lists?.apply;
|
|
7997
|
-
|
|
8044
|
+
const host = getHost();
|
|
8045
|
+
const firstPartyMutation = firstPartyCommandDoc !== void 0 && getEditor()?.editorVersion === 2 && host ? firstPartyCommandMutations.get(superdoc)?.get(host) : null;
|
|
8046
|
+
if (firstPartyCommandDoc !== void 0 && getEditor()?.editorVersion === 2 && !firstPartyMutation) return false;
|
|
8047
|
+
if (!firstPartyMutation && typeof apply !== "function") return false;
|
|
7998
8048
|
const { behavior, preset, continuity } = typeof payload === "string" ? presetFromToolbarStyleKey(payload) : payload && typeof payload === "object" ? payload : {};
|
|
7999
8049
|
const input = {
|
|
8000
8050
|
kind,
|
|
@@ -8003,7 +8053,7 @@ function createSuperDocUI(options) {
|
|
|
8003
8053
|
if (preset !== void 0) input.preset = preset;
|
|
8004
8054
|
if (continuity !== void 0) input.continuity = continuity;
|
|
8005
8055
|
try {
|
|
8006
|
-
return settleCommandExecution(apply.call(lists, input));
|
|
8056
|
+
return settleCommandExecution(firstPartyMutation ? firstPartyMutation.runListApply(input) : apply.call(lists, input));
|
|
8007
8057
|
} catch {
|
|
8008
8058
|
return false;
|
|
8009
8059
|
}
|
|
@@ -8625,6 +8675,9 @@ function createSuperDocUI(options) {
|
|
|
8625
8675
|
const doc = getDoc();
|
|
8626
8676
|
const linksApi = doc?.hyperlinks;
|
|
8627
8677
|
if (!linksApi) return false;
|
|
8678
|
+
const hyperlinkHost = getHost();
|
|
8679
|
+
const hyperlinkHandles = typeof hyperlinkHost?.getHandles === "function" ? hyperlinkHost.getHandles() : null;
|
|
8680
|
+
const trustedLinksApi = firstPartyCommandDoc ? (hyperlinkHandles?.editing)?.hyperlinks : linksApi;
|
|
8628
8681
|
const record = readLinkPayloadRecord(payload);
|
|
8629
8682
|
const href = readLinkPayloadHref(payload);
|
|
8630
8683
|
const payloadTarget = readLinkPayloadTarget(payload);
|
|
@@ -8648,7 +8701,7 @@ function createSuperDocUI(options) {
|
|
|
8648
8701
|
}
|
|
8649
8702
|
}
|
|
8650
8703
|
if (existing && href === null) {
|
|
8651
|
-
const remove =
|
|
8704
|
+
const remove = trustedLinksApi?.remove;
|
|
8652
8705
|
if (typeof remove !== "function") return false;
|
|
8653
8706
|
try {
|
|
8654
8707
|
return callEditorMutation("hyperlinks.remove", remove, {
|
|
@@ -8660,7 +8713,7 @@ function createSuperDocUI(options) {
|
|
|
8660
8713
|
}
|
|
8661
8714
|
}
|
|
8662
8715
|
if ((existing || requestedHyperlinkTarget) && typeof href === "string" && href.trim() !== "") {
|
|
8663
|
-
const patch =
|
|
8716
|
+
const patch = trustedLinksApi?.patch;
|
|
8664
8717
|
const updateTarget = linksApi.updateTarget;
|
|
8665
8718
|
if (!(!hasRequestedHyperlinkTarget && existing && typeof patch === "function") && !(hasRequestedHyperlinkTarget && typeof updateTarget === "function")) return false;
|
|
8666
8719
|
const shouldReplaceText = typeof text === "string" && text !== (hasRequestedHyperlinkTarget ? currentText : existing?.text ?? currentText);
|
|
@@ -8750,7 +8803,7 @@ function createSuperDocUI(options) {
|
|
|
8750
8803
|
}
|
|
8751
8804
|
if (typeof href === "string" && href.trim() !== "") {
|
|
8752
8805
|
const normalizedHref = href.trim();
|
|
8753
|
-
const wrap =
|
|
8806
|
+
const wrap = trustedLinksApi?.wrap;
|
|
8754
8807
|
const textTargets = textAddressesFromTarget(payloadTarget);
|
|
8755
8808
|
const wrapTargets = textTargets.length > 0 ? textTargets : selectionTextAddresses(state.selection);
|
|
8756
8809
|
if (wrapTargets.length > 0) {
|
|
@@ -8764,7 +8817,7 @@ function createSuperDocUI(options) {
|
|
|
8764
8817
|
return false;
|
|
8765
8818
|
}
|
|
8766
8819
|
}
|
|
8767
|
-
const insert =
|
|
8820
|
+
const insert = trustedLinksApi?.insert;
|
|
8768
8821
|
const text = readLinkPayloadText(payload, normalizedHref);
|
|
8769
8822
|
if (typeof insert !== "function" || text.trim() === "") return false;
|
|
8770
8823
|
const target = collapsedTextAddressFromTarget(payloadTarget) ?? collapsedTextAddressFromSelection(state.selection);
|
|
@@ -8835,8 +8888,13 @@ function createSuperDocUI(options) {
|
|
|
8835
8888
|
if (typeof record.alt === "string") input.alt = record.alt;
|
|
8836
8889
|
if (typeof record.title === "string") input.title = record.title;
|
|
8837
8890
|
if (record.size && typeof record.size === "object") input.size = record.size;
|
|
8891
|
+
const imageHost = getHost();
|
|
8892
|
+
const imageHandles = typeof imageHost?.getHandles === "function" ? imageHost.getHandles() : null;
|
|
8893
|
+
const trustedImageCommands = firstPartyCommandDoc ? (imageHandles?.editing)?.images : null;
|
|
8894
|
+
const create = firstPartyCommandDoc ? trustedImageCommands?.create : op;
|
|
8895
|
+
if (typeof create !== "function") return false;
|
|
8838
8896
|
try {
|
|
8839
|
-
return callEditorMutation(descriptor.docRoute,
|
|
8897
|
+
return callEditorMutation(descriptor.docRoute, create, input);
|
|
8840
8898
|
} catch {
|
|
8841
8899
|
return false;
|
|
8842
8900
|
}
|
|
@@ -8850,6 +8908,13 @@ function createSuperDocUI(options) {
|
|
|
8850
8908
|
return false;
|
|
8851
8909
|
}
|
|
8852
8910
|
};
|
|
8911
|
+
const tableInsertionCommands = () => {
|
|
8912
|
+
if (firstPartyCommandDoc === null) return null;
|
|
8913
|
+
const host = getHost();
|
|
8914
|
+
if (!host) return null;
|
|
8915
|
+
if (firstPartyCommandDoc !== void 0) return ((typeof host.getHandles === "function" ? host.getHandles() : null)?.editing)?.tables ?? null;
|
|
8916
|
+
return typeof host.getCodeTableEditingCommands === "function" ? host.getCodeTableEditingCommands() : null;
|
|
8917
|
+
};
|
|
8853
8918
|
/**
|
|
8854
8919
|
* Route a table cell-context command (`tables.*`) against the live table
|
|
8855
8920
|
* context resolved from the shared facade. Fails closed (`false`) when the
|
|
@@ -8866,16 +8931,14 @@ function createSuperDocUI(options) {
|
|
|
8866
8931
|
if (!input) return false;
|
|
8867
8932
|
try {
|
|
8868
8933
|
if (spec.action === "insert-row-before" || spec.action === "insert-row-after") {
|
|
8869
|
-
const
|
|
8870
|
-
const tableCommands = ((typeof host?.getHandles === "function" ? host.getHandles() : null)?.editing)?.tables;
|
|
8934
|
+
const tableCommands = tableInsertionCommands();
|
|
8871
8935
|
if (typeof tableCommands?.insertRow !== "function") return false;
|
|
8872
8936
|
const options = editorMutationOptionsForRoute(descriptor.docRoute);
|
|
8873
8937
|
if (options && options.success === false) return options;
|
|
8874
8938
|
return options ? tableCommands.insertRow(input, options) : tableCommands.insertRow(input);
|
|
8875
8939
|
}
|
|
8876
8940
|
if (spec.action === "insert-column-before" || spec.action === "insert-column-after") {
|
|
8877
|
-
const
|
|
8878
|
-
const tableCommands = ((typeof host?.getHandles === "function" ? host.getHandles() : null)?.editing)?.tables;
|
|
8941
|
+
const tableCommands = tableInsertionCommands();
|
|
8879
8942
|
if (typeof tableCommands?.insertColumn !== "function") return false;
|
|
8880
8943
|
const options = editorMutationOptionsForRoute(descriptor.docRoute);
|
|
8881
8944
|
if (options && options.success === false) return options;
|
|
@@ -8974,9 +9037,10 @@ function createSuperDocUI(options) {
|
|
|
8974
9037
|
let releaseScheduledMutation = null;
|
|
8975
9038
|
try {
|
|
8976
9039
|
const commandEditor = getEditor();
|
|
9040
|
+
const commandDocSource = commandEditor?.doc;
|
|
8977
9041
|
const commandMode = readDocumentMode();
|
|
8978
9042
|
const mutate = () => {
|
|
8979
|
-
if (getEditor() !== commandEditor ||
|
|
9043
|
+
if (getEditor() !== commandEditor || commandEditor?.doc !== commandDocSource || readDocumentMode() !== commandMode) return false;
|
|
8980
9044
|
return callInlineFormatMutation(route, op, input);
|
|
8981
9045
|
};
|
|
8982
9046
|
const selectionSignature = selectionInlineValueSignature(state.selection) ?? selectionKey(state.selection);
|
|
@@ -9026,12 +9090,14 @@ function createSuperDocUI(options) {
|
|
|
9026
9090
|
return false;
|
|
9027
9091
|
}
|
|
9028
9092
|
};
|
|
9029
|
-
const
|
|
9093
|
+
const runCommand = (id, payload, context, firstParty) => {
|
|
9030
9094
|
const actionId = beginInteraction(superdoc, "command:started", () => ({
|
|
9031
9095
|
commandId: id,
|
|
9032
9096
|
selection: state.selection
|
|
9033
9097
|
}));
|
|
9034
9098
|
let result;
|
|
9099
|
+
const previousCommandDoc = firstPartyCommandDoc;
|
|
9100
|
+
firstPartyCommandDoc = firstParty && !customCommands.has(id) ? createFirstPartyCommandDoc() : void 0;
|
|
9035
9101
|
try {
|
|
9036
9102
|
result = executeCommandInternal(id, payload, context);
|
|
9037
9103
|
} catch (error) {
|
|
@@ -9041,6 +9107,8 @@ function createSuperDocUI(options) {
|
|
|
9041
9107
|
outcome: "threw"
|
|
9042
9108
|
}));
|
|
9043
9109
|
throw error;
|
|
9110
|
+
} finally {
|
|
9111
|
+
firstPartyCommandDoc = previousCommandDoc;
|
|
9044
9112
|
}
|
|
9045
9113
|
const settled = (value) => recordInteraction(superdoc, "command:settled", () => ({
|
|
9046
9114
|
actionId,
|
|
@@ -9054,8 +9122,10 @@ function createSuperDocUI(options) {
|
|
|
9054
9122
|
} catch {}
|
|
9055
9123
|
return result;
|
|
9056
9124
|
};
|
|
9125
|
+
const executeCommand = (id, payload, context) => runCommand(id, payload, context, false);
|
|
9057
9126
|
const exitFormatPainter = () => {
|
|
9058
9127
|
painterCaptureEpoch += 1;
|
|
9128
|
+
painterCommandDoc = null;
|
|
9059
9129
|
painter = {
|
|
9060
9130
|
mode: "idle",
|
|
9061
9131
|
snapshot: null,
|
|
@@ -9068,6 +9138,7 @@ function createSuperDocUI(options) {
|
|
|
9068
9138
|
recompute();
|
|
9069
9139
|
};
|
|
9070
9140
|
const executeCopyFormat = async () => {
|
|
9141
|
+
const commandDoc = firstPartyCommandDoc ?? null;
|
|
9071
9142
|
const visibleActiveMarksAtClick = [
|
|
9072
9143
|
"bold",
|
|
9073
9144
|
"italic",
|
|
@@ -9110,6 +9181,7 @@ function createSuperDocUI(options) {
|
|
|
9110
9181
|
sourceSelectionKey: selectionKey(captureSlice),
|
|
9111
9182
|
lastClickAt: now
|
|
9112
9183
|
};
|
|
9184
|
+
painterCommandDoc = commandDoc;
|
|
9113
9185
|
for (const cb of painterModeListeners) cb(painter.mode);
|
|
9114
9186
|
recompute();
|
|
9115
9187
|
return true;
|
|
@@ -9293,7 +9365,7 @@ function createSuperDocUI(options) {
|
|
|
9293
9365
|
if (painter.mode === "armed") exitFormatPainter();
|
|
9294
9366
|
return;
|
|
9295
9367
|
}
|
|
9296
|
-
const doc = getDoc();
|
|
9368
|
+
const doc = painterCommandDoc ?? getDoc();
|
|
9297
9369
|
if (!doc) return;
|
|
9298
9370
|
const targetSelection = selectionSliceFromInfo(selection, "ready");
|
|
9299
9371
|
const { lockModesById } = computeActiveContentControlLockModes(doc.contentControls, targetSelection);
|
|
@@ -9398,18 +9470,20 @@ function createSuperDocUI(options) {
|
|
|
9398
9470
|
if (painter.mode === "armed") exitFormatPainter();
|
|
9399
9471
|
recompute();
|
|
9400
9472
|
};
|
|
9401
|
-
const
|
|
9473
|
+
const runCommandAsync = (id, payload, context, firstParty) => {
|
|
9402
9474
|
const prepared = prepareCommandSelectionAsync(id, payload);
|
|
9403
9475
|
const settlement = prepared ? prepared.then(() => {
|
|
9404
|
-
|
|
9476
|
+
runCommand(id, payload, context, firstParty);
|
|
9405
9477
|
return lastCommandSettlement;
|
|
9406
9478
|
}) : (() => {
|
|
9407
|
-
|
|
9479
|
+
runCommand(id, payload, context, firstParty);
|
|
9408
9480
|
return lastCommandSettlement;
|
|
9409
9481
|
})();
|
|
9410
9482
|
if (getCommandDescriptor(id)?.inline?.kind === "toggle") lastInlineToggleCommandSettlement = settlement;
|
|
9411
9483
|
return settlement;
|
|
9412
9484
|
};
|
|
9485
|
+
const executeCommandAsync = (id, payload, context) => runCommandAsync(id, payload, context, false);
|
|
9486
|
+
const executeFirstPartyCommandAsync = (id, payload) => runCommandAsync(id, payload, void 0, true);
|
|
9413
9487
|
const makeCommandHandle = (id) => ({
|
|
9414
9488
|
id,
|
|
9415
9489
|
getState: () => state.toolbar.commands[id] ?? computeCommandState(id, getDoc(), state.selection, projectSelectionInlineValues(state.selection)),
|
|
@@ -10246,6 +10320,14 @@ function createSuperDocUI(options) {
|
|
|
10246
10320
|
kind,
|
|
10247
10321
|
scope: isAllTarget ? "all" : "id"
|
|
10248
10322
|
}, tcApi)) return false;
|
|
10323
|
+
if (firstPartyCommandDoc) {
|
|
10324
|
+
const host = getHost();
|
|
10325
|
+
const decide = (safeCall(typeof host?.getHandles === "function" ? () => host.getHandles() : void 0, null)?.trackChanges)?.decide;
|
|
10326
|
+
return typeof decide === "function" ? decide({
|
|
10327
|
+
decision: kind,
|
|
10328
|
+
target
|
|
10329
|
+
}) : false;
|
|
10330
|
+
}
|
|
10249
10331
|
const legacyName = isAllTarget ? `${kind}All` : kind;
|
|
10250
10332
|
const op = !isRangeTarget && !isMultiIdTarget && !story && tcApi && typeof tcApi[legacyName] === "function" ? tcApi[legacyName] : null;
|
|
10251
10333
|
const decide = tcApi && typeof tcApi.decide === "function" ? tcApi.decide : null;
|
|
@@ -10549,10 +10631,18 @@ function createSuperDocUI(options) {
|
|
|
10549
10631
|
const hits = [];
|
|
10550
10632
|
for (const hit of rawHits) {
|
|
10551
10633
|
if (hit.type !== "trackedChange") {
|
|
10552
|
-
const
|
|
10634
|
+
const layoutStory = hit.type === "contentControl" ? layoutStoryDatasetToStoryLocator(hit.story) : void 0;
|
|
10635
|
+
const story = hit.type === "contentControl" ? isTextboxStory(layoutStory) ? layoutStory : storyKeyToStoryLocator(hit.storyKey) ?? layoutStory : void 0;
|
|
10636
|
+
const key = `${hit.type}:${hit.id}:${JSON.stringify(story ?? null)}`;
|
|
10553
10637
|
if (seen.has(key)) continue;
|
|
10554
10638
|
seen.add(key);
|
|
10555
|
-
|
|
10639
|
+
if (hit.type === "contentControl") {
|
|
10640
|
+
const { storyKey: _storyKey, story: _paintedStory, ...publicHit } = hit;
|
|
10641
|
+
hits.push(story ? {
|
|
10642
|
+
...publicHit,
|
|
10643
|
+
story
|
|
10644
|
+
} : publicHit);
|
|
10645
|
+
} else hits.push(hit);
|
|
10556
10646
|
continue;
|
|
10557
10647
|
}
|
|
10558
10648
|
const story = storyKeyToStoryLocator(hit.storyKey) ?? layoutStoryDatasetToStoryLocator(hit.story);
|
|
@@ -11522,6 +11612,7 @@ function createSuperDocUI(options) {
|
|
|
11522
11612
|
listeners.clear();
|
|
11523
11613
|
searchListeners.clear();
|
|
11524
11614
|
painterCaptureEpoch += 1;
|
|
11615
|
+
painterCommandDoc = null;
|
|
11525
11616
|
painterModeListeners.clear();
|
|
11526
11617
|
searchRequestGeneration += 1;
|
|
11527
11618
|
customCommands.clear();
|
|
@@ -11591,6 +11682,7 @@ function createSuperDocUI(options) {
|
|
|
11591
11682
|
destroy
|
|
11592
11683
|
};
|
|
11593
11684
|
controllerRef = controller;
|
|
11685
|
+
firstPartyCommandExecutors.set(controller, executeFirstPartyCommandAsync);
|
|
11594
11686
|
return controller;
|
|
11595
11687
|
}
|
|
11596
11688
|
/**
|
|
@@ -11792,6 +11884,12 @@ Object.defineProperty(exports, "createSuperDocUI", {
|
|
|
11792
11884
|
return createSuperDocUI;
|
|
11793
11885
|
}
|
|
11794
11886
|
});
|
|
11887
|
+
Object.defineProperty(exports, "executeFirstPartyCommandAsync", {
|
|
11888
|
+
enumerable: true,
|
|
11889
|
+
get: function() {
|
|
11890
|
+
return executeFirstPartyCommandAsync;
|
|
11891
|
+
}
|
|
11892
|
+
});
|
|
11795
11893
|
Object.defineProperty(exports, "getV2TrackedChangeMutationImpact", {
|
|
11796
11894
|
enumerable: true,
|
|
11797
11895
|
get: function() {
|
|
@@ -11804,6 +11902,12 @@ Object.defineProperty(exports, "recordInteraction", {
|
|
|
11804
11902
|
return recordInteraction;
|
|
11805
11903
|
}
|
|
11806
11904
|
});
|
|
11905
|
+
Object.defineProperty(exports, "registerFirstPartyCommandMutation", {
|
|
11906
|
+
enumerable: true,
|
|
11907
|
+
get: function() {
|
|
11908
|
+
return registerFirstPartyCommandMutation;
|
|
11909
|
+
}
|
|
11910
|
+
});
|
|
11807
11911
|
Object.defineProperty(exports, "shallowEqual", {
|
|
11808
11912
|
enumerable: true,
|
|
11809
11913
|
get: function() {
|