superdoc 2.0.0-next.27 → 2.0.0-next.28

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.
Files changed (32) hide show
  1. package/dist/chunks/{create-super-doc-ui-Dvl3EZsv.es.js → create-super-doc-ui-BlnUCtrx.es.js} +171 -51
  2. package/dist/chunks/{create-super-doc-ui-pYMthdDn.cjs → create-super-doc-ui-CZBUMdjl.cjs} +171 -51
  3. package/dist/collaboration-upgrade-engine.cjs +1 -1
  4. package/dist/collaboration-upgrade-engine.es.js +1 -1
  5. package/dist/document-api/src/contract/operation-definitions.d.ts +1 -1
  6. package/dist/document-api/src/track-changes/track-changes.d.ts +6 -2
  7. package/dist/document-api/src/types/clipboard.d.ts +5 -1
  8. package/dist/document-api/src/types/table-operations.types.d.ts +6 -4
  9. package/dist/document-api/src/types/track-changes.types.d.ts +15 -0
  10. package/dist/layout-engine/contracts/src/incremental-dependency.d.ts +10 -0
  11. package/dist/layout-engine/contracts/src/index.d.ts +38 -0
  12. package/dist/layout-engine/layout-bridge/src/incrementalLayout.d.ts +23 -1
  13. package/dist/layout-engine/layout-engine/src/index.d.ts +17 -0
  14. package/dist/layout-engine/layout-engine/src/paginator.d.ts +16 -0
  15. package/dist/layout-engine/layout-engine/src/paragraph-layout-eligibility.d.ts +1 -4
  16. package/dist/public/ui-react.cjs +1 -1
  17. package/dist/public/ui-react.es.js +1 -1
  18. package/dist/public/ui.cjs +1 -1
  19. package/dist/public/ui.es.js +1 -1
  20. package/dist/style.css +82 -63
  21. package/dist/style.layered.css +82 -63
  22. package/dist/superdoc/src/core/types/index.d.ts +7 -0
  23. package/dist/superdoc/src/public/ui/reasons.d.ts +8 -0
  24. package/dist/superdoc/src/stores/comments-store.d.ts +9 -9
  25. package/dist/superdoc/src/stores/helpers/floating-comment-instances.d.ts +2 -10
  26. package/dist/superdoc/src/stores/superdoc-store.d.ts +27 -27
  27. package/dist/superdoc.cjs +137 -29
  28. package/dist/superdoc.es.js +137 -29
  29. package/dist-cdn/style.layered.css +1 -1
  30. package/dist-cdn/superdoc.min.css +1 -1
  31. package/dist-cdn/superdoc.min.js +37 -37
  32. package/package.json +1 -1
@@ -311,7 +311,8 @@ const SUPERDOC_UI_REASONS = {
311
311
  historyEmpty: "history-empty",
312
312
  searchUnavailable: "search-unavailable",
313
313
  searchInvalidPattern: "search-invalid-pattern",
314
- replaceUnsupported: "replace-unsupported"
314
+ replaceUnsupported: "replace-unsupported",
315
+ contentControlLocked: "content-control-locked"
315
316
  };
