superdoc 2.30.0-next.4 → 2.30.0-next.9

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 (48) hide show
  1. package/dist/chunks/{create-super-doc-ui-CbEDXtpm.es.js → create-super-doc-ui-Cq8trPVC.es.js} +494 -107
  2. package/dist/chunks/{create-super-doc-ui--kQBNTyt.cjs → create-super-doc-ui-FH5GSHph.cjs} +492 -105
  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/comments/comment-create-attribution.d.ts +4 -0
  6. package/dist/document-api/src/comments/comments.types.d.ts +4 -0
  7. package/dist/document-api/src/contract/command-catalog.d.ts +1 -1
  8. package/dist/document-api/src/contract/operation-definitions.d.ts +25 -7
  9. package/dist/document-api/src/contract/operation-registry.d.ts +2 -2
  10. package/dist/document-api/src/contract/schemas.d.ts +7 -1
  11. package/dist/document-api/src/index.d.ts +7 -1
  12. package/dist/document-api/src/paragraphs/paragraphs.d.ts +8 -3
  13. package/dist/document-api/src/paragraphs/paragraphs.types.d.ts +49 -5
  14. package/dist/document-api/src/tables/data/table-preset-appearance.generated.d.ts +2 -0
  15. package/dist/document-api/src/tables/table-style-presets.d.ts +73 -0
  16. package/dist/document-api/src/tables/tables.d.ts +4 -1
  17. package/dist/document-api/src/types/sd-props.d.ts +7 -0
  18. package/dist/document-api/src/types/table-operations.types.d.ts +12 -15
  19. package/dist/layout-engine/contracts/src/index.d.ts +1 -0
  20. package/dist/layout-engine/contracts/src/table-cell-vector-overlay.d.ts +2 -0
  21. package/dist/layout-engine/painters/dom/src/index.d.ts +2 -0
  22. package/dist/public/ui-react.cjs +1 -1
  23. package/dist/public/ui-react.es.js +1 -1
  24. package/dist/public/ui-vue.cjs +1 -1
  25. package/dist/public/ui-vue.es.js +1 -1
  26. package/dist/public/ui.cjs +1 -1
  27. package/dist/public/ui.es.js +1 -1
  28. package/dist/style.css +1 -1
  29. package/dist/style.layered.css +1 -1
  30. package/dist/superdoc/src/composables/use-comment-sidebar.d.ts +6 -0
  31. package/dist/superdoc/src/core/config/normalize-interaction-config.d.ts +10 -1
  32. package/dist/superdoc/src/core/editor-runtime/types.d.ts +4 -0
  33. package/dist/superdoc/src/core/types/index.d.ts +39 -0
  34. package/dist/superdoc/src/public/index.d.cts +4 -0
  35. package/dist/superdoc/src/public/index.d.ts +1 -1
  36. package/dist/superdoc/src/public/ui/format-painter-paragraph.d.ts +7 -0
  37. package/dist/superdoc/src/public/ui/format-painter-state.d.ts +5 -9
  38. package/dist/superdoc/src/public/ui/inline-values.d.ts +1 -1
  39. package/dist/superdoc/src/public/ui/reasons.d.ts +1 -0
  40. package/dist/superdoc/src/public/ui/selection-targets.d.ts +2 -0
  41. package/dist/superdoc/src/stores/comments-store.d.ts +21 -9
  42. package/dist/superdoc/src/stores/helpers/review-presentation.d.ts +1 -0
  43. package/dist/superdoc.cjs +239 -60
  44. package/dist/superdoc.es.js +239 -60
  45. package/dist-cdn/style.layered.css +1 -1
  46. package/dist-cdn/superdoc.min.css +1 -1
  47. package/dist-cdn/superdoc.min.js +38 -38
  48. package/package.json +2 -2
@@ -1,7 +1,7 @@
1
1
  import { i as __toESM$2 } from "./chunks/rolldown-runtime-0pSA04fp.es.js";
2
2
  import { $ as vModelSelect, A as onActivated, B as renderList, C as isRef$1, D as normalizeClass, E as nextTick, F as openBlock, G as toDisplayString, H as resolveDirective, I as provide$1, J as toRefs, K as toRaw$2, L as reactive, M as onDeactivated, N as onMounted, O as normalizeProps, P as onScopeDispose$1, Q as vModelCheckbox, R as readonly, S as isReactive$1, T as mergeProps, U as resolveDynamicComponent, V as renderSlot, W as shallowRef$1, X as useAttrs, Y as unref, Z as useSlots, _ as getCurrentInstance, a as computed$1, at as withModifiers, b as hasInjectionContext, c as createCommentVNode, ct as isThenable$1, d as createStaticVNode, et as vModelText, f as createTextVNode, g as effectScope, h as defineComponent, i as Transition, it as withKeys, j as onBeforeUnmount, k as normalizeStyle, l as createElementBlock, m as defineAsyncComponent, n as Fragment, nt as withCtx, o as createApp, p as createVNode, q as toRef, r as Teleport, rt as withDirectives, s as createBlock, st as isPlainObject$1, t as _plugin_vue_export_helper_default, tt as watch$1, u as createElementVNode, v as getCurrentScope, w as markRaw, x as inject$1, y as h, z as ref } from "./chunks/_plugin-vue_export-helper-CmkaJDnr.es.js";
3
3
  import { t as blank_default } from "./chunks/blank-docx-DzQccOlW.es.js";
4
- import { C as createInteractionHistory, E as recordInteraction, S as closeInteractionHistory, T as isWorkflowRecordingEnabled, _ as isAllowed, a as registerFirstPartyCommandMutation, b as isRecord, c as applyV2CommentInvalidationFromMutation, d as createImageFilePicker, f as resolveImageSrc, g as createTrackedChangePermissionResolver, h as PERMISSIONS, i as readFirstPartyPageNumbers, l as getV2TrackedChangeMutationImpact, m as BUILT_IN_PERMISSION_METHOD, n as executeFirstPartyCommandAsync, r as executeFirstPartyShortcutAsync, s as getCommandDescriptor, t as createSuperDocUI, u as mutationCommittedEventChangedDocument, v as isSyntheticTrackedChangeCommentLaneItem, w as getWorkflowRecording, x as DOM_CLASS_NAMES, y as isStoryLocator } from "./chunks/create-super-doc-ui-CbEDXtpm.es.js";
4
+ import { C as createInteractionHistory, E as recordInteraction, S as closeInteractionHistory, T as isWorkflowRecordingEnabled, _ as isAllowed, a as registerFirstPartyCommandMutation, b as isRecord, c as applyV2CommentInvalidationFromMutation, d as createImageFilePicker, f as resolveImageSrc, g as createTrackedChangePermissionResolver, h as PERMISSIONS, i as readFirstPartyPageNumbers, l as getV2TrackedChangeMutationImpact, m as BUILT_IN_PERMISSION_METHOD, n as executeFirstPartyCommandAsync, r as executeFirstPartyShortcutAsync, s as getCommandDescriptor, t as createSuperDocUI, u as mutationCommittedEventChangedDocument, v as isSyntheticTrackedChangeCommentLaneItem, w as getWorkflowRecording, x as DOM_CLASS_NAMES, y as isStoryLocator } from "./chunks/create-super-doc-ui-Cq8trPVC.es.js";
5
5
  import { t as import_eventemitter3 } from "./chunks/eventemitter3-DEIiXiH2.es.js";
