superdoc 2.0.0-next.28 → 2.0.0-next.29

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.
@@ -21,7 +21,8 @@ function getV2TrackedChangeMutationImpact(event) {
21
21
  if (upsertIds.size === 0 && removedIds.size === 0) return null;
22
22
  return {
23
23
  upsertIds,
24
- removedIds
24
+ removedIds,
25
+ reconcileMode: event.origin === "history" ? "authoritative" : "targeted"
25
26
  };
26
27
  }
27
28
  var normalizeIds = (values) => new Set(Array.from(values ?? []).filter((value) => typeof value === "string" && value.length > 0));
@@ -31,7 +32,7 @@ var itemId = (item) => {
31
32
  if (typeof item?.address?.entityId === "string" && item.address.entityId.length > 0) return item.address.entityId;
32
33
  return null;
33
34
  };
34
- var contextMatches = (left, right) => left?.adapter === right?.adapter && left?.documentId === right?.documentId && left?.editor === right?.editor;
35
+ var contextMatches = (left, right) => left?.adapter === right?.adapter && left?.documentId === right?.documentId && left?.editor === right?.editor && left?.reconcileToken === right?.reconcileToken;
35
36
  function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onReconciled }) {
36
37
  const pendingUpserts = /* @__PURE__ */ new Map();
37
38
  let sequence = 0;
@@ -48,43 +49,78 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
48
49
  }
49
50
  return clearedIds;
50
51
  };
51
- const readySnapshot = () => new Map([...pendingUpserts].filter(([, entry]) => entry.ready === true));
52
+ const readySnapshot = (reconcileMode) => new Map([...pendingUpserts].filter(([, entry]) => entry.ready === true && entry.reconcileMode === reconcileMode));
52
53
  const markRenderGatedReady = () => {
53
- for (const entry of pendingUpserts.values()) if (entry.gate === "render") entry.ready = true;
54
+ let changed = false;
55
+ for (const entry of pendingUpserts.values()) {
56
+ if (entry.gate !== "render" || entry.ready) continue;
57
+ entry.ready = true;
58
+ changed = true;
59
+ }
60
+ return changed;
61
+ };
62
+ const markEntriesReadyThrough = (maxVersion) => {
63
+ let changed = false;
64
+ for (const entry of pendingUpserts.values()) {
65
+ if (entry.version > maxVersion || entry.ready) continue;
66
+ entry.ready = true;
67
+ changed = true;
68
+ }
69
+ return changed;
54
70
  };