316
317
  const BUILT_IN_COMMAND_IDS = {
317
318
  bold: "bold",
@@ -2451,6 +2452,31 @@ function createSuperDocUI(options) {
2451
2452
  let explicitActiveChange = null;
2452
2453
  let explicitActiveChangeRevision = 0;
2453
2454
  let queuedTrackChangeNavigationInvalidation = 0;
2455
+ const mirrorTrackedChangeFocusToHost = (next) => {
2456
+ const host = getHost();
2457
+ if (typeof host?.getHandles !== "function") return;
2458
+ const handles = safeCall(() => host.getHandles(), null);
2459
+ const review = handles?.review;
2460
+ if (!review) return;
2461
+ if (next) {
2462
+ if (typeof review.setActiveReviewTarget !== "function") return;
2463
+ const layout = handles?.layout;
2464
+ safeCall(() => review.setActiveReviewTarget({
2465
+ entityType: "trackedChange",
2466
+ entityId: next.id,
2467
+ ...next.paintedEntityId ? { paintedEntityId: next.paintedEntityId } : {},
2468
+ origin: "panel",
2469
+ layoutEpoch: typeof layout?.generation === "number" ? layout.generation : 0,
2470
+ story: next.story ?? {
2471
+ kind: "story",
2472
+ storyType: "body"
2473
+ }
2474
+ }), null);
2475
+ return;
2476
+ }
2477
+ if (typeof review.getActiveReviewTarget !== "function" || typeof review.clearActiveReviewTarget !== "function") return;
2478
+ if (safeCall(() => review.getActiveReviewTarget(), null)?.entityType === "trackedChange") safeCall(() => review.clearActiveReviewTarget(), void 0);
2479
+ };
2454
2480
  const setExplicitActiveChange = (next, options$1) => {
2455
2481
  explicitActiveChange = next;
2456
2482
  explicitActiveChangeRevision += 1;
@@ -2464,6 +2490,8 @@ function createSuperDocUI(options) {
2464
2490
  let lastEffectiveInlineReadKey = null;
2465
2491
  let pendingEffectiveInlineRead = null;
2466
2492
  let asyncRefreshScheduled = false;
2493
+ let asyncReadFailureRetryTimer = null;
2494
+ let asyncReadFailureRetryAtMs = 0;
2467
2495
  let foregroundAsyncRetryTimer = null;
2468
2496
  let pendingSelectionSeedValidationToken = null;
2469
2497
  let typingContentInvalidationTimer = null;
@@ -2478,6 +2506,19 @@ function createSuperDocUI(options) {
2478
2506
  if (typeof queueMicrotask === "function") queueMicrotask(run);
2479
2507
  else Promise.resolve().then(run);
2480
2508
  };
2509
+ const ASYNC_READ_FAILURE_RETRY_BASE_MS = 250;
2510
+ const ASYNC_READ_FAILURE_RETRY_MAX_MS = 5e3;
2511
+ const scheduleAsyncReadFailureRetry = (retryAtMs) => {
2512
+ if (disposed) return;
2513
+ if (asyncReadFailureRetryTimer && asyncReadFailureRetryAtMs <= retryAtMs) return;
2514
+ if (asyncReadFailureRetryTimer) clearTimeout(asyncReadFailureRetryTimer);
2515
+ asyncReadFailureRetryAtMs = retryAtMs;
2516
+ asyncReadFailureRetryTimer = setTimeout(() => {
2517
+ asyncReadFailureRetryTimer = null;
2518
+ asyncReadFailureRetryAtMs = 0;
2519
+ if (!disposed) recompute();
2520
+ }, Math.max(0, retryAtMs - Date.now()));
2521
+ };
2481
2522
  const editorIdentityIds = /* @__PURE__ */ new WeakMap();
2482
2523
  let editorIdentityCounter = 0;
2483
2524
  const editorIdentityId = (editor) => {
@@ -2714,7 +2755,7 @@ function createSuperDocUI(options) {
2714
2755
  const read = host?.getDocumentLoadingSnapshot;
2715
2756
  if (typeof read !== "function") return "unknown";
2716
2757
  const stage = safeCall(() => read.call(host), null)?.sourceStage;
2717
- if (stage === "source-loading") return "loading";
2758
+ if (stage === "opening" || stage === "ready-window" || stage === "source-loading") return "loading";
2718
2759
  if (stage === "source-complete" || stage === "source-failed" || stage === "source-cancelled") return "complete";
2719
2760
  return "unknown";
2720
2761
  };
@@ -2880,17 +2921,24 @@ function createSuperDocUI(options) {
2880
2921
  token,
2881
2922
  value: normalize(raw),
2882
2923
  hasSettled: true,
2883
- inflightToken: null
2924
+ inflightToken: null,
2925
+ failedToken: null,
2926
+ failureCount: 0,
2927
+ retryAtMs: 0
2884
2928
  };
2885
2929
  asyncReads.set(key, settled);
2886
2930
  return settled;
2887
2931
  }
2888
2932
  const prev = asyncReads.get(key);
2933
+ const retryingSameToken = prev?.failedToken === token;
2889
2934
  asyncReads.set(key, {
2890
2935
  token: prev?.token ?? null,
2891
2936
  value: prev?.value ?? null,
2892
2937
  hasSettled: prev?.hasSettled ?? false,
2893
- inflightToken: token
2938
+ inflightToken: token,
2939
+ failedToken: retryingSameToken ? token : null,
2940
+ failureCount: retryingSameToken ? prev.failureCount ?? 0 : 0,
2941
+ retryAtMs: 0
2894
2942
  });
2895
2943
  Promise.resolve(raw).then((resolved) => {
2896
2944
  const entry = asyncReads.get(key);
@@ -2899,17 +2947,26 @@ function createSuperDocUI(options) {
2899
2947
  token,
2900
2948
  value: normalize(resolved),
2901
2949
  hasSettled: true,
2902
- inflightToken: null
2950
+ inflightToken: null,
2951
+ failedToken: null,
2952
+ failureCount: 0,
2953
+ retryAtMs: 0
2903
2954
  });
2904
2955
  scheduleAsyncRefresh();
2905
2956
  }, () => {
2906
2957
  const entry = asyncReads.get(key);
2907
2958
  if (!entry || entry.inflightToken !== token) return;
2959
+ const failureCount = entry.failedToken === token ? (entry.failureCount ?? 0) + 1 : 1;
2960
+ const retryDelayMs = Math.min(ASYNC_READ_FAILURE_RETRY_MAX_MS, ASYNC_READ_FAILURE_RETRY_BASE_MS * 2 ** Math.min(failureCount - 1, 8));
2961
+ const retryAtMs = Date.now() + retryDelayMs;
2908
2962
  asyncReads.set(key, {
2909
2963
  ...entry,
2910
- inflightToken: null
2964
+ inflightToken: null,
2965
+ failedToken: token,
2966
+ failureCount,
2967
+ retryAtMs
2911
2968
  });
2912
- scheduleAsyncRefresh();
2969
+ scheduleAsyncReadFailureRetry(retryAtMs);
2913
2970
  });
2914
2971
  return null;
2915
2972
  };
@@ -2970,6 +3027,17 @@ function createSuperDocUI(options) {
2970
3027
  status: "pending"
2971
3028
  };
2972
3029
  }
3030
+ if (entry?.failedToken === token && entry.inflightToken == null && (entry.retryAtMs ?? 0) > Date.now()) {
3031
+ scheduleAsyncReadFailureRetry(entry.retryAtMs);
3032
+ if (entry.hasSettled) return {
3033
+ value: entry.value,
3034
+ status: "stale"
3035
+ };
3036
+ return {
3037
+ value: null,
3038
+ status: "pending"
3039
+ };
3040
+ }
2973
3041
  if (!entry && key.startsWith("effInline:") && shouldDeferEffectiveInlineRead(key)) return {
2974
3042
  value: null,
2975
3043
  status: "pending"
@@ -3021,6 +3089,9 @@ function createSuperDocUI(options) {
3021
3089
  reviewMutationReconciler.reset();
3022
3090
  lastCoordinatorEditor = editor;
3023
3091
  asyncReads.clear();
3092
+ if (asyncReadFailureRetryTimer) clearTimeout(asyncReadFailureRetryTimer);
3093
+ asyncReadFailureRetryTimer = null;
3094
+ asyncReadFailureRetryAtMs = 0;
3024
3095
  if (pendingEffectiveInlineRead?.timer) clearTimeout(pendingEffectiveInlineRead.timer);
3025
3096
  pendingEffectiveInlineRead = null;
3026
3097
  lastEffectiveInlineReadKey = null;
@@ -3284,22 +3355,29 @@ function createSuperDocUI(options) {
3284
3355
  activeIds
3285
3356
  };
3286
3357
  };
3287
- const computeActiveContentControlIds = (ccApi, selection$1) => {
3358
+ const computeActiveContentControlLockModes = (ccApi, selection$1) => {
3288
3359
  if (!ccApi || typeof ccApi.listInRange !== "function") return {
3289
- ids: [],
3360
+ lockModesById: /* @__PURE__ */ new Map(),
3290
3361
  status: "ready"
3291
3362
  };
3292
3363
  const range = selectionBlockRange(selection$1);
3293
3364
  if (!range) return {
3294
- ids: [],
3365
+ lockModesById: /* @__PURE__ */ new Map(),
3295
3366
  status: "ready"
3296
3367
  };
3297
3368
  const { value, status } = readAsync(`contentControls:inRange:${selectionSignature(selection$1)}`, contentToken(), () => ccApi.listInRange(range), (raw) => raw && Array.isArray(raw.items) ? raw.items : []);
3298
3369
  const rows = value ?? [];
3299
- const ids = [];
3300
- for (const row of rows) if (typeof row?.id === "string") ids.push(row.id);
3370
+ const lockModesById = /* @__PURE__ */ new Map();
3371
+ for (const row of rows) if (typeof row?.id === "string") lockModesById.set(row.id, typeof row.lockMode === "string" ? row.lockMode : "unlocked");
3372
+ return {
3373
+ lockModesById,
3374
+ status
3375
+ };
3376
+ };
3377
+ const computeActiveContentControlIds = (ccApi, selection$1) => {
3378
+ const { lockModesById, status } = computeActiveContentControlLockModes(ccApi, selection$1);
3301
3379
  return {
3302
- ids,
3380
+ ids: [...lockModesById.keys()],
3303
3381
  status
3304
3382
  };
3305
3383
  };
@@ -3615,14 +3693,20 @@ function createSuperDocUI(options) {
3615
3693
  frozenProjectedValues = projectedInlineValues;
3616
3694
  frozenProjectedValuesKey = `${selectionKey(selection$1)}:${contentToken()}`;
3617
3695
  }
3696
+ const ccApi = doc?.contentControls;
3697
+ const { lockModesById } = computeActiveContentControlLockModes(ccApi, selection$1);
3618
3698
  const states = {};
3619
- for (const id of allCommandIds()) states[id] = computeCommandState(id, doc, selection$1, projectedInlineValues);
3699
+ for (const id of allCommandIds()) states[id] = computeCommandState(id, doc, selection$1, projectedInlineValues, lockModesById);
3620
3700
  return states;
3621
3701
  };
3622
3702
  const unavailableRouteReason = (doc) => {
3623
3703
  if (doc) return SUPERDOC_UI_REASONS.operationUnavailable;
3624
3704
  return getEditor() ? SUPERDOC_UI_REASONS.documentApiUnavailable : SUPERDOC_UI_REASONS.notReady;
3625
3705
  };
3706
+ const blocksContentStyling = (lockMode) => lockMode === "contentLocked" || lockMode === "sdtContentLocked";
3707
+ const contentControlLockReason = (lockModesById) => {
3708
+ for (const lockMode of lockModesById.values()) if (blocksContentStyling(lockMode)) return SUPERDOC_UI_REASONS.contentControlLocked;
3709
+ };
3626
3710
  const trackDecisionReason = (command, supported, readonly, selection$1, doc) => {
3627
3711
  if (!supported) return command.scope === "all" ? SUPERDOC_UI_REASONS.bulkDecisionsDisabled : unavailableRouteReason(doc);
3628
3712
  if (readonly) return SUPERDOC_UI_REASONS.documentReadonly;
@@ -3645,7 +3729,7 @@ function createSuperDocUI(options) {
3645
3729
  if (support && (support.status === "supported" || support.enabled === true)) return void 0;
3646
3730
  return SUPERDOC_UI_REASONS.bulkDecisionsDisabled;
3647
3731
  };
3648
- const computeCommandState = (id, doc, selection$1, projectedInlineValues) => {
3732
+ const computeCommandState = (id, doc, selection$1, projectedInlineValues, lockModesById = /* @__PURE__ */ new Map()) => {
3649
3733
  if (customCommands.has(id)) return normalizeCommandState({
3650
3734
  supported: true,
3651
3735
  enabled: true,
@@ -3720,6 +3804,13 @@ function createSuperDocUI(options) {
3720
3804
  supported: true,
3721
3805
  reason: SUPERDOC_UI_REASONS.documentReadonly
3722
3806
  }, "builtin");
3807
+ const lockReason = contentControlLockReason(lockModesById);
3808
+ if (lockReason) return normalizeCommandState({
3809
+ enabled: false,
3810
+ active: false,
3811
+ supported: true,
3812
+ reason: lockReason
3813
+ }, "builtin");
3723
3814
  const enabled = selectionBlockIds(selection$1).length > 0 || resolveInlineSelectionTarget(selection$1) != null;
3724
3815
  return normalizeCommandState({
3725
3816
  enabled,
@@ -3770,18 +3861,28 @@ function createSuperDocUI(options) {
3770
3861
  value,
3771
3862
  reason: SUPERDOC_UI_REASONS.documentReadonly
3772
3863
  }, "builtin");
3773
- if (descriptor.inline && !resolveInlineSelectionTarget(selection$1)) return normalizeCommandState(selectionBlockIds(selection$1).length > 0 && typeof getHost()?.setPendingInlineFormat === "function" ? {
3774
- enabled: true,
3775
- active,
3776
- supported: true,
3777
- value
3778
- } : {
3779
- enabled: false,
3780
- active,
3781
- supported: true,
3782
- value,
3783
- reason: SUPERDOC_UI_REASONS.rangeSelectionRequired
3784
- }, "builtin");
3864
+ if (descriptor.inline && !resolveInlineSelectionTarget(selection$1)) {
3865
+ const lockReason = contentControlLockReason(lockModesById);
3866
+ if (lockReason) return normalizeCommandState({
3867
+ enabled: false,
3868
+ active,
3869
+ supported: true,
3870
+ value,
3871
+ reason: lockReason
3872
+ }, "builtin");
3873
+ return normalizeCommandState(selectionBlockIds(selection$1).length > 0 && typeof getHost()?.setPendingInlineFormat === "function" ? {
3874
+ enabled: true,
3875
+ active,
3876
+ supported: true,
3877
+ value
3878
+ } : {
3879
+ enabled: false,
3880
+ active,
3881
+ supported: true,
3882
+ value,
3883
+ reason: SUPERDOC_UI_REASONS.rangeSelectionRequired
3884
+ }, "builtin");
3885
+ }
3785
3886
  if ((descriptor.blockParagraph || descriptor.list) && selectionBlockIds(selection$1).length === 0) return normalizeCommandState({
3786
3887
  enabled: false,
3787
3888
  active,
@@ -3795,6 +3896,16 @@ function createSuperDocUI(options) {
3795
3896
  supported: true,
3796
3897
  reason: SUPERDOC_UI_REASONS.rangeSelectionRequired
3797
3898
  }, "builtin");
3899
+ if (descriptor.inline) {
3900
+ const lockReason = contentControlLockReason(lockModesById);
3901
+ if (lockReason) return normalizeCommandState({
3902
+ enabled: false,
3903
+ active,
3904
+ supported: true,
3905
+ value,
3906
+ reason: lockReason
3907
+ }, "builtin");
3908
+ }
3798
3909
  return normalizeCommandState({
3799
3910
  enabled: true,
3800
3911
  active,
@@ -4753,7 +4864,10 @@ function createSuperDocUI(options) {
4753
4864
  }
4754
4865
  function executeTrackDecisionCommand(command, payload) {
4755
4866
  if (command.scope === "id" && payload == null) {
4756
- if (state.selection.activeChangeIds.length > 1) return executeTrackDecisionTargets(command.kind, state.selection.activeChangeIds);
4867
+ if (state.selection.activeChangeIds.length > 1) return executeTrackDecisionTarget(command.kind, {
4868
+ kind: "ids",
4869
+ ids: state.selection.activeChangeIds
4870
+ }, null);
4757
4871
  if (state.selection.activeChangeIds.length === 1 && !state.selection.empty && state.selection.selectionTarget) {
4758
4872
  const route = activeChangePartialDecisionRoute();
4759
4873
  if (route === "unavailable") return false;
@@ -5025,6 +5139,9 @@ function createSuperDocUI(options) {
5025
5139
  return true;
5026
5140
  };
5027
5141
  const executeClearFormattingCommand = () => {
5142
+ const doc = getDoc();
5143
+ const { lockModesById } = computeActiveContentControlLockModes(doc?.contentControls, state.selection);
5144
+ if (contentControlLockReason(lockModesById)) return false;
5028
5145
  const immediateResults = [];
5029
5146
  const settledResults = [];
5030
5147
  const record = (result) => {
@@ -5040,7 +5157,6 @@ function createSuperDocUI(options) {
5040
5157
  settledResults.push(Promise.resolve(false));
5041
5158
  }
5042
5159
  };
5043
- const doc = getDoc();
5044
5160
  const defaultStyleId = getStyleCatalog().cache?.full.defaults.paragraphStyleId ?? DEFAULT_PARAGRAPH_STYLE_ID;
5045
5161
  const rangeTarget = resolveInlineSelectionTarget(state.selection);
5046
5162
  if (rangeTarget) {
@@ -5446,7 +5562,7 @@ function createSuperDocUI(options) {
5446
5562
  const rows = Number(record.rows ?? record.rowCount);
5447
5563
  const columns = Number(record.columns ?? record.cols ?? record.colCount);
5448
5564
  if (!Number.isInteger(rows) || rows < 1 || !Number.isInteger(columns) || columns < 1) return false;
5449
- const caret = readDocumentMode() !== "suggesting" ? collapsedTextAddressFromSelection(state.selection) : null;
5565
+ const caret = collapsedTextAddressFromSelection(state.selection);
5450
5566
  const at = caret && typeof caret.blockId === "string" ? {
5451
5567
  kind: "inParagraph",
5452
5568
  target: paragraphTarget(caret.blockId),
@@ -5595,9 +5711,12 @@ function createSuperDocUI(options) {
5595
5711
  const route = descriptor.docRoute;
5596
5712
  if (!route) return false;
5597
5713
  if (descriptor.mutates && readDocumentMode() === "viewing") return false;
5598
- const op = resolveDocOperation(getDoc(), route);
5714
+ const doc = getDoc();
5715
+ const op = resolveDocOperation(doc, route);
5599
5716
  if (!op) return false;
5600
5717
  if (descriptor.inline) {
5718
+ const { lockModesById } = computeActiveContentControlLockModes(doc?.contentControls, state.selection);
5719
+ if (contentControlLockReason(lockModesById)) return false;
5601
5720
  const target = resolveInlineSelectionTarget(state.selection);
5602
5721
  if (!target) {
5603
5722
  if (state.selection.empty === false) return settleCommandExecution(false);
@@ -5855,6 +5974,12 @@ function createSuperDocUI(options) {
5855
5974
  }
5856
5975
  const doc = getDoc();
5857
5976
  if (!doc) return;
5977
+ const targetSelection = selectionSliceFromInfo(selection$1, "ready");
5978
+ const { lockModesById } = computeActiveContentControlLockModes(doc.contentControls, targetSelection);
5979
+ if (contentControlLockReason(lockModesById)) {
5980
+ recompute();
5981
+ return;
5982
+ }
5858
5983
  const selTarget = selection$1["target"];
5859
5984
  const selectionTarget = selection$1["selectionTarget"];
5860
5985
  if (!(selection$1["empty"] === true) && Object.keys(snap.inline).length > 0) {
@@ -6426,6 +6551,7 @@ function createSuperDocUI(options) {
6426
6551
  setActive: (input) => {
6427
6552
  if (input == null) {
6428
6553
  setExplicitActiveChange(null);
6554
+ mirrorTrackedChangeFocusToHost(null);
6429
6555
  recompute();
6430
6556
  return true;
6431
6557
  }
@@ -6435,6 +6561,7 @@ function createSuperDocUI(options) {
6435
6561
  story: input.story
6436
6562
  };
6437
6563
  if (typeof requested.id !== "string" || requested.id.length === 0) return false;
6564
+ const paintedEntityId = requested.id;
6438
6565
  if (requested.story) {
6439
6566
  const allStoryItems = readAllStoryTrackChanges();
6440
6567
  if (!allStoryItems) return false;
@@ -6447,7 +6574,9 @@ function createSuperDocUI(options) {
6447
6574
  if (!bodyItems.some((item) => readEntityId(item) === publicId)) return false;
6448
6575
  requested.id = publicId;
6449
6576
  }
6577
+ if (paintedEntityId !== requested.id) requested.paintedEntityId = paintedEntityId;
6450
6578
  setExplicitActiveChange(requested);
6579
+ mirrorTrackedChangeFocusToHost(requested);
6451
6580
  recompute();
6452
6581
  return true;
6453
6582
  },
@@ -6466,10 +6595,11 @@ function createSuperDocUI(options) {
6466
6595
  reason: SUPERDOC_UI_REASONS.targetUnresolved
6467
6596
  };
6468
6597
  const previousActiveChange = explicitActiveChange;
6469
- setExplicitActiveChange(story ? {
6598
+ const requestedActiveChange = story ? {
6470
6599
  id: changeId,
6471
6600
  story
6472
- } : { id: changeId });
6601
+ } : { id: changeId };
6602
+ setExplicitActiveChange(requestedActiveChange);
6473
6603
  recompute();
6474
6604
  const optimisticActiveChange = explicitActiveChange;
6475
6605
  const optimisticRevision = explicitActiveChangeRevision;
@@ -6485,6 +6615,7 @@ function createSuperDocUI(options) {
6485
6615
  ok: false
6486
6616
  };
6487
6617
  if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible) rollback();
6618
+ else mirrorTrackedChangeFocusToHost(requestedActiveChange);
6488
6619
  return result;
6489
6620
  }
6490
6621
  };
@@ -6511,12 +6642,13 @@ function createSuperDocUI(options) {
6511
6642
  const tcApi = getDoc()?.trackChanges;
6512
6643
  const isAllTarget = target.scope === "all";
6513
6644
  const isRangeTarget = target.kind === "range";
6645
+ const isMultiIdTarget = target.kind === "ids";
6514
6646
  if (bulkTrackDecisionBlockedReason({
6515
6647
  kind,
6516
6648
  scope: isAllTarget ? "all" : "id"
6517
6649
  }, tcApi)) return false;
6518
6650
  const legacyName = isAllTarget ? `${kind}All` : kind;
6519
- const op = !isRangeTarget && !story && tcApi && typeof tcApi[legacyName] === "function" ? tcApi[legacyName] : null;
6651
+ const op = !isRangeTarget && !isMultiIdTarget && !story && tcApi && typeof tcApi[legacyName] === "function" ? tcApi[legacyName] : null;
6520
6652
  const decide = tcApi && typeof tcApi.decide === "function" ? tcApi.decide : null;
6521
6653
  if (!op && !decide) return false;
6522
6654
  return op ? op.call(tcApi, changeId ?? {}) : decide.call(tcApi, {
@@ -6524,23 +6656,6 @@ function createSuperDocUI(options) {
6524
6656
  target
6525
6657
  });
6526
6658
  };
6527
- const executeTrackDecisionTargets = (kind, changeIds) => {
6528
- const immediateResults = [];
6529
- const settledResults = [];
6530
- for (const changeId of changeIds) try {
6531
- const result = settleOperationResult(callTrackDecisionTarget(kind, {
6532
- kind: "id",
6533
- id: changeId
6534
- }, changeId));
6535
- immediateResults.push(result.immediate);
6536
- settledResults.push(result.settled);
6537
- } catch {
6538
- immediateResults.push(false);
6539
- settledResults.push(Promise.resolve(false));
6540
- }
6541
- pendingCommandSettlement = Promise.all(settledResults).then((results) => combineCommandResults(results));
6542
- return settleCommandExecution(combineCommandResults(immediateResults));
6543
- };
6544
6659
  const contentControlsSub = sliceHandle((s) => s.contentControls);
6545
6660
  const findContentControl = (id) => {
6546
6661
  return contentControlsSub.get().items.find((item) => item?.id === id) ?? null;
@@ -7468,6 +7583,11 @@ function createSuperDocUI(options) {
7468
7583
  clearTimeout(foregroundAsyncRetryTimer);
7469
7584
  foregroundAsyncRetryTimer = null;
7470
7585
  }
7586
+ if (asyncReadFailureRetryTimer) {
7587
+ clearTimeout(asyncReadFailureRetryTimer);
7588
+ asyncReadFailureRetryTimer = null;
7589
+ asyncReadFailureRetryAtMs = 0;
7590
+ }
7471
7591
  if (pendingEffectiveInlineRead?.timer) {
7472
7592
  clearTimeout(pendingEffectiveInlineRead.timer);
7473
7593
  pendingEffectiveInlineRead.timer = null;