superdoc 2.27.0 → 2.28.0-next.10
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-DpVh2nQH.cjs → create-super-doc-ui-B4c55pFy.cjs} +575 -86
- package/dist/chunks/{create-super-doc-ui-cHUUipYM.es.js → create-super-doc-ui-C4Ka5Ph3.es.js} +570 -87
- 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 +46 -46
- 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 +5 -4
- package/dist/document-api/src/replace/replace.d.ts +4 -1
- 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/mutation-plan.types.d.ts +13 -4
- package/dist/document-api/src/types/temporary-mutation.d.ts +5 -1
- package/dist/document-api/src/types/track-changes.types.d.ts +10 -2
- package/dist/layout-engine/contracts/src/index.d.ts +3 -1
- package/dist/layout-engine/contracts/src/resolved-layout.d.ts +1 -0
- package/dist/layout-engine/contracts/src/run-helpers.d.ts +7 -0
- package/dist/layout-engine/painters/dom/src/page-content.d.ts +1 -0
- package/dist/layout-engine/painters/dom/src/review-markers.d.ts +3 -0
- package/dist/layout-engine/painters/dom/src/table/renderTableCell.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/collaboration/resolve-v2-collaboration-target.d.ts +2 -0
- 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 +35 -1
- package/dist/superdoc/src/core/v2-integration/v2-integration.d.ts +0 -8
- package/dist/superdoc/src/internal/toolbar/built-in/LinkedStyle.vue.d.ts +3 -1
- 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/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/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/style-match-patch.d.ts +7 -0
- package/dist/superdoc/src/public/ui/types.d.ts +20 -2
- package/dist/superdoc/src/public/ui.d.cts +18 -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 +476 -216
- package/dist/superdoc.es.js +473 -215
- 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/footnote-table-order.docx +0 -0
- package/dist/images/altText_add.svg +0 -3
- package/dist/images/altText_disclaimer.svg +0 -3
- package/dist/images/altText_done.svg +0 -3
- package/dist/images/altText_spinner.svg +0 -30
- package/dist/images/altText_warning.svg +0 -3
- package/dist/images/annotation-check.svg +0 -11
- package/dist/images/annotation-comment.svg +0 -16
- package/dist/images/annotation-help.svg +0 -26
- package/dist/images/annotation-insert.svg +0 -10
- package/dist/images/annotation-key.svg +0 -11
- package/dist/images/annotation-newparagraph.svg +0 -11
- package/dist/images/annotation-noicon.svg +0 -7
- package/dist/images/annotation-note.svg +0 -42
- package/dist/images/annotation-paperclip.svg +0 -6
- package/dist/images/annotation-paragraph.svg +0 -16
- package/dist/images/annotation-pushpin.svg +0 -7
- package/dist/images/checkmark.svg +0 -5
- package/dist/images/comment-actionsButton.svg +0 -3
- package/dist/images/comment-closeButton.svg +0 -3
- package/dist/images/comment-editButton.svg +0 -8
- package/dist/images/comment-popup-editButton.svg +0 -5
- package/dist/images/cursor-editorFreeHighlight.svg +0 -6
- package/dist/images/cursor-editorFreeText.svg +0 -3
- package/dist/images/cursor-editorInk.svg +0 -4
- package/dist/images/cursor-editorTextHighlight.svg +0 -8
- package/dist/images/editor-toolbar-delete.svg +0 -5
- package/dist/images/editor-toolbar-edit.svg +0 -3
- package/dist/images/findbarButton-next.svg +0 -3
- package/dist/images/findbarButton-previous.svg +0 -3
- package/dist/images/gv-toolbarButton-download.svg +0 -3
- package/dist/images/loading-icon.gif +0 -0
- package/dist/images/loading.svg +0 -1
- package/dist/images/messageBar_closingButton.svg +0 -3
- package/dist/images/messageBar_info.svg +0 -3
- package/dist/images/messageBar_warning.svg +0 -3
- package/dist/images/pages_closeButton.svg +0 -3
- package/dist/images/pages_selected.svg +0 -7
- package/dist/images/pages_viewArrow.svg +0 -3
- package/dist/images/pages_viewButton.svg +0 -3
- package/dist/images/secondaryToolbarButton-documentProperties.svg +0 -3
- package/dist/images/secondaryToolbarButton-firstPage.svg +0 -3
- package/dist/images/secondaryToolbarButton-handTool.svg +0 -3
- package/dist/images/secondaryToolbarButton-lastPage.svg +0 -3
- package/dist/images/secondaryToolbarButton-rotateCcw.svg +0 -3
- package/dist/images/secondaryToolbarButton-rotateCw.svg +0 -3
- package/dist/images/secondaryToolbarButton-scrollHorizontal.svg +0 -3
- package/dist/images/secondaryToolbarButton-scrollPage.svg +0 -3
- package/dist/images/secondaryToolbarButton-scrollVertical.svg +0 -3
- package/dist/images/secondaryToolbarButton-scrollWrapped.svg +0 -3
- package/dist/images/secondaryToolbarButton-selectTool.svg +0 -3
- package/dist/images/secondaryToolbarButton-spreadEven.svg +0 -3
- package/dist/images/secondaryToolbarButton-spreadNone.svg +0 -3
- package/dist/images/secondaryToolbarButton-spreadOdd.svg +0 -3
- package/dist/images/toolbarButton-bookmark.svg +0 -3
- package/dist/images/toolbarButton-currentOutlineItem.svg +0 -3
- package/dist/images/toolbarButton-download.svg +0 -4
- package/dist/images/toolbarButton-editorFreeText.svg +0 -5
- package/dist/images/toolbarButton-editorHighlight.svg +0 -6
- package/dist/images/toolbarButton-editorInk.svg +0 -4
- package/dist/images/toolbarButton-editorSignature.svg +0 -6
- package/dist/images/toolbarButton-editorStamp.svg +0 -8
- package/dist/images/toolbarButton-menuArrow.svg +0 -3
- package/dist/images/toolbarButton-openFile.svg +0 -3
- package/dist/images/toolbarButton-pageDown.svg +0 -3
- package/dist/images/toolbarButton-pageUp.svg +0 -3
- package/dist/images/toolbarButton-presentationMode.svg +0 -3
- package/dist/images/toolbarButton-print.svg +0 -3
- package/dist/images/toolbarButton-search.svg +0 -3
- package/dist/images/toolbarButton-secondaryToolbarToggle.svg +0 -3
- package/dist/images/toolbarButton-viewAttachments.svg +0 -3
- package/dist/images/toolbarButton-viewLayers.svg +0 -3
- package/dist/images/toolbarButton-viewOutline.svg +0 -3
- package/dist/images/toolbarButton-viewThumbnail.svg +0 -3
- package/dist/images/toolbarButton-viewsManagerToggle.svg +0 -3
- package/dist/images/toolbarButton-zoomIn.svg +0 -3
- package/dist/images/toolbarButton-zoomOut.svg +0 -3
- package/dist/images/treeitem-collapsed.svg +0 -1
- package/dist/images/treeitem-expanded.svg +0 -1
- 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
- package/dist-cdn/footnote-table-order.docx +0 -0
|
@@ -2459,6 +2459,69 @@ function createDialogWorkflow(editor, options, onSuccess) {
|
|
|
2459
2459
|
};
|
|
2460
2460
|
}
|
|
2461
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
|
|
2462
2525
|
//#region src/public/ui/format-painter-helpers.js
|
|
2463
2526
|
/**
|
|
2464
2527
|
* Maps SDRunProps field names to InlineRunPatch field names.
|
|
@@ -3629,6 +3692,25 @@ function getCommandDescriptor(id) {
|
|
|
3629
3692
|
}
|
|
3630
3693
|
//#endregion
|
|
3631
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
|
+
}
|
|
3632
3714
|
function parseCommaSeparatedIds(value) {
|
|
3633
3715
|
return value.split(",").map((id) => id.trim()).filter(Boolean);
|
|
3634
3716
|
}
|
|
@@ -3700,6 +3782,16 @@ function collectEntityHitsFromChain(start, stopAt) {
|
|
|
3700
3782
|
for (const hit of pendingStory) hit.story = layoutStory;
|
|
3701
3783
|
pendingStory = [];
|
|
3702
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
|
+
}
|
|
3703
3795
|
const citationId = node.getAttribute("data-citation-id");
|
|
3704
3796
|
if (citationId) {
|
|
3705
3797
|
const key = `citation:${citationId}`;
|
|
@@ -6090,6 +6182,7 @@ function createSuperDocUI(options) {
|
|
|
6090
6182
|
pointerSelecting: false,
|
|
6091
6183
|
keyboardSelecting: false
|
|
6092
6184
|
};
|
|
6185
|
+
const paintedInlineTargets = /* @__PURE__ */ new WeakSet();
|
|
6093
6186
|
let painterCaptureEpoch = 0;
|
|
6094
6187
|
let painterCommandDoc = null;
|
|
6095
6188
|
const painterModeListeners = /* @__PURE__ */ new Set();
|
|
@@ -6186,7 +6279,7 @@ function createSuperDocUI(options) {
|
|
|
6186
6279
|
const readHostSelectionSnapshot = () => {
|
|
6187
6280
|
const handles = safeCall(() => hostMethod(getHost(), "getHandles")?.() ?? null, null);
|
|
6188
6281
|
const editing = isPlainObject(handles) ? handles.editing : void 0;
|
|
6189
|
-
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");
|
|
6190
6283
|
if (!getSnapshot) return null;
|
|
6191
6284
|
const snapshot = safeCall(() => getSnapshot(), null);
|
|
6192
6285
|
return snapshot && typeof snapshot === "object" ? snapshot : null;
|
|
@@ -6400,7 +6493,7 @@ function createSuperDocUI(options) {
|
|
|
6400
6493
|
return left.id === right.id && left.paintedEntityId === right.paintedEntityId && storyLocatorSignature(left.story) === storyLocatorSignature(right.story);
|
|
6401
6494
|
};
|
|
6402
6495
|
const hasPendingTrackChangeRevealFocus = (focus) => Array.from(pendingTrackChangeRevealFocuses).some((pendingFocus) => explicitActiveChangesEqual(pendingFocus, focus));
|
|
6403
|
-
const
|
|
6496
|
+
const mirrorReviewFocusToHost = (entityType, next) => {
|
|
6404
6497
|
const readHandles = hostMethod(getHost(), "getHandles");
|
|
6405
6498
|
if (!readHandles) return;
|
|
6406
6499
|
const handles = safeCall(() => readHandles(), null);
|
|
@@ -6411,15 +6504,15 @@ function createSuperDocUI(options) {
|
|
|
6411
6504
|
if (!setActiveReviewTarget) return;
|
|
6412
6505
|
const layout = isPlainObject(handles.layout) ? handles.layout : void 0;
|
|
6413
6506
|
safeCall(() => setActiveReviewTarget({
|
|
6414
|
-
entityType
|
|
6507
|
+
entityType,
|
|
6415
6508
|
entityId: next.id,
|
|
6416
6509
|
...next.paintedEntityId ? { paintedEntityId: next.paintedEntityId } : {},
|
|
6417
6510
|
origin: "panel",
|
|
6418
6511
|
layoutEpoch: typeof layout?.generation === "number" ? layout.generation : 0,
|
|
6419
|
-
story: next.story ?? {
|
|
6512
|
+
...entityType === "trackedChange" ? { story: next.story ?? {
|
|
6420
6513
|
kind: "story",
|
|
6421
6514
|
storyType: "body"
|
|
6422
|
-
}
|
|
6515
|
+
} } : {}
|
|
6423
6516
|
}), null);
|
|
6424
6517
|
return;
|
|
6425
6518
|
}
|
|
@@ -6427,10 +6520,22 @@ function createSuperDocUI(options) {
|
|
|
6427
6520
|
const clearActiveReviewTarget = hostMethod(review, "clearActiveReviewTarget");
|
|
6428
6521
|
if (!getActiveReviewTarget || !clearActiveReviewTarget) return;
|
|
6429
6522
|
const activeTarget = safeCall(() => getActiveReviewTarget(), null);
|
|
6430
|
-
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);
|
|
6431
6535
|
};
|
|
6432
6536
|
const setExplicitActiveChange = (next, options) => {
|
|
6433
6537
|
explicitActiveChange = next;
|
|
6538
|
+
if (next) explicitActiveCommentId = null;
|
|
6434
6539
|
explicitActiveChangeRevision += 1;
|
|
6435
6540
|
trackChangeRevealInvalidation += 1;
|
|
6436
6541
|
if (options?.invalidateQueuedNavigation !== false) queuedTrackChangeNavigationInvalidation += 1;
|
|
@@ -7100,7 +7205,7 @@ function createSuperDocUI(options) {
|
|
|
7100
7205
|
failureCount: retryingSameToken ? prev.failureCount ?? 0 : 0,
|
|
7101
7206
|
retryAtMs: 0
|
|
7102
7207
|
});
|
|
7103
|
-
Promise.resolve(raw).then((resolved) => {
|
|
7208
|
+
const settled = Promise.resolve(raw).then((resolved) => {
|
|
7104
7209
|
const entry = asyncReads.get(key);
|
|
7105
7210
|
if (!entry || entry.inflightToken !== token) return;
|
|
7106
7211
|
asyncReads.set(key, {
|
|
@@ -7139,6 +7244,7 @@ function createSuperDocUI(options) {
|
|
|
7139
7244
|
const retryAtMs = Date.now() + retryDelayMs;
|
|
7140
7245
|
asyncReads.set(key, {
|
|
7141
7246
|
...entry,
|
|
7247
|
+
settled: void 0,
|
|
7142
7248
|
inflightToken: null,
|
|
7143
7249
|
failedToken: token,
|
|
7144
7250
|
failureCount,
|
|
@@ -7146,6 +7252,8 @@ function createSuperDocUI(options) {
|
|
|
7146
7252
|
});
|
|
7147
7253
|
scheduleAsyncReadFailureRetry(retryAtMs);
|
|
7148
7254
|
});
|
|
7255
|
+
const entry = asyncReads.get(key);
|
|
7256
|
+
if (entry?.inflightToken === token) entry.settled = settled;
|
|
7149
7257
|
return null;
|
|
7150
7258
|
};
|
|
7151
7259
|
/**
|
|
@@ -7487,15 +7595,53 @@ function createSuperDocUI(options) {
|
|
|
7487
7595
|
* Explicit whole-table changes have a complete local source range and also
|
|
7488
7596
|
* seed clears, so a delayed worker read cannot retain a cleared table target.
|
|
7489
7597
|
*/
|
|
7490
|
-
|
|
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();
|
|
7491
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
|
+
}
|
|
7492
7639
|
if (isNonCollapsedHostSelection(hostSelectionSnapshot) && !(foreground && foreground.active > 0)) {
|
|
7493
7640
|
typedCaretValidationHeld = false;
|
|
7494
7641
|
pendingSelectionSeedValidationToken = null;
|
|
7495
7642
|
issueAsyncRead("selection", selectionReadToken(), selectionCurrentRun, normalizeSelectionInfo);
|
|
7496
7643
|
return;
|
|
7497
7644
|
}
|
|
7498
|
-
const host = getHost();
|
|
7499
7645
|
const read = host?.readLiveSelectionSyncSnapshot;
|
|
7500
7646
|
if (typeof read !== "function") return;
|
|
7501
7647
|
const seed = normalizeSelectionInfo(safeCall(() => read.call(host), null));
|
|
@@ -7504,21 +7650,7 @@ function createSuperDocUI(options) {
|
|
|
7504
7650
|
typedCaretValidationHeld = false;
|
|
7505
7651
|
pendingSelectionSeedValidationToken = null;
|
|
7506
7652
|
wholeTableParagraphSeed = null;
|
|
7507
|
-
|
|
7508
|
-
const rawLifetime = safeCall(() => hostMethod(host, "getForegroundInteractionLifetime")?.() ?? null, null);
|
|
7509
|
-
const lifetime = hasAbortedFlag(rawLifetime) ? rawLifetime : null;
|
|
7510
|
-
const mount = safeCall(() => hostMethod(host, "getMountedHandle")?.() ?? null, null);
|
|
7511
|
-
const mode = readDocumentMode();
|
|
7512
|
-
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 = {
|
|
7513
|
-
editor,
|
|
7514
|
-
host,
|
|
7515
|
-
doc: editor.doc,
|
|
7516
|
-
mount,
|
|
7517
|
-
lifetime,
|
|
7518
|
-
sourceToken: contentToken(),
|
|
7519
|
-
mode,
|
|
7520
|
-
info: seed
|
|
7521
|
-
};
|
|
7653
|
+
captureWholeTableParagraphSeed(host, seed, initialTableSelection);
|
|
7522
7654
|
const token = selectionReadToken();
|
|
7523
7655
|
asyncReads.set("selection", {
|
|
7524
7656
|
token,
|
|
@@ -7676,7 +7808,7 @@ function createSuperDocUI(options) {
|
|
|
7676
7808
|
const directory = asyncReads.get("comments");
|
|
7677
7809
|
const directoryItems = directory?.token === contentToken() && directory.hasSettled && Array.isArray(directory.value) ? directory.value : null;
|
|
7678
7810
|
const activeValidationItems = directoryLeaseCounts.comments > 0 ? directoryItems : items;
|
|
7679
|
-
if (explicitActiveCommentId && activeValidationItems &&
|
|
7811
|
+
if (explicitActiveCommentId && activeValidationItems && (activeValidationItems !== items || listStatus === "ready")) explicitActiveCommentId = resolveActiveCommentId(activeValidationItems, explicitActiveCommentId);
|
|
7680
7812
|
const activeId = explicitActiveCommentId ?? activeIds[0] ?? null;
|
|
7681
7813
|
return {
|
|
7682
7814
|
status: combineStatus(listStatus, selection.status),
|
|
@@ -8321,12 +8453,13 @@ function createSuperDocUI(options) {
|
|
|
8321
8453
|
];
|
|
8322
8454
|
function effectiveInlineUniformityInput(selection) {
|
|
8323
8455
|
const cellTarget = currentCellSelectionTarget();
|
|
8324
|
-
const
|
|
8456
|
+
const paintedTarget = cellTarget ? null : currentUnrepresentableSelectionTarget(selection);
|
|
8457
|
+
const target = cellTarget ?? paintedTarget ?? selection.selectionTarget;
|
|
8325
8458
|
if (!target) return null;
|
|
8326
8459
|
const tableCellSelection = cellTarget ? tableCellSelectionForTarget(cellTarget) : null;
|
|
8327
8460
|
return {
|
|
8328
8461
|
target,
|
|
8329
|
-
offsetSpace: "selection",
|
|
8462
|
+
offsetSpace: cellTarget || paintedTarget ? "selection" : "kernel",
|
|
8330
8463
|
...tableCellSelection ? { tableCellSelection } : {}
|
|
8331
8464
|
};
|
|
8332
8465
|
}
|
|
@@ -8464,7 +8597,11 @@ function createSuperDocUI(options) {
|
|
|
8464
8597
|
const getNodeById = hostMethod(doc, "getNodeById");
|
|
8465
8598
|
const raw = await Promise.resolve(getNode ? getNode(address) : getNodeById?.({
|
|
8466
8599
|
nodeId: address["nodeId"],
|
|
8467
|
-
nodeType: address["nodeType"]
|
|
8600
|
+
nodeType: address["nodeType"],
|
|
8601
|
+
story: address["story"] ?? {
|
|
8602
|
+
kind: "story",
|
|
8603
|
+
storyType: "body"
|
|
8604
|
+
}
|
|
8468
8605
|
}));
|
|
8469
8606
|
return isPlainObject(raw) ? raw : void 0;
|
|
8470
8607
|
};
|
|
@@ -9010,7 +9147,8 @@ function createSuperDocUI(options) {
|
|
|
9010
9147
|
const token = contentToken();
|
|
9011
9148
|
const read = readAsync(key, token, () => isBodyStory ? doc.getNodeById({
|
|
9012
9149
|
nodeId: blockId,
|
|
9013
|
-
nodeType: "paragraph"
|
|
9150
|
+
nodeType: "paragraph",
|
|
9151
|
+
story
|
|
9014
9152
|
}) : doc.getNode(paragraphTarget(blockId, story)), (raw) => raw && typeof raw === "object" ? raw : null);
|
|
9015
9153
|
const entry = asyncReads.get(key);
|
|
9016
9154
|
return {
|
|
@@ -9219,7 +9357,11 @@ function createSuperDocUI(options) {
|
|
|
9219
9357
|
const isBodyStory = !story || story.storyType === "body";
|
|
9220
9358
|
const raw = story && typeof doc.getNode === "function" ? await doc.getNode(paragraphTarget(blockId, story)) : isBodyStory && typeof doc.getNodeById === "function" ? await doc.getNodeById({
|
|
9221
9359
|
nodeId: blockId,
|
|
9222
|
-
nodeType: "paragraph"
|
|
9360
|
+
nodeType: "paragraph",
|
|
9361
|
+
story: {
|
|
9362
|
+
kind: "story",
|
|
9363
|
+
storyType: "body"
|
|
9364
|
+
}
|
|
9223
9365
|
}) : null;
|
|
9224
9366
|
return readParagraphIndentationFromResult(raw && typeof raw === "object" ? raw : null);
|
|
9225
9367
|
} catch {
|
|
@@ -9896,14 +10038,15 @@ function createSuperDocUI(options) {
|
|
|
9896
10038
|
const tableSelection = isPlainObject(handles) ? handles.selection : void 0;
|
|
9897
10039
|
const subscribeWholeTable = hostMethod(tableSelection, "subscribeWholeTable");
|
|
9898
10040
|
if (subscribeWholeTable) {
|
|
9899
|
-
const refreshWholeTable = () => {
|
|
10041
|
+
const refreshWholeTable = (initial = false) => {
|
|
10042
|
+
const native = initial ? readHostSelectionSnapshot() : null;
|
|
9900
10043
|
selectionEpoch += 1;
|
|
9901
|
-
refreshSelectionFromHost(void 0, false, true);
|
|
10044
|
+
refreshSelectionFromHost(void 0, false, true, native);
|
|
9902
10045
|
recompute("host-selection");
|
|
9903
10046
|
};
|
|
9904
|
-
const detach = subscribeWholeTable(refreshWholeTable);
|
|
10047
|
+
const detach = subscribeWholeTable(() => refreshWholeTable());
|
|
9905
10048
|
if (typeof detach === "function") unsubscribeCallbacks.push(() => detach());
|
|
9906
|
-
if (hostMethod(tableSelection, "getWholeTableNodeId")?.()) refreshWholeTable();
|
|
10049
|
+
if (hostMethod(tableSelection, "getWholeTableNodeId")?.()) refreshWholeTable(true);
|
|
9907
10050
|
}
|
|
9908
10051
|
} catch {
|
|
9909
10052
|
currentHostSelectionSource = null;
|
|
@@ -9924,10 +10067,35 @@ function createSuperDocUI(options) {
|
|
|
9924
10067
|
};
|
|
9925
10068
|
let trackedChangeNavigationInFlight = 0;
|
|
9926
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);
|
|
9927
10071
|
const syncTrackedChangeFocusFromHostReviewTarget = (rawTarget, rawSnapshot) => {
|
|
9928
10072
|
const rejection = (rawSnapshot && typeof rawSnapshot === "object" ? rawSnapshot : null)?.lastInteractionRejection;
|
|
9929
|
-
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;
|
|
9930
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
|
+
}
|
|
9931
10099
|
let next = null;
|
|
9932
10100
|
if (target?.entityType === "trackedChange" && typeof target.entityId === "string" && target.entityId.length > 0) {
|
|
9933
10101
|
const targetStory = target.story && typeof target.story === "object" ? target.story : void 0;
|
|
@@ -9952,7 +10120,7 @@ function createSuperDocUI(options) {
|
|
|
9952
10120
|
}
|
|
9953
10121
|
if (rawTarget == null && next == null && explicitActiveChange != null && hasPendingTrackChangeRevealFocus(explicitActiveChange)) return false;
|
|
9954
10122
|
const previousPublication = lastPublishedHostReviewTarget;
|
|
9955
|
-
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;
|
|
9956
10124
|
lastPublishedHostReviewTarget = {
|
|
9957
10125
|
raw: rawTarget,
|
|
9958
10126
|
focus: next,
|
|
@@ -10330,11 +10498,16 @@ function createSuperDocUI(options) {
|
|
|
10330
10498
|
* ordinary/insertion selections are visible-space, while a selection that
|
|
10331
10499
|
* reaches painted deleted text is projected in tracked space by the host.
|
|
10332
10500
|
*
|
|
10333
|
-
* Cross-block
|
|
10334
|
-
*
|
|
10501
|
+
* Cross-block and object-containing coverage use the model-backed tracked
|
|
10502
|
+
* target when the explicit text selection cannot represent the range.
|
|
10335
10503
|
*/
|
|
10336
10504
|
function trackDecisionRangeFromSelection(selection) {
|
|
10337
10505
|
if (selection.empty) return null;
|
|
10506
|
+
if (!selection.selectionTarget && selection.trackedTarget) return {
|
|
10507
|
+
kind: "range",
|
|
10508
|
+
coordinateSpace: "tracked",
|
|
10509
|
+
range: selection.trackedTarget
|
|
10510
|
+
};
|
|
10338
10511
|
const explicit = selection.selectionTarget;
|
|
10339
10512
|
const start = explicit?.start;
|
|
10340
10513
|
const end = explicit?.end;
|
|
@@ -10488,7 +10661,7 @@ function createSuperDocUI(options) {
|
|
|
10488
10661
|
kind: "blocked",
|
|
10489
10662
|
reason: SUPERDOC_UI_REASONS.operationUnavailable
|
|
10490
10663
|
};
|
|
10491
|
-
if (!selection.selectionTarget) return null;
|
|
10664
|
+
if (!selection.selectionTarget && !selection.trackedTarget && selection.target?.kind !== "text") return null;
|
|
10492
10665
|
const target = trackDecisionRangeFromSelection(selection);
|
|
10493
10666
|
if (!target && route() !== "id") return {
|
|
10494
10667
|
kind: "blocked",
|
|
@@ -10828,25 +11001,35 @@ function createSuperDocUI(options) {
|
|
|
10828
11001
|
pendingCommandSettlement = settledResults.length ? Promise.all(settledResults).then((results) => combineCommandResults(results)) : null;
|
|
10829
11002
|
return combineCommandResults(immediateResults);
|
|
10830
11003
|
};
|
|
10831
|
-
/**
|
|
10832
|
-
* Call an inline `format.*` operation against the live selection. Mirrors
|
|
10833
|
-
* `callEditorMutation` (suggesting mode adds `changeMode: 'tracked'`), and
|
|
10834
|
-
* when the target is the host's own editable `selectionTarget` it also
|
|
10835
|
-
* carries the PRIVATE V2 option `offsetSpace: 'selection'` (browser
|
|
10836
|
-
* selection offsets count an inline object as one caret position). The
|
|
10837
|
-
* option is not part of public `MutationOptions`; this is the same cast
|
|
10838
|
-
* pattern the delete/replace callers use.
|
|
10839
|
-
*/
|
|
10840
11004
|
function currentCellSelectionTarget() {
|
|
11005
|
+
return captureInputSelectionTarget(true);
|
|
11006
|
+
}
|
|
11007
|
+
function captureInputSelectionTarget(requireTableCells = false) {
|
|
10841
11008
|
const handles = safeCall(() => hostMethod(getHost(), "getHandles")?.(), null);
|
|
10842
11009
|
const selection = isPlainObject(handles) ? handles.selection : void 0;
|
|
10843
11010
|
const held = hostMethod(selection, "getSnapshot")?.();
|
|
10844
|
-
if (!isPlainObject(held) || !held.tableCells) return null;
|
|
11011
|
+
if (requireTableCells && (!isPlainObject(held) || !held.tableCells)) return null;
|
|
10845
11012
|
const resolved = hostMethod(selection, "toSelectionTarget")?.();
|
|
10846
11013
|
return isPlainObject(resolved) && resolved.kind === "ok" && resolved.mode === "range" ? capturedTableCellTarget(resolved.target) : null;
|
|
10847
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
|
+
}
|
|
10848
11024
|
function resolveInlineCommandTarget(selection) {
|
|
10849
|
-
|
|
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);
|
|
10850
11033
|
}
|
|
10851
11034
|
function tableCellSelectionForTarget(target) {
|
|
10852
11035
|
const cellTarget = currentCellSelectionTarget();
|
|
@@ -10866,10 +11049,15 @@ function createSuperDocUI(options) {
|
|
|
10866
11049
|
offsetSpace: "selection",
|
|
10867
11050
|
tableCellSelection
|
|
10868
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
|
+
});
|
|
10869
11057
|
if (!selection.selectionTarget) return options ? op(input, options) : op(input);
|
|
10870
11058
|
return op(input, {
|
|
10871
11059
|
...options,
|
|
10872
|
-
offsetSpace: "
|
|
11060
|
+
offsetSpace: "kernel"
|
|
10873
11061
|
});
|
|
10874
11062
|
};
|
|
10875
11063
|
/** Build the `format.paragraph.*` / `styles.paragraph.*` input for a block. */
|
|
@@ -11098,13 +11286,16 @@ function createSuperDocUI(options) {
|
|
|
11098
11286
|
};
|
|
11099
11287
|
pendingCommandSettlement = (async () => {
|
|
11100
11288
|
const plans = await Promise.all(blockIds.map((blockId) => planBlock(blockId).catch(() => null)));
|
|
11101
|
-
|
|
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)) {
|
|
11102
11292
|
const rangeRoute = mode === "indent" ? "lists.indentRange" : "lists.outdentRange";
|
|
11103
11293
|
const rangeOp = resolveDocOperation(doc, rangeRoute);
|
|
11104
11294
|
if (rangeOp) try {
|
|
11105
11295
|
return await settleOperationResult(callEditorMutation(rangeRoute, rangeOp, {
|
|
11106
11296
|
paraIds: blockIds,
|
|
11107
|
-
story
|
|
11297
|
+
story,
|
|
11298
|
+
...preserveFirstItemLevel ? { preserveFirstItemLevel: true } : {}
|
|
11108
11299
|
})).settled;
|
|
11109
11300
|
} catch {
|
|
11110
11301
|
return false;
|
|
@@ -11644,23 +11835,32 @@ function createSuperDocUI(options) {
|
|
|
11644
11835
|
const record = readLinkPayloadRecord(payload);
|
|
11645
11836
|
return Boolean(readLinkPayloadTarget(payload) || isPlainObject(record.hyperlinkTarget) || isPlainObject(record.textTarget));
|
|
11646
11837
|
};
|
|
11647
|
-
const
|
|
11838
|
+
const currentWholeTableParagraphOwner = () => {
|
|
11648
11839
|
const owner = wholeTableParagraphSeed, host = getHost();
|
|
11649
|
-
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;
|
|
11650
11841
|
const tableId = owner.info.tableSelection?.tableId;
|
|
11651
11842
|
const activeTable = safeCall(() => {
|
|
11652
11843
|
const handles = hostMethod(host, "getHandles")?.();
|
|
11653
11844
|
return hostMethod(isPlainObject(handles) ? handles.selection : void 0, "getWholeTableNodeId")?.();
|
|
11654
11845
|
}, null);
|
|
11655
|
-
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;
|
|
11656
11847
|
const applied = appliedSelectionPresentation(state.selection);
|
|
11657
11848
|
const info = normalizeSelectionInfo(applied?.selection);
|
|
11658
|
-
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;
|
|
11659
11858
|
};
|
|
11660
11859
|
const commandSelectionIsReady = (id, descriptor, payload) => {
|
|
11661
11860
|
const foreground = foregroundMutationState();
|
|
11662
11861
|
if (foreground && (foreground.active > 0 || foreground.pending > 0)) return false;
|
|
11663
11862
|
if (descriptor?.blockParagraph && currentWholeTableParagraphSelection()) return true;
|
|
11863
|
+
if (descriptor?.blockParagraph && state.selection.tableSelection?.type === "table" && !state.selection.selectionTarget) return false;
|
|
11664
11864
|
if (state.selection.status !== "ready") return false;
|
|
11665
11865
|
if (trackDecisionCommand(id)?.scope === "id") return true;
|
|
11666
11866
|
if (!descriptor || descriptor.disposition !== "routed") return true;
|
|
@@ -12081,10 +12281,23 @@ function createSuperDocUI(options) {
|
|
|
12081
12281
|
const cellTarget = currentCellSelectionTarget();
|
|
12082
12282
|
const tableCellSelection = tableCellSelectionForTarget(cellTarget);
|
|
12083
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
|
+
}
|
|
12084
12296
|
return {
|
|
12085
|
-
selection
|
|
12297
|
+
selection,
|
|
12086
12298
|
cellTarget,
|
|
12087
|
-
tableCellSelection
|
|
12299
|
+
tableCellSelection,
|
|
12300
|
+
paintedTarget
|
|
12088
12301
|
};
|
|
12089
12302
|
};
|
|
12090
12303
|
const waitForSelectionSettle = () => new Promise((resolve) => setTimeout(resolve, 16));
|
|
@@ -12102,7 +12315,7 @@ function createSuperDocUI(options) {
|
|
|
12102
12315
|
break;
|
|
12103
12316
|
}
|
|
12104
12317
|
if (selectionRead?.selection && !selectionRead.selection.empty && key !== painter.sourceSelectionKey) {
|
|
12105
|
-
await applyFormatPainter(selectionRead.selection, selectionRead.cellTarget, selectionRead.tableCellSelection);
|
|
12318
|
+
await applyFormatPainter(selectionRead.selection, selectionRead.cellTarget, selectionRead.tableCellSelection, selectionRead.paintedTarget);
|
|
12106
12319
|
return;
|
|
12107
12320
|
}
|
|
12108
12321
|
if (painter.snapshot?.paragraph) {
|
|
@@ -12110,10 +12323,10 @@ function createSuperDocUI(options) {
|
|
|
12110
12323
|
const caretSel = caretRead.selection;
|
|
12111
12324
|
if (!caretSel) return;
|
|
12112
12325
|
if (selectionKey(caretSel) === painter.sourceSelectionKey) return;
|
|
12113
|
-
await applyFormatPainter(caretSel, caretRead.cellTarget, caretRead.tableCellSelection);
|
|
12326
|
+
await applyFormatPainter(caretSel, caretRead.cellTarget, caretRead.tableCellSelection, caretRead.paintedTarget);
|
|
12114
12327
|
}
|
|
12115
12328
|
};
|
|
12116
|
-
const applyFormatPainter = async (selection, cellTarget, tableCellSelection) => {
|
|
12329
|
+
const applyFormatPainter = async (selection, cellTarget, tableCellSelection, paintedTarget) => {
|
|
12117
12330
|
const snap = painter.snapshot;
|
|
12118
12331
|
if (!snap) {
|
|
12119
12332
|
if (painter.mode === "armed") exitFormatPainter();
|
|
@@ -12131,7 +12344,7 @@ function createSuperDocUI(options) {
|
|
|
12131
12344
|
return;
|
|
12132
12345
|
}
|
|
12133
12346
|
const selTarget = selection.target;
|
|
12134
|
-
const selectionTarget = cellTarget ?? selection.selectionTarget;
|
|
12347
|
+
const selectionTarget = cellTarget ?? paintedTarget ?? selection.selectionTarget;
|
|
12135
12348
|
const selectionIsEmpty = selection.empty === true;
|
|
12136
12349
|
const segments = Array.isArray(selTarget?.segments) ? selTarget.segments : [];
|
|
12137
12350
|
const targetStory = selTarget?.story;
|
|
@@ -12369,13 +12582,16 @@ function createSuperDocUI(options) {
|
|
|
12369
12582
|
const snapshot = selectionSub.get();
|
|
12370
12583
|
if (snapshot.empty) return null;
|
|
12371
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;
|
|
12372
12588
|
if (!snapshot.target && !snapshot.selectionTarget && !cells) return null;
|
|
12373
12589
|
const capture = {
|
|
12374
12590
|
...snapshot,
|
|
12375
12591
|
capturedAt: Date.now(),
|
|
12376
|
-
...cells ? { _tableCellSelectionTarget: cells } : {}
|
|
12592
|
+
...cells ? { _tableCellSelectionTarget: cells } : {},
|
|
12593
|
+
...painted ? { _paintedSelectionTarget: painted } : {}
|
|
12377
12594
|
};
|
|
12378
|
-
const hostSelection = selectionHostSnapshots.get(snapshot);
|
|
12379
12595
|
if (hostSelection) selectionHostSnapshots.set(capture, hostSelection);
|
|
12380
12596
|
return capture;
|
|
12381
12597
|
},
|
|
@@ -12401,7 +12617,13 @@ function createSuperDocUI(options) {
|
|
|
12401
12617
|
ok: false,
|
|
12402
12618
|
reason: SUPERDOC_UI_REASONS.targetUnresolved
|
|
12403
12619
|
});
|
|
12404
|
-
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);
|
|
12405
12627
|
if (!target) return done({
|
|
12406
12628
|
ok: false,
|
|
12407
12629
|
reason: SUPERDOC_UI_REASONS.targetUnresolved
|
|
@@ -12414,7 +12636,7 @@ function createSuperDocUI(options) {
|
|
|
12414
12636
|
reason: resolved.reason
|
|
12415
12637
|
});
|
|
12416
12638
|
try {
|
|
12417
|
-
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" }] : [])));
|
|
12418
12640
|
} catch {
|
|
12419
12641
|
return done({
|
|
12420
12642
|
ok: false,
|
|
@@ -12833,6 +13055,10 @@ function createSuperDocUI(options) {
|
|
|
12833
13055
|
};
|
|
12834
13056
|
const commentsSub = sliceHandle((s) => s.comments);
|
|
12835
13057
|
const commentsSnap = directorySnapshotHandle(commentsSub, select((s) => computeCommentsDirectorySnapshot(s.selection, s.comments)), "comments");
|
|
13058
|
+
documentResetHooks.push(() => {
|
|
13059
|
+
setExplicitActiveChange(null);
|
|
13060
|
+
explicitActiveCommentId = null;
|
|
13061
|
+
});
|
|
12836
13062
|
const comments = {
|
|
12837
13063
|
get: commentsSnap.get,
|
|
12838
13064
|
getSnapshot: commentsSnap.getSnapshot,
|
|
@@ -12926,6 +13152,7 @@ function createSuperDocUI(options) {
|
|
|
12926
13152
|
setActive: (commentId) => {
|
|
12927
13153
|
if (commentId == null) {
|
|
12928
13154
|
explicitActiveCommentId = null;
|
|
13155
|
+
mirrorReviewFocusToHost("comment", null);
|
|
12929
13156
|
recompute();
|
|
12930
13157
|
return true;
|
|
12931
13158
|
}
|
|
@@ -12938,7 +13165,9 @@ function createSuperDocUI(options) {
|
|
|
12938
13165
|
const resolvedId = resolveActiveCommentId(items, commentId);
|
|
12939
13166
|
if (!resolvedId) return false;
|
|
12940
13167
|
if (!items.some((entry) => readEntityId(entry) === resolvedId)) return false;
|
|
13168
|
+
setExplicitActiveChange(null);
|
|
12941
13169
|
explicitActiveCommentId = resolvedId;
|
|
13170
|
+
mirrorReviewFocusToHost("comment", { id: resolvedId });
|
|
12942
13171
|
recompute();
|
|
12943
13172
|
return true;
|
|
12944
13173
|
},
|
|
@@ -12998,7 +13227,7 @@ function createSuperDocUI(options) {
|
|
|
12998
13227
|
};
|
|
12999
13228
|
const navigateAndScrollCurrentRequest = async (step, requestedAtInvalidation) => {
|
|
13000
13229
|
if (queuedTrackChangeNavigationInvalidation !== requestedAtInvalidation) return { success: false };
|
|
13001
|
-
const
|
|
13230
|
+
const previousFocus = readReviewFocus();
|
|
13002
13231
|
const activeId = navigateTrackChange(step, { invalidateQueuedNavigation: false });
|
|
13003
13232
|
if (activeId == null) return { success: false };
|
|
13004
13233
|
const optimisticActiveChange = explicitActiveChange;
|
|
@@ -13006,7 +13235,7 @@ function createSuperDocUI(options) {
|
|
|
13006
13235
|
const isCurrent = () => queuedTrackChangeNavigationInvalidation === requestedAtInvalidation && explicitActiveChange === optimisticActiveChange && explicitActiveChangeRevision === optimisticRevision;
|
|
13007
13236
|
const rollback = () => {
|
|
13008
13237
|
if (!isCurrent()) return;
|
|
13009
|
-
|
|
13238
|
+
restoreReviewFocus(previousFocus);
|
|
13010
13239
|
recompute();
|
|
13011
13240
|
};
|
|
13012
13241
|
if (optimisticActiveChange) pendingTrackChangeRevealFocuses.add(optimisticActiveChange);
|
|
@@ -13026,10 +13255,8 @@ function createSuperDocUI(options) {
|
|
|
13026
13255
|
shouldContinue: isCurrent
|
|
13027
13256
|
});
|
|
13028
13257
|
if (!isCurrent()) return { success: false };
|
|
13029
|
-
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible)
|
|
13030
|
-
|
|
13031
|
-
mirrorTrackedChangeFocusToHost(previousActiveChange);
|
|
13032
|
-
} else {
|
|
13258
|
+
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible) rollback();
|
|
13259
|
+
else {
|
|
13033
13260
|
if (result.ok) await restampVisibleTrackedChangeCarrierAliases(activeId);
|
|
13034
13261
|
if (!isCurrent()) return { success: false };
|
|
13035
13262
|
mirrorTrackedChangeFocusToHost(optimisticActiveChange);
|
|
@@ -13160,7 +13387,7 @@ function createSuperDocUI(options) {
|
|
|
13160
13387
|
const matchingRow = matchStory ? loadedItems.find((item) => entityRowMatchesRequest(item, publicId, matchStory)) : loadedItems.find((item) => readEntityId(item) === publicId);
|
|
13161
13388
|
const story = matchStory ? requestedStory : readEntityRequestStory(matchingRow);
|
|
13162
13389
|
const importedId = deriveTrackedChangeImportedId(matchingRow);
|
|
13163
|
-
const
|
|
13390
|
+
const previousFocus = readReviewFocus();
|
|
13164
13391
|
const requestedActiveChange = {
|
|
13165
13392
|
id: publicId,
|
|
13166
13393
|
...story ? { story } : {},
|
|
@@ -13188,7 +13415,7 @@ function createSuperDocUI(options) {
|
|
|
13188
13415
|
const isCurrent = () => trackChangeRevealInvalidation === revealInvalidation && explicitActiveChange === optimisticActiveChange && explicitActiveChangeRevision === optimisticRevision;
|
|
13189
13416
|
const rollback = () => {
|
|
13190
13417
|
if (!isCurrent()) return;
|
|
13191
|
-
|
|
13418
|
+
restoreReviewFocus(previousFocus);
|
|
13192
13419
|
recompute();
|
|
13193
13420
|
};
|
|
13194
13421
|
recompute();
|
|
@@ -13202,10 +13429,8 @@ function createSuperDocUI(options) {
|
|
|
13202
13429
|
success: false,
|
|
13203
13430
|
ok: false
|
|
13204
13431
|
};
|
|
13205
|
-
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible)
|
|
13206
|
-
|
|
13207
|
-
mirrorTrackedChangeFocusToHost(previousActiveChange);
|
|
13208
|
-
} else {
|
|
13432
|
+
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible) rollback();
|
|
13433
|
+
else {
|
|
13209
13434
|
if (result.ok) await restampVisibleTrackedChangeCarrierAliases(publicId);
|
|
13210
13435
|
if (!isCurrent()) return {
|
|
13211
13436
|
success: false,
|
|
@@ -13540,14 +13765,14 @@ function createSuperDocUI(options) {
|
|
|
13540
13765
|
if (root instanceof HTMLElement) return root;
|
|
13541
13766
|
return null;
|
|
13542
13767
|
};
|
|
13543
|
-
const
|
|
13544
|
-
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;
|
|
13545
13770
|
const dom = globalThis.document;
|
|
13546
|
-
if (!dom || typeof dom.elementFromPoint !== "function") return
|
|
13771
|
+
if (!dom || typeof dom.elementFromPoint !== "function") return null;
|
|
13547
13772
|
const container = resolveVisibleHost();
|
|
13548
|
-
if (!container) return
|
|
13773
|
+
if (!container) return null;
|
|
13549
13774
|
const startEl = dom.elementFromPoint(x, y);
|
|
13550
|
-
if (!startEl || !container.contains(startEl)) return
|
|
13775
|
+
if (!startEl || !container.contains(startEl)) return null;
|
|
13551
13776
|
const primaryEls = [startEl];
|
|
13552
13777
|
const addPrimaryEl = (el) => {
|
|
13553
13778
|
if (el && container.contains(el) && !primaryEls.includes(el)) primaryEls.push(el);
|
|
@@ -13562,6 +13787,17 @@ function createSuperDocUI(options) {
|
|
|
13562
13787
|
}
|
|
13563
13788
|
for (const el of stacked) addPrimaryEl(el);
|
|
13564
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;
|
|
13565
13801
|
const markerEls = [];
|
|
13566
13802
|
const addMarkerEl = (el) => {
|
|
13567
13803
|
if (el && container.contains(el) && !markerEls.includes(el) && !primaryEls.includes(el)) markerEls.push(el);
|
|
@@ -13575,7 +13811,7 @@ function createSuperDocUI(options) {
|
|
|
13575
13811
|
} catch {
|
|
13576
13812
|
return false;
|
|
13577
13813
|
}
|
|
13578
|
-
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;
|
|
13579
13815
|
};
|
|
13580
13816
|
for (const el of primaryEls) {
|
|
13581
13817
|
const queryAll = el.querySelectorAll;
|
|
@@ -13599,6 +13835,18 @@ function createSuperDocUI(options) {
|
|
|
13599
13835
|
const seen = /* @__PURE__ */ new Set();
|
|
13600
13836
|
const hits = [];
|
|
13601
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
|
+
}
|
|
13602
13850
|
if (hit.type !== "trackedChange") {
|
|
13603
13851
|
const layoutStory = hit.type === "contentControl" ? layoutStoryDatasetToStoryLocator(hit.story) : void 0;
|
|
13604
13852
|
const story = hit.type === "contentControl" ? isTextboxStory(layoutStory) ? layoutStory : storyKeyToStoryLocator(hit.storyKey) ?? layoutStory : void 0;
|
|
@@ -13754,6 +14002,149 @@ function createSuperDocUI(options) {
|
|
|
13754
14002
|
if (status !== "ready") return { reason: "not-ready" };
|
|
13755
14003
|
return value ? { target: value } : { reason: "unresolved" };
|
|
13756
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();
|
|
13757
14148
|
const viewport = {
|
|
13758
14149
|
getRects: async (input) => {
|
|
13759
14150
|
const initialHost = getHost();
|
|
@@ -14731,6 +15122,92 @@ function createSuperDocUI(options) {
|
|
|
14731
15122
|
}
|
|
14732
15123
|
}, 120);
|
|
14733
15124
|
};
|
|
15125
|
+
const updateStyleToMatchSelection = (input) => {
|
|
15126
|
+
const mode = readDocumentMode();
|
|
15127
|
+
if (mode === "viewing") return failedReceipt("The document is read-only.", "DOCUMENT_READONLY");
|
|
15128
|
+
if (mode === "suggesting") return failedReceipt("A style definition cannot be changed as a tracked suggestion.", "PRECONDITION_FAILED");
|
|
15129
|
+
const sourceToken = contentToken();
|
|
15130
|
+
const readPositionKey = () => {
|
|
15131
|
+
const snapshot = readHostSelectionSnapshot();
|
|
15132
|
+
if (!snapshot) return null;
|
|
15133
|
+
return JSON.stringify({
|
|
15134
|
+
story: snapshot.story,
|
|
15135
|
+
tableCells: snapshot.tableCells,
|
|
15136
|
+
points: ["anchor", "focus"].map((side) => {
|
|
15137
|
+
const point = snapshot[side];
|
|
15138
|
+
return point ? [
|
|
15139
|
+
point.blockId,
|
|
15140
|
+
point.blockOffset,
|
|
15141
|
+
point.trackedBlockOffset,
|
|
15142
|
+
point.story,
|
|
15143
|
+
point.inlineAffinity,
|
|
15144
|
+
point.outsideContentControl,
|
|
15145
|
+
point.visualCaret
|
|
15146
|
+
] : null;
|
|
15147
|
+
})
|
|
15148
|
+
});
|
|
15149
|
+
};
|
|
15150
|
+
const requestedPosition = readPositionKey();
|
|
15151
|
+
const stale = failedReceipt("The selection or document changed while reading its style.", "REVISION_MISMATCH");
|
|
15152
|
+
return readSelectionInfoFresh().then((selection) => {
|
|
15153
|
+
const selectionToken = selectionKey(selection);
|
|
15154
|
+
const isCurrent = () => !disposed && contentToken() === sourceToken && readPositionKey() === requestedPosition && selectionKey(state.selection) === selectionToken && readDocumentMode() === mode;
|
|
15155
|
+
if (!isCurrent()) return stale;
|
|
15156
|
+
const active = computeActiveParagraphStyle(selection, getStyleCatalog().cache).style;
|
|
15157
|
+
const story = storyLocatorSignature(selectionStory(selection));
|
|
15158
|
+
const keys = [styleCatalogReadKey({ includePreview: true }), ...selectionBlockIds(selection).map((id) => `node:${story}:${id}`)];
|
|
15159
|
+
const unreadable = failedReceipt("The selection formatting could not be read.", "PRECONDITION_FAILED");
|
|
15160
|
+
const run = (active) => {
|
|
15161
|
+
if (keys.some((key) => {
|
|
15162
|
+
const entry = asyncReads.get(key);
|
|
15163
|
+
return entry && (!entry.hasSettled || entry.token !== sourceToken || entry.failedToken === sourceToken);
|
|
15164
|
+
})) return unreadable;
|
|
15165
|
+
const styleId = input?.styleId ?? active.styleId;
|
|
15166
|
+
if (!styleId) return failedReceipt("Choose a style to update: the selection does not have a single paragraph style.", "INVALID_TARGET");
|
|
15167
|
+
const doc = getDoc();
|
|
15168
|
+
const readSelection = resolveDocOperation(doc, "format.readSelection");
|
|
15169
|
+
const apply = resolveDocOperation(doc, "styles.apply");
|
|
15170
|
+
if (!readSelection || !apply) return failedReceipt("Updating a style to match the selection is unavailable.");
|
|
15171
|
+
let reads;
|
|
15172
|
+
try {
|
|
15173
|
+
reads = [readSelection({
|
|
15174
|
+
selection: "current",
|
|
15175
|
+
keys: STYLE_MATCH_READ_KEYS,
|
|
15176
|
+
view: "effective"
|
|
15177
|
+
}), readSelection({
|
|
15178
|
+
selection: "current",
|
|
15179
|
+
keys: STYLE_MATCH_READ_KEYS,
|
|
15180
|
+
view: "direct"
|
|
15181
|
+
})];
|
|
15182
|
+
} catch {
|
|
15183
|
+
return unreadable;
|
|
15184
|
+
}
|
|
15185
|
+
return Promise.all(reads).then(([effective, direct]) => {
|
|
15186
|
+
if (!isCurrent()) return stale;
|
|
15187
|
+
const patch = buildStyleMatchPatch(effective, direct, { selectionUsesStyle: !active.mixed && active.styleId === styleId });
|
|
15188
|
+
if (Object.keys(patch).length === 0) return failedReceipt("The selection already matches the style.", "NO_OP");
|
|
15189
|
+
const fallback = failedReceipt("Updating the style failed.");
|
|
15190
|
+
return safeCall(() => settleWorkflowReceipt(apply({
|
|
15191
|
+
target: {
|
|
15192
|
+
scope: "style",
|
|
15193
|
+
styleId,
|
|
15194
|
+
channel: "run"
|
|
15195
|
+
},
|
|
15196
|
+
patch
|
|
15197
|
+
}), fallback), fallback);
|
|
15198
|
+
}, () => unreadable);
|
|
15199
|
+
};
|
|
15200
|
+
const pending = keys.flatMap((key) => {
|
|
15201
|
+
const entry = asyncReads.get(key);
|
|
15202
|
+
return entry?.inflightToken === sourceToken && entry.settled ? [entry.settled] : [];
|
|
15203
|
+
});
|
|
15204
|
+
if (pending.length === 0) return run(active);
|
|
15205
|
+
return Promise.all(pending).then(() => {
|
|
15206
|
+
if (!isCurrent()) return stale;
|
|
15207
|
+
return run(computeActiveParagraphStyle(selection, getStyleCatalog().cache).style);
|
|
15208
|
+
});
|
|
15209
|
+
});
|
|
15210
|
+
};
|
|
14734
15211
|
const stylesSub = sliceHandle((s) => s.styles);
|
|
14735
15212
|
const stylesSnap = snapshotHandle(stylesSub);
|
|
14736
15213
|
const styles = {
|
|
@@ -14743,7 +15220,8 @@ function createSuperDocUI(options) {
|
|
|
14743
15220
|
return readStyleCatalogLive(options).value;
|
|
14744
15221
|
},
|
|
14745
15222
|
getQuickGallery: () => stylesSub.get().quickGallery,
|
|
14746
|
-
getActiveParagraphStyle: () => computeActiveParagraphStyle(state.selection, getStyleCatalog().cache).style
|
|
15223
|
+
getActiveParagraphStyle: () => computeActiveParagraphStyle(state.selection, getStyleCatalog().cache).style,
|
|
15224
|
+
updateToMatchSelection: (input) => updateStyleToMatchSelection(input)
|
|
14747
15225
|
};
|
|
14748
15226
|
const openWatermarkSurface = hostMethod(superdoc, "openSurface");
|
|
14749
15227
|
const watermark = createWatermarkController({
|
|
@@ -14758,6 +15236,7 @@ function createSuperDocUI(options) {
|
|
|
14758
15236
|
const createScope = () => {
|
|
14759
15237
|
const scopeUnsubs = [];
|
|
14760
15238
|
return {
|
|
15239
|
+
decorations: createDecorationsHandle((handle) => scopeUnsubs.push(() => handle.dispose())),
|
|
14761
15240
|
select: (selector, equality) => {
|
|
14762
15241
|
const sub = select(selector, equality);
|
|
14763
15242
|
return {
|
|
@@ -14778,6 +15257,9 @@ function createSuperDocUI(options) {
|
|
|
14778
15257
|
if (disposed) return;
|
|
14779
15258
|
watermark.destroy();
|
|
14780
15259
|
clearContentControlHighlight();
|
|
15260
|
+
for (const handle of Array.from(liveDecorations.keys())) handle.dispose();
|
|
15261
|
+
detachDecorationPointer?.();
|
|
15262
|
+
decorationListeners.clear();
|
|
14781
15263
|
disposed = true;
|
|
14782
15264
|
completedFallbackSearch = null;
|
|
14783
15265
|
if (searchRefreshTimer !== null) clearTimeout(searchRefreshTimer);
|
|
@@ -14860,6 +15342,7 @@ function createSuperDocUI(options) {
|
|
|
14860
15342
|
zoom,
|
|
14861
15343
|
document: documentHandle,
|
|
14862
15344
|
viewport,
|
|
15345
|
+
decorations,
|
|
14863
15346
|
metadata,
|
|
14864
15347
|
tables,
|
|
14865
15348
|
search,
|
|
@@ -15150,6 +15633,12 @@ Object.defineProperty(exports, "isPlainObject", {
|
|
|
15150
15633
|
return isPlainObject;
|
|
15151
15634
|
}
|
|
15152
15635
|
});
|
|
15636
|
+
Object.defineProperty(exports, "isRecord", {
|
|
15637
|
+
enumerable: true,
|
|
15638
|
+
get: function() {
|
|
15639
|
+
return isRecord;
|
|
15640
|
+
}
|
|
15641
|
+
});
|
|
15153
15642
|
Object.defineProperty(exports, "isSyntheticTrackedChangeCommentLaneItem", {
|
|
15154
15643
|
enumerable: true,
|
|
15155
15644
|
get: function() {
|