superdoc 2.27.0-next.1 → 2.27.0-next.11
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-BCQ5RHxy.es.js → create-super-doc-ui-B29zw5qD.es.js} +192 -13
- package/dist/chunks/{create-super-doc-ui-DK14sCrT.cjs → create-super-doc-ui-D1eOhAjv.cjs} +197 -12
- package/dist/collaboration-upgrade-engine.cjs +1 -1
- package/dist/collaboration-upgrade-engine.es.js +1 -1
- package/dist/document-api/src/contract/operation-definitions.d.ts +2 -2
- package/dist/document-api/src/history/history.types.d.ts +0 -6
- package/dist/document-api/src/index.d.ts +4 -4
- package/dist/document-api/src/lists/lists.types.d.ts +3 -0
- package/dist/document-api/src/styles/apply.d.ts +26 -2
- package/dist/document-api/src/styles/index.d.ts +3 -3
- package/dist/document-api/src/styles/schema.d.ts +3 -1
- package/dist/document-api/src/styles/validation.d.ts +10 -9
- package/dist/document-api/src/types/receipt.d.ts +2 -1
- package/dist/document-api/src/types/temporary-mutation.d.ts +39 -4
- package/dist/layout-engine/contracts/src/direction-context.d.ts +1 -2
- package/dist/layout-engine/contracts/src/resolved-layout.d.ts +0 -34
- package/dist/layout-engine/layout-bridge/src/neutral-hit.d.ts +0 -7
- package/dist/layout-engine/layout-engine/src/index.d.ts +0 -1
- package/dist/layout-engine/painters/dom/src/features/inline-direction/run-direction.d.ts +0 -3
- 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 +1 -1
- package/dist/style.layered.css +1 -1
- package/dist/superdoc/src/core/types/index.d.ts +3 -60
- package/dist/superdoc/src/core/v2-integration/v2-integration.d.ts +2 -5
- package/dist/superdoc/src/helpers/tracked-change-comment-lane.d.ts +1 -0
- package/dist/superdoc/src/helpers/v2-review-mutation-impact.d.ts +0 -6
- package/dist/superdoc/src/internal/toolbar/built-in/LinkedStyle.vue.d.ts +3 -1
- package/dist/superdoc/src/internal/toolbar/built-in/toolbarTexts.d.ts +1 -0
- package/dist/superdoc/src/internal/toolbar/built-in-toolbar.d.ts +1 -0
- package/dist/superdoc/src/public/ui/style-match-patch.d.ts +7 -0
- package/dist/superdoc/src/public/ui/types.d.ts +5 -1
- package/dist/superdoc/src/public/ui-react.d.ts +0 -5
- package/dist/superdoc/src/public/ui-vue.d.ts +0 -5
- package/dist/superdoc/src/public/ui.d.cts +18 -0
- package/dist/superdoc/src/public/ui.d.ts +1 -10
- package/dist/superdoc.cjs +117 -85
- package/dist/superdoc.es.js +110 -80
- package/dist-cdn/style.layered.css +1 -1
- package/dist-cdn/superdoc.min.css +1 -1
- package/dist-cdn/superdoc.min.js +38 -38
- package/package.json +2 -5
- package/dist/superdoc/src/components/CommentsLayer/comment-schemas.d.ts +0 -18
- package/dist/superdoc/src/components/CommentsLayer/types.d.ts +0 -3
- package/dist/superdoc/src/components/CommentsLayer/use-conversation.d.ts +0 -22
- package/dist/superdoc/src/components/CommentsLayer/use-floating-comment.d.ts +0 -11
- package/dist/superdoc/src/core/collaboration/room-overwrite.d.ts +0 -22
- package/dist/superdoc/src/core/index.d.ts +0 -1
- package/dist/superdoc/src/stores/hrbr-fields-store.d.ts +0 -43
package/dist/chunks/{create-super-doc-ui-BCQ5RHxy.es.js → create-super-doc-ui-B29zw5qD.es.js}
RENAMED
|
@@ -1078,6 +1078,15 @@ var decodeLayoutStoryDataset = (raw) => {
|
|
|
1078
1078
|
`${DOM_CLASS_NAMES.BLOCK_SDT}${DATA_ATTRS.SDT_ID}`;
|
|
1079
1079
|
`${DATA_ATTRS.DRAGGABLE}`;
|
|
1080
1080
|
//#endregion
|
|
1081
|
+
//#region src/helpers/tracked-change-comment-lane.ts
|
|
1082
|
+
var TRACKED_CHANGE_COMMENT_LANE_ID_PREFIX = "tc-comment:";
|
|
1083
|
+
function isSyntheticTrackedChangeCommentLaneItem(item) {
|
|
1084
|
+
if (!item || typeof item !== "object") return false;
|
|
1085
|
+
const { id, commentId } = item;
|
|
1086
|
+
const itemId = id ?? commentId;
|
|
1087
|
+
return typeof itemId === "string" && itemId.startsWith(TRACKED_CHANGE_COMMENT_LANE_ID_PREFIX);
|
|
1088
|
+
}
|
|
1089
|
+
//#endregion
|
|
1081
1090
|
//#region src/public/ui/viewport-batch.ts
|
|
1082
1091
|
/** No rendering or scrolling: read only geometry already acknowledged by the host. */
|
|
1083
1092
|
async function readViewportBatch(input, read, generation, disposed) {
|
|
@@ -2449,6 +2458,69 @@ function createDialogWorkflow(editor, options, onSuccess) {
|
|
|
2449
2458
|
};
|
|
2450
2459
|
}
|
|
2451
2460
|
//#endregion
|
|
2461
|
+
//#region src/public/ui/style-match-patch.ts
|
|
2462
|
+
var STYLE_MATCH_KEYS = [
|
|
2463
|
+
["bold", "bold"],
|
|
2464
|
+
["italic", "italic"],
|
|
2465
|
+
["underline", "underline"],
|
|
2466
|
+
["color", "color"],
|
|
2467
|
+
["fontSize", "fontSize"],
|
|
2468
|
+
["rFonts", "fontFamily"]
|
|
2469
|
+
];
|
|
2470
|
+
var STYLE_MATCH_READ_KEYS = [...STYLE_MATCH_KEYS.map(([readKey]) => readKey), "rStyle"];
|
|
2471
|
+
function buildStyleMatchPatch(effective, direct, options) {
|
|
2472
|
+
const patch = {};
|
|
2473
|
+
const characterStyle = direct.properties.rStyle;
|
|
2474
|
+
const hasCharacterStyle = characterStyle != null && characterStyle.state !== "unset";
|
|
2475
|
+
for (const [readKey, styleKey] of STYLE_MATCH_KEYS) {
|
|
2476
|
+
const read = effective.properties[readKey];
|
|
2477
|
+
if (read?.state !== "uniform") continue;
|
|
2478
|
+
if (options.selectionUsesStyle && !hasCharacterStyle && direct.properties[readKey]?.state === "unset") continue;
|
|
2479
|
+
patch[styleKey] = toStyleValue(readKey, read.value);
|
|
2480
|
+
}
|
|
2481
|
+
return patch;
|
|
2482
|
+
}
|
|
2483
|
+
function toStyleValue(key, value) {
|
|
2484
|
+
switch (key) {
|
|
2485
|
+
case "bold":
|
|
2486
|
+
case "italic": return value === true;
|
|
2487
|
+
case "underline": return underlineValue(value);
|
|
2488
|
+
case "color": return typeof value === "string" && value.length > 0 ? { val: value.replace(/^#/, "") } : null;
|
|
2489
|
+
case "fontSize": return typeof value === "number" && Number.isFinite(value) ? Math.round(value * 2) : null;
|
|
2490
|
+
case "rFonts": return fontsValue(value);
|
|
2491
|
+
default: return null;
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
function underlineValue(value) {
|
|
2495
|
+
if (value === true) return { val: "single" };
|
|
2496
|
+
if (!value || typeof value !== "object") return { val: "none" };
|
|
2497
|
+
const underline = value;
|
|
2498
|
+
const result = { val: typeof underline.style === "string" && underline.style ? underline.style : "single" };
|
|
2499
|
+
if (typeof underline.color === "string") result.color = underline.color;
|
|
2500
|
+
if (typeof underline.themeColor === "string") result.themeColor = underline.themeColor;
|
|
2501
|
+
return result;
|
|
2502
|
+
}
|
|
2503
|
+
var FONT_SLOTS = {
|
|
2504
|
+
ascii: "ascii",
|
|
2505
|
+
hAnsi: "hAnsi",
|
|
2506
|
+
eastAsia: "eastAsia",
|
|
2507
|
+
cs: "cs",
|
|
2508
|
+
asciiTheme: "asciiTheme",
|
|
2509
|
+
hAnsiTheme: "hAnsiTheme",
|
|
2510
|
+
eastAsiaTheme: "eastAsiaTheme",
|
|
2511
|
+
csTheme: "cstheme",
|
|
2512
|
+
hint: "hint"
|
|
2513
|
+
};
|
|
2514
|
+
function fontsValue(value) {
|
|
2515
|
+
if (!value || typeof value !== "object") return null;
|
|
2516
|
+
const result = {};
|
|
2517
|
+
for (const [slot, styleSlot] of Object.entries(FONT_SLOTS)) {
|
|
2518
|
+
const font = value[slot];
|
|
2519
|
+
if (typeof font === "string" && font.length > 0) result[styleSlot] = font;
|
|
2520
|
+
}
|
|
2521
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
2522
|
+
}
|
|
2523
|
+
//#endregion
|
|
2452
2524
|
//#region src/public/ui/format-painter-helpers.js
|
|
2453
2525
|
/**
|
|
2454
2526
|
* Maps SDRunProps field names to InlineRunPatch field names.
|
|
@@ -2634,12 +2706,6 @@ function getV2TrackedChangeMutationImpact(event) {
|
|
|
2634
2706
|
}
|
|
2635
2707
|
/**
|
|
2636
2708
|
* Comment ids retired by a committed v2 mutation.
|
|
2637
|
-
*
|
|
2638
|
-
* AIDEV-NOTE: History commits put invalidated comment ids on `result`; cut and
|
|
2639
|
-
* other command receipts use `receipt`. Same origin split as
|
|
2640
|
-
* getV2TrackedChangeMutationImpact. Reading the wrong field, or treating a
|
|
2641
|
-
* tracked-change entity as a comment, leaves a sidebar card after cut or
|
|
2642
|
-
* undo/redo.
|
|
2643
2709
|
*/
|
|
2644
2710
|
function collectV2InvalidatedCommentIds(event) {
|
|
2645
2711
|
const removedIds = /* @__PURE__ */ new Set();
|
|
@@ -7096,7 +7162,7 @@ function createSuperDocUI(options) {
|
|
|
7096
7162
|
failureCount: retryingSameToken ? prev.failureCount ?? 0 : 0,
|
|
7097
7163
|
retryAtMs: 0
|
|
7098
7164
|
});
|
|
7099
|
-
Promise.resolve(raw).then((resolved) => {
|
|
7165
|
+
const settled = Promise.resolve(raw).then((resolved) => {
|
|
7100
7166
|
const entry = asyncReads.get(key);
|
|
7101
7167
|
if (!entry || entry.inflightToken !== token) return;
|
|
7102
7168
|
asyncReads.set(key, {
|
|
@@ -7135,6 +7201,7 @@ function createSuperDocUI(options) {
|
|
|
7135
7201
|
const retryAtMs = Date.now() + retryDelayMs;
|
|
7136
7202
|
asyncReads.set(key, {
|
|
7137
7203
|
...entry,
|
|
7204
|
+
settled: void 0,
|
|
7138
7205
|
inflightToken: null,
|
|
7139
7206
|
failedToken: token,
|
|
7140
7207
|
failureCount,
|
|
@@ -7142,6 +7209,8 @@ function createSuperDocUI(options) {
|
|
|
7142
7209
|
});
|
|
7143
7210
|
scheduleAsyncReadFailureRetry(retryAtMs);
|
|
7144
7211
|
});
|
|
7212
|
+
const entry = asyncReads.get(key);
|
|
7213
|
+
if (entry?.inflightToken === token) entry.settled = settled;
|
|
7145
7214
|
return null;
|
|
7146
7215
|
};
|
|
7147
7216
|
/**
|
|
@@ -7451,7 +7520,10 @@ function createSuperDocUI(options) {
|
|
|
7451
7520
|
if (hostSelection && info && typeof info === "object") selectionHostSnapshots.set(info, hostSelection);
|
|
7452
7521
|
return info;
|
|
7453
7522
|
};
|
|
7454
|
-
const result = current({
|
|
7523
|
+
const result = current({
|
|
7524
|
+
includeText: true,
|
|
7525
|
+
...getEditor()?.editorVersion === 2 ? { offsetSpace: "selection" } : {}
|
|
7526
|
+
});
|
|
7455
7527
|
return isPromiseLike(result) ? Promise.resolve(result).then(tag) : tag(result);
|
|
7456
7528
|
}
|
|
7457
7529
|
/** True when a host sync snapshot is a resolved collapsed caret (not a range). */
|
|
@@ -7588,7 +7660,10 @@ function createSuperDocUI(options) {
|
|
|
7588
7660
|
}
|
|
7589
7661
|
let raw;
|
|
7590
7662
|
try {
|
|
7591
|
-
raw = current.call(selectionApi, {
|
|
7663
|
+
raw = current.call(selectionApi, {
|
|
7664
|
+
includeText: true,
|
|
7665
|
+
...getEditor()?.editorVersion === 2 ? { offsetSpace: "selection" } : {}
|
|
7666
|
+
});
|
|
7592
7667
|
if (isPromiseLike(raw)) raw = await Promise.resolve(raw);
|
|
7593
7668
|
} catch {
|
|
7594
7669
|
raw = null;
|
|
@@ -7606,9 +7681,26 @@ function createSuperDocUI(options) {
|
|
|
7606
7681
|
recompute();
|
|
7607
7682
|
return selection;
|
|
7608
7683
|
};
|
|
7684
|
+
const realComments = (items) => items.filter((item) => !isSyntheticTrackedChangeCommentLaneItem(item));
|
|
7685
|
+
let lastWindowComments = null;
|
|
7686
|
+
const realCommentsOfWindow = (window) => {
|
|
7687
|
+
const items = window?.commentItems;
|
|
7688
|
+
if (!Array.isArray(items)) return null;
|
|
7689
|
+
const last = lastWindowComments;
|
|
7690
|
+
if (last?.source === items && shallowEqual(last.rows, items)) return last.real;
|
|
7691
|
+
lastWindowComments = {
|
|
7692
|
+
source: items,
|
|
7693
|
+
rows: [...items],
|
|
7694
|
+
real: realComments(items)
|
|
7695
|
+
};
|
|
7696
|
+
return lastWindowComments.real;
|
|
7697
|
+
};
|
|
7609
7698
|
const readCommentsDirectory = () => {
|
|
7610
7699
|
const listComments = hostMethod(getDoc()?.comments, "list");
|
|
7611
|
-
return readAsync("comments", contentToken(), () => listComments ? listComments() : void 0, (raw) =>
|
|
7700
|
+
return readAsync("comments", contentToken(), () => listComments ? listComments() : void 0, (raw) => {
|
|
7701
|
+
const items = isPlainObject(raw) ? raw.items : void 0;
|
|
7702
|
+
return Array.isArray(items) ? realComments(items) : [];
|
|
7703
|
+
});
|
|
7612
7704
|
};
|
|
7613
7705
|
const readTrackChangesDirectory = (key = "trackChanges") => {
|
|
7614
7706
|
const token = contentToken();
|
|
@@ -7641,7 +7733,7 @@ function createSuperDocUI(options) {
|
|
|
7641
7733
|
const reviewWindow = getV2ReviewWindowSnapshot();
|
|
7642
7734
|
const hasWindowFeed = hasV2ReviewWindowFeed();
|
|
7643
7735
|
const catalog = !hasWindowFeed ? readCommentsDirectory() : null;
|
|
7644
|
-
const windowItems = hasWindowFeed
|
|
7736
|
+
const windowItems = hasWindowFeed ? realCommentsOfWindow(reviewWindow) : null;
|
|
7645
7737
|
const value = hasWindowFeed ? windowItems : catalog.value;
|
|
7646
7738
|
const listStatus = hasWindowFeed ? reviewWindowSliceStatus(reviewWindow) : catalog.status;
|
|
7647
7739
|
const items = value ?? [];
|
|
@@ -14704,6 +14796,92 @@ function createSuperDocUI(options) {
|
|
|
14704
14796
|
}
|
|
14705
14797
|
}, 120);
|
|
14706
14798
|
};
|
|
14799
|
+
const updateStyleToMatchSelection = (input) => {
|
|
14800
|
+
const mode = readDocumentMode();
|
|
14801
|
+
if (mode === "viewing") return failedReceipt("The document is read-only.", "DOCUMENT_READONLY");
|
|
14802
|
+
if (mode === "suggesting") return failedReceipt("A style definition cannot be changed as a tracked suggestion.", "PRECONDITION_FAILED");
|
|
14803
|
+
const sourceToken = contentToken();
|
|
14804
|
+
const readPositionKey = () => {
|
|
14805
|
+
const snapshot = readHostSelectionSnapshot();
|
|
14806
|
+
if (!snapshot) return null;
|
|
14807
|
+
return JSON.stringify({
|
|
14808
|
+
story: snapshot.story,
|
|
14809
|
+
tableCells: snapshot.tableCells,
|
|
14810
|
+
points: ["anchor", "focus"].map((side) => {
|
|
14811
|
+
const point = snapshot[side];
|
|
14812
|
+
return point ? [
|
|
14813
|
+
point.blockId,
|
|
14814
|
+
point.blockOffset,
|
|
14815
|
+
point.trackedBlockOffset,
|
|
14816
|
+
point.story,
|
|
14817
|
+
point.inlineAffinity,
|
|
14818
|
+
point.outsideContentControl,
|
|
14819
|
+
point.visualCaret
|
|
14820
|
+
] : null;
|
|
14821
|
+
})
|
|
14822
|
+
});
|
|
14823
|
+
};
|
|
14824
|
+
const requestedPosition = readPositionKey();
|
|
14825
|
+
const stale = failedReceipt("The selection or document changed while reading its style.", "REVISION_MISMATCH");
|
|
14826
|
+
return readSelectionInfoFresh().then((selection) => {
|
|
14827
|
+
const selectionToken = selectionKey(selection);
|
|
14828
|
+
const isCurrent = () => !disposed && contentToken() === sourceToken && readPositionKey() === requestedPosition && selectionKey(state.selection) === selectionToken && readDocumentMode() === mode;
|
|
14829
|
+
if (!isCurrent()) return stale;
|
|
14830
|
+
const active = computeActiveParagraphStyle(selection, getStyleCatalog().cache).style;
|
|
14831
|
+
const story = storyLocatorSignature(selectionStory(selection));
|
|
14832
|
+
const keys = [styleCatalogReadKey({ includePreview: true }), ...selectionBlockIds(selection).map((id) => `node:${story}:${id}`)];
|
|
14833
|
+
const unreadable = failedReceipt("The selection formatting could not be read.", "PRECONDITION_FAILED");
|
|
14834
|
+
const run = (active) => {
|
|
14835
|
+
if (keys.some((key) => {
|
|
14836
|
+
const entry = asyncReads.get(key);
|
|
14837
|
+
return entry && (!entry.hasSettled || entry.token !== sourceToken || entry.failedToken === sourceToken);
|
|
14838
|
+
})) return unreadable;
|
|
14839
|
+
const styleId = input?.styleId ?? active.styleId;
|
|
14840
|
+
if (!styleId) return failedReceipt("Choose a style to update: the selection does not have a single paragraph style.", "INVALID_TARGET");
|
|
14841
|
+
const doc = getDoc();
|
|
14842
|
+
const readSelection = resolveDocOperation(doc, "format.readSelection");
|
|
14843
|
+
const apply = resolveDocOperation(doc, "styles.apply");
|
|
14844
|
+
if (!readSelection || !apply) return failedReceipt("Updating a style to match the selection is unavailable.");
|
|
14845
|
+
let reads;
|
|
14846
|
+
try {
|
|
14847
|
+
reads = [readSelection({
|
|
14848
|
+
selection: "current",
|
|
14849
|
+
keys: STYLE_MATCH_READ_KEYS,
|
|
14850
|
+
view: "effective"
|
|
14851
|
+
}), readSelection({
|
|
14852
|
+
selection: "current",
|
|
14853
|
+
keys: STYLE_MATCH_READ_KEYS,
|
|
14854
|
+
view: "direct"
|
|
14855
|
+
})];
|
|
14856
|
+
} catch {
|
|
14857
|
+
return unreadable;
|
|
14858
|
+
}
|
|
14859
|
+
return Promise.all(reads).then(([effective, direct]) => {
|
|
14860
|
+
if (!isCurrent()) return stale;
|
|
14861
|
+
const patch = buildStyleMatchPatch(effective, direct, { selectionUsesStyle: !active.mixed && active.styleId === styleId });
|
|
14862
|
+
if (Object.keys(patch).length === 0) return failedReceipt("The selection already matches the style.", "NO_OP");
|
|
14863
|
+
const fallback = failedReceipt("Updating the style failed.");
|
|
14864
|
+
return safeCall(() => settleWorkflowReceipt(apply({
|
|
14865
|
+
target: {
|
|
14866
|
+
scope: "style",
|
|
14867
|
+
styleId,
|
|
14868
|
+
channel: "run"
|
|
14869
|
+
},
|
|
14870
|
+
patch
|
|
14871
|
+
}), fallback), fallback);
|
|
14872
|
+
}, () => unreadable);
|
|
14873
|
+
};
|
|
14874
|
+
const pending = keys.flatMap((key) => {
|
|
14875
|
+
const entry = asyncReads.get(key);
|
|
14876
|
+
return entry?.inflightToken === sourceToken && entry.settled ? [entry.settled] : [];
|
|
14877
|
+
});
|
|
14878
|
+
if (pending.length === 0) return run(active);
|
|
14879
|
+
return Promise.all(pending).then(() => {
|
|
14880
|
+
if (!isCurrent()) return stale;
|
|
14881
|
+
return run(computeActiveParagraphStyle(selection, getStyleCatalog().cache).style);
|
|
14882
|
+
});
|
|
14883
|
+
});
|
|
14884
|
+
};
|
|
14707
14885
|
const stylesSub = sliceHandle((s) => s.styles);
|
|
14708
14886
|
const stylesSnap = snapshotHandle(stylesSub);
|
|
14709
14887
|
const styles = {
|
|
@@ -14716,7 +14894,8 @@ function createSuperDocUI(options) {
|
|
|
14716
14894
|
return readStyleCatalogLive(options).value;
|
|
14717
14895
|
},
|
|
14718
14896
|
getQuickGallery: () => stylesSub.get().quickGallery,
|
|
14719
|
-
getActiveParagraphStyle: () => computeActiveParagraphStyle(state.selection, getStyleCatalog().cache).style
|
|
14897
|
+
getActiveParagraphStyle: () => computeActiveParagraphStyle(state.selection, getStyleCatalog().cache).style,
|
|
14898
|
+
updateToMatchSelection: (input) => updateStyleToMatchSelection(input)
|
|
14720
14899
|
};
|
|
14721
14900
|
const openWatermarkSurface = hostMethod(superdoc, "openSurface");
|
|
14722
14901
|
const watermark = createWatermarkController({
|
|
@@ -15051,4 +15230,4 @@ function commandIsActive(descriptor, selection) {
|
|
|
15051
15230
|
return descriptor.activeMark ? selection.activeMarks.includes(descriptor.activeMark) : false;
|
|
15052
15231
|
}
|
|
15053
15232
|
//#endregion
|
|
15054
|
-
export {
|
|
15233
|
+
export { getWorkflowRecording as _, registerFirstPartyCommandMutation as a, getV2TrackedChangeMutationImpact as c, resolveImageSrc as d, shallowEqual as f, createInteractionHistory as g, closeInteractionHistory as h, readFirstPartyPageNumbers as i, isPlainObject as l, DOM_CLASS_NAMES as m, executeFirstPartyCommandAsync as n, BUILT_IN_COMMAND_IDS as o, isSyntheticTrackedChangeCommentLaneItem as p, executeFirstPartyShortcutAsync as r, applyV2CommentInvalidationFromMutation as s, createSuperDocUI as t, createImageFilePicker as u, isWorkflowRecordingEnabled as v, recordInteraction as y };
|
|
@@ -1078,6 +1078,15 @@ var decodeLayoutStoryDataset = (raw) => {
|
|
|
1078
1078
|
`${DOM_CLASS_NAMES.BLOCK_SDT}${DATA_ATTRS.SDT_ID}`;
|
|
1079
1079
|
`${DATA_ATTRS.DRAGGABLE}`;
|
|
1080
1080
|
//#endregion
|
|
1081
|
+
//#region src/helpers/tracked-change-comment-lane.ts
|
|
1082
|
+
var TRACKED_CHANGE_COMMENT_LANE_ID_PREFIX = "tc-comment:";
|
|
1083
|
+
function isSyntheticTrackedChangeCommentLaneItem(item) {
|
|
1084
|
+
if (!item || typeof item !== "object") return false;
|
|
1085
|
+
const { id, commentId } = item;
|
|
1086
|
+
const itemId = id ?? commentId;
|
|
1087
|
+
return typeof itemId === "string" && itemId.startsWith(TRACKED_CHANGE_COMMENT_LANE_ID_PREFIX);
|
|
1088
|
+
}
|
|
1089
|
+
//#endregion
|
|
1081
1090
|
//#region src/public/ui/viewport-batch.ts
|
|
1082
1091
|
/** No rendering or scrolling: read only geometry already acknowledged by the host. */
|
|
1083
1092
|
async function readViewportBatch(input, read, generation, disposed) {
|
|
@@ -2450,6 +2459,69 @@ function createDialogWorkflow(editor, options, onSuccess) {
|
|
|
2450
2459
|
};
|
|
2451
2460
|
}
|
|
2452
2461
|
//#endregion
|
|
2462
|
+
//#region src/public/ui/style-match-patch.ts
|
|
2463
|
+
var STYLE_MATCH_KEYS = [
|
|
2464
|
+
["bold", "bold"],
|
|
2465
|
+
["italic", "italic"],
|
|
2466
|
+
["underline", "underline"],
|
|
2467
|
+
["color", "color"],
|
|
2468
|
+
["fontSize", "fontSize"],
|
|
2469
|
+
["rFonts", "fontFamily"]
|
|
2470
|
+
];
|
|
2471
|
+
var STYLE_MATCH_READ_KEYS = [...STYLE_MATCH_KEYS.map(([readKey]) => readKey), "rStyle"];
|
|
2472
|
+
function buildStyleMatchPatch(effective, direct, options) {
|
|
2473
|
+
const patch = {};
|
|
2474
|
+
const characterStyle = direct.properties.rStyle;
|
|
2475
|
+
const hasCharacterStyle = characterStyle != null && characterStyle.state !== "unset";
|
|
2476
|
+
for (const [readKey, styleKey] of STYLE_MATCH_KEYS) {
|
|
2477
|
+
const read = effective.properties[readKey];
|
|
2478
|
+
if (read?.state !== "uniform") continue;
|
|
2479
|
+
if (options.selectionUsesStyle && !hasCharacterStyle && direct.properties[readKey]?.state === "unset") continue;
|
|
2480
|
+
patch[styleKey] = toStyleValue(readKey, read.value);
|
|
2481
|
+
}
|
|
2482
|
+
return patch;
|
|
2483
|
+
}
|
|
2484
|
+
function toStyleValue(key, value) {
|
|
2485
|
+
switch (key) {
|
|
2486
|
+
case "bold":
|
|
2487
|
+
case "italic": return value === true;
|
|
2488
|
+
case "underline": return underlineValue(value);
|
|
2489
|
+
case "color": return typeof value === "string" && value.length > 0 ? { val: value.replace(/^#/, "") } : null;
|
|
2490
|
+
case "fontSize": return typeof value === "number" && Number.isFinite(value) ? Math.round(value * 2) : null;
|
|
2491
|
+
case "rFonts": return fontsValue(value);
|
|
2492
|
+
default: return null;
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
function underlineValue(value) {
|
|
2496
|
+
if (value === true) return { val: "single" };
|
|
2497
|
+
if (!value || typeof value !== "object") return { val: "none" };
|
|
2498
|
+
const underline = value;
|
|
2499
|
+
const result = { val: typeof underline.style === "string" && underline.style ? underline.style : "single" };
|
|
2500
|
+
if (typeof underline.color === "string") result.color = underline.color;
|
|
2501
|
+
if (typeof underline.themeColor === "string") result.themeColor = underline.themeColor;
|
|
2502
|
+
return result;
|
|
2503
|
+
}
|
|
2504
|
+
var FONT_SLOTS = {
|
|
2505
|
+
ascii: "ascii",
|
|
2506
|
+
hAnsi: "hAnsi",
|
|
2507
|
+
eastAsia: "eastAsia",
|
|
2508
|
+
cs: "cs",
|
|
2509
|
+
asciiTheme: "asciiTheme",
|
|
2510
|
+
hAnsiTheme: "hAnsiTheme",
|
|
2511
|
+
eastAsiaTheme: "eastAsiaTheme",
|
|
2512
|
+
csTheme: "cstheme",
|
|
2513
|
+
hint: "hint"
|
|
2514
|
+
};
|
|
2515
|
+
function fontsValue(value) {
|
|
2516
|
+
if (!value || typeof value !== "object") return null;
|
|
2517
|
+
const result = {};
|
|
2518
|
+
for (const [slot, styleSlot] of Object.entries(FONT_SLOTS)) {
|
|
2519
|
+
const font = value[slot];
|
|
2520
|
+
if (typeof font === "string" && font.length > 0) result[styleSlot] = font;
|
|
2521
|
+
}
|
|
2522
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
2523
|
+
}
|
|
2524
|
+
//#endregion
|
|
2453
2525
|
//#region src/public/ui/format-painter-helpers.js
|
|
2454
2526
|
/**
|
|
2455
2527
|
* Maps SDRunProps field names to InlineRunPatch field names.
|
|
@@ -2635,12 +2707,6 @@ function getV2TrackedChangeMutationImpact(event) {
|
|
|
2635
2707
|
}
|
|
2636
2708
|
/**
|
|
2637
2709
|
* Comment ids retired by a committed v2 mutation.
|
|
2638
|
-
*
|
|
2639
|
-
* AIDEV-NOTE: History commits put invalidated comment ids on `result`; cut and
|
|
2640
|
-
* other command receipts use `receipt`. Same origin split as
|
|
2641
|
-
* getV2TrackedChangeMutationImpact. Reading the wrong field, or treating a
|
|
2642
|
-
* tracked-change entity as a comment, leaves a sidebar card after cut or
|
|
2643
|
-
* undo/redo.
|
|
2644
2710
|
*/
|
|
2645
2711
|
function collectV2InvalidatedCommentIds(event) {
|
|
2646
2712
|
const removedIds = /* @__PURE__ */ new Set();
|
|
@@ -7097,7 +7163,7 @@ function createSuperDocUI(options) {
|
|
|
7097
7163
|
failureCount: retryingSameToken ? prev.failureCount ?? 0 : 0,
|
|
7098
7164
|
retryAtMs: 0
|
|
7099
7165
|
});
|
|
7100
|
-
Promise.resolve(raw).then((resolved) => {
|
|
7166
|
+
const settled = Promise.resolve(raw).then((resolved) => {
|
|
7101
7167
|
const entry = asyncReads.get(key);
|
|
7102
7168
|
if (!entry || entry.inflightToken !== token) return;
|
|
7103
7169
|
asyncReads.set(key, {
|
|
@@ -7136,6 +7202,7 @@ function createSuperDocUI(options) {
|
|
|
7136
7202
|
const retryAtMs = Date.now() + retryDelayMs;
|
|
7137
7203
|
asyncReads.set(key, {
|
|
7138
7204
|
...entry,
|
|
7205
|
+
settled: void 0,
|
|
7139
7206
|
inflightToken: null,
|
|
7140
7207
|
failedToken: token,
|
|
7141
7208
|
failureCount,
|
|
@@ -7143,6 +7210,8 @@ function createSuperDocUI(options) {
|
|
|
7143
7210
|
});
|
|
7144
7211
|
scheduleAsyncReadFailureRetry(retryAtMs);
|
|
7145
7212
|
});
|
|
7213
|
+
const entry = asyncReads.get(key);
|
|
7214
|
+
if (entry?.inflightToken === token) entry.settled = settled;
|
|
7146
7215
|
return null;
|
|
7147
7216
|
};
|
|
7148
7217
|
/**
|
|
@@ -7452,7 +7521,10 @@ function createSuperDocUI(options) {
|
|
|
7452
7521
|
if (hostSelection && info && typeof info === "object") selectionHostSnapshots.set(info, hostSelection);
|
|
7453
7522
|
return info;
|
|
7454
7523
|
};
|
|
7455
|
-
const result = current({
|
|
7524
|
+
const result = current({
|
|
7525
|
+
includeText: true,
|
|
7526
|
+
...getEditor()?.editorVersion === 2 ? { offsetSpace: "selection" } : {}
|
|
7527
|
+
});
|
|
7456
7528
|
return isPromiseLike(result) ? Promise.resolve(result).then(tag) : tag(result);
|
|
7457
7529
|
}
|
|
7458
7530
|
/** True when a host sync snapshot is a resolved collapsed caret (not a range). */
|
|
@@ -7589,7 +7661,10 @@ function createSuperDocUI(options) {
|
|
|
7589
7661
|
}
|
|
7590
7662
|
let raw;
|
|
7591
7663
|
try {
|
|
7592
|
-
raw = current.call(selectionApi, {
|
|
7664
|
+
raw = current.call(selectionApi, {
|
|
7665
|
+
includeText: true,
|
|
7666
|
+
...getEditor()?.editorVersion === 2 ? { offsetSpace: "selection" } : {}
|
|
7667
|
+
});
|
|
7593
7668
|
if (isPromiseLike(raw)) raw = await Promise.resolve(raw);
|
|
7594
7669
|
} catch {
|
|
7595
7670
|
raw = null;
|
|
@@ -7607,9 +7682,26 @@ function createSuperDocUI(options) {
|
|
|
7607
7682
|
recompute();
|
|
7608
7683
|
return selection;
|
|
7609
7684
|
};
|
|
7685
|
+
const realComments = (items) => items.filter((item) => !isSyntheticTrackedChangeCommentLaneItem(item));
|
|
7686
|
+
let lastWindowComments = null;
|
|
7687
|
+
const realCommentsOfWindow = (window) => {
|
|
7688
|
+
const items = window?.commentItems;
|
|
7689
|
+
if (!Array.isArray(items)) return null;
|
|
7690
|
+
const last = lastWindowComments;
|
|
7691
|
+
if (last?.source === items && shallowEqual(last.rows, items)) return last.real;
|
|
7692
|
+
lastWindowComments = {
|
|
7693
|
+
source: items,
|
|
7694
|
+
rows: [...items],
|
|
7695
|
+
real: realComments(items)
|
|
7696
|
+
};
|
|
7697
|
+
return lastWindowComments.real;
|
|
7698
|
+
};
|
|
7610
7699
|
const readCommentsDirectory = () => {
|
|
7611
7700
|
const listComments = hostMethod(getDoc()?.comments, "list");
|
|
7612
|
-
return readAsync("comments", contentToken(), () => listComments ? listComments() : void 0, (raw) =>
|
|
7701
|
+
return readAsync("comments", contentToken(), () => listComments ? listComments() : void 0, (raw) => {
|
|
7702
|
+
const items = isPlainObject(raw) ? raw.items : void 0;
|
|
7703
|
+
return Array.isArray(items) ? realComments(items) : [];
|
|
7704
|
+
});
|
|
7613
7705
|
};
|
|
7614
7706
|
const readTrackChangesDirectory = (key = "trackChanges") => {
|
|
7615
7707
|
const token = contentToken();
|
|
@@ -7642,7 +7734,7 @@ function createSuperDocUI(options) {
|
|
|
7642
7734
|
const reviewWindow = getV2ReviewWindowSnapshot();
|
|
7643
7735
|
const hasWindowFeed = hasV2ReviewWindowFeed();
|
|
7644
7736
|
const catalog = !hasWindowFeed ? readCommentsDirectory() : null;
|
|
7645
|
-
const windowItems = hasWindowFeed
|
|
7737
|
+
const windowItems = hasWindowFeed ? realCommentsOfWindow(reviewWindow) : null;
|
|
7646
7738
|
const value = hasWindowFeed ? windowItems : catalog.value;
|
|
7647
7739
|
const listStatus = hasWindowFeed ? reviewWindowSliceStatus(reviewWindow) : catalog.status;
|
|
7648
7740
|
const items = value ?? [];
|
|
@@ -14705,6 +14797,92 @@ function createSuperDocUI(options) {
|
|
|
14705
14797
|
}
|
|
14706
14798
|
}, 120);
|
|
14707
14799
|
};
|
|
14800
|
+
const updateStyleToMatchSelection = (input) => {
|
|
14801
|
+
const mode = readDocumentMode();
|
|
14802
|
+
if (mode === "viewing") return failedReceipt("The document is read-only.", "DOCUMENT_READONLY");
|
|
14803
|
+
if (mode === "suggesting") return failedReceipt("A style definition cannot be changed as a tracked suggestion.", "PRECONDITION_FAILED");
|
|
14804
|
+
const sourceToken = contentToken();
|
|
14805
|
+
const readPositionKey = () => {
|
|
14806
|
+
const snapshot = readHostSelectionSnapshot();
|
|
14807
|
+
if (!snapshot) return null;
|
|
14808
|
+
return JSON.stringify({
|
|
14809
|
+
story: snapshot.story,
|
|
14810
|
+
tableCells: snapshot.tableCells,
|
|
14811
|
+
points: ["anchor", "focus"].map((side) => {
|
|
14812
|
+
const point = snapshot[side];
|
|
14813
|
+
return point ? [
|
|
14814
|
+
point.blockId,
|
|
14815
|
+
point.blockOffset,
|
|
14816
|
+
point.trackedBlockOffset,
|
|
14817
|
+
point.story,
|
|
14818
|
+
point.inlineAffinity,
|
|
14819
|
+
point.outsideContentControl,
|
|
14820
|
+
point.visualCaret
|
|
14821
|
+
] : null;
|
|
14822
|
+
})
|
|
14823
|
+
});
|
|
14824
|
+
};
|
|
14825
|
+
const requestedPosition = readPositionKey();
|
|
14826
|
+
const stale = failedReceipt("The selection or document changed while reading its style.", "REVISION_MISMATCH");
|
|
14827
|
+
return readSelectionInfoFresh().then((selection) => {
|
|
14828
|
+
const selectionToken = selectionKey(selection);
|
|
14829
|
+
const isCurrent = () => !disposed && contentToken() === sourceToken && readPositionKey() === requestedPosition && selectionKey(state.selection) === selectionToken && readDocumentMode() === mode;
|
|
14830
|
+
if (!isCurrent()) return stale;
|
|
14831
|
+
const active = computeActiveParagraphStyle(selection, getStyleCatalog().cache).style;
|
|
14832
|
+
const story = storyLocatorSignature(selectionStory(selection));
|
|
14833
|
+
const keys = [styleCatalogReadKey({ includePreview: true }), ...selectionBlockIds(selection).map((id) => `node:${story}:${id}`)];
|
|
14834
|
+
const unreadable = failedReceipt("The selection formatting could not be read.", "PRECONDITION_FAILED");
|
|
14835
|
+
const run = (active) => {
|
|
14836
|
+
if (keys.some((key) => {
|
|
14837
|
+
const entry = asyncReads.get(key);
|
|
14838
|
+
return entry && (!entry.hasSettled || entry.token !== sourceToken || entry.failedToken === sourceToken);
|
|
14839
|
+
})) return unreadable;
|
|
14840
|
+
const styleId = input?.styleId ?? active.styleId;
|
|
14841
|
+
if (!styleId) return failedReceipt("Choose a style to update: the selection does not have a single paragraph style.", "INVALID_TARGET");
|
|
14842
|
+
const doc = getDoc();
|
|
14843
|
+
const readSelection = resolveDocOperation(doc, "format.readSelection");
|
|
14844
|
+
const apply = resolveDocOperation(doc, "styles.apply");
|
|
14845
|
+
if (!readSelection || !apply) return failedReceipt("Updating a style to match the selection is unavailable.");
|
|
14846
|
+
let reads;
|
|
14847
|
+
try {
|
|
14848
|
+
reads = [readSelection({
|
|
14849
|
+
selection: "current",
|
|
14850
|
+
keys: STYLE_MATCH_READ_KEYS,
|
|
14851
|
+
view: "effective"
|
|
14852
|
+
}), readSelection({
|
|
14853
|
+
selection: "current",
|
|
14854
|
+
keys: STYLE_MATCH_READ_KEYS,
|
|
14855
|
+
view: "direct"
|
|
14856
|
+
})];
|
|
14857
|
+
} catch {
|
|
14858
|
+
return unreadable;
|
|
14859
|
+
}
|
|
14860
|
+
return Promise.all(reads).then(([effective, direct]) => {
|
|
14861
|
+
if (!isCurrent()) return stale;
|
|
14862
|
+
const patch = buildStyleMatchPatch(effective, direct, { selectionUsesStyle: !active.mixed && active.styleId === styleId });
|
|
14863
|
+
if (Object.keys(patch).length === 0) return failedReceipt("The selection already matches the style.", "NO_OP");
|
|
14864
|
+
const fallback = failedReceipt("Updating the style failed.");
|
|
14865
|
+
return safeCall(() => settleWorkflowReceipt(apply({
|
|
14866
|
+
target: {
|
|
14867
|
+
scope: "style",
|
|
14868
|
+
styleId,
|
|
14869
|
+
channel: "run"
|
|
14870
|
+
},
|
|
14871
|
+
patch
|
|
14872
|
+
}), fallback), fallback);
|
|
14873
|
+
}, () => unreadable);
|
|
14874
|
+
};
|
|
14875
|
+
const pending = keys.flatMap((key) => {
|
|
14876
|
+
const entry = asyncReads.get(key);
|
|
14877
|
+
return entry?.inflightToken === sourceToken && entry.settled ? [entry.settled] : [];
|
|
14878
|
+
});
|
|
14879
|
+
if (pending.length === 0) return run(active);
|
|
14880
|
+
return Promise.all(pending).then(() => {
|
|
14881
|
+
if (!isCurrent()) return stale;
|
|
14882
|
+
return run(computeActiveParagraphStyle(selection, getStyleCatalog().cache).style);
|
|
14883
|
+
});
|
|
14884
|
+
});
|
|
14885
|
+
};
|
|
14708
14886
|
const stylesSub = sliceHandle((s) => s.styles);
|
|
14709
14887
|
const stylesSnap = snapshotHandle(stylesSub);
|
|
14710
14888
|
const styles = {
|
|
@@ -14717,7 +14895,8 @@ function createSuperDocUI(options) {
|
|
|
14717
14895
|
return readStyleCatalogLive(options).value;
|
|
14718
14896
|
},
|
|
14719
14897
|
getQuickGallery: () => stylesSub.get().quickGallery,
|
|
14720
|
-
getActiveParagraphStyle: () => computeActiveParagraphStyle(state.selection, getStyleCatalog().cache).style
|
|
14898
|
+
getActiveParagraphStyle: () => computeActiveParagraphStyle(state.selection, getStyleCatalog().cache).style,
|
|
14899
|
+
updateToMatchSelection: (input) => updateStyleToMatchSelection(input)
|
|
14721
14900
|
};
|
|
14722
14901
|
const openWatermarkSurface = hostMethod(superdoc, "openSurface");
|
|
14723
14902
|
const watermark = createWatermarkController({
|
|
@@ -15124,6 +15303,12 @@ Object.defineProperty(exports, "isPlainObject", {
|
|
|
15124
15303
|
return isPlainObject;
|
|
15125
15304
|
}
|
|
15126
15305
|
});
|
|
15306
|
+
Object.defineProperty(exports, "isSyntheticTrackedChangeCommentLaneItem", {
|
|
15307
|
+
enumerable: true,
|
|
15308
|
+
get: function() {
|
|
15309
|
+
return isSyntheticTrackedChangeCommentLaneItem;
|
|
15310
|
+
}
|
|
15311
|
+
});
|
|
15127
15312
|
Object.defineProperty(exports, "isWorkflowRecordingEnabled", {
|
|
15128
15313
|
enumerable: true,
|
|
15129
15314
|
get: function() {
|
|
@@ -19,7 +19,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
|
|
|
19
19
|
var PRIVATE_ENGINE_INFO = (0, _superdoc_docx_engine_collaboration_upgrade_engine.getCollaborationUpgradeEngineInfo)();
|
|
20
20
|
var ENGINE_INFO = Object.freeze({
|
|
21
21
|
...PRIVATE_ENGINE_INFO,
|
|
22
|
-
superdocVersion: "2.27.0-next.
|
|
22
|
+
superdocVersion: "2.27.0-next.11",
|
|
23
23
|
roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
|
|
24
24
|
supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
|
|
25
25
|
supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
|
|
@@ -18,7 +18,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
|
|
|
18
18
|
var PRIVATE_ENGINE_INFO = getCollaborationUpgradeEngineInfo$1();
|
|
19
19
|
var ENGINE_INFO = Object.freeze({
|
|
20
20
|
...PRIVATE_ENGINE_INFO,
|
|
21
|
-
superdocVersion: "2.27.0-next.
|
|
21
|
+
superdocVersion: "2.27.0-next.11",
|
|
22
22
|
roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
|
|
23
23
|
supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
|
|
24
24
|
supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
|
|
@@ -42,7 +42,7 @@ export declare const OPERATION_DEFINITIONS: {
|
|
|
42
42
|
};
|
|
43
43
|
readonly 'styles.apply': {
|
|
44
44
|
readonly memberPath: "styles.apply";
|
|
45
|
-
readonly description: "Apply
|
|
45
|
+
readonly description: "Apply style changes to the active Style Definitions part. Targets docDefaults run and paragraph channels, or the run properties of an existing named paragraph style (scope \"style\"), with set-style patch semantics. Redefining a named style updates every paragraph that references it; its linked character style receives the same patch, null removes a property so the style inherits it again, and an object value replaces that property whole.";
|
|
46
46
|
readonly expectedResult: "Returns a StylesApplyReceipt with per-channel success/failure details for each property change.";
|
|
47
47
|
readonly requiresDocumentContext: true;
|
|
48
48
|
readonly metadata: CommandStaticMetadata;
|
|
@@ -2523,7 +2523,7 @@ export declare const OPERATION_DEFINITIONS: {
|
|
|
2523
2523
|
readonly 'contentControls.validateWordCompatibility': {
|
|
2524
2524
|
readonly memberPath: "contentControls.validateWordCompatibility";
|
|
2525
2525
|
readonly description: "Validate a content control for Word compatibility issues.";
|
|
2526
|
-
readonly expectedResult: "Returns a
|
|
2526
|
+
readonly expectedResult: "Returns read-only diagnostics for incompatible content structure and metadata or configuration issues. `compatible` is false only when a diagnostic has error severity; warnings leave it true.";
|
|
2527
2527
|
readonly requiresDocumentContext: true;
|
|
2528
2528
|
readonly metadata: CommandStaticMetadata;
|
|
2529
2529
|
readonly referenceDocPath: "content-controls/validate-word-compatibility.mdx";
|
|
@@ -43,12 +43,6 @@ export interface SDHistoryCollaborationMeta {
|
|
|
43
43
|
* Result of a history.undo or history.redo action.
|
|
44
44
|
* Mirrors PlanReceipt's revision shape for consistency.
|
|
45
45
|
*
|
|
46
|
-
* AIDEV-NOTE: this shape carries optional ref-effect
|
|
47
|
-
* fields. v1 callers leave them undefined; v2 (`V2HistoryAdapter`) populates
|
|
48
|
-
* them from the stored semantic delta of the undone/redone transaction so
|
|
49
|
-
* callers' held refs stay accurate across history actions. Never make any
|
|
50
|
-
* of the new fields required — v1 adapters MUST keep compiling unchanged.
|
|
51
|
-
*
|
|
52
46
|
* The shape also carries three optional collaboration fields:
|
|
53
47
|
* `status`, `diagnosticCode`, and `collaboration`. v1 leaves them
|
|
54
48
|
* undefined; collaborative v2 sessions populate them so callers can react
|