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
package/dist/chunks/{create-super-doc-ui-cHUUipYM.es.js → create-super-doc-ui-C4Ka5Ph3.es.js}
RENAMED
|
@@ -2458,6 +2458,69 @@ function createDialogWorkflow(editor, options, onSuccess) {
|
|
|
2458
2458
|
};
|
|
2459
2459
|
}
|
|
2460
2460
|
//#endregion
|
|
2461
|
+
//#region src/public/ui/style-match-patch.ts
|
|
2462
|
+
var STYLE_MATCH_KEYS = [
|
|
2463
|
+
["bold", "bold"],
|
|
2464
|
+
["italic", "italic"],
|
|
2465
|
+
["underline", "underline"],
|
|
2466
|
+
["color", "color"],
|
|
2467
|
+
["fontSize", "fontSize"],
|
|
2468
|
+
["rFonts", "fontFamily"]
|
|
2469
|
+
];
|
|
2470
|
+
var STYLE_MATCH_READ_KEYS = [...STYLE_MATCH_KEYS.map(([readKey]) => readKey), "rStyle"];
|
|
2471
|
+
function buildStyleMatchPatch(effective, direct, options) {
|
|
2472
|
+
const patch = {};
|
|
2473
|
+
const characterStyle = direct.properties.rStyle;
|
|
2474
|
+
const hasCharacterStyle = characterStyle != null && characterStyle.state !== "unset";
|
|
2475
|
+
for (const [readKey, styleKey] of STYLE_MATCH_KEYS) {
|
|
2476
|
+
const read = effective.properties[readKey];
|
|
2477
|
+
if (read?.state !== "uniform") continue;
|
|
2478
|
+
if (options.selectionUsesStyle && !hasCharacterStyle && direct.properties[readKey]?.state === "unset") continue;
|
|
2479
|
+
patch[styleKey] = toStyleValue(readKey, read.value);
|
|
2480
|
+
}
|
|
2481
|
+
return patch;
|
|
2482
|
+
}
|
|
2483
|
+
function toStyleValue(key, value) {
|
|
2484
|
+
switch (key) {
|
|
2485
|
+
case "bold":
|
|
2486
|
+
case "italic": return value === true;
|
|
2487
|
+
case "underline": return underlineValue(value);
|
|
2488
|
+
case "color": return typeof value === "string" && value.length > 0 ? { val: value.replace(/^#/, "") } : null;
|
|
2489
|
+
case "fontSize": return typeof value === "number" && Number.isFinite(value) ? Math.round(value * 2) : null;
|
|
2490
|
+
case "rFonts": return fontsValue(value);
|
|
2491
|
+
default: return null;
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
function underlineValue(value) {
|
|
2495
|
+
if (value === true) return { val: "single" };
|
|
2496
|
+
if (!value || typeof value !== "object") return { val: "none" };
|
|
2497
|
+
const underline = value;
|
|
2498
|
+
const result = { val: typeof underline.style === "string" && underline.style ? underline.style : "single" };
|
|
2499
|
+
if (typeof underline.color === "string") result.color = underline.color;
|
|
2500
|
+
if (typeof underline.themeColor === "string") result.themeColor = underline.themeColor;
|
|
2501
|
+
return result;
|
|
2502
|
+
}
|
|
2503
|
+
var FONT_SLOTS = {
|
|
2504
|
+
ascii: "ascii",
|
|
2505
|
+
hAnsi: "hAnsi",
|
|
2506
|
+
eastAsia: "eastAsia",
|
|
2507
|
+
cs: "cs",
|
|
2508
|
+
asciiTheme: "asciiTheme",
|
|
2509
|
+
hAnsiTheme: "hAnsiTheme",
|
|
2510
|
+
eastAsiaTheme: "eastAsiaTheme",
|
|
2511
|
+
csTheme: "cstheme",
|
|
2512
|
+
hint: "hint"
|
|
2513
|
+
};
|
|
2514
|
+
function fontsValue(value) {
|
|
2515
|
+
if (!value || typeof value !== "object") return null;
|
|
2516
|
+
const result = {};
|
|
2517
|
+
for (const [slot, styleSlot] of Object.entries(FONT_SLOTS)) {
|
|
2518
|
+
const font = value[slot];
|
|
2519
|
+
if (typeof font === "string" && font.length > 0) result[styleSlot] = font;
|
|
2520
|
+
}
|
|
2521
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
2522
|
+
}
|
|
2523
|
+
//#endregion
|
|
2461
2524
|
//#region src/public/ui/format-painter-helpers.js
|
|
2462
2525
|
/**
|
|
2463
2526
|
* Maps SDRunProps field names to InlineRunPatch field names.
|
|
@@ -3628,6 +3691,25 @@ function getCommandDescriptor(id) {
|
|
|
3628
3691
|
}
|
|
3629
3692
|
//#endregion
|
|
3630
3693
|
//#region src/public/ui/entity-at.ts
|
|
3694
|
+
function readDecorationProviders(node) {
|
|
3695
|
+
const encoded = node.getAttribute("data-superdoc-extension-decorations");
|
|
3696
|
+
if (encoded) try {
|
|
3697
|
+
const parsed = JSON.parse(encoded);
|
|
3698
|
+
if (Array.isArray(parsed)) return parsed.filter((id) => typeof id === "string");
|
|
3699
|
+
} catch {
|
|
3700
|
+
return [];
|
|
3701
|
+
}
|
|
3702
|
+
const single = node.getAttribute("data-superdoc-extension-decoration");
|
|
3703
|
+
return single ? [single] : [];
|
|
3704
|
+
}
|
|
3705
|
+
function collectDecorationProvidersFromChain(start, stopAt) {
|
|
3706
|
+
const providers = /* @__PURE__ */ new Set();
|
|
3707
|
+
for (let element = start; element; element = element.parentElement) {
|
|
3708
|
+
for (const provider of readDecorationProviders(element)) providers.add(provider);
|
|
3709
|
+
if (element === stopAt) break;
|
|
3710
|
+
}
|
|
3711
|
+
return [...providers];
|
|
3712
|
+
}
|
|
3631
3713
|
function parseCommaSeparatedIds(value) {
|
|
3632
3714
|
return value.split(",").map((id) => id.trim()).filter(Boolean);
|
|
3633
3715
|
}
|
|
@@ -3699,6 +3781,16 @@ function collectEntityHitsFromChain(start, stopAt) {
|
|
|
3699
3781
|
for (const hit of pendingStory) hit.story = layoutStory;
|
|
3700
3782
|
pendingStory = [];
|
|
3701
3783
|
}
|
|
3784
|
+
for (const decorationProvider of readDecorationProviders(node)) {
|
|
3785
|
+
const key = `decoration:${decorationProvider}`;
|
|
3786
|
+
if (!seen.has(key)) {
|
|
3787
|
+
seen.add(key);
|
|
3788
|
+
hits.push({
|
|
3789
|
+
type: "decoration",
|
|
3790
|
+
id: decorationProvider
|
|
3791
|
+
});
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3702
3794
|
const citationId = node.getAttribute("data-citation-id");
|
|
3703
3795
|
if (citationId) {
|
|
3704
3796
|
const key = `citation:${citationId}`;
|
|
@@ -6089,6 +6181,7 @@ function createSuperDocUI(options) {
|
|
|
6089
6181
|
pointerSelecting: false,
|
|
6090
6182
|
keyboardSelecting: false
|
|
6091
6183
|
};
|
|
6184
|
+
const paintedInlineTargets = /* @__PURE__ */ new WeakSet();
|
|
6092
6185
|
let painterCaptureEpoch = 0;
|
|
6093
6186
|
let painterCommandDoc = null;
|
|
6094
6187
|
const painterModeListeners = /* @__PURE__ */ new Set();
|
|
@@ -6185,7 +6278,7 @@ function createSuperDocUI(options) {
|
|
|
6185
6278
|
const readHostSelectionSnapshot = () => {
|
|
6186
6279
|
const handles = safeCall(() => hostMethod(getHost(), "getHandles")?.() ?? null, null);
|
|
6187
6280
|
const editing = isPlainObject(handles) ? handles.editing : void 0;
|
|
6188
|
-
const getSnapshot = hostMethod(isPlainObject(editing) ? editing.selection : void 0, "getSnapshot");
|
|
6281
|
+
const getSnapshot = hostMethod(isPlainObject(editing) ? editing.selection : void 0, "getSnapshot") ?? hostMethod(isPlainObject(handles) ? handles.selection : void 0, "getSnapshot");
|
|
6189
6282
|
if (!getSnapshot) return null;
|
|
6190
6283
|
const snapshot = safeCall(() => getSnapshot(), null);
|
|
6191
6284
|
return snapshot && typeof snapshot === "object" ? snapshot : null;
|
|
@@ -6399,7 +6492,7 @@ function createSuperDocUI(options) {
|
|
|
6399
6492
|
return left.id === right.id && left.paintedEntityId === right.paintedEntityId && storyLocatorSignature(left.story) === storyLocatorSignature(right.story);
|
|
6400
6493
|
};
|
|
6401
6494
|
const hasPendingTrackChangeRevealFocus = (focus) => Array.from(pendingTrackChangeRevealFocuses).some((pendingFocus) => explicitActiveChangesEqual(pendingFocus, focus));
|
|
6402
|
-
const
|
|
6495
|
+
const mirrorReviewFocusToHost = (entityType, next) => {
|
|
6403
6496
|
const readHandles = hostMethod(getHost(), "getHandles");
|
|
6404
6497
|
if (!readHandles) return;
|
|
6405
6498
|
const handles = safeCall(() => readHandles(), null);
|
|
@@ -6410,15 +6503,15 @@ function createSuperDocUI(options) {
|
|
|
6410
6503
|
if (!setActiveReviewTarget) return;
|
|
6411
6504
|
const layout = isPlainObject(handles.layout) ? handles.layout : void 0;
|
|
6412
6505
|
safeCall(() => setActiveReviewTarget({
|
|
6413
|
-
entityType
|
|
6506
|
+
entityType,
|
|
6414
6507
|
entityId: next.id,
|
|
6415
6508
|
...next.paintedEntityId ? { paintedEntityId: next.paintedEntityId } : {},
|
|
6416
6509
|
origin: "panel",
|
|
6417
6510
|
layoutEpoch: typeof layout?.generation === "number" ? layout.generation : 0,
|
|
6418
|
-
story: next.story ?? {
|
|
6511
|
+
...entityType === "trackedChange" ? { story: next.story ?? {
|
|
6419
6512
|
kind: "story",
|
|
6420
6513
|
storyType: "body"
|
|
6421
|
-
}
|
|
6514
|
+
} } : {}
|
|
6422
6515
|
}), null);
|
|
6423
6516
|
return;
|
|
6424
6517
|
}
|
|
@@ -6426,10 +6519,22 @@ function createSuperDocUI(options) {
|
|
|
6426
6519
|
const clearActiveReviewTarget = hostMethod(review, "clearActiveReviewTarget");
|
|
6427
6520
|
if (!getActiveReviewTarget || !clearActiveReviewTarget) return;
|
|
6428
6521
|
const activeTarget = safeCall(() => getActiveReviewTarget(), null);
|
|
6429
|
-
if (isPlainObject(activeTarget) && activeTarget.entityType ===
|
|
6522
|
+
if (isPlainObject(activeTarget) && activeTarget.entityType === entityType) safeCall(() => clearActiveReviewTarget(), void 0);
|
|
6523
|
+
};
|
|
6524
|
+
const mirrorTrackedChangeFocusToHost = (next) => mirrorReviewFocusToHost("trackedChange", next);
|
|
6525
|
+
const readReviewFocus = () => ({
|
|
6526
|
+
change: explicitActiveChange,
|
|
6527
|
+
commentId: explicitActiveCommentId
|
|
6528
|
+
});
|
|
6529
|
+
const restoreReviewFocus = (previous) => {
|
|
6530
|
+
setExplicitActiveChange(previous.change, { invalidateQueuedNavigation: false });
|
|
6531
|
+
explicitActiveCommentId = previous.commentId;
|
|
6532
|
+
if (previous.commentId) mirrorReviewFocusToHost("comment", { id: previous.commentId });
|
|
6533
|
+
else mirrorTrackedChangeFocusToHost(previous.change);
|
|
6430
6534
|
};
|
|
6431
6535
|
const setExplicitActiveChange = (next, options) => {
|
|
6432
6536
|
explicitActiveChange = next;
|
|
6537
|
+
if (next) explicitActiveCommentId = null;
|
|
6433
6538
|
explicitActiveChangeRevision += 1;
|
|
6434
6539
|
trackChangeRevealInvalidation += 1;
|
|
6435
6540
|
if (options?.invalidateQueuedNavigation !== false) queuedTrackChangeNavigationInvalidation += 1;
|
|
@@ -7099,7 +7204,7 @@ function createSuperDocUI(options) {
|
|
|
7099
7204
|
failureCount: retryingSameToken ? prev.failureCount ?? 0 : 0,
|
|
7100
7205
|
retryAtMs: 0
|
|
7101
7206
|
});
|
|
7102
|
-
Promise.resolve(raw).then((resolved) => {
|
|
7207
|
+
const settled = Promise.resolve(raw).then((resolved) => {
|
|
7103
7208
|
const entry = asyncReads.get(key);
|
|
7104
7209
|
if (!entry || entry.inflightToken !== token) return;
|
|
7105
7210
|
asyncReads.set(key, {
|
|
@@ -7138,6 +7243,7 @@ function createSuperDocUI(options) {
|
|
|
7138
7243
|
const retryAtMs = Date.now() + retryDelayMs;
|
|
7139
7244
|
asyncReads.set(key, {
|
|
7140
7245
|
...entry,
|
|
7246
|
+
settled: void 0,
|
|
7141
7247
|
inflightToken: null,
|
|
7142
7248
|
failedToken: token,
|
|
7143
7249
|
failureCount,
|
|
@@ -7145,6 +7251,8 @@ function createSuperDocUI(options) {
|
|
|
7145
7251
|
});
|
|
7146
7252
|
scheduleAsyncReadFailureRetry(retryAtMs);
|
|
7147
7253
|
});
|
|
7254
|
+
const entry = asyncReads.get(key);
|
|
7255
|
+
if (entry?.inflightToken === token) entry.settled = settled;
|
|
7148
7256
|
return null;
|
|
7149
7257
|
};
|
|
7150
7258
|
/**
|
|
@@ -7486,15 +7594,53 @@ function createSuperDocUI(options) {
|
|
|
7486
7594
|
* Explicit whole-table changes have a complete local source range and also
|
|
7487
7595
|
* seed clears, so a delayed worker read cannot retain a cleared table target.
|
|
7488
7596
|
*/
|
|
7489
|
-
|
|
7597
|
+
function captureWholeTableParagraphSeed(host, seed, nativeSelection) {
|
|
7598
|
+
const editor = getEditor();
|
|
7599
|
+
const rawLifetime = safeCall(() => hostMethod(host, "getForegroundInteractionLifetime")?.() ?? null, null);
|
|
7600
|
+
const lifetime = hasAbortedFlag(rawLifetime) ? rawLifetime : null;
|
|
7601
|
+
const mount = safeCall(() => hostMethod(host, "getMountedHandle")?.() ?? null, null);
|
|
7602
|
+
const mode = readDocumentMode();
|
|
7603
|
+
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;
|
|
7604
|
+
if (nativeSelection) {
|
|
7605
|
+
const presentation = safeCall(() => hostMethod(host, "readAppliedSelectionPresentation")?.(), null);
|
|
7606
|
+
const applied = normalizeSelectionInfo(isPlainObject(presentation) ? presentation.selection : null);
|
|
7607
|
+
if (readHostSelectionSnapshot() !== nativeSelection || !isNonCollapsedHostSelection(nativeSelection) || !applied || selectionSignature(selectionSliceFromInfo(applied, "ready")) !== selectionSignature(selectionSliceFromInfo(seed, "ready")) || JSON.stringify(applied.tableSelection) !== JSON.stringify(seed.tableSelection)) return false;
|
|
7608
|
+
const snapshot = nativeSelection;
|
|
7609
|
+
const first = seed.target.segments[0]?.blockId, last = seed.target.segments.at(-1)?.blockId;
|
|
7610
|
+
const matches = (point, blockId) => !!blockId && isPlainObject(point) && point.blockId === blockId && storyLocatorSignature(point.story ?? snapshot.story) === storyLocatorSignature(seed.target?.story);
|
|
7611
|
+
if (!(matches(snapshot.anchor, first) && matches(snapshot.focus, last) || matches(snapshot.focus, first) && matches(snapshot.anchor, last))) return false;
|
|
7612
|
+
}
|
|
7613
|
+
wholeTableParagraphSeed = {
|
|
7614
|
+
editor,
|
|
7615
|
+
host,
|
|
7616
|
+
doc: editor.doc,
|
|
7617
|
+
mount,
|
|
7618
|
+
lifetime,
|
|
7619
|
+
sourceToken: contentToken(),
|
|
7620
|
+
mode,
|
|
7621
|
+
info: seed,
|
|
7622
|
+
nativeSelection
|
|
7623
|
+
};
|
|
7624
|
+
return true;
|
|
7625
|
+
}
|
|
7626
|
+
const refreshSelectionFromHost = (hostSelectionSnapshot, afterTypingPaint = false, wholeTableSelectionChanged = false, initialTableSelection = null) => {
|
|
7627
|
+
const host = getHost();
|
|
7490
7628
|
const foreground = foregroundMutationState();
|
|
7629
|
+
if (isNonCollapsedHostSelection(hostSelectionSnapshot) && readHostSelectionSnapshot() === hostSelectionSnapshot) {
|
|
7630
|
+
const seed = normalizeSelectionInfo(safeCall(() => hostMethod(host, "readLiveSelectionSyncSnapshot")?.(), null));
|
|
7631
|
+
if (seed && !seed.selectionTarget && captureWholeTableParagraphSeed(host, seed, hostSelectionSnapshot)) asyncReads.set("selection", {
|
|
7632
|
+
token: asyncReads.get("selection")?.token ?? null,
|
|
7633
|
+
value: seed,
|
|
7634
|
+
hasSettled: true,
|
|
7635
|
+
inflightToken: null
|
|
7636
|
+
});
|
|
7637
|
+
}
|
|
7491
7638
|
if (isNonCollapsedHostSelection(hostSelectionSnapshot) && !(foreground && foreground.active > 0)) {
|
|
7492
7639
|
typedCaretValidationHeld = false;
|
|
7493
7640
|
pendingSelectionSeedValidationToken = null;
|
|
7494
7641
|
issueAsyncRead("selection", selectionReadToken(), selectionCurrentRun, normalizeSelectionInfo);
|
|
7495
7642
|
return;
|
|
7496
7643
|
}
|
|
7497
|
-
const host = getHost();
|
|
7498
7644
|
const read = host?.readLiveSelectionSyncSnapshot;
|
|
7499
7645
|
if (typeof read !== "function") return;
|
|
7500
7646
|
const seed = normalizeSelectionInfo(safeCall(() => read.call(host), null));
|
|
@@ -7503,21 +7649,7 @@ function createSuperDocUI(options) {
|
|
|
7503
7649
|
typedCaretValidationHeld = false;
|
|
7504
7650
|
pendingSelectionSeedValidationToken = null;
|
|
7505
7651
|
wholeTableParagraphSeed = null;
|
|
7506
|
-
|
|
7507
|
-
const rawLifetime = safeCall(() => hostMethod(host, "getForegroundInteractionLifetime")?.() ?? null, null);
|
|
7508
|
-
const lifetime = hasAbortedFlag(rawLifetime) ? rawLifetime : null;
|
|
7509
|
-
const mount = safeCall(() => hostMethod(host, "getMountedHandle")?.() ?? null, null);
|
|
7510
|
-
const mode = readDocumentMode();
|
|
7511
|
-
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 = {
|
|
7512
|
-
editor,
|
|
7513
|
-
host,
|
|
7514
|
-
doc: editor.doc,
|
|
7515
|
-
mount,
|
|
7516
|
-
lifetime,
|
|
7517
|
-
sourceToken: contentToken(),
|
|
7518
|
-
mode,
|
|
7519
|
-
info: seed
|
|
7520
|
-
};
|
|
7652
|
+
captureWholeTableParagraphSeed(host, seed, initialTableSelection);
|
|
7521
7653
|
const token = selectionReadToken();
|
|
7522
7654
|
asyncReads.set("selection", {
|
|
7523
7655
|
token,
|
|
@@ -7675,7 +7807,7 @@ function createSuperDocUI(options) {
|
|
|
7675
7807
|
const directory = asyncReads.get("comments");
|
|
7676
7808
|
const directoryItems = directory?.token === contentToken() && directory.hasSettled && Array.isArray(directory.value) ? directory.value : null;
|
|
7677
7809
|
const activeValidationItems = directoryLeaseCounts.comments > 0 ? directoryItems : items;
|
|
7678
|
-
if (explicitActiveCommentId && activeValidationItems &&
|
|
7810
|
+
if (explicitActiveCommentId && activeValidationItems && (activeValidationItems !== items || listStatus === "ready")) explicitActiveCommentId = resolveActiveCommentId(activeValidationItems, explicitActiveCommentId);
|
|
7679
7811
|
const activeId = explicitActiveCommentId ?? activeIds[0] ?? null;
|
|
7680
7812
|
return {
|
|
7681
7813
|
status: combineStatus(listStatus, selection.status),
|
|
@@ -8320,12 +8452,13 @@ function createSuperDocUI(options) {
|
|
|
8320
8452
|
];
|
|
8321
8453
|
function effectiveInlineUniformityInput(selection) {
|
|
8322
8454
|
const cellTarget = currentCellSelectionTarget();
|
|
8323
|
-
const
|
|
8455
|
+
const paintedTarget = cellTarget ? null : currentUnrepresentableSelectionTarget(selection);
|
|
8456
|
+
const target = cellTarget ?? paintedTarget ?? selection.selectionTarget;
|
|
8324
8457
|
if (!target) return null;
|
|
8325
8458
|
const tableCellSelection = cellTarget ? tableCellSelectionForTarget(cellTarget) : null;
|
|
8326
8459
|
return {
|
|
8327
8460
|
target,
|
|
8328
|
-
offsetSpace: "selection",
|
|
8461
|
+
offsetSpace: cellTarget || paintedTarget ? "selection" : "kernel",
|
|
8329
8462
|
...tableCellSelection ? { tableCellSelection } : {}
|
|
8330
8463
|
};
|
|
8331
8464
|
}
|
|
@@ -8463,7 +8596,11 @@ function createSuperDocUI(options) {
|
|
|
8463
8596
|
const getNodeById = hostMethod(doc, "getNodeById");
|
|
8464
8597
|
const raw = await Promise.resolve(getNode ? getNode(address) : getNodeById?.({
|
|
8465
8598
|
nodeId: address["nodeId"],
|
|
8466
|
-
nodeType: address["nodeType"]
|
|
8599
|
+
nodeType: address["nodeType"],
|
|
8600
|
+
story: address["story"] ?? {
|
|
8601
|
+
kind: "story",
|
|
8602
|
+
storyType: "body"
|
|
8603
|
+
}
|
|
8467
8604
|
}));
|
|
8468
8605
|
return isPlainObject(raw) ? raw : void 0;
|
|
8469
8606
|
};
|
|
@@ -9009,7 +9146,8 @@ function createSuperDocUI(options) {
|
|
|
9009
9146
|
const token = contentToken();
|
|
9010
9147
|
const read = readAsync(key, token, () => isBodyStory ? doc.getNodeById({
|
|
9011
9148
|
nodeId: blockId,
|
|
9012
|
-
nodeType: "paragraph"
|
|
9149
|
+
nodeType: "paragraph",
|
|
9150
|
+
story
|
|
9013
9151
|
}) : doc.getNode(paragraphTarget(blockId, story)), (raw) => raw && typeof raw === "object" ? raw : null);
|
|
9014
9152
|
const entry = asyncReads.get(key);
|
|
9015
9153
|
return {
|
|
@@ -9218,7 +9356,11 @@ function createSuperDocUI(options) {
|
|
|
9218
9356
|
const isBodyStory = !story || story.storyType === "body";
|
|
9219
9357
|
const raw = story && typeof doc.getNode === "function" ? await doc.getNode(paragraphTarget(blockId, story)) : isBodyStory && typeof doc.getNodeById === "function" ? await doc.getNodeById({
|
|
9220
9358
|
nodeId: blockId,
|
|
9221
|
-
nodeType: "paragraph"
|
|
9359
|
+
nodeType: "paragraph",
|
|
9360
|
+
story: {
|
|
9361
|
+
kind: "story",
|
|
9362
|
+
storyType: "body"
|
|
9363
|
+
}
|
|
9222
9364
|
}) : null;
|
|
9223
9365
|
return readParagraphIndentationFromResult(raw && typeof raw === "object" ? raw : null);
|
|
9224
9366
|
} catch {
|
|
@@ -9895,14 +10037,15 @@ function createSuperDocUI(options) {
|
|
|
9895
10037
|
const tableSelection = isPlainObject(handles) ? handles.selection : void 0;
|
|
9896
10038
|
const subscribeWholeTable = hostMethod(tableSelection, "subscribeWholeTable");
|
|
9897
10039
|
if (subscribeWholeTable) {
|
|
9898
|
-
const refreshWholeTable = () => {
|
|
10040
|
+
const refreshWholeTable = (initial = false) => {
|
|
10041
|
+
const native = initial ? readHostSelectionSnapshot() : null;
|
|
9899
10042
|
selectionEpoch += 1;
|
|
9900
|
-
refreshSelectionFromHost(void 0, false, true);
|
|
10043
|
+
refreshSelectionFromHost(void 0, false, true, native);
|
|
9901
10044
|
recompute("host-selection");
|
|
9902
10045
|
};
|
|
9903
|
-
const detach = subscribeWholeTable(refreshWholeTable);
|
|
10046
|
+
const detach = subscribeWholeTable(() => refreshWholeTable());
|
|
9904
10047
|
if (typeof detach === "function") unsubscribeCallbacks.push(() => detach());
|
|
9905
|
-
if (hostMethod(tableSelection, "getWholeTableNodeId")?.()) refreshWholeTable();
|
|
10048
|
+
if (hostMethod(tableSelection, "getWholeTableNodeId")?.()) refreshWholeTable(true);
|
|
9906
10049
|
}
|
|
9907
10050
|
} catch {
|
|
9908
10051
|
currentHostSelectionSource = null;
|
|
@@ -9923,10 +10066,35 @@ function createSuperDocUI(options) {
|
|
|
9923
10066
|
};
|
|
9924
10067
|
let trackedChangeNavigationInFlight = 0;
|
|
9925
10068
|
let lastPublishedHostReviewTarget;
|
|
10069
|
+
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);
|
|
9926
10070
|
const syncTrackedChangeFocusFromHostReviewTarget = (rawTarget, rawSnapshot) => {
|
|
9927
10071
|
const rejection = (rawSnapshot && typeof rawSnapshot === "object" ? rawSnapshot : null)?.lastInteractionRejection;
|
|
9928
|
-
if (rawTarget == null && rejection && typeof rejection === "object" && rejection.code === "review-target-invalidated" && rejection.detail === "not-painted" && explicitActiveChange) return false;
|
|
10072
|
+
if (rawTarget == null && rejection && typeof rejection === "object" && rejection.code === "review-target-invalidated" && rejection.detail === "not-painted" && (explicitActiveChange || explicitActiveCommentId)) return false;
|
|
9929
10073
|
const target = rawTarget && typeof rawTarget === "object" ? rawTarget : null;
|
|
10074
|
+
if (target?.entityType === "comment" && typeof target.entityId === "string" && target.entityId.length > 0) {
|
|
10075
|
+
const commentId = resolveActiveCommentId(state?.comments.items ?? [], target.entityId) ?? target.entityId;
|
|
10076
|
+
const republished = isRepublishedHostReviewTarget(rawTarget, lastPublishedHostReviewTarget?.raw);
|
|
10077
|
+
lastPublishedHostReviewTarget = {
|
|
10078
|
+
raw: rawTarget,
|
|
10079
|
+
focus: null,
|
|
10080
|
+
origin: target.origin
|
|
10081
|
+
};
|
|
10082
|
+
if (republished || explicitActiveCommentId === commentId && !explicitActiveChange) return false;
|
|
10083
|
+
setExplicitActiveChange(null);
|
|
10084
|
+
explicitActiveCommentId = commentId;
|
|
10085
|
+
return true;
|
|
10086
|
+
}
|
|
10087
|
+
const previousTarget = lastPublishedHostReviewTarget?.raw;
|
|
10088
|
+
if (!target && isPlainObject(previousTarget) && previousTarget.entityType === "comment") {
|
|
10089
|
+
lastPublishedHostReviewTarget = {
|
|
10090
|
+
raw: rawTarget,
|
|
10091
|
+
focus: null,
|
|
10092
|
+
origin: void 0
|
|
10093
|
+
};
|
|
10094
|
+
if (!explicitActiveCommentId) return false;
|
|
10095
|
+
explicitActiveCommentId = null;
|
|
10096
|
+
return true;
|
|
10097
|
+
}
|
|
9930
10098
|
let next = null;
|
|
9931
10099
|
if (target?.entityType === "trackedChange" && typeof target.entityId === "string" && target.entityId.length > 0) {
|
|
9932
10100
|
const targetStory = target.story && typeof target.story === "object" ? target.story : void 0;
|
|
@@ -9951,7 +10119,7 @@ function createSuperDocUI(options) {
|
|
|
9951
10119
|
}
|
|
9952
10120
|
if (rawTarget == null && next == null && explicitActiveChange != null && hasPendingTrackChangeRevealFocus(explicitActiveChange)) return false;
|
|
9953
10121
|
const previousPublication = lastPublishedHostReviewTarget;
|
|
9954
|
-
if (previousPublication && (rawTarget
|
|
10122
|
+
if (previousPublication && (isRepublishedHostReviewTarget(rawTarget, previousPublication.raw) || target?.origin === "panel" && previousPublication.origin === "panel" && next && previousPublication.focus && explicitActiveChangesEqual(previousPublication.focus, next))) return false;
|
|
9955
10123
|
lastPublishedHostReviewTarget = {
|
|
9956
10124
|
raw: rawTarget,
|
|
9957
10125
|
focus: next,
|
|
@@ -10329,11 +10497,16 @@ function createSuperDocUI(options) {
|
|
|
10329
10497
|
* ordinary/insertion selections are visible-space, while a selection that
|
|
10330
10498
|
* reaches painted deleted text is projected in tracked space by the host.
|
|
10331
10499
|
*
|
|
10332
|
-
* Cross-block
|
|
10333
|
-
*
|
|
10500
|
+
* Cross-block and object-containing coverage use the model-backed tracked
|
|
10501
|
+
* target when the explicit text selection cannot represent the range.
|
|
10334
10502
|
*/
|
|
10335
10503
|
function trackDecisionRangeFromSelection(selection) {
|
|
10336
10504
|
if (selection.empty) return null;
|
|
10505
|
+
if (!selection.selectionTarget && selection.trackedTarget) return {
|
|
10506
|
+
kind: "range",
|
|
10507
|
+
coordinateSpace: "tracked",
|
|
10508
|
+
range: selection.trackedTarget
|
|
10509
|
+
};
|
|
10337
10510
|
const explicit = selection.selectionTarget;
|
|
10338
10511
|
const start = explicit?.start;
|
|
10339
10512
|
const end = explicit?.end;
|
|
@@ -10487,7 +10660,7 @@ function createSuperDocUI(options) {
|
|
|
10487
10660
|
kind: "blocked",
|
|
10488
10661
|
reason: SUPERDOC_UI_REASONS.operationUnavailable
|
|
10489
10662
|
};
|
|
10490
|
-
if (!selection.selectionTarget) return null;
|
|
10663
|
+
if (!selection.selectionTarget && !selection.trackedTarget && selection.target?.kind !== "text") return null;
|
|
10491
10664
|
const target = trackDecisionRangeFromSelection(selection);
|
|
10492
10665
|
if (!target && route() !== "id") return {
|
|
10493
10666
|
kind: "blocked",
|
|
@@ -10827,25 +11000,35 @@ function createSuperDocUI(options) {
|
|
|
10827
11000
|
pendingCommandSettlement = settledResults.length ? Promise.all(settledResults).then((results) => combineCommandResults(results)) : null;
|
|
10828
11001
|
return combineCommandResults(immediateResults);
|
|
10829
11002
|
};
|
|
10830
|
-
/**
|
|
10831
|
-
* Call an inline `format.*` operation against the live selection. Mirrors
|
|
10832
|
-
* `callEditorMutation` (suggesting mode adds `changeMode: 'tracked'`), and
|
|
10833
|
-
* when the target is the host's own editable `selectionTarget` it also
|
|
10834
|
-
* carries the PRIVATE V2 option `offsetSpace: 'selection'` (browser
|
|
10835
|
-
* selection offsets count an inline object as one caret position). The
|
|
10836
|
-
* option is not part of public `MutationOptions`; this is the same cast
|
|
10837
|
-
* pattern the delete/replace callers use.
|
|
10838
|
-
*/
|
|
10839
11003
|
function currentCellSelectionTarget() {
|
|
11004
|
+
return captureInputSelectionTarget(true);
|
|
11005
|
+
}
|
|
11006
|
+
function captureInputSelectionTarget(requireTableCells = false) {
|
|
10840
11007
|
const handles = safeCall(() => hostMethod(getHost(), "getHandles")?.(), null);
|
|
10841
11008
|
const selection = isPlainObject(handles) ? handles.selection : void 0;
|
|
10842
11009
|
const held = hostMethod(selection, "getSnapshot")?.();
|
|
10843
|
-
if (!isPlainObject(held) || !held.tableCells) return null;
|
|
11010
|
+
if (requireTableCells && (!isPlainObject(held) || !held.tableCells)) return null;
|
|
10844
11011
|
const resolved = hostMethod(selection, "toSelectionTarget")?.();
|
|
10845
11012
|
return isPlainObject(resolved) && resolved.kind === "ok" && resolved.mode === "range" ? capturedTableCellTarget(resolved.target) : null;
|
|
10846
11013
|
}
|
|
11014
|
+
function currentUnrepresentableSelectionTarget(selection) {
|
|
11015
|
+
if (selection.empty || selection.selectionTarget || selection.target?.kind !== "text") return null;
|
|
11016
|
+
return heldPaintedTextSelectionTarget();
|
|
11017
|
+
}
|
|
11018
|
+
function heldPaintedTextSelectionTarget() {
|
|
11019
|
+
const target = captureInputSelectionTarget();
|
|
11020
|
+
if (target) paintedInlineTargets.add(target);
|
|
11021
|
+
return target;
|
|
11022
|
+
}
|
|
10847
11023
|
function resolveInlineCommandTarget(selection) {
|
|
10848
|
-
|
|
11024
|
+
const cells = currentCellSelectionTarget();
|
|
11025
|
+
if (cells) return cells;
|
|
11026
|
+
if (!selection.empty && !selection.selectionTarget && selection.target?.kind === "text") {
|
|
11027
|
+
const snapshot = readHostSelectionSnapshot();
|
|
11028
|
+
const painted = currentUnrepresentableSelectionTarget(selection);
|
|
11029
|
+
if (painted) return snapshot && appliedSelectionPresentation(selection) && readHostSelectionSnapshot() === snapshot ? painted : null;
|
|
11030
|
+
}
|
|
11031
|
+
return resolveInlineSelectionTarget(selection);
|
|
10849
11032
|
}
|
|
10850
11033
|
function tableCellSelectionForTarget(target) {
|
|
10851
11034
|
const cellTarget = currentCellSelectionTarget();
|
|
@@ -10865,10 +11048,15 @@ function createSuperDocUI(options) {
|
|
|
10865
11048
|
offsetSpace: "selection",
|
|
10866
11049
|
tableCellSelection
|
|
10867
11050
|
});
|
|
11051
|
+
const paintedTarget = input?.target;
|
|
11052
|
+
if (paintedTarget !== null && typeof paintedTarget === "object" && (paintedInlineTargets.has(paintedTarget) || paintedTarget.coordinateSpace === "tracked")) return op(input, {
|
|
11053
|
+
...options,
|
|
11054
|
+
offsetSpace: "selection"
|
|
11055
|
+
});
|
|
10868
11056
|
if (!selection.selectionTarget) return options ? op(input, options) : op(input);
|
|
10869
11057
|
return op(input, {
|
|
10870
11058
|
...options,
|
|
10871
|
-
offsetSpace: "
|
|
11059
|
+
offsetSpace: "kernel"
|
|
10872
11060
|
});
|
|
10873
11061
|
};
|
|
10874
11062
|
/** Build the `format.paragraph.*` / `styles.paragraph.*` input for a block. */
|
|
@@ -11097,13 +11285,16 @@ function createSuperDocUI(options) {
|
|
|
11097
11285
|
};
|
|
11098
11286
|
pendingCommandSettlement = (async () => {
|
|
11099
11287
|
const plans = await Promise.all(blockIds.map((blockId) => planBlock(blockId).catch(() => null)));
|
|
11100
|
-
|
|
11288
|
+
const allListItems = plans.length === blockIds.length && plans.every((plan) => plan?.kind === "list");
|
|
11289
|
+
const preserveFirstItemLevel = blockIds.length === 1 && story.storyType === "body";
|
|
11290
|
+
if (allListItems && (readDocumentMode() !== "suggesting" || preserveFirstItemLevel)) {
|
|
11101
11291
|
const rangeRoute = mode === "indent" ? "lists.indentRange" : "lists.outdentRange";
|
|
11102
11292
|
const rangeOp = resolveDocOperation(doc, rangeRoute);
|
|
11103
11293
|
if (rangeOp) try {
|
|
11104
11294
|
return await settleOperationResult(callEditorMutation(rangeRoute, rangeOp, {
|
|
11105
11295
|
paraIds: blockIds,
|
|
11106
|
-
story
|
|
11296
|
+
story,
|
|
11297
|
+
...preserveFirstItemLevel ? { preserveFirstItemLevel: true } : {}
|
|
11107
11298
|
})).settled;
|
|
11108
11299
|
} catch {
|
|
11109
11300
|
return false;
|
|
@@ -11643,23 +11834,32 @@ function createSuperDocUI(options) {
|
|
|
11643
11834
|
const record = readLinkPayloadRecord(payload);
|
|
11644
11835
|
return Boolean(readLinkPayloadTarget(payload) || isPlainObject(record.hyperlinkTarget) || isPlainObject(record.textTarget));
|
|
11645
11836
|
};
|
|
11646
|
-
const
|
|
11837
|
+
const currentWholeTableParagraphOwner = () => {
|
|
11647
11838
|
const owner = wholeTableParagraphSeed, host = getHost();
|
|
11648
|
-
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
|
|
11839
|
+
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;
|
|
11649
11840
|
const tableId = owner.info.tableSelection?.tableId;
|
|
11650
11841
|
const activeTable = safeCall(() => {
|
|
11651
11842
|
const handles = hostMethod(host, "getHandles")?.();
|
|
11652
11843
|
return hostMethod(isPlainObject(handles) ? handles.selection : void 0, "getWholeTableNodeId")?.();
|
|
11653
11844
|
}, null);
|
|
11654
|
-
if (!tableId || activeTable !== tableId || state.selection.tableSelection?.type !== "table" || state.selection.tableSelection.tableId !== tableId || selectionSignature(state.selection) !== selectionSignature(selectionSliceFromInfo(owner.info, "ready"))) return
|
|
11845
|
+
if (!tableId || activeTable !== tableId || state.selection.tableSelection?.type !== "table" || state.selection.tableSelection.tableId !== tableId || selectionSignature(state.selection) !== selectionSignature(selectionSliceFromInfo(owner.info, "ready"))) return null;
|
|
11655
11846
|
const applied = appliedSelectionPresentation(state.selection);
|
|
11656
11847
|
const info = normalizeSelectionInfo(applied?.selection);
|
|
11657
|
-
return
|
|
11848
|
+
return info && JSON.stringify(info.tableSelection) === JSON.stringify(owner.info.tableSelection) ? {
|
|
11849
|
+
owner,
|
|
11850
|
+
info
|
|
11851
|
+
} : null;
|
|
11852
|
+
};
|
|
11853
|
+
const currentWholeTableParagraphSelection = () => {
|
|
11854
|
+
const current = currentWholeTableParagraphOwner();
|
|
11855
|
+
if (!current) return false;
|
|
11856
|
+
return current.owner.info.selectionTarget ? selectionInfoMatchesHost(current.info) : current.owner.nativeSelection !== null && readHostSelectionSnapshot() === current.owner.nativeSelection;
|
|
11658
11857
|
};
|
|
11659
11858
|
const commandSelectionIsReady = (id, descriptor, payload) => {
|
|
11660
11859
|
const foreground = foregroundMutationState();
|
|
11661
11860
|
if (foreground && (foreground.active > 0 || foreground.pending > 0)) return false;
|
|
11662
11861
|
if (descriptor?.blockParagraph && currentWholeTableParagraphSelection()) return true;
|
|
11862
|
+
if (descriptor?.blockParagraph && state.selection.tableSelection?.type === "table" && !state.selection.selectionTarget) return false;
|
|
11663
11863
|
if (state.selection.status !== "ready") return false;
|
|
11664
11864
|
if (trackDecisionCommand(id)?.scope === "id") return true;
|
|
11665
11865
|
if (!descriptor || descriptor.disposition !== "routed") return true;
|
|
@@ -12080,10 +12280,23 @@ function createSuperDocUI(options) {
|
|
|
12080
12280
|
const cellTarget = currentCellSelectionTarget();
|
|
12081
12281
|
const tableCellSelection = tableCellSelectionForTarget(cellTarget);
|
|
12082
12282
|
const rawSelection = typeof selectionApi?.["current"] === "function" ? await Promise.resolve(selectionApi["current"]({ includeText: true })) : readSelectionInfoLive().value;
|
|
12283
|
+
const selection = normalizeSelectionInfo(rawSelection);
|
|
12284
|
+
let paintedTarget = null;
|
|
12285
|
+
if (selection && !selection.empty && !selection.selectionTarget && selection.target?.kind === "text" && !cellTarget) {
|
|
12286
|
+
const nativeSelection = readHostSelectionSnapshot();
|
|
12287
|
+
paintedTarget = heldPaintedTextSelectionTarget();
|
|
12288
|
+
if (paintedTarget && (!nativeSelection || !appliedSelectionPresentation(selectionSliceFromInfo(selection, "ready")) || readHostSelectionSnapshot() !== nativeSelection)) return {
|
|
12289
|
+
selection: null,
|
|
12290
|
+
cellTarget: null,
|
|
12291
|
+
tableCellSelection: null,
|
|
12292
|
+
paintedTarget: null
|
|
12293
|
+
};
|
|
12294
|
+
}
|
|
12083
12295
|
return {
|
|
12084
|
-
selection
|
|
12296
|
+
selection,
|
|
12085
12297
|
cellTarget,
|
|
12086
|
-
tableCellSelection
|
|
12298
|
+
tableCellSelection,
|
|
12299
|
+
paintedTarget
|
|
12087
12300
|
};
|
|
12088
12301
|
};
|
|
12089
12302
|
const waitForSelectionSettle = () => new Promise((resolve) => setTimeout(resolve, 16));
|
|
@@ -12101,7 +12314,7 @@ function createSuperDocUI(options) {
|
|
|
12101
12314
|
break;
|
|
12102
12315
|
}
|
|
12103
12316
|
if (selectionRead?.selection && !selectionRead.selection.empty && key !== painter.sourceSelectionKey) {
|
|
12104
|
-
await applyFormatPainter(selectionRead.selection, selectionRead.cellTarget, selectionRead.tableCellSelection);
|
|
12317
|
+
await applyFormatPainter(selectionRead.selection, selectionRead.cellTarget, selectionRead.tableCellSelection, selectionRead.paintedTarget);
|
|
12105
12318
|
return;
|
|
12106
12319
|
}
|
|
12107
12320
|
if (painter.snapshot?.paragraph) {
|
|
@@ -12109,10 +12322,10 @@ function createSuperDocUI(options) {
|
|
|
12109
12322
|
const caretSel = caretRead.selection;
|
|
12110
12323
|
if (!caretSel) return;
|
|
12111
12324
|
if (selectionKey(caretSel) === painter.sourceSelectionKey) return;
|
|
12112
|
-
await applyFormatPainter(caretSel, caretRead.cellTarget, caretRead.tableCellSelection);
|
|
12325
|
+
await applyFormatPainter(caretSel, caretRead.cellTarget, caretRead.tableCellSelection, caretRead.paintedTarget);
|
|
12113
12326
|
}
|
|
12114
12327
|
};
|
|
12115
|
-
const applyFormatPainter = async (selection, cellTarget, tableCellSelection) => {
|
|
12328
|
+
const applyFormatPainter = async (selection, cellTarget, tableCellSelection, paintedTarget) => {
|
|
12116
12329
|
const snap = painter.snapshot;
|
|
12117
12330
|
if (!snap) {
|
|
12118
12331
|
if (painter.mode === "armed") exitFormatPainter();
|
|
@@ -12130,7 +12343,7 @@ function createSuperDocUI(options) {
|
|
|
12130
12343
|
return;
|
|
12131
12344
|
}
|
|
12132
12345
|
const selTarget = selection.target;
|
|
12133
|
-
const selectionTarget = cellTarget ?? selection.selectionTarget;
|
|
12346
|
+
const selectionTarget = cellTarget ?? paintedTarget ?? selection.selectionTarget;
|
|
12134
12347
|
const selectionIsEmpty = selection.empty === true;
|
|
12135
12348
|
const segments = Array.isArray(selTarget?.segments) ? selTarget.segments : [];
|
|
12136
12349
|
const targetStory = selTarget?.story;
|
|
@@ -12368,13 +12581,16 @@ function createSuperDocUI(options) {
|
|
|
12368
12581
|
const snapshot = selectionSub.get();
|
|
12369
12582
|
if (snapshot.empty) return null;
|
|
12370
12583
|
const cells = currentCellSelectionTarget();
|
|
12584
|
+
const painted = cells ? null : currentUnrepresentableSelectionTarget(snapshot);
|
|
12585
|
+
const hostSelection = selectionHostSnapshots.get(snapshot);
|
|
12586
|
+
if ((cells || painted || hostSelection && !snapshot.selectionTarget) && (!hostSelection || readHostSelectionSnapshot() !== hostSelection)) return null;
|
|
12371
12587
|
if (!snapshot.target && !snapshot.selectionTarget && !cells) return null;
|
|
12372
12588
|
const capture = {
|
|
12373
12589
|
...snapshot,
|
|
12374
12590
|
capturedAt: Date.now(),
|
|
12375
|
-
...cells ? { _tableCellSelectionTarget: cells } : {}
|
|
12591
|
+
...cells ? { _tableCellSelectionTarget: cells } : {},
|
|
12592
|
+
...painted ? { _paintedSelectionTarget: painted } : {}
|
|
12376
12593
|
};
|
|
12377
|
-
const hostSelection = selectionHostSnapshots.get(snapshot);
|
|
12378
12594
|
if (hostSelection) selectionHostSnapshots.set(capture, hostSelection);
|
|
12379
12595
|
return capture;
|
|
12380
12596
|
},
|
|
@@ -12400,7 +12616,13 @@ function createSuperDocUI(options) {
|
|
|
12400
12616
|
ok: false,
|
|
12401
12617
|
reason: SUPERDOC_UI_REASONS.targetUnresolved
|
|
12402
12618
|
});
|
|
12403
|
-
const
|
|
12619
|
+
const hasPaintedTarget = "_paintedSelectionTarget" in capture;
|
|
12620
|
+
const paintedTarget = hasPaintedTarget ? capturedTableCellTarget(capture._paintedSelectionTarget) : null;
|
|
12621
|
+
if (hasPaintedTarget && !paintedTarget) return done({
|
|
12622
|
+
ok: false,
|
|
12623
|
+
reason: SUPERDOC_UI_REASONS.targetUnresolved
|
|
12624
|
+
});
|
|
12625
|
+
const target = cellTarget ?? paintedTarget ?? selectionTargetForRestore(capture);
|
|
12404
12626
|
if (!target) return done({
|
|
12405
12627
|
ok: false,
|
|
12406
12628
|
reason: SUPERDOC_UI_REASONS.targetUnresolved
|
|
@@ -12413,7 +12635,7 @@ function createSuperDocUI(options) {
|
|
|
12413
12635
|
reason: resolved.reason
|
|
12414
12636
|
});
|
|
12415
12637
|
try {
|
|
12416
|
-
return done(normalizeHostSelectionApplyResult(hostMethod(resolved.helper, "apply")?.(target, ...cellTarget ? [{ tableCells: true }] : [])));
|
|
12638
|
+
return done(normalizeHostSelectionApplyResult(hostMethod(resolved.helper, "apply")?.(target, ...cellTarget ? [{ tableCells: true }] : paintedTarget ? [{ offsetSpace: "selection" }] : [])));
|
|
12417
12639
|
} catch {
|
|
12418
12640
|
return done({
|
|
12419
12641
|
ok: false,
|
|
@@ -12832,6 +13054,10 @@ function createSuperDocUI(options) {
|
|
|
12832
13054
|
};
|
|
12833
13055
|
const commentsSub = sliceHandle((s) => s.comments);
|
|
12834
13056
|
const commentsSnap = directorySnapshotHandle(commentsSub, select((s) => computeCommentsDirectorySnapshot(s.selection, s.comments)), "comments");
|
|
13057
|
+
documentResetHooks.push(() => {
|
|
13058
|
+
setExplicitActiveChange(null);
|
|
13059
|
+
explicitActiveCommentId = null;
|
|
13060
|
+
});
|
|
12835
13061
|
const comments = {
|
|
12836
13062
|
get: commentsSnap.get,
|
|
12837
13063
|
getSnapshot: commentsSnap.getSnapshot,
|
|
@@ -12925,6 +13151,7 @@ function createSuperDocUI(options) {
|
|
|
12925
13151
|
setActive: (commentId) => {
|
|
12926
13152
|
if (commentId == null) {
|
|
12927
13153
|
explicitActiveCommentId = null;
|
|
13154
|
+
mirrorReviewFocusToHost("comment", null);
|
|
12928
13155
|
recompute();
|
|
12929
13156
|
return true;
|
|
12930
13157
|
}
|
|
@@ -12937,7 +13164,9 @@ function createSuperDocUI(options) {
|
|
|
12937
13164
|
const resolvedId = resolveActiveCommentId(items, commentId);
|
|
12938
13165
|
if (!resolvedId) return false;
|
|
12939
13166
|
if (!items.some((entry) => readEntityId(entry) === resolvedId)) return false;
|
|
13167
|
+
setExplicitActiveChange(null);
|
|
12940
13168
|
explicitActiveCommentId = resolvedId;
|
|
13169
|
+
mirrorReviewFocusToHost("comment", { id: resolvedId });
|
|
12941
13170
|
recompute();
|
|
12942
13171
|
return true;
|
|
12943
13172
|
},
|
|
@@ -12997,7 +13226,7 @@ function createSuperDocUI(options) {
|
|
|
12997
13226
|
};
|
|
12998
13227
|
const navigateAndScrollCurrentRequest = async (step, requestedAtInvalidation) => {
|
|
12999
13228
|
if (queuedTrackChangeNavigationInvalidation !== requestedAtInvalidation) return { success: false };
|
|
13000
|
-
const
|
|
13229
|
+
const previousFocus = readReviewFocus();
|
|
13001
13230
|
const activeId = navigateTrackChange(step, { invalidateQueuedNavigation: false });
|
|
13002
13231
|
if (activeId == null) return { success: false };
|
|
13003
13232
|
const optimisticActiveChange = explicitActiveChange;
|
|
@@ -13005,7 +13234,7 @@ function createSuperDocUI(options) {
|
|
|
13005
13234
|
const isCurrent = () => queuedTrackChangeNavigationInvalidation === requestedAtInvalidation && explicitActiveChange === optimisticActiveChange && explicitActiveChangeRevision === optimisticRevision;
|
|
13006
13235
|
const rollback = () => {
|
|
13007
13236
|
if (!isCurrent()) return;
|
|
13008
|
-
|
|
13237
|
+
restoreReviewFocus(previousFocus);
|
|
13009
13238
|
recompute();
|
|
13010
13239
|
};
|
|
13011
13240
|
if (optimisticActiveChange) pendingTrackChangeRevealFocuses.add(optimisticActiveChange);
|
|
@@ -13025,10 +13254,8 @@ function createSuperDocUI(options) {
|
|
|
13025
13254
|
shouldContinue: isCurrent
|
|
13026
13255
|
});
|
|
13027
13256
|
if (!isCurrent()) return { success: false };
|
|
13028
|
-
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible)
|
|
13029
|
-
|
|
13030
|
-
mirrorTrackedChangeFocusToHost(previousActiveChange);
|
|
13031
|
-
} else {
|
|
13257
|
+
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible) rollback();
|
|
13258
|
+
else {
|
|
13032
13259
|
if (result.ok) await restampVisibleTrackedChangeCarrierAliases(activeId);
|
|
13033
13260
|
if (!isCurrent()) return { success: false };
|
|
13034
13261
|
mirrorTrackedChangeFocusToHost(optimisticActiveChange);
|
|
@@ -13159,7 +13386,7 @@ function createSuperDocUI(options) {
|
|
|
13159
13386
|
const matchingRow = matchStory ? loadedItems.find((item) => entityRowMatchesRequest(item, publicId, matchStory)) : loadedItems.find((item) => readEntityId(item) === publicId);
|
|
13160
13387
|
const story = matchStory ? requestedStory : readEntityRequestStory(matchingRow);
|
|
13161
13388
|
const importedId = deriveTrackedChangeImportedId(matchingRow);
|
|
13162
|
-
const
|
|
13389
|
+
const previousFocus = readReviewFocus();
|
|
13163
13390
|
const requestedActiveChange = {
|
|
13164
13391
|
id: publicId,
|
|
13165
13392
|
...story ? { story } : {},
|
|
@@ -13187,7 +13414,7 @@ function createSuperDocUI(options) {
|
|
|
13187
13414
|
const isCurrent = () => trackChangeRevealInvalidation === revealInvalidation && explicitActiveChange === optimisticActiveChange && explicitActiveChangeRevision === optimisticRevision;
|
|
13188
13415
|
const rollback = () => {
|
|
13189
13416
|
if (!isCurrent()) return;
|
|
13190
|
-
|
|
13417
|
+
restoreReviewFocus(previousFocus);
|
|
13191
13418
|
recompute();
|
|
13192
13419
|
};
|
|
13193
13420
|
recompute();
|
|
@@ -13201,10 +13428,8 @@ function createSuperDocUI(options) {
|
|
|
13201
13428
|
success: false,
|
|
13202
13429
|
ok: false
|
|
13203
13430
|
};
|
|
13204
|
-
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible)
|
|
13205
|
-
|
|
13206
|
-
mirrorTrackedChangeFocusToHost(previousActiveChange);
|
|
13207
|
-
} else {
|
|
13431
|
+
if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible) rollback();
|
|
13432
|
+
else {
|
|
13208
13433
|
if (result.ok) await restampVisibleTrackedChangeCarrierAliases(publicId);
|
|
13209
13434
|
if (!isCurrent()) return {
|
|
13210
13435
|
success: false,
|
|
@@ -13539,14 +13764,14 @@ function createSuperDocUI(options) {
|
|
|
13539
13764
|
if (root instanceof HTMLElement) return root;
|
|
13540
13765
|
return null;
|
|
13541
13766
|
};
|
|
13542
|
-
const
|
|
13543
|
-
if (typeof x !== "number" || typeof y !== "number" || !Number.isFinite(x) || !Number.isFinite(y)) return
|
|
13767
|
+
const pointHitElements = (x, y) => {
|
|
13768
|
+
if (typeof x !== "number" || typeof y !== "number" || !Number.isFinite(x) || !Number.isFinite(y)) return null;
|
|
13544
13769
|
const dom = globalThis.document;
|
|
13545
|
-
if (!dom || typeof dom.elementFromPoint !== "function") return
|
|
13770
|
+
if (!dom || typeof dom.elementFromPoint !== "function") return null;
|
|
13546
13771
|
const container = resolveVisibleHost();
|
|
13547
|
-
if (!container) return
|
|
13772
|
+
if (!container) return null;
|
|
13548
13773
|
const startEl = dom.elementFromPoint(x, y);
|
|
13549
|
-
if (!startEl || !container.contains(startEl)) return
|
|
13774
|
+
if (!startEl || !container.contains(startEl)) return null;
|
|
13550
13775
|
const primaryEls = [startEl];
|
|
13551
13776
|
const addPrimaryEl = (el) => {
|
|
13552
13777
|
if (el && container.contains(el) && !primaryEls.includes(el)) primaryEls.push(el);
|
|
@@ -13561,6 +13786,17 @@ function createSuperDocUI(options) {
|
|
|
13561
13786
|
}
|
|
13562
13787
|
for (const el of stacked) addPrimaryEl(el);
|
|
13563
13788
|
}
|
|
13789
|
+
return {
|
|
13790
|
+
container,
|
|
13791
|
+
elements: primaryEls,
|
|
13792
|
+
x,
|
|
13793
|
+
y
|
|
13794
|
+
};
|
|
13795
|
+
};
|
|
13796
|
+
const pointEntityHits = (x, y) => {
|
|
13797
|
+
const point = pointHitElements(x, y);
|
|
13798
|
+
if (!point) return [];
|
|
13799
|
+
const { container, elements: primaryEls } = point;
|
|
13564
13800
|
const markerEls = [];
|
|
13565
13801
|
const addMarkerEl = (el) => {
|
|
13566
13802
|
if (el && container.contains(el) && !markerEls.includes(el) && !primaryEls.includes(el)) markerEls.push(el);
|
|
@@ -13574,7 +13810,7 @@ function createSuperDocUI(options) {
|
|
|
13574
13810
|
} catch {
|
|
13575
13811
|
return false;
|
|
13576
13812
|
}
|
|
13577
|
-
return rect != null && x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
|
13813
|
+
return rect != null && point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom;
|
|
13578
13814
|
};
|
|
13579
13815
|
for (const el of primaryEls) {
|
|
13580
13816
|
const queryAll = el.querySelectorAll;
|
|
@@ -13598,6 +13834,18 @@ function createSuperDocUI(options) {
|
|
|
13598
13834
|
const seen = /* @__PURE__ */ new Set();
|
|
13599
13835
|
const hits = [];
|
|
13600
13836
|
for (const hit of rawHits) {
|
|
13837
|
+
if (hit.type === "decoration") {
|
|
13838
|
+
const owner = decorationOwnerForProvider(hit.id);
|
|
13839
|
+
if (!owner) continue;
|
|
13840
|
+
const key = `decoration:${owner.id}`;
|
|
13841
|
+
if (seen.has(key)) continue;
|
|
13842
|
+
seen.add(key);
|
|
13843
|
+
hits.push({
|
|
13844
|
+
type: "decoration",
|
|
13845
|
+
id: owner.id
|
|
13846
|
+
});
|
|
13847
|
+
continue;
|
|
13848
|
+
}
|
|
13601
13849
|
if (hit.type !== "trackedChange") {
|
|
13602
13850
|
const layoutStory = hit.type === "contentControl" ? layoutStoryDatasetToStoryLocator(hit.story) : void 0;
|
|
13603
13851
|
const story = hit.type === "contentControl" ? isTextboxStory(layoutStory) ? layoutStory : storyKeyToStoryLocator(hit.storyKey) ?? layoutStory : void 0;
|
|
@@ -13753,6 +14001,149 @@ function createSuperDocUI(options) {
|
|
|
13753
14001
|
if (status !== "ready") return { reason: "not-ready" };
|
|
13754
14002
|
return value ? { target: value } : { reason: "unresolved" };
|
|
13755
14003
|
};
|
|
14004
|
+
const liveDecorations = /* @__PURE__ */ new Map();
|
|
14005
|
+
const decorationOwnerForProvider = (providerId) => {
|
|
14006
|
+
const owner = currentHostVisuals()?.providerOwner?.(providerId);
|
|
14007
|
+
return isPlainObject(owner) && typeof owner.id === "string" ? owner : null;
|
|
14008
|
+
};
|
|
14009
|
+
const currentHostVisuals = () => getEditor()?.visuals ?? null;
|
|
14010
|
+
const decorationListeners = /* @__PURE__ */ new Set();
|
|
14011
|
+
let detachDecorationPointer = null;
|
|
14012
|
+
let hoveredDecorations = [];
|
|
14013
|
+
let lastPointer = {
|
|
14014
|
+
clientX: 0,
|
|
14015
|
+
clientY: 0
|
|
14016
|
+
};
|
|
14017
|
+
const decorationIdsAt = (x, y) => {
|
|
14018
|
+
const point = pointHitElements(x, y);
|
|
14019
|
+
if (!point) return [];
|
|
14020
|
+
const ids = /* @__PURE__ */ new Set();
|
|
14021
|
+
for (const element of point.elements) for (const provider of collectDecorationProvidersFromChain(element, point.container)) {
|
|
14022
|
+
const owner = decorationOwnerForProvider(provider);
|
|
14023
|
+
if (owner) ids.add(owner.id);
|
|
14024
|
+
}
|
|
14025
|
+
return [...ids];
|
|
14026
|
+
};
|
|
14027
|
+
const decorationData = (id) => {
|
|
14028
|
+
const owner = currentHostVisuals()?.ownerById?.(id);
|
|
14029
|
+
return isPlainObject(owner?.data) ? owner.data : void 0;
|
|
14030
|
+
};
|
|
14031
|
+
const emitDecorationEvent = (type, decoration, point) => {
|
|
14032
|
+
const payload = {
|
|
14033
|
+
type,
|
|
14034
|
+
id: decoration.id,
|
|
14035
|
+
...decoration.data ? { data: decoration.data } : {},
|
|
14036
|
+
clientX: point.clientX,
|
|
14037
|
+
clientY: point.clientY
|
|
14038
|
+
};
|
|
14039
|
+
for (const listener of Array.from(decorationListeners)) safeCall(() => listener(payload), void 0);
|
|
14040
|
+
};
|
|
14041
|
+
const leaveHoveredDecorations = (onlyId) => {
|
|
14042
|
+
const leaving = hoveredDecorations.filter((decoration) => onlyId === void 0 || decoration.id === onlyId);
|
|
14043
|
+
hoveredDecorations = hoveredDecorations.filter((decoration) => !leaving.includes(decoration));
|
|
14044
|
+
for (const decoration of leaving) emitDecorationEvent("hover-leave", decoration, lastPointer);
|
|
14045
|
+
};
|
|
14046
|
+
const attachDecorationPointer = () => {
|
|
14047
|
+
if (detachDecorationPointer || decorationListeners.size === 0) return;
|
|
14048
|
+
const host = resolveVisibleHost();
|
|
14049
|
+
if (!host) return;
|
|
14050
|
+
const onClick = (event) => {
|
|
14051
|
+
for (const id of decorationIdsAt(event.clientX, event.clientY)) emitDecorationEvent("click", {
|
|
14052
|
+
id,
|
|
14053
|
+
data: decorationData(id)
|
|
14054
|
+
}, event);
|
|
14055
|
+
};
|
|
14056
|
+
const onMove = (event) => {
|
|
14057
|
+
lastPointer = {
|
|
14058
|
+
clientX: event.clientX,
|
|
14059
|
+
clientY: event.clientY
|
|
14060
|
+
};
|
|
14061
|
+
const nextIds = decorationIdsAt(event.clientX, event.clientY);
|
|
14062
|
+
const leaving = hoveredDecorations.filter((decoration) => !nextIds.includes(decoration.id));
|
|
14063
|
+
const kept = hoveredDecorations.filter((decoration) => nextIds.includes(decoration.id));
|
|
14064
|
+
const entering = nextIds.filter((id) => !kept.some((decoration) => decoration.id === id)).map((id) => ({
|
|
14065
|
+
id,
|
|
14066
|
+
data: decorationData(id)
|
|
14067
|
+
}));
|
|
14068
|
+
hoveredDecorations = [...kept, ...entering];
|
|
14069
|
+
for (const decoration of leaving) emitDecorationEvent("hover-leave", decoration, event);
|
|
14070
|
+
for (const decoration of entering) emitDecorationEvent("hover-enter", decoration, event);
|
|
14071
|
+
};
|
|
14072
|
+
const onLeave = (event) => {
|
|
14073
|
+
lastPointer = {
|
|
14074
|
+
clientX: event.clientX,
|
|
14075
|
+
clientY: event.clientY
|
|
14076
|
+
};
|
|
14077
|
+
leaveHoveredDecorations();
|
|
14078
|
+
};
|
|
14079
|
+
host.addEventListener("click", onClick);
|
|
14080
|
+
host.addEventListener("pointermove", onMove);
|
|
14081
|
+
host.addEventListener("pointerleave", onLeave);
|
|
14082
|
+
detachDecorationPointer = () => {
|
|
14083
|
+
host.removeEventListener("click", onClick);
|
|
14084
|
+
host.removeEventListener("pointermove", onMove);
|
|
14085
|
+
host.removeEventListener("pointerleave", onLeave);
|
|
14086
|
+
leaveHoveredDecorations();
|
|
14087
|
+
detachDecorationPointer = null;
|
|
14088
|
+
};
|
|
14089
|
+
};
|
|
14090
|
+
const subscribeDecorationPointer = (listener) => {
|
|
14091
|
+
if (disposed) throw new Error("ui.decorations.subscribe called on a destroyed UI controller.");
|
|
14092
|
+
decorationListeners.add(listener);
|
|
14093
|
+
attachDecorationPointer();
|
|
14094
|
+
return () => {
|
|
14095
|
+
decorationListeners.delete(listener);
|
|
14096
|
+
if (decorationListeners.size === 0) detachDecorationPointer?.();
|
|
14097
|
+
};
|
|
14098
|
+
};
|
|
14099
|
+
documentResetHooks.push(() => {
|
|
14100
|
+
leaveHoveredDecorations();
|
|
14101
|
+
const current = currentHostVisuals();
|
|
14102
|
+
for (const [handle, owner] of Array.from(liveDecorations)) if (owner.visuals !== current || owner.generation !== current.generation()) handle.dispose();
|
|
14103
|
+
});
|
|
14104
|
+
activeEditorResetHooks.push(() => {
|
|
14105
|
+
detachDecorationPointer?.();
|
|
14106
|
+
attachDecorationPointer();
|
|
14107
|
+
});
|
|
14108
|
+
const createDecorationsHandle = (track) => ({
|
|
14109
|
+
subscribe: (listener) => {
|
|
14110
|
+
const unsubscribe = subscribeDecorationPointer(listener);
|
|
14111
|
+
track?.({ dispose: unsubscribe });
|
|
14112
|
+
return unsubscribe;
|
|
14113
|
+
},
|
|
14114
|
+
highlight: (id, options) => {
|
|
14115
|
+
if (disposed) throw new Error("ui.decorations.highlight called on a destroyed UI controller.");
|
|
14116
|
+
const visuals = currentHostVisuals();
|
|
14117
|
+
if (!visuals) throw new Error("ui.decorations.highlight requires a ready document.");
|
|
14118
|
+
const inner = visuals.highlight(id, options);
|
|
14119
|
+
let handleDisposed = false;
|
|
14120
|
+
const handle = {
|
|
14121
|
+
id: inner.id,
|
|
14122
|
+
replace: (targets) => inner.replace(targets),
|
|
14123
|
+
add: (targets) => inner.add(targets),
|
|
14124
|
+
clear: () => {
|
|
14125
|
+
if (handleDisposed) return;
|
|
14126
|
+
inner.clear();
|
|
14127
|
+
leaveHoveredDecorations(inner.id);
|
|
14128
|
+
},
|
|
14129
|
+
invalidate: () => inner.invalidate(),
|
|
14130
|
+
dispose: () => {
|
|
14131
|
+
if (handleDisposed) return;
|
|
14132
|
+
handleDisposed = true;
|
|
14133
|
+
liveDecorations.delete(handle);
|
|
14134
|
+
inner.dispose();
|
|
14135
|
+
leaveHoveredDecorations(inner.id);
|
|
14136
|
+
}
|
|
14137
|
+
};
|
|
14138
|
+
liveDecorations.set(handle, {
|
|
14139
|
+
visuals,
|
|
14140
|
+
generation: visuals.generation()
|
|
14141
|
+
});
|
|
14142
|
+
track?.(handle);
|
|
14143
|
+
return handle;
|
|
14144
|
+
}
|
|
14145
|
+
});
|
|
14146
|
+
const decorations = createDecorationsHandle();
|
|
13756
14147
|
const viewport = {
|
|
13757
14148
|
getRects: async (input) => {
|
|
13758
14149
|
const initialHost = getHost();
|
|
@@ -14730,6 +15121,92 @@ function createSuperDocUI(options) {
|
|
|
14730
15121
|
}
|
|
14731
15122
|
}, 120);
|
|
14732
15123
|
};
|
|
15124
|
+
const updateStyleToMatchSelection = (input) => {
|
|
15125
|
+
const mode = readDocumentMode();
|
|
15126
|
+
if (mode === "viewing") return failedReceipt("The document is read-only.", "DOCUMENT_READONLY");
|
|
15127
|
+
if (mode === "suggesting") return failedReceipt("A style definition cannot be changed as a tracked suggestion.", "PRECONDITION_FAILED");
|
|
15128
|
+
const sourceToken = contentToken();
|
|
15129
|
+
const readPositionKey = () => {
|
|
15130
|
+
const snapshot = readHostSelectionSnapshot();
|
|
15131
|
+
if (!snapshot) return null;
|
|
15132
|
+
return JSON.stringify({
|
|
15133
|
+
story: snapshot.story,
|
|
15134
|
+
tableCells: snapshot.tableCells,
|
|
15135
|
+
points: ["anchor", "focus"].map((side) => {
|
|
15136
|
+
const point = snapshot[side];
|
|
15137
|
+
return point ? [
|
|
15138
|
+
point.blockId,
|
|
15139
|
+
point.blockOffset,
|
|
15140
|
+
point.trackedBlockOffset,
|
|
15141
|
+
point.story,
|
|
15142
|
+
point.inlineAffinity,
|
|
15143
|
+
point.outsideContentControl,
|
|
15144
|
+
point.visualCaret
|
|
15145
|
+
] : null;
|
|
15146
|
+
})
|
|
15147
|
+
});
|
|
15148
|
+
};
|
|
15149
|
+
const requestedPosition = readPositionKey();
|
|
15150
|
+
const stale = failedReceipt("The selection or document changed while reading its style.", "REVISION_MISMATCH");
|
|
15151
|
+
return readSelectionInfoFresh().then((selection) => {
|
|
15152
|
+
const selectionToken = selectionKey(selection);
|
|
15153
|
+
const isCurrent = () => !disposed && contentToken() === sourceToken && readPositionKey() === requestedPosition && selectionKey(state.selection) === selectionToken && readDocumentMode() === mode;
|
|
15154
|
+
if (!isCurrent()) return stale;
|
|
15155
|
+
const active = computeActiveParagraphStyle(selection, getStyleCatalog().cache).style;
|
|
15156
|
+
const story = storyLocatorSignature(selectionStory(selection));
|
|
15157
|
+
const keys = [styleCatalogReadKey({ includePreview: true }), ...selectionBlockIds(selection).map((id) => `node:${story}:${id}`)];
|
|
15158
|
+
const unreadable = failedReceipt("The selection formatting could not be read.", "PRECONDITION_FAILED");
|
|
15159
|
+
const run = (active) => {
|
|
15160
|
+
if (keys.some((key) => {
|
|
15161
|
+
const entry = asyncReads.get(key);
|
|
15162
|
+
return entry && (!entry.hasSettled || entry.token !== sourceToken || entry.failedToken === sourceToken);
|
|
15163
|
+
})) return unreadable;
|
|
15164
|
+
const styleId = input?.styleId ?? active.styleId;
|
|
15165
|
+
if (!styleId) return failedReceipt("Choose a style to update: the selection does not have a single paragraph style.", "INVALID_TARGET");
|
|
15166
|
+
const doc = getDoc();
|
|
15167
|
+
const readSelection = resolveDocOperation(doc, "format.readSelection");
|
|
15168
|
+
const apply = resolveDocOperation(doc, "styles.apply");
|
|
15169
|
+
if (!readSelection || !apply) return failedReceipt("Updating a style to match the selection is unavailable.");
|
|
15170
|
+
let reads;
|
|
15171
|
+
try {
|
|
15172
|
+
reads = [readSelection({
|
|
15173
|
+
selection: "current",
|
|
15174
|
+
keys: STYLE_MATCH_READ_KEYS,
|
|
15175
|
+
view: "effective"
|
|
15176
|
+
}), readSelection({
|
|
15177
|
+
selection: "current",
|
|
15178
|
+
keys: STYLE_MATCH_READ_KEYS,
|
|
15179
|
+
view: "direct"
|
|
15180
|
+
})];
|
|
15181
|
+
} catch {
|
|
15182
|
+
return unreadable;
|
|
15183
|
+
}
|
|
15184
|
+
return Promise.all(reads).then(([effective, direct]) => {
|
|
15185
|
+
if (!isCurrent()) return stale;
|
|
15186
|
+
const patch = buildStyleMatchPatch(effective, direct, { selectionUsesStyle: !active.mixed && active.styleId === styleId });
|
|
15187
|
+
if (Object.keys(patch).length === 0) return failedReceipt("The selection already matches the style.", "NO_OP");
|
|
15188
|
+
const fallback = failedReceipt("Updating the style failed.");
|
|
15189
|
+
return safeCall(() => settleWorkflowReceipt(apply({
|
|
15190
|
+
target: {
|
|
15191
|
+
scope: "style",
|
|
15192
|
+
styleId,
|
|
15193
|
+
channel: "run"
|
|
15194
|
+
},
|
|
15195
|
+
patch
|
|
15196
|
+
}), fallback), fallback);
|
|
15197
|
+
}, () => unreadable);
|
|
15198
|
+
};
|
|
15199
|
+
const pending = keys.flatMap((key) => {
|
|
15200
|
+
const entry = asyncReads.get(key);
|
|
15201
|
+
return entry?.inflightToken === sourceToken && entry.settled ? [entry.settled] : [];
|
|
15202
|
+
});
|
|
15203
|
+
if (pending.length === 0) return run(active);
|
|
15204
|
+
return Promise.all(pending).then(() => {
|
|
15205
|
+
if (!isCurrent()) return stale;
|
|
15206
|
+
return run(computeActiveParagraphStyle(selection, getStyleCatalog().cache).style);
|
|
15207
|
+
});
|
|
15208
|
+
});
|
|
15209
|
+
};
|
|
14733
15210
|
const stylesSub = sliceHandle((s) => s.styles);
|
|
14734
15211
|
const stylesSnap = snapshotHandle(stylesSub);
|
|
14735
15212
|
const styles = {
|
|
@@ -14742,7 +15219,8 @@ function createSuperDocUI(options) {
|
|
|
14742
15219
|
return readStyleCatalogLive(options).value;
|
|
14743
15220
|
},
|
|
14744
15221
|
getQuickGallery: () => stylesSub.get().quickGallery,
|
|
14745
|
-
getActiveParagraphStyle: () => computeActiveParagraphStyle(state.selection, getStyleCatalog().cache).style
|
|
15222
|
+
getActiveParagraphStyle: () => computeActiveParagraphStyle(state.selection, getStyleCatalog().cache).style,
|
|
15223
|
+
updateToMatchSelection: (input) => updateStyleToMatchSelection(input)
|
|
14746
15224
|
};
|
|
14747
15225
|
const openWatermarkSurface = hostMethod(superdoc, "openSurface");
|
|
14748
15226
|
const watermark = createWatermarkController({
|
|
@@ -14757,6 +15235,7 @@ function createSuperDocUI(options) {
|
|
|
14757
15235
|
const createScope = () => {
|
|
14758
15236
|
const scopeUnsubs = [];
|
|
14759
15237
|
return {
|
|
15238
|
+
decorations: createDecorationsHandle((handle) => scopeUnsubs.push(() => handle.dispose())),
|
|
14760
15239
|
select: (selector, equality) => {
|
|
14761
15240
|
const sub = select(selector, equality);
|
|
14762
15241
|
return {
|
|
@@ -14777,6 +15256,9 @@ function createSuperDocUI(options) {
|
|
|
14777
15256
|
if (disposed) return;
|
|
14778
15257
|
watermark.destroy();
|
|
14779
15258
|
clearContentControlHighlight();
|
|
15259
|
+
for (const handle of Array.from(liveDecorations.keys())) handle.dispose();
|
|
15260
|
+
detachDecorationPointer?.();
|
|
15261
|
+
decorationListeners.clear();
|
|
14780
15262
|
disposed = true;
|
|
14781
15263
|
completedFallbackSearch = null;
|
|
14782
15264
|
if (searchRefreshTimer !== null) clearTimeout(searchRefreshTimer);
|
|
@@ -14859,6 +15341,7 @@ function createSuperDocUI(options) {
|
|
|
14859
15341
|
zoom,
|
|
14860
15342
|
document: documentHandle,
|
|
14861
15343
|
viewport,
|
|
15344
|
+
decorations,
|
|
14862
15345
|
metadata,
|
|
14863
15346
|
tables,
|
|
14864
15347
|
search,
|
|
@@ -15077,4 +15560,4 @@ function commandIsActive(descriptor, selection) {
|
|
|
15077
15560
|
return descriptor.activeMark ? selection.activeMarks.includes(descriptor.activeMark) : false;
|
|
15078
15561
|
}
|
|
15079
15562
|
//#endregion
|
|
15080
|
-
export {
|
|
15563
|
+
export { createInteractionHistory as _, registerFirstPartyCommandMutation as a, recordInteraction as b, applyV2CommentInvalidationFromMutation as c, createImageFilePicker as d, resolveImageSrc as f, closeInteractionHistory as g, DOM_CLASS_NAMES as h, readFirstPartyPageNumbers as i, getV2TrackedChangeMutationImpact as l, isSyntheticTrackedChangeCommentLaneItem as m, executeFirstPartyCommandAsync as n, isRecord as o, shallowEqual as p, executeFirstPartyShortcutAsync as r, BUILT_IN_COMMAND_IDS as s, createSuperDocUI as t, isPlainObject as u, getWorkflowRecording as v, isWorkflowRecordingEnabled as y };
|