55
- const notifyReconciled = async (context, ids, result) => {
56
- if (ids.size === 0 || typeof onReconciled !== "function") return;
71
+ const notifyReconciled = async (context, ids, result, allowEmpty = false) => {
72
+ if (!allowEmpty && ids.size === 0 || typeof onReconciled !== "function") return;
57
73
  try {
58
74
  await onReconciled(context, ids, result);
59
75
  } catch {}
60
76
  };
61
77
  const idsFromResult = (result) => normalizeIds(result?.resolvedIds ?? (result?.items ?? []).map(itemId).filter(Boolean));
78
+ const reconcileTargetedSnapshot = async (context, snapshot, capturedGeneration) => {
79
+ const result = await reconcile(context, {
80
+ upsertIds: new Set(snapshot.keys()),
81
+ removedIds: /* @__PURE__ */ new Set(),
82
+ reconcileMode: "targeted"
83
+ });
84
+ if (!isCurrent(capturedGeneration, context)) return;
85
+ await notifyReconciled(context, clearResolved(idsFromResult(result), snapshot), result);
86
+ if (new Set([...snapshot].filter(([id, version]) => pendingUpserts.get(id) === version).map(([id]) => id)).size === 0) return;
87
+ const fallback = await hydrate(context, {
88
+ trackedChangesListMode: "interaction-prime",
89
+ refreshReason: "mutation-render-reconcile",
90
+ blocking: false
91
+ });
92
+ if (!isCurrent(capturedGeneration, context)) return;
93
+ await notifyReconciled(context, clearResolved(idsFromResult(fallback), snapshot), fallback);
94
+ };
95
+ const reconcileAuthoritativeSnapshot = async (context, snapshot, capturedGeneration) => {
96
+ const result = await hydrate(context, {
97
+ trackedChangesListMode: "all",
98
+ refreshReason: "mutation-history-render-reconcile",
99
+ blocking: true
100
+ });
101
+ if (!isCurrent(capturedGeneration, context)) return;
102
+ if (![...snapshot].some(([id, entry]) => pendingUpserts.get(id) === entry)) return;
103
+ const transportSucceeded = result?.ok === true;
104
+ const catalogIsAuthoritative = transportSucceeded && result?.complete === true && result?.sourceCoverageComplete === true;
105
+ const returnedIds = transportSucceeded ? idsFromResult(result) : /* @__PURE__ */ new Set();
106
+ const clearedIds = catalogIsAuthoritative ? clearResolved(new Set(snapshot.keys()), snapshot) : /* @__PURE__ */ new Set();
107
+ await notifyReconciled(context, catalogIsAuthoritative ? clearedIds : returnedIds, {
108
+ ...result,
109
+ reconcileMode: "authoritative"
110
+ }, true);
111
+ };
62
112
  const flush = () => {
63
- if (flushInFlight) {
64
- flushRequested = true;
65
- return flushInFlight;
66
- }
67
- const snapshot = readySnapshot();
68
- if (snapshot.size === 0) return null;
113
+ if (flushInFlight) return flushInFlight;
114
+ const targetedSnapshot = readySnapshot("targeted");
115
+ const authoritativeSnapshot = readySnapshot("authoritative");
116
+ if (targetedSnapshot.size === 0 && authoritativeSnapshot.size === 0) return null;
69
117
  const context = getContext();
70
118
  if (!context?.adapter) return null;
71
119
  flushRequested = false;
72
120
  const capturedGeneration = generation;
73
- const upsertIds = new Set(snapshot.keys());
74
- flushInFlight = Promise.resolve().then(() => reconcile(context, {
75
- upsertIds,
76
- removedIds: /* @__PURE__ */ new Set()
77
- })).then(async (result) => {
78
- if (!isCurrent(capturedGeneration, context)) return;
79
- await notifyReconciled(context, clearResolved(idsFromResult(result), snapshot), result);
80
- if (new Set([...snapshot].filter(([id, version]) => pendingUpserts.get(id) === version).map(([id]) => id)).size === 0) return;
81
- const fallback = await hydrate(context, {
82
- trackedChangesListMode: "interaction-prime",
83
- refreshReason: "mutation-render-reconcile",
84
- blocking: false
85
- });
86
- if (!isCurrent(capturedGeneration, context)) return;
87
- await notifyReconciled(context, clearResolved(idsFromResult(fallback), snapshot), fallback);
121
+ flushInFlight = Promise.resolve().then(async () => {
122
+ if (authoritativeSnapshot.size > 0) await reconcileAuthoritativeSnapshot(context, authoritativeSnapshot, capturedGeneration).catch(() => void 0);
123
+ if (targetedSnapshot.size > 0) await reconcileTargetedSnapshot(context, targetedSnapshot, capturedGeneration).catch(() => void 0);
88
124
  }).catch(() => {}).finally(() => {
89
125
  flushInFlight = null;
90
126
  if (flushRequested) flush();
@@ -93,8 +129,18 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
93
129
  };
94
130
  const enqueueWithGate = (impact, gate) => {
95
131
  if (!impact) return;
132
+ const reconcileMode = impact.reconcileMode === "authoritative" ? "authoritative" : "targeted";
96
133
  const removedIds = normalizeIds(impact.removedIds);
97
- for (const id of removedIds) pendingUpserts.delete(id);
134
+ for (const id of removedIds) {
135
+ const existing = pendingUpserts.get(id);
136
+ if (existing?.reconcileMode === "authoritative") pendingUpserts.set(id, {
137
+ ...existing,
138
+ version: ++sequence,
139
+ gate,
140
+ ready: false
141
+ });
142
+ else pendingUpserts.delete(id);
143
+ }
98
144
  const context = getContext();
99
145
  if (removedIds.size > 0 && context?.adapter) try {
100
146
  Promise.resolve(reconcile(context, {
@@ -102,16 +148,20 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
102
148
  removedIds
103
149
  })).catch(() => void 0);
104
150
  } catch {}
105
- for (const id of normalizeIds(impact.upsertIds)) if (!removedIds.has(id)) pendingUpserts.set(id, {
106
- version: ++sequence,
107
- gate,
108
- ready: false
109
- });
151
+ for (const id of normalizeIds(impact.upsertIds)) if (!removedIds.has(id)) {
152
+ const existing = pendingUpserts.get(id);
153
+ pendingUpserts.set(id, {
154
+ version: ++sequence,
155
+ gate,
156
+ ready: false,
157
+ reconcileMode: reconcileMode === "authoritative" || existing?.reconcileMode === "authoritative" ? "authoritative" : "targeted"
158
+ });
159
+ }
110
160
  };
111
161
  const enqueue = (impact) => enqueueWithGate(impact, "render");
112
- const onRender = () => {
113
- markRenderGatedReady();
114
- flushRequested = true;
162
+ const onRender = (supersedesInFlight = false) => {
163
+ const madeReady = markRenderGatedReady();
164
+ if (flushInFlight && (madeReady || supersedesInFlight)) flushRequested = true;
115
165
  flush();
116
166
  };
117
167
  return {
@@ -125,18 +175,22 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
125
175
  const context = getContext();
126
176
  if (!context?.adapter) return;
127
177
  const capturedGeneration = generation;
128
- const capturedEntries = new Map([...normalizeIds(impact.upsertIds)].flatMap((id) => {
178
+ const capturedSequence = sequence;
179
+ const impactedIds = new Set([...normalizeIds(impact.upsertIds), ...normalizeIds(impact.removedIds)]);
180
+ const capturedEntries = new Map([...impactedIds].flatMap((id) => {
129
181
  const entry = pendingUpserts.get(id);
130
182
  return entry ? [[id, entry]] : [];
131
183
  }));
132
184
  Promise.resolve().then(() => waitForPaint()).then(() => {
133
185
  if (!isCurrent(capturedGeneration, context)) return;
134
- markRenderGatedReady();
186
+ let madeReady = markRenderGatedReady();
187
+ if (markEntriesReadyThrough(capturedSequence)) madeReady = true;
135
188
  for (const [id, entry] of capturedEntries) {
136
189
  if (pendingUpserts.get(id) !== entry) continue;
190
+ if (!entry.ready) madeReady = true;
137
191
  entry.ready = true;
138
192
  }
139
- flushRequested = true;
193
+ if (flushInFlight && (madeReady || capturedSequence > 0)) flushRequested = true;
140
194
  flush();
141
195
  }).catch(() => {
142
196
  if (!isCurrent(capturedGeneration, context)) return;
@@ -2276,7 +2330,13 @@ function buildTableCommandInput(action, context) {
2276
2330
  function createSuperDocUI(options) {
2277
2331
  const superdoc = options.superdoc;
2278
2332
  const optimisticInlineValues = /* @__PURE__ */ new Map();
2333
+ const optimisticInlineToggles = /* @__PURE__ */ new Map();
2334
+ const pendingInlineToggleMutations = [];
2279
2335
  let lastOptimisticInlineSelectionSignature = null;
2336
+ let optimisticInlineToggleGeneration = 0;
2337
+ let inlineToggleMutationActive = false;
2338
+ let inlineToggleMutationIdle = Promise.resolve();
2339
+ let resolveInlineToggleMutationIdle = null;
2280
2340
  let painter = {
2281
2341
  mode: "idle",
2282
2342
  snapshot: null,
@@ -2531,6 +2591,16 @@ function createSuperDocUI(options) {
2531
2591
  return `e${id}`;
2532
2592
  };
2533
2593
  let documentMutationRevision = 0;
2594
+ let reviewMutationToken = {};
2595
+ let authoritativeTrackChangesPendingToken = null;
2596
+ let authoritativeTrackChangesRetryTimer = null;
2597
+ let authoritativeTrackChangesFailureCount = 0;
2598
+ const clearAuthoritativeTrackChangesRetry = () => {
2599
+ if (authoritativeTrackChangesRetryTimer) clearTimeout(authoritativeTrackChangesRetryTimer);
2600
+ authoritativeTrackChangesRetryTimer = null;
2601
+ authoritativeTrackChangesFailureCount = 0;
2602
+ };
2603
+ let scheduleAuthoritativeTrackChangesRetry = (_reconcileToken) => void 0;
2534
2604
  let postDecisionTrackChangesToken = null;
2535
2605
  let postDecisionTrackChangesReconcileToken = null;
2536
2606
  let postDecisionTrackChangeIds = /* @__PURE__ */ new Set();
@@ -2576,28 +2646,92 @@ function createSuperDocUI(options) {
2576
2646
  run();
2577
2647
  }, POST_DECISION_TRACKED_CHANGES_RECONCILE_DELAY_MS);
2578
2648
  };
2579
- const markPostDecisionTrackChanges = (ids) => {
2649
+ const notifyPostDecisionTrackChanges = (receipt) => {
2650
+ const notify = () => {
2651
+ if (disposed) return;
2652
+ for (const listener of [...listeners]) listener(state);
2653
+ };
2654
+ const record = isLooseObject(receipt) ? receipt : null;
2655
+ const readiness = getEditor()?.documentMutationReadiness;
2656
+ const waitForPostPaintTask = () => {
2657
+ const requestFrame = globalThis.requestAnimationFrame;
2658
+ if (typeof requestFrame !== "function") return Promise.resolve();
2659
+ return new Promise((resolve) => {
2660
+ let settled = false;
2661
+ const finish = () => {
2662
+ if (settled) return;
2663
+ settled = true;
2664
+ clearTimeout(fallback);
2665
+ resolve();
2666
+ };
2667
+ const fallback = setTimeout(finish, 250);
2668
+ requestFrame(() => requestFrame(() => setTimeout(finish, 0)));
2669
+ });
2670
+ };
2671
+ if (record?.success === true && typeof record.txId === "string" && record.txId.length > 0 && typeof readiness?.whenPainted === "function") try {
2672
+ Promise.resolve(readiness.whenPainted.call(readiness, record)).then(waitForPostPaintTask, () => void 0).then(notify, notify);
2673
+ return;
2674
+ } catch {}
2675
+ notify();
2676
+ };
2677
+ const publishPostDecisionTrackChanges = (ids, receipt) => {
2678
+ const previous = state.trackChanges;
2679
+ const items = previous.items.filter((item) => {
2680
+ const id = readEntityId(item);
2681
+ return !id || !ids.has(id);
2682
+ });
2683
+ if (items.length === previous.items.length) return;
2684
+ if (explicitActiveChange && ids.has(explicitActiveChange.id)) setExplicitActiveChange(null);
2685
+ const authors = /* @__PURE__ */ new Set();
2686
+ for (const item of items) {
2687
+ const change = trackChangesItemPayload(item);
2688
+ const row = item;
2689
+ const author = change.author ?? change.authorEmail ?? row.author ?? row.authorEmail;
2690
+ if (typeof author === "string") authors.add(author);
2691
+ }
2692
+ const removedCount = previous.items.length - items.length;
2693
+ state = {
2694
+ ...state,
2695
+ trackChanges: {
2696
+ ...previous,
2697
+ items,
2698
+ total: Math.max(items.length, previous.total - removedCount),
2699
+ activeId: previous.activeId && ids.has(previous.activeId) ? null : previous.activeId,
2700
+ authors: [...authors]
2701
+ }
2702
+ };
2703
+ notifyPostDecisionTrackChanges(receipt);
2704
+ };
2705
+ const markPostDecisionTrackChanges = (ids, receipt) => {
2580
2706
  if (ids.size === 0) return;
2581
- postDecisionTrackChangesToken = contentToken();
2582
- postDecisionTrackChangeIds = new Set(ids);
2707
+ const token = contentToken();
2708
+ const alreadyRemoved = postDecisionTrackChangesToken === token ? postDecisionTrackChangeIds : /* @__PURE__ */ new Set();
2709
+ const newlyRemoved = new Set([...ids].filter((id) => !alreadyRemoved.has(id)));
2710
+ if (newlyRemoved.size === 0) return;
2711
+ postDecisionTrackChangesToken = token;
2712
+ postDecisionTrackChangeIds = new Set([...alreadyRemoved, ...newlyRemoved]);
2583
2713
  applyPostDecisionTrackChangesToCache(postDecisionTrackChangeIds);
2584
2714
  schedulePostDecisionTrackChangesReconcile();
2585
- recompute();
2715
+ publishPostDecisionTrackChanges(newlyRemoved, receipt);
2586
2716
  };
2587
2717
  const postDecisionTrackChangeIdsForToken = (token) => postDecisionTrackChangesToken === token && postDecisionTrackChangeIds.size > 0 ? postDecisionTrackChangeIds : null;
2588
- const mergeTrackedChangeItemsIntoCache = (items) => {
2718
+ const mergeTrackedChangeItemsIntoCache = (items, orderedItems = []) => {
2589
2719
  const projected = items.map(projectTrackChangesItem).filter((item) => item != null && readEntityId(item) != null);
2590
2720
  if (projected.length === 0) return;
2721
+ const orderedIds = orderedItems.map(projectTrackChangesItem).map((item) => item == null ? null : readEntityId(item)).filter((id) => id != null);
2591
2722
  for (const key of ["trackChanges", "trackChanges:all"]) {
2592
2723
  const entry = asyncReads.get(key);
2593
2724
  const nextValue = entry?.hasSettled && Array.isArray(entry.value) ? [...entry.value] : [];
2725
+ const insertedIds = /* @__PURE__ */ new Set();
2594
2726
  let changed = false;
2595
2727
  for (const fresh of projected) {
2596
2728
  const id = readEntityId(fresh);
2597
2729
  if (!id) continue;
2598
2730
  const index = nextValue.findIndex((candidate) => readEntityId(candidate) === id);
2599
- if (index < 0) nextValue.push(fresh);
2600
- else {
2731
+ if (index < 0) {
2732
+ nextValue.push(fresh);
2733
+ insertedIds.add(id);
2734
+ } else {
2601
2735
  const previous = nextValue[index];
2602
2736
  nextValue[index] = isLooseObject(previous) ? {
2603
2737
  ...previous,
@@ -2606,6 +2740,24 @@ function createSuperDocUI(options) {
2606
2740
  }
2607
2741
  changed = true;
2608
2742
  }
2743
+ if (key === "trackChanges" && insertedIds.size > 0 && orderedIds.length > 0) {
2744
+ const placeableIds = new Set(orderedIds.filter((id) => insertedIds.has(id)));
2745
+ const insertedRows = new Map(nextValue.filter((item) => placeableIds.has(readEntityId(item) ?? "")).map((item) => [readEntityId(item), item]));
2746
+ const placedValue = nextValue.filter((item) => !placeableIds.has(readEntityId(item) ?? ""));
2747
+ for (const [orderIndex, id] of orderedIds.entries()) {
2748
+ if (!placeableIds.has(id)) continue;
2749
+ const item = insertedRows.get(id);
2750
+ if (!item) continue;
2751
+ const followingAnchor = orderedIds.slice(orderIndex + 1).map((candidateId) => placedValue.findIndex((candidate) => readEntityId(candidate) === candidateId)).find((index) => index >= 0);
2752
+ if (followingAnchor != null) {
2753
+ placedValue.splice(followingAnchor, 0, item);
2754
+ continue;
2755
+ }
2756
+ const precedingAnchor = orderedIds.slice(0, orderIndex).reverse().map((candidateId) => placedValue.findIndex((candidate) => readEntityId(candidate) === candidateId)).find((index) => index >= 0);
2757
+ placedValue.splice(precedingAnchor == null ? placedValue.length : precedingAnchor + 1, 0, item);
2758
+ }
2759
+ nextValue.splice(0, nextValue.length, ...placedValue);
2760
+ }
2609
2761
  if (!changed) continue;
2610
2762
  asyncReads.set(key, {
2611
2763
  token: entry?.token ?? null,
@@ -2615,6 +2767,57 @@ function createSuperDocUI(options) {
2615
2767
  });
2616
2768
  }
2617
2769
  };
2770
+ const replaceTrackedChangeItemsInCache = (items) => {
2771
+ const token = contentToken();
2772
+ const suppressedIds = postDecisionTrackChangeIdsForToken(token);
2773
+ const projected = items.map(projectTrackChangesItem).filter((item) => {
2774
+ if (item == null) return false;
2775
+ const id = readEntityId(item);
2776
+ return id != null && !suppressedIds?.has(id);
2777
+ });
2778
+ for (const key of ["trackChanges", "trackChanges:all"]) asyncReads.set(key, {
2779
+ token,
2780
+ value: [...projected],
2781
+ hasSettled: true,
2782
+ inflightToken: null
2783
+ });
2784
+ };
2785
+ const hydrateTrackedChanges = async (context, options$1) => {
2786
+ try {
2787
+ const listTrackedChanges = context.v2TrackedChanges?.listTrackedChanges;
2788
+ if (typeof listTrackedChanges === "function") {
2789
+ const result$1 = await Promise.resolve(listTrackedChanges.call(context.v2TrackedChanges, {
2790
+ mode: options$1.trackedChangesListMode,
2791
+ refreshReason: options$1.refreshReason,
2792
+ blocking: options$1.blocking,
2793
+ ...options$1.targetIds?.length ? { targetIds: options$1.targetIds } : {}
2794
+ }));
2795
+ const ok = options$1.trackedChangesListMode === "all" && options$1.refreshReason === "mutation-history-render-reconcile" ? result$1?.ok === true : result$1?.ok !== false;
2796
+ return {
2797
+ ok,
2798
+ items: ok && Array.isArray(result$1?.items) ? result$1.items : [],
2799
+ ...typeof result$1?.complete === "boolean" ? { complete: result$1.complete } : {},
2800
+ ...typeof result$1?.sourceCoverageComplete === "boolean" ? { sourceCoverageComplete: result$1.sourceCoverageComplete } : {}
2801
+ };
2802
+ }
2803
+ const list = context.docTrackChanges?.list;
2804
+ if (typeof list !== "function") return {
2805
+ ok: false,
2806
+ items: []
2807
+ };
2808
+ const result = await Promise.resolve(list.call(context.docTrackChanges));
2809
+ return {
2810
+ ok: true,
2811
+ items: Array.isArray(result?.items) ? result.items : []
2812
+ };
2813
+ } catch (error) {
2814
+ return {
2815
+ ok: false,
2816
+ items: [],
2817
+ failures: [error]
2818
+ };
2819
+ }
2820
+ };
2618
2821
  const reviewMutationReconciler = createV2ReviewMutationReconciler({
2619
2822
  getContext: () => {
2620
2823
  const editor = getEditor();
@@ -2628,6 +2831,7 @@ function createSuperDocUI(options) {
2628
2831
  editor,
2629
2832
  adapter,
2630
2833
  documentId: rawDocumentId == null ? null : String(rawDocumentId),
2834
+ reconcileToken: reviewMutationToken,
2631
2835
  v2TrackedChanges,
2632
2836
  docTrackChanges
2633
2837
  };
@@ -2641,6 +2845,9 @@ function createSuperDocUI(options) {
2641
2845
  resolvedIds: [],
2642
2846
  unresolvedIds: []
2643
2847
  };
2848
+ const settledTrackChanges = asyncReads.get("trackChanges");
2849
+ const cachedIds = new Set(settledTrackChanges?.hasSettled && Array.isArray(settledTrackChanges.value) ? settledTrackChanges.value.map(readEntityId).filter((id) => id != null) : []);
2850
+ const idsNeedingPlacement = new Set(requestedIds.filter((id) => !cachedIds.has(id)));
2644
2851
  const getTrackedChange = context.v2TrackedChanges?.getTrackedChange;
2645
2852
  const getRawTrackedChange = context.docTrackChanges?.get;
2646
2853
  if (typeof getTrackedChange !== "function" && typeof getRawTrackedChange !== "function") return {
@@ -2689,55 +2896,59 @@ function createSuperDocUI(options) {
2689
2896
  resolvedIds.push(read.id);
2690
2897
  } else unresolvedIds.push(read.id);
2691
2898
  }
2899
+ let orderedItems;
2900
+ const placementIds = resolvedIds.filter((id) => idsNeedingPlacement.has(id));
2901
+ if (placementIds.length > 0) {
2902
+ const orderResult = await hydrateTrackedChanges(context, {
2903
+ trackedChangesListMode: "interaction-prime",
2904
+ refreshReason: "mutation-render-reconcile",
2905
+ blocking: false,
2906
+ targetIds: placementIds
2907
+ });
2908
+ if (orderResult.ok) orderedItems = orderResult.items;
2909
+ }
2692
2910
  return {
2693
2911
  ok: unresolvedIds.length === 0,
2694
2912
  items,
2913
+ orderedItems,
2695
2914
  resolvedIds,
2696
2915
  unresolvedIds,
2697
2916
  failures: reads.filter((read) => !read.ok).map((read) => read.result)
2698
2917
  };
2699
2918
  },
2700
- hydrate: async (context, options$1) => {
2701
- try {
2702
- const listTrackedChanges = context.v2TrackedChanges?.listTrackedChanges;
2703
- if (typeof listTrackedChanges === "function") {
2704
- const result$1 = await Promise.resolve(listTrackedChanges.call(context.v2TrackedChanges, {
2705
- mode: options$1.trackedChangesListMode,
2706
- refreshReason: options$1.refreshReason,
2707
- blocking: options$1.blocking
2708
- }));
2709
- return {
2710
- ok: result$1?.ok !== false,
2711
- items: result$1?.ok !== false && Array.isArray(result$1?.items) ? result$1.items : []
2712
- };
2713
- }
2714
- const list = context.docTrackChanges?.list;
2715
- if (typeof list !== "function") return {
2716
- ok: false,
2717
- items: []
2718
- };
2719
- const result = await Promise.resolve(list.call(context.docTrackChanges));
2720
- return {
2721
- ok: true,
2722
- items: Array.isArray(result?.items) ? result.items : []
2723
- };
2724
- } catch (error) {
2725
- return {
2726
- ok: false,
2727
- items: [],
2728
- failures: [error]
2729
- };
2919
+ hydrate: hydrateTrackedChanges,
2920
+ onReconciled: (context, ids, result) => {
2921
+ if (result?.reconcileMode === "authoritative") {
2922
+ if (context.reconcileToken !== reviewMutationToken) return;
2923
+ if (result.ok === true && result.complete === true && result.sourceCoverageComplete === true) {
2924
+ clearAuthoritativeTrackChangesRetry();
2925
+ replaceTrackedChangeItemsInCache(result.items ?? []);
2926
+ authoritativeTrackChangesPendingToken = null;
2927
+ } else if (result.ok === true) {
2928
+ clearAuthoritativeTrackChangesRetry();
2929
+ mergeTrackedChangeItemsIntoCache(result.items ?? []);
2930
+ } else scheduleAuthoritativeTrackChangesRetry(context.reconcileToken);
2931
+ recompute();
2932
+ return;
2730
2933
  }
2731
- },
2732
- onReconciled: (_context, ids, result) => {
2733
2934
  mergeTrackedChangeItemsIntoCache((result?.items ?? []).filter((item) => {
2734
2935
  const projected = projectTrackChangesItem(item);
2735
2936
  const id = projected == null ? null : readEntityId(projected);
2736
2937
  return id != null && ids.has(id);
2737
- }));
2938
+ }), result?.orderedItems ?? result?.items ?? []);
2738
2939
  recompute();
2739
2940
  }
2740
2941
  });
2942
+ scheduleAuthoritativeTrackChangesRetry = (reconcileToken) => {
2943
+ if (disposed || authoritativeTrackChangesRetryTimer) return;
2944
+ const delayMs = Math.min(ASYNC_READ_FAILURE_RETRY_BASE_MS * 2 ** authoritativeTrackChangesFailureCount, ASYNC_READ_FAILURE_RETRY_MAX_MS);
2945
+ authoritativeTrackChangesFailureCount += 1;
2946
+ authoritativeTrackChangesRetryTimer = setTimeout(() => {
2947
+ authoritativeTrackChangesRetryTimer = null;
2948
+ if (disposed || authoritativeTrackChangesPendingToken === null || reconcileToken !== reviewMutationToken) return;
2949
+ reviewMutationReconciler.onRender(true);
2950
+ }, delayMs);
2951
+ };
2741
2952
  const selectionReadToken = () => `${contentToken()}|m${readDocumentMode()}|s${selectionEpoch}`;
2742
2953
  const selectionSignature = (selection$1) => JSON.stringify({
2743
2954
  t: selection$1.target ?? null,
@@ -3087,8 +3298,11 @@ function createSuperDocUI(options) {
3087
3298
  const editor = getEditor();
3088
3299
  if (editor === lastCoordinatorEditor) return;
3089
3300
  reviewMutationReconciler.reset();
3301
+ reviewMutationToken = {};
3090
3302
  lastCoordinatorEditor = editor;
3091
3303
  asyncReads.clear();
3304
+ authoritativeTrackChangesPendingToken = null;
3305
+ clearAuthoritativeTrackChangesRetry();
3092
3306
  if (asyncReadFailureRetryTimer) clearTimeout(asyncReadFailureRetryTimer);
3093
3307
  asyncReadFailureRetryTimer = null;
3094
3308
  asyncReadFailureRetryAtMs = 0;
@@ -3107,7 +3321,9 @@ function createSuperDocUI(options) {
3107
3321
  clearPostDecisionTrackChanges();
3108
3322
  };
3109
3323
  const invalidateDocumentContent = (options$1) => {
3324
+ const carryAuthoritativeTrackChangesHold = authoritativeTrackChangesPendingToken !== null;
3110
3325
  documentMutationRevision += 1;
3326
+ if (carryAuthoritativeTrackChangesHold) authoritativeTrackChangesPendingToken = contentToken();
3111
3327
  if (!options$1?.preservePostDecisionTrackChanges) clearPostDecisionTrackChanges();
3112
3328
  };
3113
3329
  const insertText = (text) => {
@@ -3298,7 +3514,12 @@ function createSuperDocUI(options) {
3298
3514
  };
3299
3515
  const readAllStoryTrackChanges = () => {
3300
3516
  const tcApi = getDoc()?.trackChanges;
3301
- const { value, status } = readAsync("trackChanges:all", contentToken(), () => tcApi?.list ? tcApi.list({ in: "all" }) : void 0, (raw) => {
3517
+ const token = contentToken();
3518
+ const heldEntry = asyncReads.get("trackChanges:all");
3519
+ const { value, status } = authoritativeTrackChangesPendingToken === token ? {
3520
+ value: heldEntry?.hasSettled ? heldEntry.value : null,
3521
+ status: heldEntry?.hasSettled ? "stale" : "pending"
3522
+ } : readAsync("trackChanges:all", token, () => tcApi?.list ? tcApi.list({ in: "all" }) : void 0, (raw) => {
3302
3523
  return (raw && Array.isArray(raw.items) ? raw.items : []).map(projectTrackChangesItem).filter((item) => item != null);
3303
3524
  });
3304
3525
  return status === "ready" ? value : null;
@@ -3309,7 +3530,11 @@ function createSuperDocUI(options) {
3309
3530
  const listTrackedChanges = typeof v2TrackedChanges?.listTrackedChanges === "function" ? v2TrackedChanges.listTrackedChanges : null;
3310
3531
  const token = contentToken();
3311
3532
  const postDecisionIds = postDecisionTrackChangeIdsForToken(token);
3312
- const { value, status: listStatus } = readAsync("trackChanges", token, () => {
3533
+ const heldEntry = asyncReads.get("trackChanges");
3534
+ const { value, status: listStatus } = authoritativeTrackChangesPendingToken === token ? {
3535
+ value: heldEntry?.hasSettled ? heldEntry.value : null,
3536
+ status: heldEntry?.hasSettled ? "stale" : "pending"
3537
+ } : readAsync("trackChanges", token, () => {
3313
3538
  if (listTrackedChanges) return postDecisionTrackChangesToken === token ? listTrackedChanges.call(v2TrackedChanges, POST_DECISION_TRACKED_CHANGES_LIST_OPTIONS) : listTrackedChanges.call(v2TrackedChanges);
3314
3539
  return tcApi?.list ? tcApi.list() : void 0;
3315
3540
  }, (raw) => raw && Array.isArray(raw.items) ? raw.items : []);
@@ -3968,6 +4193,9 @@ function createSuperDocUI(options) {
3968
4193
  if (descriptor.list?.mode === "toggle-seed" && descriptor.list.seed) return readListSeed(doc, selection$1) === descriptor.list.seed;
3969
4194
  const pending = pendingInlineActive(descriptor);
3970
4195
  if (pending !== null) return pending;
4196
+ const optimistic = optimisticInlineToggles.get(descriptor.id);
4197
+ const selectionSignature$1 = selectionInlineValueSignature(selection$1);
4198
+ if (selectionSignature$1 && optimistic?.selectionSignature === selectionSignature$1) return optimistic.active;
3971
4199
  return commandIsActive(descriptor, selection$1);
3972
4200
  };
3973
4201
  const routedCommandValue = (descriptor, doc, selection$1, projectedInlineValues) => {
@@ -4594,6 +4822,9 @@ function createSuperDocUI(options) {
4594
4822
  const selection$1 = computeSelection();
4595
4823
  if (selection$1.status === "ready") pruneSelectionScopedAsyncReads(selection$1);
4596
4824
  reconcilePendingInlineFormat(selection$1);
4825
+ const selectionSignature$1 = selectionInlineValueSignature(selection$1);
4826
+ for (const [commandId, optimistic] of optimisticInlineToggles) if (!selectionSignature$1 || optimistic.selectionSignature !== selectionSignature$1) optimisticInlineToggles.delete(commandId);
4827
+ else if (optimistic.settled && selection$1.status === "ready") optimisticInlineToggles.delete(commandId);
4597
4828
  return {
4598
4829
  ready: getEditor() != null,
4599
4830
  documentMode,
@@ -4614,7 +4845,10 @@ function createSuperDocUI(options) {
4614
4845
  };
4615
4846
  const syncOptimisticInlineSelection = (selection$1) => {
4616
4847
  const nextSignature = selectionInlineValueSignature(selection$1);
4617
- if (nextSignature && lastOptimisticInlineSelectionSignature && nextSignature !== lastOptimisticInlineSelectionSignature) optimisticInlineValues.clear();
4848
+ if (nextSignature && lastOptimisticInlineSelectionSignature && nextSignature !== lastOptimisticInlineSelectionSignature) {
4849
+ optimisticInlineValues.clear();
4850
+ optimisticInlineToggles.clear();
4851
+ }
4618
4852
  if (nextSignature) lastOptimisticInlineSelectionSignature = nextSignature;
4619
4853
  };
4620
4854
  let currentHostSelectionSource = null;
@@ -4692,24 +4926,48 @@ function createSuperDocUI(options) {
4692
4926
  try {
4693
4927
  const off = next.subscribe((event) => {
4694
4928
  const type = event?.type;
4695
- if (type === "mutation:committed") lastEditableMutationAtMs = Date.now();
4929
+ if (type === "source:complete" || type === "source:signals-complete") {
4930
+ if (authoritativeTrackChangesPendingToken !== null) {
4931
+ clearAuthoritativeTrackChangesRetry();
4932
+ reviewMutationReconciler.onRender(true);
4933
+ }
4934
+ return;
4935
+ }
4936
+ if (type === "mutation:committed") {
4937
+ lastEditableMutationAtMs = Date.now();
4938
+ clearAuthoritativeTrackChangesRetry();
4939
+ reviewMutationToken = {};
4940
+ }
4696
4941
  if (type === "mutation:committed" || type === "save:completed") {
4697
4942
  const impact = type === "mutation:committed" ? getV2TrackedChangeMutationImpact(event) : null;
4698
- if (impact?.removedIds.size) markPostDecisionTrackChanges(new Set(impact.removedIds));
4699
- if (impact?.upsertIds.size) {
4943
+ const supersedesPendingReviewReconcile = type === "mutation:committed" && reviewMutationReconciler.getPendingIds().size > 0;
4944
+ if (impact?.removedIds.size) markPostDecisionTrackChanges(new Set(impact.removedIds), event.receipt);
4945
+ const authoritativeHistoryImpact = impact?.reconcileMode === "authoritative" && impact.upsertIds.size > 0;
4946
+ if (authoritativeHistoryImpact) {
4947
+ invalidateDocumentContent();
4948
+ clearAuthoritativeTrackChangesRetry();
4949
+ authoritativeTrackChangesPendingToken = contentToken();
4950
+ recompute();
4951
+ }
4952
+ if (impact?.upsertIds.size || supersedesPendingReviewReconcile) {
4700
4953
  const receipt = event.origin === "history" ? null : event.receipt;
4701
4954
  const readiness = getEditor()?.documentMutationReadiness;
4702
- const canWaitForExactPaint = typeof receipt?.txId === "string" && receipt.txId.length > 0 && typeof readiness?.whenPainted === "function";
4955
+ const canWaitForReceiptPaint = typeof receipt?.txId === "string" && receipt.txId.length > 0 && typeof readiness?.whenPainted === "function";
4956
+ const historyRenderEpoch = event.origin === "history" && typeof readiness?.getRenderEpoch === "function" ? safeCall(() => readiness.getRenderEpoch.call(readiness), null) : null;
4957
+ const canWaitForHistoryPaint = event.origin === "history" && typeof readiness?.whenPainted === "function";
4703
4958
  const upsertImpact = {
4704
- upsertIds: impact.upsertIds,
4705
- removedIds: /* @__PURE__ */ new Set()
4959
+ upsertIds: impact?.upsertIds ?? /* @__PURE__ */ new Set(),
4960
+ removedIds: /* @__PURE__ */ new Set(),
4961
+ reconcileMode: impact?.reconcileMode === "authoritative" ? "authoritative" : "targeted"
4706
4962
  };
4707
- if (canWaitForExactPaint) reviewMutationReconciler.enqueueAfterPaint(upsertImpact, () => readiness.whenPainted.call(readiness, receipt));
4963
+ if (canWaitForReceiptPaint) reviewMutationReconciler.enqueueAfterPaint(upsertImpact, () => readiness.whenPainted.call(readiness, receipt));
4964
+ else if (canWaitForHistoryPaint) reviewMutationReconciler.enqueueAfterPaint(upsertImpact, () => readiness.whenPainted.call(readiness, typeof historyRenderEpoch === "number" ? { afterEpoch: historyRenderEpoch } : void 0));
4708
4965
  else {
4709
4966
  reviewMutationReconciler.enqueue(upsertImpact);
4710
- reviewMutationReconciler.onRender();
4967
+ reviewMutationReconciler.onRender(supersedesPendingReviewReconcile);
4711
4968
  }
4712
4969
  }
4970
+ if (authoritativeHistoryImpact) return;
4713
4971
  if (type === "mutation:committed" && isEditableTextMutationEvent(event)) {
4714
4972
  lastTypingMutationAtMs = Date.now();
4715
4973
  scheduleTypingDocumentContentInvalidation();
@@ -4903,6 +5161,7 @@ function createSuperDocUI(options) {
4903
5161
  }
4904
5162
  let lastCommandSettlement = Promise.resolve(false);
4905
5163
  let pendingCommandSettlement = null;
5164
+ let lastInlineToggleCommandSettlement = Promise.resolve(false);
4906
5165
  const awaitMutationReadiness = async (result) => {
4907
5166
  if (!isSuccessfulReceipt(result)) return result;
4908
5167
  const readiness = getEditor()?.documentMutationReadiness;
@@ -4930,6 +5189,69 @@ function createSuperDocUI(options) {
4930
5189
  settled: awaitMutationReadiness(immediate)
4931
5190
  };
4932
5191
  };
5192
+ const releaseInlineToggleMutation = () => {
5193
+ const next = pendingInlineToggleMutations.shift();
5194
+ if (!next) {
5195
+ inlineToggleMutationActive = false;
5196
+ resolveInlineToggleMutationIdle?.();
5197
+ resolveInlineToggleMutationIdle = null;
5198
+ return;
5199
+ }
5200
+ try {
5201
+ next.resolve(disposed ? false : next.mutate());
5202
+ } catch {
5203
+ next.resolve(false);
5204
+ }
5205
+ };
5206
+ const releaseInlineToggleMutationOnce = () => {
5207
+ let released = false;
5208
+ return () => {
5209
+ if (released) return;
5210
+ released = true;
5211
+ releaseInlineToggleMutation();
5212
+ };
5213
+ };
5214
+ const scheduleInlineToggleMutation = (key, mutate) => {
5215
+ if (!inlineToggleMutationActive) {
5216
+ inlineToggleMutationActive = true;
5217
+ inlineToggleMutationIdle = new Promise((resolve$1) => {
5218
+ resolveInlineToggleMutationIdle = resolve$1;
5219
+ });
5220
+ try {
5221
+ return {
5222
+ result: mutate(),
5223
+ release: releaseInlineToggleMutationOnce()
5224
+ };
5225
+ } catch (error) {
5226
+ inlineToggleMutationActive = false;
5227
+ resolveInlineToggleMutationIdle?.();
5228
+ resolveInlineToggleMutationIdle = null;
5229
+ throw error;
5230
+ }
5231
+ }
5232
+ const pending = pendingInlineToggleMutations.find((mutation) => mutation.key === key);
5233
+ if (pending) {
5234
+ pending.mutate = mutate;
5235
+ return {
5236
+ result: pending.result,
5237
+ release: () => void 0
5238
+ };
5239
+ }
5240
+ let resolve;
5241
+ const result = new Promise((settle) => {
5242
+ resolve = settle;
5243
+ });
5244
+ pendingInlineToggleMutations.push({
5245
+ key,
5246
+ mutate,
5247
+ result,
5248
+ resolve
5249
+ });
5250
+ return {
5251
+ result,
5252
+ release: releaseInlineToggleMutationOnce()
5253
+ };
5254
+ };
4933
5255
  const UNSUPPORTED_TRACKED_UI_MUTATION_ROUTES = new Set(["create.tableOfContents"]);
4934
5256
  const unsupportedTrackedMutationReceipt = (route) => failedReceipt(`Tracked authoring is not supported for ${route}.`);
4935
5257
  const editorMutationOptionsForRoute = (route) => {
@@ -4973,33 +5295,62 @@ function createSuperDocUI(options) {
4973
5295
  });
4974
5296
  return result;
4975
5297
  };
4976
- const finalizeCommandSettlement = (promise) => promise.then((settled) => {
5298
+ const captureOptimisticInlineToggle = (descriptor, selection$1, input, result) => {
5299
+ if (descriptor.inline?.kind !== "toggle") return null;
5300
+ if (!commandResultSucceeded(commandResultFromOperationResult(result))) return null;
5301
+ if (typeof input.value !== "boolean" && input.value !== null) return null;
5302
+ const selectionSignature$1 = selectionInlineValueSignature(selection$1);
5303
+ if (!selectionSignature$1) return null;
5304
+ const generation = ++optimisticInlineToggleGeneration;
5305
+ optimisticInlineToggles.set(descriptor.id, {
5306
+ selectionSignature: selectionSignature$1,
5307
+ active: input.value === true,
5308
+ generation,
5309
+ settled: false
5310
+ });
5311
+ recompute();
5312
+ return generation;
5313
+ };
5314
+ const settleOptimisticInlineToggle = (descriptor, generation, result) => {
5315
+ if (generation == null) return;
5316
+ const optimistic = optimisticInlineToggles.get(descriptor.id);
5317
+ if (!optimistic || optimistic.generation !== generation) return;
5318
+ if (!commandResultSucceeded(result)) {
5319
+ optimisticInlineToggles.delete(descriptor.id);
5320
+ return;
5321
+ }
5322
+ optimistic.settled = true;
5323
+ };
5324
+ const finalizeCommandSettlement = (promise, onSettled) => promise.then((settled) => {
5325
+ onSettled?.(settled);
4977
5326
  invalidateDocumentContent();
4978
5327
  recompute();
4979
5328
  return settled;
4980
5329
  }, () => {
5330
+ onSettled?.(false);
4981
5331
  invalidateDocumentContent();
4982
5332
  recompute();
4983
5333
  return false;
4984
5334
  });
4985
- const settleCommandExecution = (result) => {
5335
+ const settleCommandExecution = (result, onSettled) => {
4986
5336
  const pending = pendingCommandSettlement;
4987
5337
  pendingCommandSettlement = null;
4988
5338
  if (pending) {
4989
- lastCommandSettlement = finalizeCommandSettlement(pending);
5339
+ lastCommandSettlement = finalizeCommandSettlement(pending, onSettled);
4990
5340
  return commandResultFromOperationResult(result);
4991
5341
  }
4992
5342
  if (isPromiseLike(result)) {
4993
- lastCommandSettlement = finalizeCommandSettlement(settleOperationResult(result).settled);
5343
+ lastCommandSettlement = finalizeCommandSettlement(settleOperationResult(result).settled, onSettled);
4994
5344
  return true;
4995
5345
  }
4996
5346
  const settled = commandResultFromOperationResult(result);
4997
5347
  if (isSuccessfulReceipt(settled)) {
4998
5348
  if (typeof (getEditor()?.documentMutationReadiness)?.whenPainted === "function") {
4999
- lastCommandSettlement = finalizeCommandSettlement(awaitMutationReadiness(settled));
5349
+ lastCommandSettlement = finalizeCommandSettlement(awaitMutationReadiness(settled), onSettled);
5000
5350
  return settled;
5001
5351
  }
5002
5352
  }
5353
+ onSettled?.(settled);
5003
5354
  lastCommandSettlement = Promise.resolve(settled);
5004
5355
  invalidateDocumentContent();
5005
5356
  recompute();
@@ -5722,12 +6073,31 @@ function createSuperDocUI(options) {
5722
6073
  if (state.selection.empty === false) return settleCommandExecution(false);
5723
6074
  return settleCommandExecution(storePendingInlineFormat(descriptor, normalized));
5724
6075
  }
5725
- const active = commandIsActive(descriptor, state.selection);
6076
+ const active = commandActiveState(descriptor, doc, state.selection);
5726
6077
  const input = buildInlineFormatInput(descriptor.inline, target, normalized, active);
5727
6078
  if (!input) return false;
6079
+ let releaseScheduledMutation = null;
5728
6080
  try {
5729
- return settleCommandExecution(decorateInlineCommandResult(descriptor, state.selection, input, callInlineFormatMutation(route, op, input)));
6081
+ const commandEditor = getEditor();
6082
+ const commandMode = readDocumentMode();
6083
+ const mutate = () => {
6084
+ if (getEditor() !== commandEditor || getDoc() !== doc || readDocumentMode() !== commandMode) return false;
6085
+ return callInlineFormatMutation(route, op, input);
6086
+ };
6087
+ const selectionSignature$1 = selectionInlineValueSignature(state.selection) ?? selectionKey(state.selection);
6088
+ const scheduledMutation = descriptor.inline.kind === "toggle" ? scheduleInlineToggleMutation(`${descriptor.id}:${selectionSignature$1}`, mutate) : null;
6089
+ releaseScheduledMutation = scheduledMutation?.release ?? null;
6090
+ const mutationResult = scheduledMutation ? scheduledMutation.result : mutate();
6091
+ const optimisticGeneration = captureOptimisticInlineToggle(descriptor, state.selection, input, mutationResult);
6092
+ const immediate = settleCommandExecution(decorateInlineCommandResult(descriptor, state.selection, input, mutationResult), (settled) => {
6093
+ settleOptimisticInlineToggle(descriptor, optimisticGeneration, settled);
6094
+ releaseScheduledMutation?.();
6095
+ releaseScheduledMutation = null;
6096
+ });
6097
+ if (descriptor.inline.kind === "toggle") lastInlineToggleCommandSettlement = lastCommandSettlement;
6098
+ return immediate;
5730
6099
  } catch {
6100
+ releaseScheduledMutation?.();
5731
6101
  return false;
5732
6102
  }
5733
6103
  }
@@ -5756,6 +6126,15 @@ function createSuperDocUI(options) {
5756
6126
  recompute();
5757
6127
  };
5758
6128
  const executeCopyFormat = async () => {
6129
+ const visibleActiveMarksAtClick = [
6130
+ "bold",
6131
+ "italic",
6132
+ "underline",
6133
+ "strikethrough"
6134
+ ].filter((id) => state.toolbar.commands[id]?.active === true);
6135
+ const inlineToggleSettlement = await lastInlineToggleCommandSettlement;
6136
+ await inlineToggleMutationIdle;
6137
+ const visibleActiveMarks = commandResultSucceeded(inlineToggleSettlement) ? visibleActiveMarksAtClick : [];
5759
6138
  const DOUBLE_CLICK_MS = 500;
5760
6139
  const now = Date.now();
5761
6140
  if (painter.mode !== "idle") {
@@ -5778,11 +6157,9 @@ function createSuperDocUI(options) {
5778
6157
  ...painter,
5779
6158
  lastClickAt: now
5780
6159
  };
5781
- const captureSlice = state.selection;
6160
+ const captureSlice = await readSelectionInfoFresh();
5782
6161
  const sourceKey = `${selectionKey(captureSlice)}:${contentToken()}`;
5783
- const captureProjected = sourceKey && sourceKey === frozenProjectedValuesKey ? frozenProjectedValues : void 0;
5784
- const sel = readSelectionInfoLive().value;
5785
- const painterSnapshot = await captureFormatPainter(sel, captureSlice, captureProjected);
6162
+ const painterSnapshot = await captureFormatPainter(null, captureSlice, sourceKey && sourceKey === frozenProjectedValuesKey ? frozenProjectedValues : void 0, visibleActiveMarks);
5786
6163
  if (captureEpoch !== painterCaptureEpoch) return true;
5787
6164
  painter = {
5788
6165
  ...painter,
@@ -5795,7 +6172,7 @@ function createSuperDocUI(options) {
5795
6172
  recompute();
5796
6173
  return true;
5797
6174
  };
5798
- const captureFormatPainter = async (selection$1, captureSlice, captureProjected) => {
6175
+ const captureFormatPainter = async (selection$1, captureSlice, captureProjected, visibleActiveMarks = []) => {
5799
6176
  const selTarget = captureSlice?.target ?? selection$1?.target;
5800
6177
  if (!selTarget || selTarget["kind"] !== "text") return null;
5801
6178
  const segments = Array.isArray(selTarget["segments"]) ? selTarget["segments"] : [];
@@ -5819,8 +6196,8 @@ function createSuperDocUI(options) {
5819
6196
  underline: "underline",
5820
6197
  strikethrough: "strike"
5821
6198
  };
5822
- const activeMarks = captureSlice?.activeMarks ?? (Array.isArray(selection$1?.["activeMarks"]) ? selection$1["activeMarks"] : []);
5823
- for (const [markName, patchKey] of Object.entries(MARK_TO_PATCH)) if (activeMarks.includes(markName)) inlinePatch[patchKey] = true;
6199
+ const activeMarks = new Set([...captureSlice?.activeMarks ?? (Array.isArray(selection$1?.["activeMarks"]) ? selection$1["activeMarks"] : []), ...visibleActiveMarks]);
6200
+ for (const [markName, patchKey] of Object.entries(MARK_TO_PATCH)) if (activeMarks.has(markName)) inlinePatch[patchKey] = true;
5824
6201
  const projectedInlineValues = captureProjected ?? await readFormatPainterInlineValues(captureSlice ?? selectionSliceFromInfo(selection$1, "ready"));
5825
6202
  if (projectedInlineValues.fontFamily) inlinePatch["fontFamily"] = projectedInlineValues.fontFamily;
5826
6203
  if (projectedInlineValues.color) inlinePatch["color"] = projectedInlineValues.color;
@@ -6079,12 +6456,15 @@ function createSuperDocUI(options) {
6079
6456
  };
6080
6457
  const executeCommandAsync = (id, payload, context) => {
6081
6458
  const prepared = prepareCommandSelectionAsync(id, payload);
6082
- if (prepared) return prepared.then(() => {
6459
+ const settlement = prepared ? prepared.then(() => {
6083
6460
  executeCommand(id, payload, context);
6084
6461
  return lastCommandSettlement;
6085
- });
6086
- executeCommand(id, payload, context);
6087
- return lastCommandSettlement;
6462
+ }) : (() => {
6463
+ executeCommand(id, payload, context);
6464
+ return lastCommandSettlement;
6465
+ })();
6466
+ if (getCommandDescriptor(id)?.inline?.kind === "toggle") lastInlineToggleCommandSettlement = settlement;
6467
+ return settlement;
6088
6468
  };
6089
6469
  const makeCommandHandle = (id) => ({
6090
6470
  id,
@@ -7579,6 +7959,7 @@ function createSuperDocUI(options) {
7579
7959
  if (disposed) return;
7580
7960
  disposed = true;
7581
7961
  reviewMutationReconciler.reset();
7962
+ clearAuthoritativeTrackChangesRetry();
7582
7963
  if (foregroundAsyncRetryTimer) {
7583
7964
  clearTimeout(foregroundAsyncRetryTimer);
7584
7965
  foregroundAsyncRetryTimer = null;