6
6
  import { t as v4 } from "./chunks/uuid-H0Xcmmhy.es.js";
7
7
  import { a as init_dist$1, i as global, n as init_dist$2, o as Buffer, r as process$1, s as init_dist, t as require_jszip_min } from "./chunks/jszip-BzJ3CyxR.es.js";
@@ -258,7 +258,7 @@ var v_click_outside_default = {
258
258
  var DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
259
259
  function getSuperdocVersion() {
260
260
  try {
261
- return "2.30.0-next.4";
261
+ return "2.30.0-next.9";
262
262
  } catch {
263
263
  return "unknown";
264
264
  }
@@ -6828,6 +6828,18 @@ function resolveDocxExportPolicies(input = {}) {
6828
6828
  contentControls: requested?.contentControls ?? "preserve"
6829
6829
  };
6830
6830
  }
6831
+ new TextEncoder();
6832
+ function normalizeCommentIdentity(value) {
6833
+ if (value === null) return null;
6834
+ if (typeof value !== "object" || Array.isArray(value) || !("providerId" in value) || !("userId" in value) || !xmlIdentityString(value.providerId) || !xmlIdentityString(value.userId)) throw new TypeError("commentIdentity requires XML-safe non-empty providerId and userId strings.");
6835
+ return {
6836
+ providerId: value.providerId,
6837
+ userId: value.userId
6838
+ };
6839
+ }
6840
+ function xmlIdentityString(value) {
6841
+ return typeof value === "string" && value.trim().length > 0 && !/[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/u.test(value);
6842
+ }
6831
6843
  //#endregion
6832
6844
  //#region ../document-api/src/permission-ranges/permission-ranges.ts
6833
6845
  function editorKey(editor) {
@@ -8008,6 +8020,7 @@ var useCommentsStore = defineStore("comments", () => {
8008
8020
  });
8009
8021
  const debounceTimers = {};
8010
8022
  const trackedChangeResolutionSnapshots = /* @__PURE__ */ new WeakMap();
8023
+ let cachedTrackedChangeBatchIdentityIndex = null;
8011
8024
  const isBenchmarkCommentsDebugEnabled = () => {
8012
8025
  if (typeof window === "undefined") return false;
8013
8026
  return "__labsSuperDocV2BenchmarkDebug" in window;
@@ -8089,6 +8102,7 @@ var useCommentsStore = defineStore("comments", () => {
8089
8102
  const isV2EditorActive = (superdoc) => superdoc?.activeEditor?.editorVersion === 2 || v2CommentsAdapter.value !== null;
8090
8103
  const v2TrackedChangesAdapter = shallowRef$1(null);
8091
8104
  const setV2TrackedChangesAdapter = (adapter) => {
8105
+ cachedTrackedChangeBatchIdentityIndex = null;
8092
8106
  v2TrackedChangesAdapter.value = isV2TrackedChangesAdapter(adapter) ? adapter : null;
8093
8107
  };
8094
8108
  const getV2TrackedChangesAdapter = (superdoc) => {
@@ -8212,7 +8226,7 @@ var useCommentsStore = defineStore("comments", () => {
8212
8226
  * Called when a tracked change is updated. Creates a new comment if necessary,
8213
8227
  * or updates an existing tracked-change comment.
8214
8228
  */
8215
- const handleTrackedChangeUpdate = ({ superdoc, params, broadcastChanges = true, trackedChangeIdentityIndex = null }) => {
8229
+ const handleTrackedChangeUpdate = ({ superdoc, params, broadcastChanges = true, trackedChangeIdentityIndex = null, preserveDraft = false }) => {
8216
8230
  const span = startInteractionSpan("store.trackedChanges.handleUpdate", "store-reconciliation", {
8217
8231
  event: params?.event ?? null,
8218
8232
  changeId: params?.changeId ?? null,
@@ -8237,8 +8251,10 @@ var useCommentsStore = defineStore("comments", () => {
8237
8251
  const normalizedTrackedChangeLabel = typeof trackedChangeLabel === "string" && trackedChangeLabel.length > 0 ? trackedChangeLabel : null;
8238
8252
  const normalizedTrackedChangeDetailLines = normalizeTrackedChangeDetailLines(trackedChangeDetailLines);
8239
8253
  const normalizedTrackedChangeImagePreview = normalizeTrackedChangeImagePreview(trackedChangeImagePreview);
8254
+ const hasDraft = preserveDraft && (pendingComment.value !== null || currentCommentText.value !== "" || currentCommentMentions.value.length > 0);
8240
8255
  const comment = getPendingComment({
8241
8256
  documentId,
8257
+ ...hasDraft ? { commentText: "" } : {},
8242
8258
  commentId: normalizedChangeId ?? void 0,
8243
8259
  trackedChange: true,
8244
8260
  trackedChangeText,
@@ -8393,7 +8409,8 @@ var useCommentsStore = defineStore("comments", () => {
8393
8409
  addHydratedComment({
8394
8410
  superdoc: requireHost(superdoc, "handleTrackedChangeUpdate"),
8395
8411
  comment,
8396
- broadcastChanges
8412
+ broadcastChanges,
8413
+ preserveDraft: hasDraft
8397
8414
  });
8398
8415
  trackedChangeIdentityIndex?.add(comment);
8399
8416
  } else if (event === "update") {
@@ -8623,7 +8640,7 @@ var useCommentsStore = defineStore("comments", () => {
8623
8640
  /**
8624
8641
  * Add a new comment to the document
8625
8642
  */
8626
- const addCommentInternal = ({ superdoc, comment, skipEditorUpdate = false, broadcastChanges = true, isHydration = false }) => {
8643
+ const addCommentInternal = ({ superdoc, comment, skipEditorUpdate = false, broadcastChanges = true, isHydration = false, preserveDraft = false }) => {
8627
8644
  if (commentsAreReadOnly() && !isHydration) return readOnlyMutationOutcome();
8628
8645
  const v2Adapter = !skipEditorUpdate && !isHydration ? getV2CommentsAdapter(superdoc) : null;
8629
8646
  if (v2Adapter && !comment.trackedChange) {
@@ -8702,23 +8719,25 @@ var useCommentsStore = defineStore("comments", () => {
8702
8719
  };
8703
8720
  });
8704
8721
  }
8705
- let parentComment = commentsList.value.find((c) => c.commentId === activeComment.value);
8722
+ const activeId = activeComment.value;
8723
+ const parent = toRaw$2(commentsList.value).find((c) => unref(c.commentId) === activeId);
8724
+ let parentComment = parent ? reactive(parent) : void 0;
8706
8725
  if (!parentComment) parentComment = comment;
8707
8726
  const newComment = useComment(comment.getValues());
8708
- if (pendingComment.value) newComment.setText({
8709
- text: currentCommentText.value,
8710
- suppressUpdate: true
8711
- });
8712
- else newComment.setText({
8713
- text: comment.commentText,
8727
+ const text = pendingComment.value && !preserveDraft ? currentCommentText.value : comment.commentText;
8728
+ if (text === "") {
8729
+ newComment.commentText = "";
8730
+ newComment.mentions = [];
8731
+ } else newComment.setText({
8732
+ text,
8714
8733
  suppressUpdate: true
8715
8734
  });
8716
- newComment.selection.source = pendingComment.value?.selection?.source ?? newComment.selection.source;
8735
+ if (!preserveDraft) newComment.selection.source = pendingComment.value?.selection?.source ?? newComment.selection.source;
8717
8736
  if (parentComment) newComment.isInternal = parentComment.isInternal;
8718
8737
  if (!superdoc.config.isInternal) newComment.isInternal = false;
8719
8738
  commentsList.value.push(newComment);
8720
- const hadPendingComment = !!pendingComment.value;
8721
- removePendingComment(superdoc);
8739
+ const hadPendingComment = !preserveDraft && !!pendingComment.value;
8740
+ if (!preserveDraft) removePendingComment(superdoc);
8722
8741
  if (hadPendingComment) {
8723
8742
  activeComment.value = newComment.commentId;
8724
8743
  setActiveFloatingCommentInstance(newComment.commentId);
@@ -8746,12 +8765,13 @@ var useCommentsStore = defineStore("comments", () => {
8746
8765
  skipEditorUpdate,
8747
8766
  broadcastChanges
8748
8767
  });
8749
- const addHydratedComment = ({ superdoc, comment, skipEditorUpdate = false, broadcastChanges = true }) => addCommentInternal({
8768
+ const addHydratedComment = ({ superdoc, comment, skipEditorUpdate = false, broadcastChanges = true, preserveDraft = false }) => addCommentInternal({
8750
8769
  superdoc,
8751
8770
  comment,
8752
8771
  skipEditorUpdate,
8753
8772
  broadcastChanges,
8754
- isHydration: true
8773
+ isHydration: true,
8774
+ preserveDraft
8755
8775
  });
8756
8776
  const deleteComment = ({ commentId: commentIdToDelete, superdoc }) => {
8757
8777
  if (commentsAreReadOnly()) return Promise.resolve(readOnlyMutationOutcome());
@@ -9476,6 +9496,11 @@ var useCommentsStore = defineStore("comments", () => {
9476
9496
  /** Keep one mounted review window plus rows whose interaction is still live. */
9477
9497
  const boundReviewPresentationRows = ({ documentId, visibleIds }) => {
9478
9498
  const currentRows = commentsList.value;
9499
+ if (currentRows.every((row) => {
9500
+ if (!belongsToTrackedChangeSyncDocument(row, documentId)) return true;
9501
+ const id = normalizeCommentId(row.commentId);
9502
+ return Boolean(id && visibleIds.has(id));
9503
+ })) return;
9479
9504
  const identityIdsByRow = /* @__PURE__ */ new Map();
9480
9505
  const identityIdsFor = (row) => {
9481
9506
  let ids = identityIdsByRow.get(row);
@@ -9692,7 +9717,8 @@ var useCommentsStore = defineStore("comments", () => {
9692
9717
  preparedParams,
9693
9718
  preparedPresentation: preparedReview?.presentation ?? null,
9694
9719
  previousPreparedPresentation,
9695
- pruneStale: false
9720
+ pruneStale: false,
9721
+ preserveDraft: true
9696
9722
  });
9697
9723
  reconcileCommentsFromV2({
9698
9724
  superdoc,
@@ -10438,6 +10464,10 @@ var useCommentsStore = defineStore("comments", () => {
10438
10464
  const byIdentityAlias = /* @__PURE__ */ new Map();
10439
10465
  const aliasesByRow = /* @__PURE__ */ new Map();
10440
10466
  const indexedRows = /* @__PURE__ */ new Set();
10467
+ const indexedIdentities = [];
10468
+ let building = true;
10469
+ let reusable = true;
10470
+ let reused = false;
10441
10471
  let aliasLookups = 0;
10442
10472
  let candidateVisits = 0;
10443
10473
  let rowAliasBuilds = 0;
@@ -10461,6 +10491,7 @@ var useCommentsStore = defineStore("comments", () => {
10461
10491
  index.set(alias, bucket);
10462
10492
  };
10463
10493
  const add = (comment) => {
10494
+ if (!building) reusable = false;
10464
10495
  if (!comment?.trackedChange) return;
10465
10496
  if (documentId && !belongsToTrackedChangeSyncDocument(comment, documentId)) return;
10466
10497
  indexedRows.add(comment);
@@ -10472,19 +10503,49 @@ var useCommentsStore = defineStore("comments", () => {
10472
10503
  rowAliasBuilds += 1;
10473
10504
  aliasesByRow.set(comment, aliases);
10474
10505
  aliases.forEach((alias) => addAlias(byIdentityAlias, alias, comment));
10506
+ if (building) indexedIdentities.push({
10507
+ row: comment,
10508
+ aliases,
10509
+ canonicalId: normalizeCommentId(comment.trackedChangeCanonicalId)
10510
+ });
10475
10511
  };
10476
10512
  commentsList.value.forEach(add);
10513
+ building = false;
10477
10514
  return {
10515
+ inUse: false,
10478
10516
  add,
10479
10517
  aliasesFor,
10480
- work: () => ({
10481
- trackedRowsIndexed: indexedRows.size,
10482
- invalidatedIdMembershipChecks: 0,
10483
- incomingAliasLookups: aliasLookups,
10484
- candidateVisits,
10485
- rowAliasBuilds,
10486
- rowAliasCacheHits
10487
- }),
10518
+ isCurrent: () => {
10519
+ if (!reusable) return false;
10520
+ let index = 0;
10521
+ for (const row of commentsList.value) {
10522
+ if (!row?.trackedChange || documentId && !belongsToTrackedChangeSyncDocument(row, documentId)) continue;
10523
+ const previous = indexedIdentities[index++];
10524
+ if (!previous || previous.row !== row || previous.canonicalId !== normalizeCommentId(row.trackedChangeCanonicalId)) return false;
10525
+ const aliases = getCommentAliasIds(row);
10526
+ rowAliasBuilds += 1;
10527
+ if (aliases.length !== previous.aliases.length || aliases.some((alias, i) => alias !== previous.aliases[i])) return false;
10528
+ }
10529
+ reused = index === indexedIdentities.length;
10530
+ return reused;
10531
+ },
10532
+ work: () => {
10533
+ const result = {
10534
+ trackedRowsIndexed: indexedRows.size,
10535
+ invalidatedIdMembershipChecks: 0,
10536
+ incomingAliasLookups: aliasLookups,
10537
+ candidateVisits,
10538
+ rowAliasBuilds,
10539
+ rowAliasCacheHits,
10540
+ indexReused: Number(reused)
10541
+ };
10542
+ aliasLookups = 0;
10543
+ candidateVisits = 0;
10544
+ rowAliasBuilds = 0;
10545
+ rowAliasCacheHits = 0;
10546
+ reused = false;
10547
+ return result;
10548
+ },
10488
10549
  candidates({ changeId, importedId, anchorKey, canonicalId, positionAliases = [] } = {}) {
10489
10550
  const out = /* @__PURE__ */ new Set();
10490
10551
  const include = (value) => {
@@ -10507,7 +10568,30 @@ var useCommentsStore = defineStore("comments", () => {
10507
10568
  }
10508
10569
  };
10509
10570
  };
10510
- const reconcileTrackedChangesFromV2 = ({ superdoc, adapter, documentId, items, pruneStale = true, preparedParams = null, preparedPresentation = null, previousPreparedPresentation = null, liveIds: suppliedLiveIds = null, liveAnchorKeys: suppliedLiveAnchorKeys = null, hydrationGeneration } = {}) => withInteractionSpan("store.trackedChanges.reconcile", "store-reconciliation", {
10571
+ const getTrackedChangeBatchIdentityIndex = (documentId) => {
10572
+ const cached = cachedTrackedChangeBatchIdentityIndex;
10573
+ if (cached?.documentId === documentId && !cached.index.inUse) {
10574
+ cached.index.inUse = true;
10575
+ let current = false;
10576
+ try {
10577
+ current = cached.index.isCurrent() && cachedTrackedChangeBatchIdentityIndex === cached;
10578
+ } finally {
10579
+ if (!current) {
10580
+ cached.index.inUse = false;
10581
+ if (cachedTrackedChangeBatchIdentityIndex === cached) cachedTrackedChangeBatchIdentityIndex = null;
10582
+ }
10583
+ }
10584
+ if (current) return cached.index;
10585
+ }
10586
+ const index = createTrackedChangeBatchIdentityIndex(documentId);
10587
+ index.inUse = true;
10588
+ cachedTrackedChangeBatchIdentityIndex = {
10589
+ documentId,
10590
+ index
10591
+ };
10592
+ return index;
10593
+ };
10594
+ const reconcileTrackedChangesFromV2 = ({ superdoc, adapter, documentId, items, pruneStale = true, preparedParams = null, preserveDraft = false, preparedPresentation = null, previousPreparedPresentation = null, liveIds: suppliedLiveIds = null, liveAnchorKeys: suppliedLiveAnchorKeys = null, hydrationGeneration } = {}) => withInteractionSpan("store.trackedChanges.reconcile", "store-reconciliation", {
10511
10595
  documentId: documentId ?? null,
10512
10596
  itemCount: Array.isArray(items) ? items.length : null,
10513
10597
  pruneStale,
@@ -10519,13 +10603,15 @@ var useCommentsStore = defineStore("comments", () => {
10519
10603
  const liveAnchorKeys = suppliedLiveAnchorKeys instanceof Set ? suppliedLiveAnchorKeys : /* @__PURE__ */ new Set();
10520
10604
  const liveIds = suppliedLiveIds instanceof Set ? suppliedLiveIds : /* @__PURE__ */ new Set();
10521
10605
  let appliedCount = 0;
10522
- const trackedChangeIdentityIndex = createTrackedChangeBatchIdentityIndex(effectiveDocumentId == null ? null : String(effectiveDocumentId));
10606
+ const trackedChangeIdentityIndex = getTrackedChangeBatchIdentityIndex(effectiveDocumentId == null ? null : String(effectiveDocumentId));
10523
10607
  const identitySpan = startInteractionSpan("store.trackedChanges.batchIdentity", "store-reconciliation", { itemCount: items.length });
10524
- const paramsList = Array.isArray(preparedParams) ? preparedParams : items.map((item) => adapter.mapV2TrackedChangeToCommentParams(item));
10525
- const previousCoordinate = previousPreparedPresentation?.coordinate;
10526
- const coordinate = preparedPresentation?.coordinate;
10527
- const retainUnchangedRows = !pruneStale && previousCoordinate && coordinate && coordinate.documentEpoch === preparedPresentation.epoch && coordinate.documentEpoch === previousPreparedPresentation.epoch && coordinate.documentEpoch === previousCoordinate.documentEpoch && typeof coordinate.mountId === "string" && coordinate.mountId.length > 0 && coordinate.mountId === previousCoordinate.mountId && preparedPresentation.baseVersion === previousPreparedPresentation.version && preparedPresentation.version === preparedPresentation.baseVersion + 1 && coordinate.reviewVersion === preparedPresentation.version && previousCoordinate.reviewVersion === previousPreparedPresentation.version && Number.isSafeInteger(coordinate.commitSequence) && Number.isSafeInteger(previousCoordinate.commitSequence) && coordinate.commitSequence >= previousCoordinate.commitSequence;
10608
+ let enteredBatch = false;
10528
10609
  try {
10610
+ const paramsList = Array.isArray(preparedParams) ? preparedParams : items.map((item) => adapter.mapV2TrackedChangeToCommentParams(item));
10611
+ const previousCoordinate = previousPreparedPresentation?.coordinate;
10612
+ const coordinate = preparedPresentation?.coordinate;
10613
+ const retainUnchangedRows = !pruneStale && previousCoordinate && coordinate && coordinate.documentEpoch === preparedPresentation.epoch && coordinate.documentEpoch === previousPreparedPresentation.epoch && coordinate.documentEpoch === previousCoordinate.documentEpoch && typeof coordinate.mountId === "string" && coordinate.mountId.length > 0 && coordinate.mountId === previousCoordinate.mountId && preparedPresentation.baseVersion === previousPreparedPresentation.version && preparedPresentation.version === preparedPresentation.baseVersion + 1 && coordinate.reviewVersion === preparedPresentation.version && previousCoordinate.reviewVersion === previousPreparedPresentation.version && Number.isSafeInteger(coordinate.commitSequence) && Number.isSafeInteger(previousCoordinate.commitSequence) && coordinate.commitSequence >= previousCoordinate.commitSequence;
10614
+ enteredBatch = true;
10529
10615
  for (const params of paramsList) {
10530
10616
  if (!params) continue;
10531
10617
  let retainUnchangedRow = false;
@@ -10560,12 +10646,15 @@ var useCommentsStore = defineStore("comments", () => {
10560
10646
  superdoc,
10561
10647
  params,
10562
10648
  broadcastChanges: false,
10563
- trackedChangeIdentityIndex
10649
+ trackedChangeIdentityIndex,
10650
+ preserveDraft
10564
10651
  });
10565
10652
  appliedCount += 1;
10566
10653
  }
10567
10654
  } finally {
10568
- endInteractionSpan(identitySpan, trackedChangeIdentityIndex.work());
10655
+ const work = trackedChangeIdentityIndex.work();
10656
+ trackedChangeIdentityIndex.inUse = false;
10657
+ if (enteredBatch) endInteractionSpan(identitySpan, work);
10569
10658
  }
10570
10659
  if (!effectiveDocumentId || !pruneStale) {
10571
10660
  if (effectiveDocumentId) compactDuplicateBodyTrackedChangeComments(String(effectiveDocumentId));
@@ -14104,18 +14193,42 @@ var FloatingComments_default = /* @__PURE__ */ _plugin_vue_export_helper_default
14104
14193
  const { activeComment, activeFloatingCommentInstanceId, editorCommentPositions, pendingComment, editingCommentId, instantSidebarAlignmentTargetY, instantSidebarAlignmentThreadId, instantSidebarAlignmentInstanceId } = storeToRefs(piniaCommentsStore);
14105
14194
  const { activeZoom } = storeToRefs(superdocStore);
14106
14195
  const committedPresentation = computed$1(() => commentsStore.committedReviewPresentations?.[String(props.currentDocument?.id)] ?? null);
14196
+ const committedInstanceCache = /* @__PURE__ */ new Map();
14197
+ let committedInstanceCacheOwner = "";
14198
+ const sameReviewInstance = (cached, next) => {
14199
+ const before = Object.entries(cached).filter(([key]) => key !== "comment" && key !== "rowVersion");
14200
+ const after = Object.entries(next);
14201
+ if (before.length !== after.length) return false;
14202
+ const previous = new Map(before);
14203
+ return after.every(([key, value]) => previous.has(key) && (key === "positionEntry" ? JSON.stringify(previous.get(key)) === JSON.stringify(value) : Object.is(previous.get(key), value)));
14204
+ };
14107
14205
  const committedInstances = computed$1(() => {
14108
14206
  const presentation = committedPresentation.value;
14109
14207
  if (!presentation) return null;
14110
14208
  const rows = new Map(commentsStore.commentsList.filter((row) => String(row.fileId) === String(props.currentDocument?.id)).map((row) => [String(row.commentId), row]));
14111
- return presentation.instances.flatMap((instance) => {
14209
+ const owner = `${presentation.epoch}\u0000${presentation.coordinate?.mountId ?? ""}`;
14210
+ if (owner !== committedInstanceCacheOwner) {
14211
+ committedInstanceCache.clear();
14212
+ committedInstanceCacheOwner = owner;
14213
+ }
14214
+ const live = /* @__PURE__ */ new Set();
14215
+ const instances = presentation.instances.flatMap((instance) => {
14112
14216
  const comment = instance.rowId === "pending" ? pendingComment.value : rows.get(instance.rowId);
14113
- return comment ? [{
14217
+ if (!comment) return [];
14218
+ const rowVersion = presentation.rowVersions[instance.rowId] ?? 0;
14219
+ live.add(instance.id);
14220
+ const cached = committedInstanceCache.get(instance.id);
14221
+ if (cached && cached.comment === comment && cached.rowVersion === rowVersion && sameReviewInstance(cached, instance)) return [cached];
14222
+ const merged = {
14114
14223
  ...instance,
14115
14224
  comment,
14116
- rowVersion: presentation.rowVersions[instance.rowId] ?? 0
14117
- }] : [];
14225
+ rowVersion
14226
+ };
14227
+ committedInstanceCache.set(instance.id, merged);
14228
+ return [merged];
14118
14229
  });
14230
+ for (const id of committedInstanceCache.keys()) if (!live.has(id)) committedInstanceCache.delete(id);
14231
+ return instances;
14119
14232
  });
14120
14233
  const floatingCommentInstances = computed$1(() => {
14121
14234
  if (committedInstances.value) return committedInstances.value.filter((instance) => instance.rowId !== "pending");
@@ -14531,6 +14644,18 @@ var FloatingComments_default = /* @__PURE__ */ _plugin_vue_export_helper_default
14531
14644
  scheduleDeferredRemeasure(() => allPositions.value.map((pos) => pos.id));
14532
14645
  });
14533
14646
  };
14647
+ const resizeHandlers = /* @__PURE__ */ new Map();
14648
+ const resizeHandlerFor = (id) => {
14649
+ let handler = resizeHandlers.get(id);
14650
+ if (!handler) {
14651
+ handler = () => {
14652
+ const position = allPositions.value.find((candidate) => candidate.id === id);
14653
+ if (position) handleResize(position);
14654
+ };
14655
+ resizeHandlers.set(id, handler);
14656
+ }
14657
+ return handler;
14658
+ };
14534
14659
  const setInstantLayoutTransitionsDisabled = (disabled) => {
14535
14660
  if (!disabled && directDecisionContinuityTargetId.value != null) return;
14536
14661
  disableInstantLayoutTransitions.value = disabled;
@@ -14935,6 +15060,7 @@ var FloatingComments_default = /* @__PURE__ */ _plugin_vue_export_helper_default
14935
15060
  visibilityChanged = true;
14936
15061
  }
14937
15062
  if (visibilityChanged) visibleIds.value = newVisible;
15063
+ for (const id of resizeHandlers.keys()) if (!currentIds.has(id)) resizeHandlers.delete(id);
14938
15064
  for (const id of prevPositionIds) if (!currentIds.has(id)) delete _heightsCache[id];
14939
15065
  const setChanged = prevPositionIds.size !== currentIds.size || [...prevPositionIds].some((id) => !currentIds.has(id));
14940
15066
  const orderChanged = renderedPositionOrder.length !== positionOrder.length || renderedPositionOrder.some((id, index) => id !== positionOrder[index]);
@@ -15027,12 +15153,13 @@ var FloatingComments_default = /* @__PURE__ */ _plugin_vue_export_helper_default
15027
15153
  style: normalizeStyle({
15028
15154
  top: (pos.isOffscreenReviewCard && !committedPresentation.value ? pos.top - sidebarOffsetY.value : pos.top) + "px",
15029
15155
  height: pos.height + "px",
15030
- transition: committedPresentation.value || disableInstantLayoutTransitions.value ? "none" : void 0
15156
+ transition: committedPresentation.value || disableInstantLayoutTransitions.value ? "none" : void 0,
15157
+ visibility: pos.instanceRef?.provisional ? "hidden" : void 0
15031
15158
  })
15032
15159
  }, [shouldRenderDialog(pos) ? (openBlock(), createBlock(CommentDialog_default, {
15033
15160
  key: pos.id + commentsRenderKey.value,
15034
15161
  onReady: handleDialog,
15035
- onResize: ($event) => handleResize(pos),
15162
+ onResize: resizeHandlerFor(pos.id),
15036
15163
  class: "floating-comment",
15037
15164
  parent: __props.parent,
15038
15165
  comment: pos.commentRef,
@@ -15052,7 +15179,7 @@ var FloatingComments_default = /* @__PURE__ */ _plugin_vue_export_helper_default
15052
15179
  }), 128))], 4)], 36);
15053
15180
  };
15054
15181
  }
15055
- }), [["__scopeId", "data-v-df897b8d"]]);
15182
+ }), [["__scopeId", "data-v-1070f5a1"]]);
15056
15183
  //#endregion
15057
15184
  //#region src/components/CommentsLayer/PdfCommentsLayer.vue?vue&type=script&setup=true&lang.ts
15058
15185
  var _hoisted_1$22 = {
@@ -15777,6 +15904,21 @@ function useCommentSmallScreen({ commentsModuleConfig, superdocRoot, layers }) {
15777
15904
  };
15778
15905
  }
15779
15906
  //#endregion
15907
+ //#region src/composables/use-comment-sidebar.ts
15908
+ function useCommentSidebar({ documentKey, enabled, hasContent }) {
15909
+ const reserved = ref(false);
15910
+ watch$1(documentKey, () => {
15911
+ reserved.value = false;
15912
+ }, { flush: "sync" });
15913
+ watch$1(() => enabled.value && hasContent.value, (visible) => {
15914
+ if (visible) reserved.value = true;
15915
+ }, {
15916
+ immediate: true,
15917
+ flush: "sync"
15918
+ });
15919
+ return computed$1(() => enabled.value && (hasContent.value || reserved.value));
15920
+ }
15921
+ //#endregion
15780
15922
  //#region src/composables/use-compact-comment-popover.ts
15781
15923
  var POPOVER_WIDTH_PX = 320;
15782
15924
  var SAFE_MARGIN_PX = 12;
@@ -20655,7 +20797,7 @@ var SuperDoc_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__P
20655
20797
  if (commentsConfig.highlightHoverColor) vars["--sd-comments-highlight-hover"] = commentsConfig.highlightHoverColor;
20656
20798
  const activeTrackChangeColors = {
20657
20799
  ...commentsConfig.trackChangeHighlightColors || {},
20658
- ...commentsConfig.trackChangeActiveHighlightColors || {}
20800
+ ...commentsConfig.trackChangeActiveHighlightColors
20659
20801
  };
20660
20802
  if (activeTrackChangeColors.insertBorder) vars["--sd-tracked-changes-insert-border"] = activeTrackChangeColors.insertBorder;
20661
20803
  if (activeTrackChangeColors.insertBackground) vars["--sd-tracked-changes-insert-background"] = activeTrackChangeColors.insertBackground;
@@ -21635,7 +21777,7 @@ var SuperDoc_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__P
21635
21777
  const publishV2PendingPositionEntry = (entry) => {
21636
21778
  if (!entry) return;
21637
21779
  handleEditorLocationsUpdate({
21638
- ...editorCommentPositions.value ?? {},
21780
+ ...editorCommentPositions.value,
21639
21781
  pending: entry
21640
21782
  });
21641
21783
  };
@@ -22174,7 +22316,7 @@ var SuperDoc_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__P
22174
22316
  documentLoading: proxy.$superdoc.uiConfig.loading.enabled,
22175
22317
  linkPopoverResolver: getHyperlinkActivationHandler(),
22176
22318
  layoutEngineOptions: useLayoutEngine ? {
22177
- ...proxy.$superdoc.config.layoutEngineOptions || {},
22319
+ ...proxy.$superdoc.config.layoutEngineOptions,
22178
22320
  proofing: resolvedProofingConfig.value,
22179
22321
  debugLabel: proxy.$superdoc.config.layoutEngineOptions?.debugLabel ?? doc.name ?? doc.id,
22180
22322
  zoom: (activeZoom.value ?? 100) / 100,
@@ -22437,11 +22579,16 @@ var SuperDoc_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__P
22437
22579
  if (layout !== "auto") return true;
22438
22580
  return !isCompactCommentsMode.value;
22439
22581
  });
22440
- const showCommentsSidebar = computed$1(() => {
22582
+ const sidebarEnabled = computed$1(() => {
22441
22583
  if (isV2Mode.value && !v2GeometryAvailable.value && !v2ReviewSidebarUnlocked.value && !hasPdfFloatingComments.value) return false;
22442
22584
  if (!shouldRenderCommentsInViewing.value) return false;
22443
22585
  if (!shouldUseSidebarComments.value) return false;
22444
- return pendingComment.value || (floatingComments.value.length > 0 || hasOpenTrackedChanges.value) && isReady.value && layers.value && isCommentsEnabled.value && !isCommentsListVisible.value;
22586
+ return Boolean(pendingComment.value || isReady.value && layers.value && isCommentsEnabled.value && !isCommentsListVisible.value);
22587
+ });
22588
+ const showCommentsSidebar = useCommentSidebar({
22589
+ documentKey: computed$1(() => JSON.stringify(documents.value.map((document) => document.id))),
22590
+ enabled: sidebarEnabled,
22591
+ hasContent: computed$1(() => Boolean(pendingComment.value || floatingComments.value.length || hasOpenTrackedChanges.value))
22445
22592
  });
22446
22593
  const activeCompactComment = computed$1(() => {
22447
22594
  if (showCommentsSidebar.value) return null;
@@ -23065,7 +23212,7 @@ var SuperDoc_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__P
23065
23212
  ref_key: "superdocRoot",
23066
23213
  ref: superdocRoot,
23067
23214
  class: normalizeClass(["superdoc", {
23068
- "superdoc--with-sidebar": showCommentsSidebar.value,
23215
+ "superdoc--with-sidebar": unref(showCommentsSidebar),
23069
23216
  "superdoc--web-layout": unref(proxy).$superdoc.config.viewOptions?.layout === "web",
23070
23217
  "superdoc--contained": unref(proxy).$superdoc.config.contained,
23071
23218
  "high-contrast": unref(isHighContrastMode)
@@ -23213,7 +23360,7 @@ var SuperDoc_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__P
23213
23360
  onAnchorActivate: handleHighlightClick
23214
23361
  })) : createCommentVNode("", true)
23215
23362
  ])], 512),
23216
- showCommentsSidebar.value ? (openBlock(), createElementBlock("div", {
23363
+ unref(showCommentsSidebar) ? (openBlock(), createElementBlock("div", {
23217
23364
  key: 0,
23218
23365
  ref_key: "rightSidebarRef",
23219
23366
  ref: rightSidebarRef,
@@ -23236,7 +23383,7 @@ var SuperDoc_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__P
23236
23383
  ], 46, _hoisted_1$17);
23237
23384
  };
23238
23385
  }
23239
- }), [["__scopeId", "data-v-7c932add"]]);
23386
+ }), [["__scopeId", "data-v-451ab88f"]]);
23240
23387
  //#endregion
23241
23388
  //#region src/core/create-app.ts
23242
23389
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
@@ -24915,7 +25062,8 @@ function normalizeSuperDocUser(user) {
24915
25062
  if (!user || typeof user !== "object") return { ...DEFAULT_SUPERDOC_USER };
24916
25063
  return {
24917
25064
  ...DEFAULT_SUPERDOC_USER,
24918
- ...user
25065
+ ...user,
25066
+ ...user.commentIdentity !== void 0 ? { commentIdentity: normalizeCommentIdentity(user.commentIdentity) } : {}
24919
25067
  };
24920
25068
  }
24921
25069
  //#endregion
@@ -25434,6 +25582,7 @@ function normalizeUiConfig(config = {}) {
25434
25582
  * Keeping policy separate means an application can disable the built-in
25435
25583
  * comments UI without losing the rules enforced by its custom UI.
25436
25584
  */
25585
+ var isAutocapitalize = (value) => value === "off" || value === "sentences" || value === "words" || value === "characters";
25437
25586
  var isCommentInteractionLevel = (value) => value === "read" || value === "write" || value === "resolve";
25438
25587
  /**
25439
25588
  * Resolve the effective interaction policy.
@@ -25453,14 +25602,26 @@ function normalizeInteractionConfig(config = {}) {
25453
25602
  const canonicalLevel = interactionComments.level;
25454
25603
  const hasCanonicalLevel = isCommentInteractionLevel(canonicalLevel);
25455
25604
  const level = hasCanonicalLevel ? canonicalLevel : legacyReadOnly ? "read" : legacyAllowResolve ? "resolve" : "write";
25605
+ const interactionWritingAssistance = isPlainObject$1(interaction.writingAssistance) ? interaction.writingAssistance : {};
25606
+ const autocorrect = interactionWritingAssistance.autocorrect === true;
25607
+ const autocapitalize = isAutocapitalize(interactionWritingAssistance.autocapitalize) ? interactionWritingAssistance.autocapitalize : "off";
25608
+ const spellcheck = interactionWritingAssistance.spellcheck === true;
25456
25609
  const canonicalAllowDecisions = interactionTrackedChanges.allowDecisions;
25610
+ const interactionTouch = isPlainObject$1(interaction.touch) ? interaction.touch : {};
25457
25611
  return {
25458
25612
  comments: {
25459
25613
  level,
25460
25614
  readOnly: hasCanonicalLevel ? level === "read" : legacyReadOnly,
25461
25615
  allowResolve: hasCanonicalLevel ? level === "resolve" : legacyAllowResolve
25462
25616
  },
25463
- trackedChanges: { allowDecisions: typeof canonicalAllowDecisions === "boolean" ? canonicalAllowDecisions : !legacyReadOnly }
25617
+ trackedChanges: { allowDecisions: typeof canonicalAllowDecisions === "boolean" ? canonicalAllowDecisions : !legacyReadOnly },
25618
+ touch: { gestures: interactionTouch.gestures === true },
25619
+ writingAssistance: {
25620
+ enabled: autocorrect || autocapitalize !== "off" || spellcheck,
25621
+ autocorrect,
25622
+ autocapitalize,
25623
+ spellcheck
25624
+ }
25464
25625
  };
25465
25626
  }
25466
25627
  //#endregion
@@ -31967,7 +32128,7 @@ var V1_ENABLED_ON_SELECTION_REASON = /* @__PURE__ */ new Set([
31967
32128
  ]);
31968
32129
  var V1_ENABLED_ON_EMPTY_REASON = /* @__PURE__ */ new Set(["list", "numberedlist"]);
31969
32130
  function shouldKeepEnabledForV1ToolbarParity(name, commandState) {
31970
- if (name === "fontFamily" || name === "fontSize") return commandState?.reason !== "document-readonly";
32131
+ if (name === "fontFamily" || name === "fontSize") return commandState?.reason !== "document-readonly" && commandState?.reason !== "deleted-text-formatting-unsupported";
31971
32132
  if (V1_ENABLED_ON_EMPTY_REASON.has(name) && commandState?.disabled && commandState?.supported !== false && commandState?.reason == null) return true;
31972
32133
  if (!V1_ENABLED_ON_SELECTION_REASON.has(name)) return false;
31973
32134
  const reason = commandState?.reason;
@@ -32001,6 +32162,7 @@ var RESERVED_TOOLBAR_ITEM_NAMES = /* @__PURE__ */ new Set([
32001
32162
  * proof lane, and behavior tests resolve against a real object.
32002
32163
  */
32003
32164
  var BuiltInToolbar = class extends import_eventemitter3.default {
32165
+ #formattingRefusalTooltips;
32004
32166
  #imagePicker;
32005
32167
  #groupItems;
32006
32168
  #highlightOptions;
@@ -32032,6 +32194,7 @@ var BuiltInToolbar = class extends import_eventemitter3.default {
32032
32194
  showPageNumberButton: false
32033
32195
  };
32034
32196
  this.toolbarItems = [];
32197
+ this.#formattingRefusalTooltips = /* @__PURE__ */ new WeakMap();
32035
32198
  this.overflowItems = [];
32036
32199
  this.pendingSelectionCapture = void 0;
32037
32200
  this.#imagePicker = null;
@@ -32492,6 +32655,13 @@ var BuiltInToolbar = class extends import_eventemitter3.default {
32492
32655
  const commandId = resolveBuiltInItemCommandId(name);
32493
32656
  if (!commandId) return false;
32494
32657
  const commandState = this.snapshot?.commands?.[commandId];
32658
+ if (commandState?.reason === "deleted-text-formatting-unsupported") {
32659
+ if (!this.#formattingRefusalTooltips.has(item)) this.#formattingRefusalTooltips.set(item, item.tooltip.value);
32660
+ item.tooltip.value = "Select kept text, or accept or reject the deletion before formatting.";
32661
+ } else if (this.#formattingRefusalTooltips.has(item)) {
32662
+ item.tooltip.value = this.#formattingRefusalTooltips.get(item);
32663
+ this.#formattingRefusalTooltips.delete(item);
32664
+ }
32495
32665
  if ((name === "list" || name === "numberedlist") && item.attributes.value.ariaBusy !== Boolean(commandState?.pending)) item.attributes.value = {
32496
32666
  ...item.attributes.value,
32497
32667
  ariaBusy: Boolean(commandState?.pending)
@@ -33012,6 +33182,7 @@ function runtimeUserOf(user) {
33012
33182
  const text = (value) => typeof value === "string" && value ? value : void 0;
33013
33183
  return {
33014
33184
  name: text(user.name) ?? "",
33185
+ ...user.commentIdentity !== void 0 ? { commentIdentity: user.commentIdentity ? { ...user.commentIdentity } : null } : {},
33015
33186
  ...text(user.id) ? { id: text(user.id) } : {},
33016
33187
  ...text(user.email) ? { email: text(user.email) } : {},
33017
33188
  ...text(user.initials) ? { initials: text(user.initials) } : {}
@@ -33258,6 +33429,7 @@ var SuperDoc = class extends import_eventemitter3.default {
33258
33429
  if (!config.selector) throw new Error("SuperDoc: selector is required");
33259
33430
  const container = typeof config.selector === "string" ? document.querySelector(config.selector) : config.selector;
33260
33431
  if (!(container instanceof HTMLElement)) throw new Error("SuperDoc: selector must be a valid CSS selector string or DOM element");
33432
+ const user = normalizeSuperDocUser(config.user);
33261
33433
  this.#diagnostics = createInteractionHistory(this, config, () => this.version, container);
33262
33434
  this.#surfaceManager = new SurfaceManager({ getModuleConfig: () => this.#surfacesConfig });
33263
33435
  this.#contentControlClickRoot = container;
@@ -33267,7 +33439,10 @@ var SuperDoc = class extends import_eventemitter3.default {
33267
33439
  container.addEventListener("keydown", this.#handleContentControlKeyDown, true);
33268
33440
  container.addEventListener("click", this.#handleContentControlClick, true);
33269
33441
  this.#onConfig("content-control:active-change", config.onContentControlActiveChange);
33270
- this.#init(config, container);
33442
+ this.#init({
33443
+ ...config,
33444
+ user
33445
+ }, container);
33271
33446
  this.#contentControlEventBridgeReady = true;
33272
33447
  if (this.listenerCount("content-control:active-change") > 0) this.ui;
33273
33448
  }
@@ -33320,7 +33495,6 @@ var SuperDoc = class extends import_eventemitter3.default {
33320
33495
  }
33321
33496
  this.editorVersion = 2;
33322
33497
  this.#validateLegacyConfig();
33323
- this.config.user = normalizeSuperDocUser(this.config.user);
33324
33498
  if (!this.config.layoutEngineOptions.virtualization) this.config.layoutEngineOptions.virtualization = {
33325
33499
  enabled: true,
33326
33500
  window: 5,
@@ -33346,7 +33520,7 @@ var SuperDoc = class extends import_eventemitter3.default {
33346
33520
  }
33347
33521
  this.userColorMap = /* @__PURE__ */ new Map();
33348
33522
  this.colorIndex = 0;
33349
- this.version = "2.30.0-next.4";
33523
+ this.version = "2.30.0-next.9";
33350
33524
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
33351
33525
  this.superdocId = config.superdocId || v4();
33352
33526
  this.colors = this.config.colors ?? [];
@@ -34219,10 +34393,15 @@ var SuperDoc = class extends import_eventemitter3.default {
34219
34393
  this.#requireReady("setUser");
34220
34394
  const name = typeof user?.name === "string" ? user.name.trim() : "";
34221
34395
  if (!name) return Promise.reject(/* @__PURE__ */ new TypeError("SuperDoc.setUser requires a non-empty user name."));
34222
- const next = normalizeSuperDocUser({
34223
- ...user,
34224
- name
34225
- });
34396
+ let next;
34397
+ try {
34398
+ next = normalizeSuperDocUser({
34399
+ ...user,
34400
+ name
34401
+ });
34402
+ } catch (error) {
34403
+ return Promise.reject(error);
34404
+ }
34226
34405
  const applied = this.#userSwitch.then(() => this.#applyUser(next));
34227
34406
  this.#userSwitch = applied.catch(() => {});
34228
34407
  return applied;
@@ -34236,7 +34415,7 @@ var SuperDoc = class extends import_eventemitter3.default {
34236
34415
  "email",
34237
34416
  "image",
34238
34417
  "initials"
34239
- ].every((key) => (current[key] ?? null) === (next[key] ?? null))) return;
34418
+ ].every((key) => (current[key] ?? null) === (next[key] ?? null)) && current.commentIdentity === void 0 === (next.commentIdentity === void 0) && (current.commentIdentity?.providerId ?? null) === (next.commentIdentity?.providerId ?? null) && (current.commentIdentity?.userId ?? null) === (next.commentIdentity?.userId ?? null)) return;
34240
34419
  const runtimes = this.#editorRuntimeRegistry.getAll();
34241
34420
  const results = await Promise.allSettled(runtimes.map((runtime) => runtime.setUser?.(runtimeUserOf(next))));
34242
34421
  const failure = results.find((result) => result.status === "rejected");