superdoc 2.28.0-next.6 → 2.28.0-next.8
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-D1eOhAjv.cjs → create-super-doc-ui-B4c55pFy.cjs} +420 -84
- package/dist/chunks/{create-super-doc-ui-B29zw5qD.es.js → create-super-doc-ui-C4Ka5Ph3.es.js} +415 -85
- package/dist/collaboration-upgrade-engine.cjs +1 -1
- package/dist/collaboration-upgrade-engine.es.js +1 -1
- package/dist/document-api/src/content-controls/content-controls.types.d.ts +11 -0
- package/dist/document-api/src/contract/command-catalog.d.ts +1 -1
- package/dist/document-api/src/contract/operation-definitions.d.ts +33 -33
- package/dist/document-api/src/contract/operation-registry.d.ts +4 -0
- package/dist/document-api/src/export/export.d.ts +3 -1
- package/dist/document-api/src/export/export.types.d.ts +8 -0
- package/dist/document-api/src/get-node/get-node.d.ts +10 -4
- package/dist/document-api/src/hyperlinks/hyperlinks.types.d.ts +2 -0
- package/dist/document-api/src/index.d.ts +1 -0
- package/dist/document-api/src/types/track-changes.types.d.ts +10 -2
- package/dist/layout-engine/contracts/src/index.d.ts +2 -0
- package/dist/layout-engine/contracts/src/resolved-layout.d.ts +1 -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/shared/common/list-marker-utils.d.ts +3 -0
- package/dist/style.css +1 -1
- package/dist/style.layered.css +1 -1
- package/dist/superdoc/src/core/SuperDoc.d.ts +2 -6
- package/dist/superdoc/src/core/config/normalize-ui-config.d.ts +1 -0
- package/dist/superdoc/src/core/editor-runtime/types.d.ts +1 -0
- package/dist/superdoc/src/core/editor-runtime/v2/v2-editor-runtime-adapter.d.ts +2 -2
- package/dist/superdoc/src/core/extensions/types.d.ts +14 -3
- package/dist/superdoc/src/core/helpers/resolve-docx-export.d.ts +6 -0
- package/dist/superdoc/src/core/types/index.d.ts +12 -1
- package/dist/superdoc/src/core/v2-integration/v2-integration.d.ts +0 -8
- package/dist/superdoc/src/internal/toolbar/built-in/color-dropdown-helpers.d.ts +0 -1
- package/dist/superdoc/src/internal/toolbar/built-in/constants.d.ts +0 -2
- package/dist/superdoc/src/public/export-types.d.ts +3 -0
- package/dist/superdoc/src/public/ui/entity-at.d.ts +1 -0
- package/dist/superdoc/src/public/ui/format-painter-helpers.d.ts +0 -13
- package/dist/superdoc/src/public/ui/types.d.ts +16 -2
- package/dist/superdoc/src/public/ui.d.cts +14 -0
- package/dist/superdoc/src/public/ui.d.ts +1 -1
- package/dist/superdoc/src/stores/comments-store.d.ts +3 -57
- package/dist/superdoc/src/stores/superdoc-store.d.ts +9 -171
- package/dist/superdoc.cjs +224 -59
- package/dist/superdoc.es.js +224 -59
- package/dist/word-layout/src/types.d.ts +1 -0
- package/dist-cdn/style.layered.css +1 -1
- package/dist-cdn/superdoc.min.css +1 -1
- package/dist-cdn/superdoc.min.js +42 -42
- package/package.json +2 -2
- package/dist/superdoc/src/helpers/floor.d.ts +0 -1
- package/dist/superdoc/src/index.d.cts +0 -18
- package/dist/superdoc/src/index.d.ts +0 -14
|
@@ -3692,6 +3692,25 @@ function getCommandDescriptor(id) {
|
|
|
3692
3692
|
}
|
|
3693
3693
|
//#endregion
|
|
3694
3694
|
//#region src/public/ui/entity-at.ts
|
|
3695
|
+
function readDecorationProviders(node) {
|
|
3696
|
+
const encoded = node.getAttribute("data-superdoc-extension-decorations");
|
|
3697
|
+
if (encoded) try {
|
|
3698
|
+
const parsed = JSON.parse(encoded);
|
|
3699
|
+
if (Array.isArray(parsed)) return parsed.filter((id) => typeof id === "string");
|
|
3700
|
+
} catch {
|
|
3701
|
+
return [];
|
|
3702
|
+
}
|
|
3703
|
+
const single = node.getAttribute("data-superdoc-extension-decoration");
|
|
3704
|
+
return single ? [single] : [];
|
|
3705
|
+
}
|
|
3706
|
+
function collectDecorationProvidersFromChain(start, stopAt) {
|
|
3707
|
+
const providers = /* @__PURE__ */ new Set();
|
|
3708
|
+
for (let element = start; element; element = element.parentElement) {
|
|
3709
|
+
for (const provider of readDecorationProviders(element)) providers.add(provider);
|
|
3710
|
+
if (element === stopAt) break;
|
|
3711
|
+
}
|
|
3712
|
+
return [...providers];
|
|
3713
|
+
}
|
|
3695
3714
|
function parseCommaSeparatedIds(value) {
|
|
3696
3715
|
return value.split(",").map((id) => id.trim()).filter(Boolean);
|
|
3697
3716
|
}
|
|
@@ -3763,6 +3782,16 @@ function collectEntityHitsFromChain(start, stopAt) {
|
|
|
3763
3782
|
for (const hit of pendingStory) hit.story = layoutStory;
|
|
3764
3783
|
pendingStory = [];
|
|
3765
3784
|
}
|
|
3785
|
+
for (const decorationProvider of readDecorationProviders(node)) {
|
|
3786
|
+
const key = `decoration:${decorationProvider}`;
|
|
3787
|
+
if (!seen.has(key)) {
|
|
3788
|
+
seen.add(key);
|
|
3789
|
+
hits.push({
|
|
3790
|
+
type: "decoration",
|
|
3791
|
+
id: decorationProvider
|
|
3792
|
+
});
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3766
3795
|
const citationId = node.getAttribute("data-citation-id");
|
|
3767
3796
|
if (citationId) {
|
|
3768
3797
|
const key = `citation:${citationId}`;
|
|
@@ -6153,6 +6182,7 @@ function createSuperDocUI(options) {
|
|
|
6153
6182
|
pointerSelecting: false,
|
|
6154
6183
|
keyboardSelecting: false
|
|
6155
6184
|
};
|
|
6185
|
+
const paintedInlineTargets = /* @__PURE__ */ new WeakSet();
|
|
6156
6186
|
let painterCaptureEpoch = 0;
|
|
6157
6187
|
let painterCommandDoc = null;
|
|
6158
6188
|
const painterModeListeners = /* @__PURE__ */ new Set();
|
|
@@ -6249,7 +6279,7 @@ function createSuperDocUI(options) {
|
|
|
6249
6279
|
const readHostSelectionSnapshot = () => {
|
|
6250
6280
|
const handles = safeCall(() => hostMethod(getHost(), "getHandles")?.() ?? null, null);
|
|
6251
6281
|
const editing = isPlainObject(handles) ? handles.editing : void 0;
|
|
6252
|
-
const getSnapshot = hostMethod(isPlainObject(editing) ? editing.selection : void 0, "getSnapshot");
|
|
6282
|
+
const getSnapshot = hostMethod(isPlainObject(editing) ? editing.selection : void 0, "getSnapshot") ?? hostMethod(isPlainObject(handles) ? handles.selection : void 0, "getSnapshot");
|
|
6253
6283
|
if (!getSnapshot) return null;
|
|
6254
6284
|
const snapshot = safeCall(() => getSnapshot(), null);
|
|
6255
6285
|
return snapshot && typeof snapshot === "object" ? snapshot : null;
|
|
@@ -6463,7 +6493,7 @@ function createSuperDocUI(options) {
|
|
|
6463
6493
|
return left.id === right.id && left.paintedEntityId === right.paintedEntityId && storyLocatorSignature(left.story) === storyLocatorSignature(right.story);
|
|
6464
6494
|
};
|
|
6465
6495
|
const hasPendingTrackChangeRevealFocus = (focus) => Array.from(pendingTrackChangeRevealFocuses).some((pendingFocus) => explicitActiveChangesEqual(pendingFocus, focus));
|
|
6466
|
-
const
|
|
6496
|
+
const mirrorReviewFocusToHost = (entityType, next) => {
|
|
6467
6497
|
const readHandles = hostMethod(getHost(), "getHandles");
|
|
6468
6498
|
if (!readHandles) return;
|
|
6469
6499
|
const handles = safeCall(() => readHandles(), null);
|
|
@@ -6474,15 +6504,15 @@ function createSuperDocUI(options) {
|
|
|
6474
6504
|
if (!setActiveReviewTarget) return;
|
|
6475
6505
|
const layout = isPlainObject(handles.layout) ? handles.layout : void 0;
|
|
6476
6506
|
safeCall(() => setActiveReviewTarget({
|
|
6477
|
-
entityType
|
|
6507
|
+
entityType,
|
|
6478
6508
|
entityId: next.id,
|
|
6479
6509
|
...next.paintedEntityId ? { paintedEntityId: next.paintedEntityId } : {},
|
|
6480
6510
|
origin: "panel",
|
|
6481
6511
|
layoutEpoch: typeof layout?.generation === "number" ? layout.generation : 0,
|
|
6482
|
-
story: next.story ?? {
|
|
6512
|
+
...entityType === "trackedChange" ? { story: next.story ?? {
|
|
6483
6513
|
kind: "story",
|
|
6484
6514
|
storyType: "body"
|
|
6485
|
-
}
|
|
6515
|
+
} } : {}
|
|
6486
6516
|
}), null);
|
|
6487
6517
|
return;
|
|
6488
6518
|
}
|
|
@@ -6490,10 +6520,22 @@ function createSuperDocUI(options) {
|
|
|
6490
6520
|
const clearActiveReviewTarget = hostMethod(review, "clearActiveReviewTarget");
|
|
6491
6521
|
if (!getActiveReviewTarget || !clearActiveReviewTarget) return;
|
|
6492
6522
|
const activeTarget = safeCall(() => getActiveReviewTarget(), null);
|
|
6493
|
-
if (isPlainObject(activeTarget) && activeTarget.entityType ===
|
|
6523
|
+
if (isPlainObject(activeTarget) && activeTarget.entityType === entityType) safeCall(() => clearActiveReviewTarget(), void 0);
|
|
6524
|
+
};
|
|
6525
|
+
const mirrorTrackedChangeFocusToHost = (next) => mirrorReviewFocusToHost("trackedChange", next);
|
|
6526
|
+
const readReviewFocus = () => ({
|
|
6527
|
+
change: explicitActiveChange,
|
|
6528
|
+
commentId: explicitActiveCommentId
|
|
6529
|
+
});
|
|
6530
|
+
const restoreReviewFocus = (previous) => {
|
|
6531
|
+
setExplicitActiveChange(previous.change, { invalidateQueuedNavigation: false });
|
|
6532
|
+
explicitActiveCommentId = previous.commentId;
|
|
6533
|
+
if (previous.commentId) mirrorReviewFocusToHost("comment", { id: previous.commentId });
|
|
6534
|
+
else mirrorTrackedChangeFocusToHost(previous.change);
|
|
6494
6535
|
};
|
|
6495
6536
|
const setExplicitActiveChange = (next, options) => {
|
|
6496
6537
|
explicitActiveChange = next;
|
|
6538
|
+
if (next) explicitActiveCommentId = null;
|
|
6497
6539
|
explicitActiveChangeRevision += 1;
|
|
6498
6540
|
trackChangeRevealInvalidation += 1;
|
|
6499
6541
|
if (options?.invalidateQueuedNavigation !== false) queuedTrackChangeNavigationInvalidation += 1;
|
|
@@ -7553,15 +7595,53 @@ function createSuperDocUI(options) {
|
|
|
7553
7595
|
* Explicit whole-table changes have a complete local source range and also
|
|
7554
7596
|
* seed clears, so a delayed worker read cannot retain a cleared table target.
|
|
7555
7597
|
*/
|
|
7556
|
-
|
|
7598
|
+
function captureWholeTableParagraphSeed(host, seed, nativeSelection) {
|
|
7599
|
+
const editor = getEditor();
|
|
7600
|
+
const rawLifetime = safeCall(() => hostMethod(host, "getForegroundInteractionLifetime")?.() ?? null, null);
|
|
7601
|
+
const lifetime = hasAbortedFlag(rawLifetime) ? rawLifetime : null;
|
|
7602
|
+
const mount = safeCall(() => hostMethod(host, "getMountedHandle")?.() ?? null, null);
|
|
7603
|
+
const mode = readDocumentMode();
|
|
7604
|
+
if (!host || !editor || !mount || !lifetime || lifetime.aborted || mode === null || seed.empty || seed.tableSelection?.kind !== "tableCells" || seed.tableSelection.type !== "table" || seed.target?.kind !== "text" || !seed.target.segments.length) return false;
|
|
7605
|
+
if (nativeSelection) {
|
|
7606
|
+
const presentation = safeCall(() => hostMethod(host, "readAppliedSelectionPresentation")?.(), null);
|
|
7607
|
+
const applied = normalizeSelectionInfo(isPlainObject(presentation) ? presentation.selection : null);
|
|
7608
|
+
if (readHostSelectionSnapshot() !== nativeSelection || !isNonCollapsedHostSelection(nativeSelection) || !applied || selectionSignature(selectionSliceFromInfo(applied, "ready")) !== selectionSignature(selectionSliceFromInfo(seed, "ready")) || JSON.stringify(applied.tableSelection) !== JSON.stringify(seed.tableSelection)) return false;
|
|
7609
|
+
const snapshot = nativeSelection;
|
|
7610
|
+
const first = seed.target.segments[0]?.blockId, last = seed.target.segments.at(-1)?.blockId;
|
|
7611
|
+
const matches = (point, blockId) => !!blockId && isPlainObject(point) && point.blockId === blockId && storyLocatorSignature(point.story ?? snapshot.story) === storyLocatorSignature(seed.target?.story);
|
|
7612
|
+
if (!(matches(snapshot.anchor, first) && matches(snapshot.focus, last) || matches(snapshot.focus, first) && matches(snapshot.anchor, last))) return false;
|
|
7613
|
+
}
|
|
7614
|
+
wholeTableParagraphSeed = {
|
|
7615
|
+
editor,
|
|
7616
|
+
host,
|
|
7617
|
+
doc: editor.doc,
|
|
7618
|
+
mount,
|
|
7619
|
+
lifetime,
|
|
7620
|
+
sourceToken: contentToken(),
|
|
7621
|
+
mode,
|
|
7622
|
+
info: seed,
|
|
7623
|
+
nativeSelection
|
|
7624
|
+
};
|
|
7625
|
+
return true;
|
|
7626
|
+
}
|
|
7627
|
+
const refreshSelectionFromHost = (hostSelectionSnapshot, afterTypingPaint = false, wholeTableSelectionChanged = false, initialTableSelection = null) => {
|
|
7628
|
+
const host = getHost();
|
|
7557
7629
|
const foreground = foregroundMutationState();
|
|
7630
|
+
if (isNonCollapsedHostSelection(hostSelectionSnapshot) && readHostSelectionSnapshot() === hostSelectionSnapshot) {
|
|
7631
|
+
const seed = normalizeSelectionInfo(safeCall(() => hostMethod(host, "readLiveSelectionSyncSnapshot")?.(), null));
|
|
7632
|
+
if (seed && !seed.selectionTarget && captureWholeTableParagraphSeed(host, seed, hostSelectionSnapshot)) asyncReads.set("selection", {
|
|
7633
|
+
token: asyncReads.get("selection")?.token ?? null,
|
|
7634
|
+
value: seed,
|
|
7635
|
+
hasSettled: true,
|
|
7636
|
+
inflightToken: null
|
|
7637
|
+
});
|
|
7638
|
+
}
|
|
7558
7639
|
if (isNonCollapsedHostSelection(hostSelectionSnapshot) && !(foreground && foreground.active > 0)) {
|
|
7559
7640
|
typedCaretValidationHeld = false;
|
|
7560
7641
|
pendingSelectionSeedValidationToken = null;
|
|
7561
7642
|
issueAsyncRead("selection", selectionReadToken(), selectionCurrentRun, normalizeSelectionInfo);
|
|
7562
7643
|
return;
|
|
7563
7644
|
}
|
|
7564
|
-
const host = getHost();
|
|
7565
7645
|
const read = host?.readLiveSelectionSyncSnapshot;
|
|
7566
7646
|
if (typeof read !== "function") return;
|
|
7567
7647
|
const seed = normalizeSelectionInfo(safeCall(() => read.call(host), null));
|
|
@@ -7570,21 +7650,7 @@ function createSuperDocUI(options) {
|
|
|
7570
7650
|
typedCaretValidationHeld = false;
|
|
7571
7651
|
pendingSelectionSeedValidationToken = null;
|
|
7572
7652
|
wholeTableParagraphSeed = null;
|
|
7573
|
-
|
|
7574
|
-
const rawLifetime = safeCall(() => hostMethod(host, "getForegroundInteractionLifetime")?.() ?? null, null);
|
|
7575
|
-
const lifetime = hasAbortedFlag(rawLifetime) ? rawLifetime : null;
|
|
7576
|
-
const mount = safeCall(() => hostMethod(host, "getMountedHandle")?.() ?? null, null);
|
|
7577
|
-
const mode = readDocumentMode();
|
|
7578
|
-
if (host && editor && mount && lifetime && !lifetime.aborted && mode !== null && !seed.empty && seed.tableSelection?.kind === "tableCells" && seed.tableSelection.type === "table" && seed.target?.segments.length && seed.selectionTarget) wholeTableParagraphSeed = {
|
|
7579
|
-
editor,
|
|
7580
|
-
host,
|
|
7581
|
-
doc: editor.doc,
|
|
7582
|
-
mount,
|
|
7583
|
-
lifetime,
|
|
7584
|
-
sourceToken: contentToken(),
|
|
7585
|
-
mode,
|
|
7586
|
-
info: seed
|
|
7587
|
-
};
|
|
7653
|
+
captureWholeTableParagraphSeed(host, seed, initialTableSelection);
|
|
7588
7654
|
const token = selectionReadToken();
|
|
7589
7655
|
asyncReads.set("selection", {
|
|
7590
7656
|
token,
|
|
@@ -7742,7 +7808,7 @@ function createSuperDocUI(options) {
|
|
|
7742
7808
|
const directory = asyncReads.get("comments");
|
|
7743
7809
|
const directoryItems = directory?.token === contentToken() && directory.hasSettled && Array.isArray(directory.value) ? directory.value : null;
|
|
7744
7810
|
const activeValidationItems = directoryLeaseCounts.comments > 0 ? directoryItems : items;
|
|
7745
|
-
if (explicitActiveCommentId && activeValidationItems &&
|
|
7811
|
+
if (explicitActiveCommentId && activeValidationItems && (activeValidationItems !== items || listStatus === "ready")) explicitActiveCommentId = resolveActiveCommentId(activeValidationItems, explicitActiveCommentId);
|
|
7746
7812
|
const activeId = explicitActiveCommentId ?? activeIds[0] ?? null;
|
|
7747
7813
|
return {
|
|
7748
7814
|
status: combineStatus(listStatus, selection.status),
|
|
@@ -8387,12 +8453,13 @@ function createSuperDocUI(options) {
|
|
|
8387
8453
|
];
|
|
8388
8454
|
function effectiveInlineUniformityInput(selection) {
|
|
8389
8455
|
const cellTarget = currentCellSelectionTarget();
|
|
8390
|
-
const
|
|
8456
|
+
const paintedTarget = cellTarget ? null : currentUnrepresentableSelectionTarget(selection);
|
|
8457
|
+
const target = cellTarget ?? paintedTarget ?? selection.selectionTarget;
|
|
8391
8458
|
if (!target) return null;
|
|
8392
8459
|
const tableCellSelection = cellTarget ? tableCellSelectionForTarget(cellTarget) : null;
|
|
8393
8460
|
return {
|
|
8394
8461
|
target,
|
|
8395
|
-
offsetSpace: "selection",
|
|
8462
|
+
offsetSpace: cellTarget || paintedTarget ? "selection" : "kernel",
|
|
8396
8463
|
...tableCellSelection ? { tableCellSelection } : {}
|
|
8397
8464
|
};
|
|
8398
8465
|
}
|
|
@@ -8530,7 +8597,11 @@ function createSuperDocUI(options) {
|
|
|
8530
8597
|
const getNodeById = hostMethod(doc, "getNodeById");
|
|
8531
8598
|
const raw = await Promise.resolve(getNode ? getNode(address) : getNodeById?.({
|
|
8532
8599
|
nodeId: address["nodeId"],
|
|
8533
|
-
nodeType: address["nodeType"]
|
|
8600
|
+
nodeType: address["nodeType"],
|
|
8601
|
+
story: address["story"] ?? {
|
|
8602
|
+
kind: "story",
|
|
8603
|
+
storyType: "body"
|
|
8604
|
+
}
|
|
8534
8605
|
}));
|
|
8535
8606
|
return isPlainObject(raw) ? raw : void 0;
|
|
8536
8607
|
};
|
|
@@ -9076,7 +9147,8 @@ function createSuperDocUI(options) {
|
|
|
9076
9147
|
const token = contentToken();
|
|
9077
9148
|
const read = readAsync(key, token, () => isBodyStory ? doc.getNodeById({
|
|
9078
9149
|
nodeId: blockId,
|
|
9079
|
-
nodeType: "paragraph"
|
|
9150
|
+
nodeType: "paragraph",
|
|
9151
|
+
story
|
|
9080
9152
|
}) : doc.getNode(paragraphTarget(blockId, story)), (raw) => raw && typeof raw === "object" ? raw : null);
|
|
9081
9153
|
const entry = asyncReads.get(key);
|
|
9082
9154
|
return {
|
|
@@ -9285,7 +9357,11 @@ function createSuperDocUI(options) {
|
|
|
9285
9357
|
const isBodyStory = !story || story.storyType === "body";
|
|
9286
9358
|
const raw = story && typeof doc.getNode === "function" ? await doc.getNode(paragraphTarget(blockId, story)) : isBodyStory && typeof doc.getNodeById === "function" ? await doc.getNodeById({
|
|
9287
9359
|
nodeId: blockId,
|
|
9288
|
-
nodeType: "paragraph"
|
|
9360
|
+
nodeType: "paragraph",
|
|
9361
|
+
story: {
|
|
9362
|
+
kind: "story",
|
|
9363
|
+
storyType: "body"
|
|
9364
|
+
}
|
|
9289
9365
|
}) : null;
|
|
9290
9366
|
return readParagraphIndentationFromResult(raw && typeof raw === "object" ? raw : null);
|
|
9291
9367
|
} catch {
|
|
@@ -9962,14 +10038,15 @@ function createSuperDocUI(options) {
|
|
|
9962
10038
|
const tableSelection = isPlainObject(handles) ? handles.selection : void 0;
|
|
9963
10039
|
const subscribeWholeTable = hostMethod(tableSelection, "subscribeWholeTable");
|
|
9964
10040
|
if (subscribeWholeTable) {
|
|
9965
|
-
const refreshWholeTable = () => {
|
|
10041
|
+
const refreshWholeTable = (initial = false) => {
|
|
10042
|
+
const native = initial ? readHostSelectionSnapshot() : null;
|
|
9966
10043
|
selectionEpoch += 1;
|
|
9967
|
-
refreshSelectionFromHost(void 0, false, true);
|
|
10044
|
+
refreshSelectionFromHost(void 0, false, true, native);
|
|
9968
10045
|
recompute("host-selection");
|
|
9969
10046
|
};
|
|
9970
|
-
const detach = subscribeWholeTable(refreshWholeTable);
|
|
10047
|
+
const detach = subscribeWholeTable(() => refreshWholeTable());
|
|
9971
10048
|
if (typeof detach === "function") unsubscribeCallbacks.push(() => detach());
|
|
9972
|
-
if (hostMethod(tableSelection, "getWholeTableNodeId")?.()) refreshWholeTable();
|
|
10049
|
+
if (hostMethod(tableSelection, "getWholeTableNodeId")?.()) refreshWholeTable(true);
|
|
9973
10050
|
}
|
|
9974
10051
|
} catch {
|
|
9975
10052
|
currentHostSelectionSource = null;
|
|
@@ -9990,10 +10067,35 @@ function createSuperDocUI(options) {
|
|
|
9990
10067
|
};
|
|
9991
10068
|
let trackedChangeNavigationInFlight = 0;
|
|
9992
10069
|
let lastPublishedHostReviewTarget;
|
|
10070
|
+
const isRepublishedHostReviewTarget = (left, right) => left === right || isPlainObject(left) && isPlainObject(right) && left.layoutEpoch !== right.layoutEpoch && left.origin === right.origin && left.entityType === right.entityType && left.entityId === right.entityId && left.paintedEntityId === right.paintedEntityId && storyLocatorSignature(left.story) === storyLocatorSignature(right.story);
|
|
9993
10071
|
const syncTrackedChangeFocusFromHostReviewTarget = (rawTarget, rawSnapshot) => {
|
|
9994
10072
|
const rejection = (rawSnapshot && typeof rawSnapshot === "object" ? rawSnapshot : null)?.lastInteractionRejection;
|
|
9995
|
-
if (rawTarget == null && rejection && typeof rejection === "object" && rejection.code === "review-target-invalidated" && rejection.detail === "not-painted" && explicitActiveChange) return false;
|
|
10073
|
+
if (rawTarget == null && rejection && typeof rejection === "object" && rejection.code === "review-target-invalidated" && rejection.detail === "not-painted" && (explicitActiveChange || explicitActiveCommentId)) return false;
|
|
9996
10074
|
const target = rawTarget && typeof rawTarget === "object" ? rawTarget : null;
|
|
10075
|
+
if (target?.entityType === "comment" && typeof target.entityId === "string" && target.entityId.length > 0) {
|
|
10076
|
+
const commentId = resolveActiveCommentId(state?.comments.items ?? [], target.entityId) ?? target.entityId;
|
|
10077
|
+
const republished = isRepublishedHostReviewTarget(rawTarget, lastPublishedHostReviewTarget?.raw);
|
|
10078
|
+
lastPublishedHostReviewTarget = {
|
|
10079
|
+
raw: rawTarget,
|
|
10080
|
+
focus: null,
|
|
10081
|
+
origin: target.origin
|
|
10082
|
+
};
|
|
10083
|
+
if (republished || explicitActiveCommentId === commentId && !explicitActiveChange) return false;
|
|
10084
|
+
setExplicitActiveChange(null);
|
|
10085
|
+
explicitActiveCommentId = commentId;
|
|
10086
|
+
return true;
|
|
10087
|
+
}
|
|
10088
|
+
const previousTarget = lastPublishedHostReviewTarget?.raw;
|
|
10089
|
+
if (!target && isPlainObject(previousTarget) && previousTarget.entityType === "comment") {
|
|
10090
|
+
lastPublishedHostReviewTarget = {
|
|
10091
|
+
raw: rawTarget,
|
|
10092
|
+
focus: null,
|
|
10093
|
+
origin: void 0
|
|
10094
|
+
};
|
|
10095
|
+
if (!explicitActiveCommentId) return false;
|
|
10096
|
+
explicitActiveCommentId = null;
|
|
10097
|
+
return true;
|
|
10098
|
+
}
|
|
9997
10099
|
let next = null;
|
|
9998
10100
|
if (target?.entityType === "trackedChange" && typeof target.entityId === "string" && target.entityId.length > 0) {
|
|
9999
10101
|
const targetStory = target.story && typeof target.story === "object" ? target.story : void 0;
|
|
@@ -10018,7 +10120,7 @@ function createSuperDocUI(options) {
|
|
|
10018
10120
|
}
|
|
10019
10121
|
if (rawTarget == null && next == null && explicitActiveChange != null && hasPendingTrackChangeRevealFocus(explicitActiveChange)) return false;
|
|
10020
10122
|
const previousPublication = lastPublishedHostReviewTarget;
|
|
10021
|
-
if (previousPublication && (rawTarget
|
|
10123
|
+
if (previousPublication && (isRepublishedHostReviewTarget(rawTarget, previousPublication.raw) || target?.origin === "panel" && previousPublication.origin === "panel" && next && previousPublication.focus && explicitActiveChangesEqual(previousPublication.focus, next))) return false;
|
|
10022
10124
|
lastPublishedHostReviewTarget = {
|
|
10023
10125
|
raw: rawTarget,
|
|
10024
10126
|
focus: next,
|
|
@@ -10396,11 +10498,16 @@ function createSuperDocUI(options) {
|
|
|
10396
10498
|
* ordinary/insertion selections are visible-space, while a selection that
|
|
10397
10499
|
* reaches painted deleted text is projected in tracked space by the host.
|
|
10398
10500
|
*
|
|
10399
|
-
* Cross-block
|
|
10400
|
-
*
|
|
10501
|
+
* Cross-block and object-containing coverage use the model-backed tracked
|
|
10502
|
+
* target when the explicit text selection cannot represent the range.
|
|
10401
10503
|
*/
|
|
10402
10504
|
function trackDecisionRangeFromSelection(selection) {
|
|
10403
10505
|
if (selection.empty) return null;
|
|
10506
|
+
if (!selection.selectionTarget && selection.trackedTarget) return {
|
|
10507
|
+
kind: "range",
|
|
10508
|
+
coordinateSpace: "tracked",
|
|
10509
|
+
range: selection.trackedTarget
|
|
10510
|
+
};
|
|
10404
10511
|
const explicit = selection.selectionTarget;
|
|
10405
10512
|
const start = explicit?.start;
|
|
10406
10513
|
const end = explicit?.end;
|
|
@@ -10554,7 +10661,7 @@ function createSuperDocUI(options) {
|
|
|
10554
10661
|
kind: "blocked",
|
|
10555
10662
|
reason: SUPERDOC_UI_REASONS.operationUnavailable
|
|
10556
10663
|
};
|
|
10557
|
-
if (!selection.selectionTarget) return null;
|
|
10664
|
+
if (!selection.selectionTarget && !selection.trackedTarget && selection.target?.kind !== "text") return null;
|
|
10558
10665
|
const target = trackDecisionRangeFromSelection(selection);
|
|
10559
10666
|
if (!target && route() !== "id") return {
|
|
10560
10667
|
kind: "blocked",
|
|
@@ -10894,25 +11001,35 @@ function createSuperDocUI(options) {
|
|
|
10894
11001
|
pendingCommandSettlement = settledResults.length ? Promise.all(settledResults).then((results) => combineCommandResults(results)) : null;
|
|
10895
11002
|
return combineCommandResults(immediateResults);
|
|
10896
11003
|
};
|
|
10897
|
-
/**
|
|
10898
|
-
* Call an inline `format.*` operation against the live selection. Mirrors
|
|
10899
|
-
* `callEditorMutation` (suggesting mode adds `changeMode: 'tracked'`), and
|
|
10900
|
-
* when the target is the host's own editable `selectionTarget` it also
|
|
10901
|
-
* carries the PRIVATE V2 option `offsetSpace: 'selection'` (browser
|
|
10902
|
-
* selection offsets count an inline object as one caret position). The
|
|
10903
|
-
* option is not part of public `MutationOptions`; this is the same cast
|
|
10904
|
-
* pattern the delete/replace callers use.
|
|
10905
|
-
*/
|
|
10906
11004
|
function currentCellSelectionTarget() {
|
|
11005
|
+
return captureInputSelectionTarget(true);
|
|
11006
|
+
}
|
|
11007
|
+
function captureInputSelectionTarget(requireTableCells = false) {
|
|
10907
11008
|
const handles = safeCall(() => hostMethod(getHost(), "getHandles")?.(), null);
|
|
10908
11009
|
const selection = isPlainObject(handles) ? handles.selection : void 0;
|
|
10909
11010
|
const held = hostMethod(selection, "getSnapshot")?.();
|
|
10910
|
-
if (!isPlainObject(held) || !held.tableCells) return null;
|
|
11011
|
+
if (requireTableCells && (!isPlainObject(held) || !held.tableCells)) return null;
|
|
10911
11012
|
const resolved = hostMethod(selection, "toSelectionTarget")?.();
|
|
10912
11013
|
return isPlainObject(resolved) && resolved.kind === "ok" && resolved.mode === "range" ? capturedTableCellTarget(resolved.target) : null;
|
|
10913
11014
|
}
|
|
11015
|
+
function currentUnrepresentableSelectionTarget(selection) {
|
|
11016
|
+
if (selection.empty || selection.selectionTarget || selection.target?.kind !== "text") return null;
|
|
11017
|
+
return heldPaintedTextSelectionTarget();
|
|
11018
|
+
}
|
|
11019
|
+
function heldPaintedTextSelectionTarget() {
|
|
11020
|
+
const target = captureInputSelectionTarget();
|
|
11021
|
+
if (target) paintedInlineTargets.add(target);
|
|
11022
|
+
return target;
|
|
11023
|
+
}
|
|
10914
11024
|
function resolveInlineCommandTarget(selection) {
|
|
10915
|
-
|
|
11025
|
+
const cells = currentCellSelectionTarget();
|
|
11026
|
+
if (cells) return cells;
|
|
11027
|
+
if (!selection.empty && !selection.selectionTarget && selection.target?.kind === "text") {
|
|
11028
|
+
const snapshot = readHostSelectionSnapshot();
|
|
11029
|
+
const painted = currentUnrepresentableSelectionTarget(selection);
|
|
11030
|
+
if (painted) return snapshot && appliedSelectionPresentation(selection) && readHostSelectionSnapshot() === snapshot ? painted : null;
|
|
11031
|
+
}
|
|
11032
|
+
return resolveInlineSelectionTarget(selection);
|
|
10916
11033
|
}
|
|
10917
11034
|
function tableCellSelectionForTarget(target) {
|
|
10918
11035
|
const cellTarget = currentCellSelectionTarget();
|
|
@@ -10932,10 +11049,15 @@ function createSuperDocUI(options) {
|
|
|
10932
11049
|
offsetSpace: "selection",
|
|
10933
11050
|
tableCellSelection
|
|
10934
11051
|
});
|
|
11052
|
+
const paintedTarget = input?.target;
|
|
11053
|
+
if (paintedTarget !== null && typeof paintedTarget === "object" && (paintedInlineTargets.has(paintedTarget) || paintedTarget.coordinateSpace === "tracked")) return op(input, {
|
|
11054
|
+
...options,
|
|
11055
|
+
offsetSpace: "selection"
|
|
11056
|
+
});
|
|
10935
11057
|
if (!selection.selectionTarget) return options ? op(input, options) : op(input);
|
|
10936
11058
|
return op(input, {
|
|
10937
11059
|
...options,
|
|
10938
|
-
offsetSpace: "
|
|
11060
|
+
offsetSpace: "kernel"
|
|
10939
11061
|
});
|
|
10940
11062
|
};
|
|
10941
11063
|
/** Build the `format.paragraph.*` / `styles.paragraph.*` input for a block. */
|
|
@@ -11164,13 +11286,16 @@ function createSuperDocUI(options) {
|
|
|
11164
11286
|
};
|
|
11165
11287
|
pendingCommandSettlement = (async () => {
|
|
11166
11288
|
const plans = await Promise.all(blockIds.map((blockId) => planBlock(blockId).catch(() => null)));
|
|
11167
|
-
|
|
11289
|
+
const allListItems = plans.length === blockIds.length && plans.every((plan) => plan?.kind === "list");
|
|
11290
|
+
const preserveFirstItemLevel = blockIds.length === 1 && story.storyType === "body";
|
|
11291
|
+
if (allListItems && (readDocumentMode() !== "suggesting" || preserveFirstItemLevel)) {
|
|
11168
11292
|
const rangeRoute = mode === "indent" ? "lists.indentRange" : "lists.outdentRange";
|
|
11169
11293
|
const rangeOp = resolveDocOperation(doc, rangeRoute);
|
|
11170
11294
|
if (rangeOp) try {
|
|
11171
11295
|
return await settleOperationResult(callEditorMutation(rangeRoute, rangeOp, {
|
|
11172
11296
|
paraIds: blockIds,
|
|
11173
|
-
story
|
|
11297
|
+
story,
|
|
11298
|
+
...preserveFirstItemLevel ? { preserveFirstItemLevel: true } : {}
|
|
11174
11299
|
})).settled;
|
|
11175
11300
|
} catch {
|
|
11176
11301
|
return false;
|
|
@@ -11710,23 +11835,32 @@ function createSuperDocUI(options) {
|
|
|
11710
11835
|
const record = readLinkPayloadRecord(payload);
|
|
11711
11836
|
return Boolean(readLinkPayloadTarget(payload) || isPlainObject(record.hyperlinkTarget) || isPlainObject(record.textTarget));
|
|
11712
11837
|
};
|
|
11713
|
-
const
|
|
11838
|
+
const currentWholeTableParagraphOwner = () => {
|
|
11714
11839
|
const owner = wholeTableParagraphSeed, host = getHost();
|
|
11715
|
-
if (!owner || disposed || owner.lifetime.aborted || owner.host !== host || owner.editor !== getEditor() || owner.editor.doc !== owner.doc || owner.sourceToken !== contentToken() || owner.mode !== readDocumentMode() || safeCall(() => hostMethod(host, "getMountedHandle")?.(), null) !== owner.mount) return
|
|
11840
|
+
if (!owner || disposed || owner.lifetime.aborted || owner.host !== host || owner.editor !== getEditor() || owner.editor.doc !== owner.doc || owner.sourceToken !== contentToken() || owner.mode !== readDocumentMode() || safeCall(() => hostMethod(host, "getMountedHandle")?.(), null) !== owner.mount) return null;
|
|
11716
11841
|
const tableId = owner.info.tableSelection?.tableId;
|
|
11717
11842
|
const activeTable = safeCall(() => {
|
|
11718
11843
|
const handles = hostMethod(host, "getHandles")?.();
|
|
11719
11844
|
return hostMethod(isPlainObject(handles) ? handles.selection : void 0, "getWholeTableNodeId")?.();
|
|
11720
11845
|
}, null);
|
|
11721
|
-
if (!tableId || activeTable !== tableId || state.selection.tableSelection?.type !== "table" || state.selection.tableSelection.tableId !== tableId || selectionSignature(state.selection) !== selectionSignature(selectionSliceFromInfo(owner.info, "ready"))) return
|
|
11846
|
+
if (!tableId || activeTable !== tableId || state.selection.tableSelection?.type !== "table" || state.selection.tableSelection.tableId !== tableId || selectionSignature(state.selection) !== selectionSignature(selectionSliceFromInfo(owner.info, "ready"))) return null;
|
|
11722
11847
|
const applied = appliedSelectionPresentation(state.selection);
|
|
11723
11848
|
const info = normalizeSelectionInfo(applied?.selection);
|
|
11724
|
-
return
|
|
11849
|
+
return info && JSON.stringify(info.tableSelection) === JSON.stringify(owner.info.tableSelection) ? {
|
|
11850
|
+
owner,
|
|
11851
|
+
info
|
|
11852
|
+
} : null;
|
|
11853
|
+
};
|
|
11854
|
+
const currentWholeTableParagraphSelection = () => {
|
|
11855
|
+
const current = currentWholeTableParagraphOwner();
|
|
11856
|
+
if (!current) return false;
|
|
11857
|
+
return current.owner.info.selectionTarget ? selectionInfoMatchesHost(current.info) : current.owner.nativeSelection !== null && readHostSelectionSnapshot() === current.owner.nativeSelection;
|
|
11725
11858
|
};
|
|
11726
11859
|
const commandSelectionIsReady = (id, descriptor, payload) => {
|
|
11727
11860
|
const foreground = foregroundMutationState();
|
|
11728
11861
|
if (foreground && (foreground.active > 0 || foreground.pending > 0)) return false;
|
|
11729
11862
|
if (descriptor?.blockParagraph && currentWholeTableParagraphSelection()) return true;
|
|
11863
|
+
if (descriptor?.blockParagraph && state.selection.tableSelection?.type === "table" && !state.selection.selectionTarget) return false;
|
|
11730
11864
|
if (state.selection.status !== "ready") return false;
|
|
11731
11865
|
if (trackDecisionCommand(id)?.scope === "id") return true;
|
|
11732
11866
|
if (!descriptor || descriptor.disposition !== "routed") return true;
|
|
@@ -12147,10 +12281,23 @@ function createSuperDocUI(options) {
|
|
|
12147
12281
|
const cellTarget = currentCellSelectionTarget();
|
|
12148
12282
|
const tableCellSelection = tableCellSelectionForTarget(cellTarget);
|
|
12149
12283
|
const rawSelection = typeof selectionApi?.["current"] === "function" ? await Promise.resolve(selectionApi["current"]({ includeText: true })) : readSelectionInfoLive().value;
|
|
12284
|
+
const selection = normalizeSelectionInfo(rawSelection);
|
|
12285
|
+
let paintedTarget = null;
|
|
12286
|
+
if (selection && !selection.empty && !selection.selectionTarget && selection.target?.kind === "text" && !cellTarget) {
|
|
12287
|
+
const nativeSelection = readHostSelectionSnapshot();
|
|
12288
|
+
paintedTarget = heldPaintedTextSelectionTarget();
|
|
12289
|
+
if (paintedTarget && (!nativeSelection || !appliedSelectionPresentation(selectionSliceFromInfo(selection, "ready")) || readHostSelectionSnapshot() !== nativeSelection)) return {
|
|
12290
|
+
selection: null,
|
|
12291
|
+
cellTarget: null,
|
|
12292
|
+
tableCellSelection: null,
|
|
12293
|
+
paintedTarget: null
|
|
12294
|
+
};
|
|
12295
|
+
}
|
|
12150
12296
|
return {
|
|
12151
|
-
selection
|
|
12297
|
+
selection,
|
|
12152
12298
|
cellTarget,
|
|
12153
|
-
tableCellSelection
|
|
12299
|
+
tableCellSelection,
|
|
12300
|
+
paintedTarget
|
|
12154
12301
|
};
|
|
12155
12302
|
};
|
|
12156
12303
|
const waitForSelectionSettle = () => new Promise((resolve) => setTimeout(resolve, 16));
|
|
@@ -12168,7 +12315,7 @@ function createSuperDocUI(options) {
|
|
|
12168
12315
|
break;
|
|
12169
12316
|
}
|
|
12170
12317
|
if (selectionRead?.selection && !selectionRead.selection.empty && key !== painter.sourceSelectionKey) {
|
|
12171
|
-
await applyFormatPainter(selectionRead.selection, selectionRead.cellTarget, selectionRead.tableCellSelection);
|
|
12318
|
+
await applyFormatPainter(selectionRead.selection, selectionRead.cellTarget, selectionRead.tableCellSelection, selectionRead.paintedTarget);
|
|
12172
12319
|
return;
|
|
12173
12320
|
}
|
|
12174
12321
|
if (painter.snapshot?.paragraph) {
|
|
@@ -12176,10 +12323,10 @@ function createSuperDocUI(options) {
|
|
|
12176
12323
|
const caretSel = caretRead.selection;
|
|
12177
12324
|
if (!caretSel) return;
|
|
12178
12325
|
if (selectionKey(caretSel) === painter.sourceSelectionKey) return;
|
|
12179
|
-
await applyFormatPainter(caretSel, caretRead.cellTarget, caretRead.tableCellSelection);
|
|
12326
|
+
await applyFormatPainter(caretSel, caretRead.cellTarget, caretRead.tableCellSelection, caretRead.paintedTarget);
|
|
12180
12327
|
}
|
|
12181
12328
|
};
|
|
12182
|
-
const applyFormatPainter = async (selection, cellTarget, tableCellSelection) => {
|
|
12329
|
+
const applyFormatPainter = async (selection, cellTarget, tableCellSelection, paintedTarget) => {
|
|
12183
12330
|
const snap = painter.snapshot;
|
|
12184
12331
|
if (!snap) {
|
|
12185
12332
|
if (painter.mode === "armed") exitFormatPainter();
|
|
@@ -12197,7 +12344,7 @@ function createSuperDocUI(options) {
|
|
|
12197
12344
|
return;
|
|
12198
12345
|
}
|
|
12199
12346
|
const selTarget = selection.target;
|
|
12200
|
-
const selectionTarget = cellTarget ?? selection.selectionTarget;
|
|
12347
|
+
const selectionTarget = cellTarget ?? paintedTarget ?? selection.selectionTarget;
|
|
12201
12348
|
const selectionIsEmpty = selection.empty === true;
|
|
12202
12349
|
const segments = Array.isArray(selTarget?.segments) ? selTarget.segments : [];
|
|
12203
12350
|
const targetStory = selTarget?.story;
|
|
@@ -12435,13 +12582,16 @@ function createSuperDocUI(options) {
|
|
|
12435
12582
|
const snapshot = selectionSub.get();
|
|
12436
12583
|
if (snapshot.empty) return null;
|
|
12437
12584
|
const cells = currentCellSelectionTarget();
|
|
12585
|
+
const painted = cells ? null : currentUnrepresentableSelectionTarget(snapshot);
|
|
12586
|
+
const hostSelection = selectionHostSnapshots.get(snapshot);
|
|
12587
|
+
if ((cells || painted || hostSelection && !snapshot.selectionTarget) && (!hostSelection || readHostSelectionSnapshot() !== hostSelection)) return null;
|
|
12438
12588
|
if (!snapshot.target && !snapshot.selectionTarget && !cells) return null;
|
|
12439
12589
|
const capture = {
|
|
12440
12590
|
...snapshot,
|
|
12441
12591
|
capturedAt: Date.now(),
|
|
12442
|
-
...cells ? { _tableCellSelectionTarget: cells } : {}
|
|
12592
|
+
...cells ? { _tableCellSelectionTarget: cells } : {},
|
|
12593
|
+
...painted ? { _paintedSelectionTarget: painted } : {}
|
|
12443
12594
|
};
|
|
12444
|
-
const hostSelection = selectionHostSnapshots.get(snapshot);
|
|
12445
12595
|
if (hostSelection) selectionHostSnapshots.set(capture, hostSelection);
|
|
12446
12596
|
return capture;
|
|
12447
12597
|
},
|
|
@@ -12467,7 +12617,13 @@ function createSuperDocUI(options) {
|
|
|
12467
12617
|
ok: false,
|
|
12468
12618
|
reason: SUPERDOC_UI_REASONS.targetUnresolved
|
|
12469
12619
|
});
|
|
12470
|
-
const
|
|
12620
|
+
const hasPaintedTarget = "_paintedSelectionTarget" in capture;
|
|
12621
|
+
const paintedTarget = hasPaintedTarget ? capturedTableCellTarget(capture._paintedSelectionTarget) : null;
|
|
12622
|
+
if (hasPaintedTarget && !paintedTarget) return done({
|
|
12623
|
+
ok: false,
|
|
12624
|
+
reason: SUPERDOC_UI_REASONS.targetUnresolved
|
|
12625
|
+
});
|
|
12626
|
+
const target = cellTarget ?? paintedTarget ?? selectionTargetForRestore(capture);
|
|
12471
12627
|
if (!target) return done({
|
|
12472
12628
|
ok: false,
|
|
12473
12629
|
reason: SUPERDOC_UI_REASONS.targetUnresolved
|
|
@@ -12480,7 +12636,7 @@ function createSuperDocUI(options) {
|
|
|
12480
12636
|
reason: resolved.reason
|
|
12481
12637
|
});
|
|
12482
12638
|
try {
|
|
12483
|
-
return done(normalizeHostSelectionApplyResult(hostMethod(resolved.helper, "apply")?.(target, ...cellTarget ? [{ tableCells: true }] : [])));
|
|
12639
|
+
return done(normalizeHostSelectionApplyResult(hostMethod(resolved.helper, "apply")?.(target, ...cellTarget ? [{ tableCells: true }] : paintedTarget ? [{ offsetSpace: "selection" }] : [])));
|
|
12484
12640
|
} catch {
|
|
12485
12641
|
return done({
|
|
12486
12642
|
ok: false,
|
|
@@ -12899,6 +13055,10 @@ function createSuperDocUI(options) {
|
|
|
12899
13055
|
};
|
|
12900
13056
|
const commentsSub = sliceHandle((s) => s.comments);
|
|
12901
13057
|
const commentsSnap = directorySnapshotHandle(commentsSub, select((s) => computeCommentsDirectorySnapshot(s.selection, s.comments)), "comments");
|
|
13058
|
+
documentResetHooks.push(() => {
|
|
13059
|
+
setExplicitActiveChange(null);
|
|
13060
|
+
explicitActiveCommentId = null;
|
|
13061
|
+
});
|
|
12902
13062
|
const comments = {
|
|
12903
13063
|
get: commentsSnap.get,
|
|
12904
13064
|
getSnapshot: commentsSnap.getSnapshot,
|
|
@@ -12992,6 +13152,7 @@ function createSuperDocUI(options) {
|
|
|
12992
13152
|
setActive: (commentId) => {
|
|
12993
13153
|
if (commentId == null) {
|
|
12994
13154
|
explicitActiveCommentId = null;
|
|
13155
|
+
mirrorReviewFocusToHost("comment", null);
|
|
12995
13156
|
recompute();
|
|
12996
13157
|
return true;
|
|
12997
13158
|
}
|
|
@@ -13004,7 +13165,9 @@ function createSuperDocUI(options) {
|
|
|
13004
13165
|
const resolvedId = resolveActiveCommentId(items, commentId);
|
|
13005
13166
|
if (!resolvedId) return false;
|
|
13006
13167
|
if (!items.some((entry) => readEntityId(entry) === resolvedId)) return false;
|
|
13168
|
+
setExplicitActiveChange(null);
|
|
13007
13169
|
explicitActiveCommentId = resolvedId;
|
|
13170
|
+
mirrorReviewFocusToHost("comment", { id: resolvedId });
|
|
13008
13171
|
recompute();
|
|
13009
13172
|
return true;
|
|
13010
13173
|
},
|
|
@@ -13064,7 +13227,7 @@ function createSuperDocUI(options) {
|
|
|
13064
13227
|
};
|
|
13065
13228
|
const navigateAndScrollCurrentRequest = async (step, requestedAtInvalidation) => {
|
|
13066
13229
|
if (queuedTrackChangeNavigationInvalidation !== requestedAtInvalidation) return { success: false };
|
|
13067
|
-
const
|
|
13230
|
+
const previousFocus = readReviewFocus();
|
|
13068
13231
|
const activeId = navigateTrackChange(step, { invalidateQueuedNavigation: false });
|
|
13069
13232
|
if (activeId == null) return { success: false };
|
|
13070
13233
|
const optimisticActiveChange = explicitActiveChange;
|
|
@@ -13072,7 +13235,7 @@ function createSuperDocUI(options) {
|
|
|
13072
13235
|
const isCurrent = () => queuedTrackChangeNavigationInvalidation === requestedAtInvalidation && explicitActiveChange === optimisticActiveChange && explicitActiveChangeRevision === optimisticRevision;
|
|
13073
13236
|
const rollback = () => {
|
|
13074
13237
|
if (!isCurrent()) return;
|
|
13075
|
-
|
|
13238
|
+
restoreReviewFocus(previousFocus);
|
|
13076
13239
|
recompute();
|
|
13077
13240
|
};
|
|
13078
13241
|
if (optimisticActiveChange) pendingTrackChangeRevealFocuses.add(optimisticActiveChange);
|
|
@@ -13092,10 +13255,8 @@ function createSuperDocUI(options) {
|
|
|
13092
13255
|
shouldContinue: isCurrent
|
|
13093
13256
|
});
|
|
13094
13257
|
if (!isCurrent()) return { success: false };
|
|
13095
|
-
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible)
|
|
13096
|
-
|
|
13097
|
-
mirrorTrackedChangeFocusToHost(previousActiveChange);
|
|
13098
|
-
} else {
|
|
13258
|
+
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible) rollback();
|
|
13259
|
+
else {
|
|
13099
13260
|
if (result.ok) await restampVisibleTrackedChangeCarrierAliases(activeId);
|
|
13100
13261
|
if (!isCurrent()) return { success: false };
|
|
13101
13262
|
mirrorTrackedChangeFocusToHost(optimisticActiveChange);
|
|
@@ -13226,7 +13387,7 @@ function createSuperDocUI(options) {
|
|
|
13226
13387
|
const matchingRow = matchStory ? loadedItems.find((item) => entityRowMatchesRequest(item, publicId, matchStory)) : loadedItems.find((item) => readEntityId(item) === publicId);
|
|
13227
13388
|
const story = matchStory ? requestedStory : readEntityRequestStory(matchingRow);
|
|
13228
13389
|
const importedId = deriveTrackedChangeImportedId(matchingRow);
|
|
13229
|
-
const
|
|
13390
|
+
const previousFocus = readReviewFocus();
|
|
13230
13391
|
const requestedActiveChange = {
|
|
13231
13392
|
id: publicId,
|
|
13232
13393
|
...story ? { story } : {},
|
|
@@ -13254,7 +13415,7 @@ function createSuperDocUI(options) {
|
|
|
13254
13415
|
const isCurrent = () => trackChangeRevealInvalidation === revealInvalidation && explicitActiveChange === optimisticActiveChange && explicitActiveChangeRevision === optimisticRevision;
|
|
13255
13416
|
const rollback = () => {
|
|
13256
13417
|
if (!isCurrent()) return;
|
|
13257
|
-
|
|
13418
|
+
restoreReviewFocus(previousFocus);
|
|
13258
13419
|
recompute();
|
|
13259
13420
|
};
|
|
13260
13421
|
recompute();
|
|
@@ -13268,10 +13429,8 @@ function createSuperDocUI(options) {
|
|
|
13268
13429
|
success: false,
|
|
13269
13430
|
ok: false
|
|
13270
13431
|
};
|
|
13271
|
-
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible)
|
|
13272
|
-
|
|
13273
|
-
mirrorTrackedChangeFocusToHost(previousActiveChange);
|
|
13274
|
-
} else {
|
|
13432
|
+
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible) rollback();
|
|
13433
|
+
else {
|
|
13275
13434
|
if (result.ok) await restampVisibleTrackedChangeCarrierAliases(publicId);
|
|
13276
13435
|
if (!isCurrent()) return {
|
|
13277
13436
|
success: false,
|
|
@@ -13606,14 +13765,14 @@ function createSuperDocUI(options) {
|
|
|
13606
13765
|
if (root instanceof HTMLElement) return root;
|
|
13607
13766
|
return null;
|
|
13608
13767
|
};
|
|
13609
|
-
const
|
|
13610
|
-
if (typeof x !== "number" || typeof y !== "number" || !Number.isFinite(x) || !Number.isFinite(y)) return
|
|
13768
|
+
const pointHitElements = (x, y) => {
|
|
13769
|
+
if (typeof x !== "number" || typeof y !== "number" || !Number.isFinite(x) || !Number.isFinite(y)) return null;
|
|
13611
13770
|
const dom = globalThis.document;
|
|
13612
|
-
if (!dom || typeof dom.elementFromPoint !== "function") return
|
|
13771
|
+
if (!dom || typeof dom.elementFromPoint !== "function") return null;
|
|
13613
13772
|
const container = resolveVisibleHost();
|
|
13614
|
-
if (!container) return
|
|
13773
|
+
if (!container) return null;
|
|
13615
13774
|
const startEl = dom.elementFromPoint(x, y);
|
|
13616
|
-
if (!startEl || !container.contains(startEl)) return
|
|
13775
|
+
if (!startEl || !container.contains(startEl)) return null;
|
|
13617
13776
|
const primaryEls = [startEl];
|
|
13618
13777
|
const addPrimaryEl = (el) => {
|
|
13619
13778
|
if (el && container.contains(el) && !primaryEls.includes(el)) primaryEls.push(el);
|
|
@@ -13628,6 +13787,17 @@ function createSuperDocUI(options) {
|
|
|
13628
13787
|
}
|
|
13629
13788
|
for (const el of stacked) addPrimaryEl(el);
|
|
13630
13789
|
}
|
|
13790
|
+
return {
|
|
13791
|
+
container,
|
|
13792
|
+
elements: primaryEls,
|
|
13793
|
+
x,
|
|
13794
|
+
y
|
|
13795
|
+
};
|
|
13796
|
+
};
|
|
13797
|
+
const pointEntityHits = (x, y) => {
|
|
13798
|
+
const point = pointHitElements(x, y);
|
|
13799
|
+
if (!point) return [];
|
|
13800
|
+
const { container, elements: primaryEls } = point;
|
|
13631
13801
|
const markerEls = [];
|
|
13632
13802
|
const addMarkerEl = (el) => {
|
|
13633
13803
|
if (el && container.contains(el) && !markerEls.includes(el) && !primaryEls.includes(el)) markerEls.push(el);
|
|
@@ -13641,7 +13811,7 @@ function createSuperDocUI(options) {
|
|
|
13641
13811
|
} catch {
|
|
13642
13812
|
return false;
|
|
13643
13813
|
}
|
|
13644
|
-
return rect != null && x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
|
13814
|
+
return rect != null && point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom;
|
|
13645
13815
|
};
|
|
13646
13816
|
for (const el of primaryEls) {
|
|
13647
13817
|
const queryAll = el.querySelectorAll;
|
|
@@ -13665,6 +13835,18 @@ function createSuperDocUI(options) {
|
|
|
13665
13835
|
const seen = /* @__PURE__ */ new Set();
|
|
13666
13836
|
const hits = [];
|
|
13667
13837
|
for (const hit of rawHits) {
|
|
13838
|
+
if (hit.type === "decoration") {
|
|
13839
|
+
const owner = decorationOwnerForProvider(hit.id);
|
|
13840
|
+
if (!owner) continue;
|
|
13841
|
+
const key = `decoration:${owner.id}`;
|
|
13842
|
+
if (seen.has(key)) continue;
|
|
13843
|
+
seen.add(key);
|
|
13844
|
+
hits.push({
|
|
13845
|
+
type: "decoration",
|
|
13846
|
+
id: owner.id
|
|
13847
|
+
});
|
|
13848
|
+
continue;
|
|
13849
|
+
}
|
|
13668
13850
|
if (hit.type !== "trackedChange") {
|
|
13669
13851
|
const layoutStory = hit.type === "contentControl" ? layoutStoryDatasetToStoryLocator(hit.story) : void 0;
|
|
13670
13852
|
const story = hit.type === "contentControl" ? isTextboxStory(layoutStory) ? layoutStory : storyKeyToStoryLocator(hit.storyKey) ?? layoutStory : void 0;
|
|
@@ -13820,6 +14002,149 @@ function createSuperDocUI(options) {
|
|
|
13820
14002
|
if (status !== "ready") return { reason: "not-ready" };
|
|
13821
14003
|
return value ? { target: value } : { reason: "unresolved" };
|
|
13822
14004
|
};
|
|
14005
|
+
const liveDecorations = /* @__PURE__ */ new Map();
|
|
14006
|
+
const decorationOwnerForProvider = (providerId) => {
|
|
14007
|
+
const owner = currentHostVisuals()?.providerOwner?.(providerId);
|
|
14008
|
+
return isPlainObject(owner) && typeof owner.id === "string" ? owner : null;
|
|
14009
|
+
};
|
|
14010
|
+
const currentHostVisuals = () => getEditor()?.visuals ?? null;
|
|
14011
|
+
const decorationListeners = /* @__PURE__ */ new Set();
|
|
14012
|
+
let detachDecorationPointer = null;
|
|
14013
|
+
let hoveredDecorations = [];
|
|
14014
|
+
let lastPointer = {
|
|
14015
|
+
clientX: 0,
|
|
14016
|
+
clientY: 0
|
|
14017
|
+
};
|
|
14018
|
+
const decorationIdsAt = (x, y) => {
|
|
14019
|
+
const point = pointHitElements(x, y);
|
|
14020
|
+
if (!point) return [];
|
|
14021
|
+
const ids = /* @__PURE__ */ new Set();
|
|
14022
|
+
for (const element of point.elements) for (const provider of collectDecorationProvidersFromChain(element, point.container)) {
|
|
14023
|
+
const owner = decorationOwnerForProvider(provider);
|
|
14024
|
+
if (owner) ids.add(owner.id);
|
|
14025
|
+
}
|
|
14026
|
+
return [...ids];
|
|
14027
|
+
};
|
|
14028
|
+
const decorationData = (id) => {
|
|
14029
|
+
const owner = currentHostVisuals()?.ownerById?.(id);
|
|
14030
|
+
return isPlainObject(owner?.data) ? owner.data : void 0;
|
|
14031
|
+
};
|
|
14032
|
+
const emitDecorationEvent = (type, decoration, point) => {
|
|
14033
|
+
const payload = {
|
|
14034
|
+
type,
|
|
14035
|
+
id: decoration.id,
|
|
14036
|
+
...decoration.data ? { data: decoration.data } : {},
|
|
14037
|
+
clientX: point.clientX,
|
|
14038
|
+
clientY: point.clientY
|
|
14039
|
+
};
|
|
14040
|
+
for (const listener of Array.from(decorationListeners)) safeCall(() => listener(payload), void 0);
|
|
14041
|
+
};
|
|
14042
|
+
const leaveHoveredDecorations = (onlyId) => {
|
|
14043
|
+
const leaving = hoveredDecorations.filter((decoration) => onlyId === void 0 || decoration.id === onlyId);
|
|
14044
|
+
hoveredDecorations = hoveredDecorations.filter((decoration) => !leaving.includes(decoration));
|
|
14045
|
+
for (const decoration of leaving) emitDecorationEvent("hover-leave", decoration, lastPointer);
|
|
14046
|
+
};
|
|
14047
|
+
const attachDecorationPointer = () => {
|
|
14048
|
+
if (detachDecorationPointer || decorationListeners.size === 0) return;
|
|
14049
|
+
const host = resolveVisibleHost();
|
|
14050
|
+
if (!host) return;
|
|
14051
|
+
const onClick = (event) => {
|
|
14052
|
+
for (const id of decorationIdsAt(event.clientX, event.clientY)) emitDecorationEvent("click", {
|
|
14053
|
+
id,
|
|
14054
|
+
data: decorationData(id)
|
|
14055
|
+
}, event);
|
|
14056
|
+
};
|
|
14057
|
+
const onMove = (event) => {
|
|
14058
|
+
lastPointer = {
|
|
14059
|
+
clientX: event.clientX,
|
|
14060
|
+
clientY: event.clientY
|
|
14061
|
+
};
|
|
14062
|
+
const nextIds = decorationIdsAt(event.clientX, event.clientY);
|
|
14063
|
+
const leaving = hoveredDecorations.filter((decoration) => !nextIds.includes(decoration.id));
|
|
14064
|
+
const kept = hoveredDecorations.filter((decoration) => nextIds.includes(decoration.id));
|
|
14065
|
+
const entering = nextIds.filter((id) => !kept.some((decoration) => decoration.id === id)).map((id) => ({
|
|
14066
|
+
id,
|
|
14067
|
+
data: decorationData(id)
|
|
14068
|
+
}));
|
|
14069
|
+
hoveredDecorations = [...kept, ...entering];
|
|
14070
|
+
for (const decoration of leaving) emitDecorationEvent("hover-leave", decoration, event);
|
|
14071
|
+
for (const decoration of entering) emitDecorationEvent("hover-enter", decoration, event);
|
|
14072
|
+
};
|
|
14073
|
+
const onLeave = (event) => {
|
|
14074
|
+
lastPointer = {
|
|
14075
|
+
clientX: event.clientX,
|
|
14076
|
+
clientY: event.clientY
|
|
14077
|
+
};
|
|
14078
|
+
leaveHoveredDecorations();
|
|
14079
|
+
};
|
|
14080
|
+
host.addEventListener("click", onClick);
|
|
14081
|
+
host.addEventListener("pointermove", onMove);
|
|
14082
|
+
host.addEventListener("pointerleave", onLeave);
|
|
14083
|
+
detachDecorationPointer = () => {
|
|
14084
|
+
host.removeEventListener("click", onClick);
|
|
14085
|
+
host.removeEventListener("pointermove", onMove);
|
|
14086
|
+
host.removeEventListener("pointerleave", onLeave);
|
|
14087
|
+
leaveHoveredDecorations();
|
|
14088
|
+
detachDecorationPointer = null;
|
|
14089
|
+
};
|
|
14090
|
+
};
|
|
14091
|
+
const subscribeDecorationPointer = (listener) => {
|
|
14092
|
+
if (disposed) throw new Error("ui.decorations.subscribe called on a destroyed UI controller.");
|
|
14093
|
+
decorationListeners.add(listener);
|
|
14094
|
+
attachDecorationPointer();
|
|
14095
|
+
return () => {
|
|
14096
|
+
decorationListeners.delete(listener);
|
|
14097
|
+
if (decorationListeners.size === 0) detachDecorationPointer?.();
|
|
14098
|
+
};
|
|
14099
|
+
};
|
|
14100
|
+
documentResetHooks.push(() => {
|
|
14101
|
+
leaveHoveredDecorations();
|
|
14102
|
+
const current = currentHostVisuals();
|
|
14103
|
+
for (const [handle, owner] of Array.from(liveDecorations)) if (owner.visuals !== current || owner.generation !== current.generation()) handle.dispose();
|
|
14104
|
+
});
|
|
14105
|
+
activeEditorResetHooks.push(() => {
|
|
14106
|
+
detachDecorationPointer?.();
|
|
14107
|
+
attachDecorationPointer();
|
|
14108
|
+
});
|
|
14109
|
+
const createDecorationsHandle = (track) => ({
|
|
14110
|
+
subscribe: (listener) => {
|
|
14111
|
+
const unsubscribe = subscribeDecorationPointer(listener);
|
|
14112
|
+
track?.({ dispose: unsubscribe });
|
|
14113
|
+
return unsubscribe;
|
|
14114
|
+
},
|
|
14115
|
+
highlight: (id, options) => {
|
|
14116
|
+
if (disposed) throw new Error("ui.decorations.highlight called on a destroyed UI controller.");
|
|
14117
|
+
const visuals = currentHostVisuals();
|
|
14118
|
+
if (!visuals) throw new Error("ui.decorations.highlight requires a ready document.");
|
|
14119
|
+
const inner = visuals.highlight(id, options);
|
|
14120
|
+
let handleDisposed = false;
|
|
14121
|
+
const handle = {
|
|
14122
|
+
id: inner.id,
|
|
14123
|
+
replace: (targets) => inner.replace(targets),
|
|
14124
|
+
add: (targets) => inner.add(targets),
|
|
14125
|
+
clear: () => {
|
|
14126
|
+
if (handleDisposed) return;
|
|
14127
|
+
inner.clear();
|
|
14128
|
+
leaveHoveredDecorations(inner.id);
|
|
14129
|
+
},
|
|
14130
|
+
invalidate: () => inner.invalidate(),
|
|
14131
|
+
dispose: () => {
|
|
14132
|
+
if (handleDisposed) return;
|
|
14133
|
+
handleDisposed = true;
|
|
14134
|
+
liveDecorations.delete(handle);
|
|
14135
|
+
inner.dispose();
|
|
14136
|
+
leaveHoveredDecorations(inner.id);
|
|
14137
|
+
}
|
|
14138
|
+
};
|
|
14139
|
+
liveDecorations.set(handle, {
|
|
14140
|
+
visuals,
|
|
14141
|
+
generation: visuals.generation()
|
|
14142
|
+
});
|
|
14143
|
+
track?.(handle);
|
|
14144
|
+
return handle;
|
|
14145
|
+
}
|
|
14146
|
+
});
|
|
14147
|
+
const decorations = createDecorationsHandle();
|
|
13823
14148
|
const viewport = {
|
|
13824
14149
|
getRects: async (input) => {
|
|
13825
14150
|
const initialHost = getHost();
|
|
@@ -14911,6 +15236,7 @@ function createSuperDocUI(options) {
|
|
|
14911
15236
|
const createScope = () => {
|
|
14912
15237
|
const scopeUnsubs = [];
|
|
14913
15238
|
return {
|
|
15239
|
+
decorations: createDecorationsHandle((handle) => scopeUnsubs.push(() => handle.dispose())),
|
|
14914
15240
|
select: (selector, equality) => {
|
|
14915
15241
|
const sub = select(selector, equality);
|
|
14916
15242
|
return {
|
|
@@ -14931,6 +15257,9 @@ function createSuperDocUI(options) {
|
|
|
14931
15257
|
if (disposed) return;
|
|
14932
15258
|
watermark.destroy();
|
|
14933
15259
|
clearContentControlHighlight();
|
|
15260
|
+
for (const handle of Array.from(liveDecorations.keys())) handle.dispose();
|
|
15261
|
+
detachDecorationPointer?.();
|
|
15262
|
+
decorationListeners.clear();
|
|
14934
15263
|
disposed = true;
|
|
14935
15264
|
completedFallbackSearch = null;
|
|
14936
15265
|
if (searchRefreshTimer !== null) clearTimeout(searchRefreshTimer);
|
|
@@ -15013,6 +15342,7 @@ function createSuperDocUI(options) {
|
|
|
15013
15342
|
zoom,
|
|
15014
15343
|
document: documentHandle,
|
|
15015
15344
|
viewport,
|
|
15345
|
+
decorations,
|
|
15016
15346
|
metadata,
|
|
15017
15347
|
tables,
|
|
15018
15348
|
search,
|
|
@@ -15303,6 +15633,12 @@ Object.defineProperty(exports, "isPlainObject", {
|
|
|
15303
15633
|
return isPlainObject;
|
|
15304
15634
|
}
|
|
15305
15635
|
});
|
|
15636
|
+
Object.defineProperty(exports, "isRecord", {
|
|
15637
|
+
enumerable: true,
|
|
15638
|
+
get: function() {
|
|
15639
|
+
return isRecord;
|
|
15640
|
+
}
|
|
15641
|
+
});
|
|
15306
15642
|
Object.defineProperty(exports, "isSyntheticTrackedChangeCommentLaneItem", {
|
|
15307
15643
|
enumerable: true,
|
|
15308
15644
|
get: function() {
|