superdoc 2.22.1-next.2 → 2.23.0-next.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/chunks/{create-super-doc-ui-MSiU8Kg0.cjs → create-super-doc-ui-CbiiPcgr.cjs} +5 -1
  2. package/dist/chunks/{create-super-doc-ui-DmGX1w-i.es.js → create-super-doc-ui-DHW9Toxn.es.js} +5 -1
  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/capabilities/capabilities.d.ts +7 -0
  6. package/dist/document-api/src/index.d.ts +11 -3
  7. package/dist/document-api/src/insert/insert.d.ts +2 -1
  8. package/dist/document-api/src/types/clipboard.d.ts +25 -0
  9. package/dist/document-api/src/types/sd-contract.d.ts +1 -1
  10. package/dist/document-api/src/write/operation-cancellation.d.ts +54 -0
  11. package/dist/layout-engine/contracts/src/index.d.ts +2 -0
  12. package/dist/layout-engine/layout-bridge/src/incrementalLayout.d.ts +2 -0
  13. package/dist/layout-engine/layout-engine/src/index.d.ts +2 -0
  14. package/dist/layout-engine/painters/dom/src/paragraph/list-marker.d.ts +3 -1
  15. package/dist/layout-engine/painters/dom/src/table/border-utils.d.ts +1 -1
  16. package/dist/layout-engine/style-engine/src/normalize/index.d.ts +1 -1
  17. package/dist/layout-engine/style-engine/src/normalize/run-attrs.d.ts +12 -0
  18. package/dist/public/ui-react.cjs +1 -1
  19. package/dist/public/ui-react.es.js +1 -1
  20. package/dist/public/ui-vue.cjs +1 -1
  21. package/dist/public/ui-vue.es.js +1 -1
  22. package/dist/public/ui.cjs +1 -1
  23. package/dist/public/ui.es.js +1 -1
  24. package/dist/shared/common/list-marker-utils.d.ts +1 -1
  25. package/dist/style.css +106 -114
  26. package/dist/style.layered.css +106 -114
  27. package/dist/superdoc/src/core/collaboration/permissions.d.ts +1 -0
  28. package/dist/superdoc.cjs +95 -47
  29. package/dist/superdoc.es.js +95 -47
  30. package/dist-cdn/style.layered.css +1 -1
  31. package/dist-cdn/superdoc.min.css +1 -1
  32. package/dist-cdn/superdoc.min.js +43 -42
  33. package/package.json +2 -2
package/dist/superdoc.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("./chunks/rolldown-runtime-74VwNCz7.cjs");
3
3
  const require_blank_docx = require("./chunks/blank-docx-BuFAbRjs.cjs");
4
- const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-MSiU8Kg0.cjs");
4
+ const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-CbiiPcgr.cjs");
5
5
  const require_eventemitter3 = require("./chunks/eventemitter3-C_TAnXOl.cjs");
6
6
  const require_uuid = require("./chunks/uuid-BhG0ngwk.cjs");
7
7
  const require__plugin_vue_export_helper = require("./chunks/_plugin-vue_export-helper-CYxINHh_.cjs");
@@ -299,24 +299,12 @@ var awarenessStatesToArray = (context, states) => {
299
299
  };
300
300
  });
301
301
  };
302
- /**
303
- * Shuffle an array of hex colors
304
- * @param array - List of hex colors
305
- * @returns Shuffled array of hex colors
306
- */
307
- var shuffleArray = (array) => {
308
- for (let i = array.length - 1; i > 0; i--) {
309
- const j = Math.floor(Math.random() * (i + 1));
310
- [array[i], array[j]] = [array[j], array[i]];
311
- }
312
- return array;
313
- };
314
302
  //#endregion
315
303
  //#region ../../shared/common/Telemetry.ts
316
304
  var DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
317
305
  function getSuperdocVersion() {
318
306
  try {
319
- return "2.22.1-next.2";
307
+ return "2.23.0-next.10";
320
308
  } catch {
321
309
  return "unknown";
322
310
  }
@@ -7614,6 +7602,7 @@ var getTrackedChangeIndex = () => null;
7614
7602
  var resolveTrackedChangeInStory = () => null;
7615
7603
  var makeTrackedChangeAnchorKey = ({ storyKey, rawId }) => `tc::${storyKey}::${rawId}`;
7616
7604
  var COMMENT_DRAFT_BR_TAG = /<br(?:\s[^>]*)?\s*\/?>/gi;
7605
+ var COMMENT_DRAFT_BLOCK_BOUNDARY = /(?:<\/(?:p|div|li|blockquote|pre|h[1-6])\s*>\s*)+(?:<(?:p|div|li|blockquote|pre|h[1-6])(?:\s[^>]*)?\s*\/?>)+/gi;
7617
7606
  var COMMENT_DRAFT_BLOCK_OPEN_TAG = /<(?:p|div|li|blockquote|pre|h[1-6])(?:\s[^>]*)?\s*\/?>/gi;
7618
7607
  var COMMENT_DRAFT_BLOCK_CLOSE_TAG = /<\/(?:p|div|li|blockquote|pre|h[1-6])\s*>/gi;
7619
7608
  var COMMENT_DRAFT_ANY_TAG = /<\/?[A-Za-z][A-Za-z0-9:-]*(?:\s[^>]*)?\s*\/?>/g;
@@ -7707,7 +7696,7 @@ var decodeCommentDraftEntities = (value) => value.replace(COMMENT_DRAFT_ENTITY,
7707
7696
  var normalizeV2CommentDraftText = (value) => {
7708
7697
  const html = String(value ?? "");
7709
7698
  if (!html || html === "<p></p>") return "";
7710
- return decodeCommentDraftEntities(html.replace(COMMENT_DRAFT_BR_TAG, "\n").replace(COMMENT_DRAFT_BLOCK_CLOSE_TAG, "\n").replace(COMMENT_DRAFT_BLOCK_OPEN_TAG, "").replace(COMMENT_DRAFT_ANY_TAG, "")).replace(/\n{3,}/g, "\n\n").replace(/^\n+/, "").replace(/\n+$/, "");
7699
+ return decodeCommentDraftEntities(html.replace(COMMENT_DRAFT_BLOCK_BOUNDARY, "\n").replace(COMMENT_DRAFT_BR_TAG, "\n").replace(COMMENT_DRAFT_BLOCK_CLOSE_TAG, "").replace(COMMENT_DRAFT_BLOCK_OPEN_TAG, "").replace(COMMENT_DRAFT_ANY_TAG, ""));
7711
7700
  };
7712
7701
  var cloneV2TrackedChangeStory = (story) => {
7713
7702
  if (!story || typeof story !== "object") return null;
@@ -7946,6 +7935,14 @@ var useCommentsStore = defineStore("comments", () => {
7946
7935
  if (!normalizedId) return null;
7947
7936
  return normalizedId.startsWith("imported:") ? normalizedId : `imported:${normalizedId}`;
7948
7937
  };
7938
+ const positionEntriesByAlias = require__plugin_vue_export_helper.computed(() => {
7939
+ const aliases = /* @__PURE__ */ new Map();
7940
+ for (const [key, entry] of Object.entries(editorCommentPositions.value || {})) for (const alias of [normalizeCommentId(entry?.key), normalizeCommentId(entry?.threadId)]) if (alias && !aliases.has(alias)) aliases.set(alias, {
7941
+ key,
7942
+ entry
7943
+ });
7944
+ return aliases;
7945
+ });
7949
7946
  const getPositionEntryByAlias = (id) => {
7950
7947
  const normalizedId = normalizeCommentId(id);
7951
7948
  if (!normalizedId) return {
@@ -7957,15 +7954,7 @@ var useCommentsStore = defineStore("comments", () => {
7957
7954
  key: normalizedId,
7958
7955
  entry: positions[normalizedId]
7959
7956
  };
7960
- for (const [key, entry] of Object.entries(positions)) {
7961
- const entryKey = normalizeCommentId(entry?.key);
7962
- const threadId = normalizeCommentId(entry?.threadId);
7963
- if (entryKey === normalizedId || threadId === normalizedId) return {
7964
- key,
7965
- entry
7966
- };
7967
- }
7968
- return {
7957
+ return positionEntriesByAlias.value.get(normalizedId) ?? {
7969
7958
  key: null,
7970
7959
  entry: null
7971
7960
  };
@@ -8014,6 +8003,41 @@ var useCommentsStore = defineStore("comments", () => {
8014
8003
  });
8015
8004
  return matches.length === 1 ? matches[0] : null;
8016
8005
  };
8006
+ const commentIdentityIndex = require__plugin_vue_export_helper.computed(() => {
8007
+ const list = commentsList.value;
8008
+ if (!require__plugin_vue_export_helper.isReactive(list)) return null;
8009
+ const primary = /* @__PURE__ */ new Map();
8010
+ const aliases = /* @__PURE__ */ new Map();
8011
+ for (const comment of list) {
8012
+ if (!require__plugin_vue_export_helper.isReactive(comment)) return null;
8013
+ for (const key of [
8014
+ "commentId",
8015
+ "importedId",
8016
+ "trackedChangeAnchorKey",
8017
+ "trackedChange"
8018
+ ]) {
8019
+ const descriptor = Object.getOwnPropertyDescriptor(comment, key);
8020
+ if (descriptor?.get || descriptor?.set || !descriptor && key in comment) return null;
8021
+ }
8022
+ const ids = [
8023
+ comment.commentId,
8024
+ comment.importedId,
8025
+ comment.trackedChangeAnchorKey
8026
+ ];
8027
+ if (ids.some((id) => id != null && typeof id !== "string")) return null;
8028
+ if (ids[0] != null && !primary.has(ids[0])) primary.set(ids[0], comment);
8029
+ const importedPositionId = comment.trackedChange ? buildTrackedChangeImportedPositionId(ids[1]) : null;
8030
+ for (const alias of [
8031
+ ids[1],
8032
+ ids[2],
8033
+ importedPositionId
8034
+ ]) if (alias != null && !aliases.has(alias)) aliases.set(alias, comment);
8035
+ }
8036
+ return {
8037
+ primary,
8038
+ aliases
8039
+ };
8040
+ });
8017
8041
  /**
8018
8042
  * Get a comment by either ID or imported ID
8019
8043
  *
@@ -8025,7 +8049,8 @@ var useCommentsStore = defineStore("comments", () => {
8025
8049
  const byPrimaryId = (c) => c.commentId == id;
8026
8050
  const byAliasId = (c) => c.importedId == id || c.trackedChangeAnchorKey == id || c?.trackedChange && buildTrackedChangeImportedPositionId(c.importedId) == id;
8027
8051
  const findIn = (list) => list.find(byPrimaryId) ?? list.find(byAliasId);
8028
- return findIn(commentsList.value) ?? findIn(reviewDirectoryList.value) ?? getTrackedChangeCommentByPositionAlias(id);
8052
+ const index = typeof id === "string" ? commentIdentityIndex.value : null;
8053
+ return (index ? index.primary.get(id) ?? index.aliases.get(id) : findIn(commentsList.value)) ?? findIn(reviewDirectoryList.value) ?? getTrackedChangeCommentByPositionAlias(id);
8029
8054
  };
8030
8055
  const getThreadParent = (comment) => {
8031
8056
  if (!comment?.parentCommentId) return comment;
@@ -9513,7 +9538,7 @@ var useCommentsStore = defineStore("comments", () => {
9513
9538
  reason: "parent-comment-id-missing"
9514
9539
  };
9515
9540
  const plainText = normalizeV2CommentDraftText(text);
9516
- if (plainText.length === 0) return {
9541
+ if (plainText.trim().length === 0) return {
9517
9542
  ok: false,
9518
9543
  reason: "comment-text-empty"
9519
9544
  };
@@ -9590,7 +9615,7 @@ var useCommentsStore = defineStore("comments", () => {
9590
9615
  reason: "comment-id-missing"
9591
9616
  };
9592
9617
  const plainText = normalizeV2CommentDraftText(text);
9593
- if (plainText.length === 0) return {
9618
+ if (plainText.trim().length === 0) return {
9594
9619
  ok: false,
9595
9620
  reason: "comment-text-empty"
9596
9621
  };
@@ -12525,6 +12550,19 @@ var pickResolver = (context = {}) => {
12525
12550
  if (typeof deprecatedResolver === "function") return deprecatedResolver;
12526
12551
  return null;
12527
12552
  };
12553
+ var BUILT_IN_PERMISSION_METHOD = Symbol.for("superdoc.internal.permission-method.builtin");
12554
+ var BUILT_IN_PERMISSION_RESOLVER = Symbol.for("superdoc.internal.permission-resolver.builtin");
12555
+ /** Create the shell's internal, live tracked-change permission shim. */
12556
+ var createTrackedChangePermissionResolver = (superdoc) => {
12557
+ const isBuiltInPolicy = () => superdoc.canPerformPermission?.[BUILT_IN_PERMISSION_METHOD] === true && pickResolver({ superdoc }) === null;
12558
+ const resolver = (payload = {}) => isBuiltInPolicy() ? defaultDecisionFor(payload.permission, superdoc.config.role, superdoc.config.isInternal) : superdoc.canPerformPermission({
12559
+ ...payload,
12560
+ role: superdoc.config.role,
12561
+ isInternal: superdoc.config.isInternal
12562
+ });
12563
+ Object.defineProperty(resolver, BUILT_IN_PERMISSION_RESOLVER, { value: isBuiltInPolicy });
12564
+ return resolver;
12565
+ };
12528
12566
  var defaultDecisionFor = (permission, role, isInternal) => {
12529
12567
  const internalExternal = isInternal ? "internal" : "external";
12530
12568
  return PERMISSION_MATRIX[permission]?.[internalExternal]?.includes(role) ?? false;
@@ -12985,15 +13023,19 @@ var _sfc_main$35 = {
12985
13023
  const htmlToText = (html) => {
12986
13024
  const value = String(html ?? "");
12987
13025
  if (!value || value === "<p></p>") return "";
12988
- if (typeof document === "undefined") return value.replace(/<br\s*\/?>/gi, "\n").replace(/<[^>]+>/g, "");
13026
+ if (typeof document === "undefined") return value.replace(/<\/p>\s*<p\b[^>]*>/gi, "\n").replace(/<br\s*\/?>/gi, "\n").replace(/<[^>]+>/g, "");
12989
13027
  const element = document.createElement("div");
12990
13028
  element.innerHTML = value;
12991
- return element.innerText || element.textContent || "";
13029
+ element.querySelectorAll("br").forEach((br) => br.replaceWith("\n"));
13030
+ element.querySelectorAll("p").forEach((paragraph, index) => {
13031
+ if (index > 0) paragraph.before("\n");
13032
+ });
13033
+ return element.textContent || "";
12992
13034
  };
12993
13035
  const textToHtml = (value) => {
12994
- const normalized = String(value ?? "").replace(/\r\n/g, "\n").trim();
13036
+ const normalized = String(value ?? "").replace(/\r\n/g, "\n");
12995
13037
  if (!normalized) return "<p></p>";
12996
- return normalized.split(/\n{2,}/).map((paragraph) => `<p>${escapeHtml(paragraph).replace(/\n/g, "<br>")}</p>`).join("");
13038
+ return `<p>${escapeHtml(normalized).replace(/\n/g, "<br>")}</p>`;
12997
13039
  };
12998
13040
  const commentDraft = require__plugin_vue_export_helper.computed({
12999
13041
  get: () => htmlToText(currentCommentText.value),
@@ -13122,7 +13164,7 @@ var _sfc_main$35 = {
13122
13164
  };
13123
13165
  }
13124
13166
  };
13125
- var CommentInput_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(_sfc_main$35, [["__scopeId", "data-v-87953125"]]);
13167
+ var CommentInput_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(_sfc_main$35, [["__scopeId", "data-v-0720a671"]]);
13126
13168
  //#endregion
13127
13169
  //#region src/components/CommentsLayer/CommentDialog.vue
13128
13170
  var _hoisted_1$27 = [
@@ -13622,7 +13664,7 @@ var _sfc_main$34 = {
13622
13664
  return !suppressInternalExternal.value && !props.comment.trackedChange;
13623
13665
  });
13624
13666
  const hasTextContent = require__plugin_vue_export_helper.computed(() => {
13625
- return currentCommentText.value && currentCommentText.value !== "<p></p>";
13667
+ return Boolean(currentCommentText.value?.replace(/<[^>]*>/g, "").trim());
13626
13668
  });
13627
13669
  const setFocus = async () => {
13628
13670
  const editor = proxy.$superdoc.activeEditor;
@@ -14347,7 +14389,7 @@ var _sfc_main$34 = {
14347
14389
  };
14348
14390
  }
14349
14391
  };
14350
- var CommentDialog_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(_sfc_main$34, [["__scopeId", "data-v-21ad0f69"]]);
14392
+ var CommentDialog_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(_sfc_main$34, [["__scopeId", "data-v-dcbcc0d4"]]);
14351
14393
  //#endregion
14352
14394
  //#region src/components/CommentsLayer/commentsList/ReviewDirectoryListItem.vue
14353
14395
  var _hoisted_1$26 = [
@@ -22764,7 +22806,8 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
22764
22806
  documentId,
22765
22807
  commentsAdapter: commentsAdapter ?? null,
22766
22808
  trackedChangesAdapter: trackedChangesAdapter ?? null,
22767
- resolveReviewWindow: (input) => host.resolveReviewWindow(input)
22809
+ resolveReviewWindow: (input) => host.resolveReviewWindow(input),
22810
+ moveFragmentWordIds: (ids) => host.getHandles().trackChanges.moveFragmentWordIds(ids)
22768
22811
  });
22769
22812
  if (areDocumentsReady.value && !proxy.$superdoc.config.collaboration) isReady.value = true;
22770
22813
  isFloatingCommentsReady.value = true;
@@ -23523,11 +23566,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
23523
23566
  contentControlsChrome: proxy.$superdoc.uiConfig.contentControls.options.chrome,
23524
23567
  resolveTrackedChangeColor: composeAuthorColorResolver(proxy.$superdoc.config.modules?.trackChanges?.authorColors)
23525
23568
  } : void 0,
23526
- permissionResolver: (payload = {}) => proxy.$superdoc.canPerformPermission({
23527
- role: proxy.$superdoc.config.role,
23528
- isInternal: proxy.$superdoc.config.isInternal,
23529
- ...payload
23530
- })
23569
+ permissionResolver: createTrackedChangePermissionResolver(proxy.$superdoc)
23531
23570
  };
23532
23571
  };
23533
23572
  const REPLAY_MUTABLE_COMMENT_FIELDS = /* @__PURE__ */ new Set([
@@ -24570,7 +24609,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
24570
24609
  ], 38);
24571
24610
  };
24572
24611
  }
24573
- }, [["__scopeId", "data-v-99399849"]]);
24612
+ }, [["__scopeId", "data-v-3a8bc935"]]);
24574
24613
  //#endregion
24575
24614
  //#region src/core/create-app.js
24576
24615
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
@@ -40887,6 +40926,9 @@ var _sfc_main$12 = /*@__PURE__*/ Object.assign({ inheritAttrs: false }, {
40887
40926
  const handleEscape = (event) => {
40888
40927
  if (event.key === "Escape") close();
40889
40928
  };
40929
+ const handleTriggerKeydown = (event) => {
40930
+ if (event.key === "Enter" || event.key === " ") close();
40931
+ };
40890
40932
  require__plugin_vue_export_helper.watch(() => props.disabled, (disabled) => {
40891
40933
  if (disabled) close();
40892
40934
  });
@@ -40917,8 +40959,13 @@ var _sfc_main$12 = /*@__PURE__*/ Object.assign({ inheritAttrs: false }, {
40917
40959
  onMouseenter: handleTriggerMouseEnter,
40918
40960
  onMouseleave: handleTriggerMouseLeave,
40919
40961
  onFocusin: handleTriggerMouseEnter,
40920
- onFocusout: handleTriggerMouseLeave
40921
- }, [require__plugin_vue_export_helper.renderSlot(_ctx.$slots, "trigger", {}, void 0, true)], 544), (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createBlock(require__plugin_vue_export_helper.Teleport, { to: "body" }, [require__plugin_vue_export_helper.createVNode(require__plugin_vue_export_helper.Transition, { name: "fade-in-scale-up-transition" }, {
40962
+ onFocusout: handleTriggerMouseLeave,
40963
+ onClickCapture: close,
40964
+ onKeydownCapture: handleTriggerKeydown
40965
+ }, [require__plugin_vue_export_helper.renderSlot(_ctx.$slots, "trigger", {}, void 0, true)], 544), (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createBlock(require__plugin_vue_export_helper.Teleport, { to: "body" }, [require__plugin_vue_export_helper.createVNode(require__plugin_vue_export_helper.Transition, {
40966
+ name: "fade-in-scale-up-transition",
40967
+ css: isOpen.value
40968
+ }, {
40922
40969
  default: require__plugin_vue_export_helper.withCtx(() => [isOpen.value && !__props.disabled ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", {
40923
40970
  key: 0,
40924
40971
  ref_key: "contentRef",
@@ -40933,11 +40980,11 @@ var _sfc_main$12 = /*@__PURE__*/ Object.assign({ inheritAttrs: false }, {
40933
40980
  "aria-hidden": "true"
40934
40981
  }, null, -1)), require__plugin_vue_export_helper.renderSlot(_ctx.$slots, "default", {}, void 0, true)], 46, _hoisted_1$11)) : require__plugin_vue_export_helper.createCommentVNode("", true)]),
40935
40982
  _: 3
40936
- })]))], 64);
40983
+ }, 8, ["css"])]))], 64);
40937
40984
  };
40938
40985
  }
40939
40986
  });
40940
- var SdTooltip_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(_sfc_main$12, [["__scopeId", "data-v-88d296cd"]]);
40987
+ var SdTooltip_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(_sfc_main$12, [["__scopeId", "data-v-44bd03f9"]]);
40941
40988
  //#endregion
40942
40989
  //#region src/internal/toolbar/built-in/ButtonGroup.vue
40943
40990
  var _hoisted_1$10 = [
@@ -46384,13 +46431,13 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46384
46431
  commentsBlock.allowResolve = this.#interactionConfig.comments.allowResolve;
46385
46432
  }
46386
46433
  }
46387
- this.config.colors = shuffleArray(this.config.colors);
46388
46434
  this.userColorMap = /* @__PURE__ */ new Map();
46389
46435
  this.colorIndex = 0;
46390
- this.version = "2.22.1-next.2";
46436
+ this.version = "2.23.0-next.10";
46391
46437
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
46392
46438
  this.superdocId = config.superdocId || require_uuid.v4();
46393
46439
  this.colors = this.config.colors ?? [];
46440
+ this.#assignUserColor();
46394
46441
  this.#initDocuments();
46395
46442
  await loadDefaultV2IntegrationOrFallback();
46396
46443
  if (this.#destroyed) return;
@@ -48799,6 +48846,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
48799
48846
  this.highContrastModeStore?.setHighContrastMode(isHighContrast);
48800
48847
  }
48801
48848
  };
48849
+ Object.defineProperty(SuperDoc.prototype.canPerformPermission, Symbol.for("superdoc.internal.permission-method.builtin"), { value: true });
48802
48850
  //#endregion
48803
48851
  //#region src/core/theme/create-theme.ts
48804
48852
  var COLORS_TO_VARS = {
@@ -1,6 +1,6 @@
1
1
  import { i as __toESM$2 } from "./chunks/rolldown-runtime-0pSA04fp.es.js";
2
2
  import { t as blank_default } from "./chunks/blank-docx-DzQccOlW.es.js";
3
- import { c as createImageFilePicker, d as DOM_CLASS_NAMES, f as closeInteractionHistory, g as recordInteraction, h as isWorkflowRecordingEnabled, i as registerFirstPartyCommandMutation, l as resolveImageSrc, m as getWorkflowRecording, n as executeFirstPartyCommandAsync, o as applyV2CommentInvalidationFromMutation, p as createInteractionHistory, r as readFirstPartyPageNumbers, s as getV2TrackedChangeMutationImpact, t as createSuperDocUI } from "./chunks/create-super-doc-ui-DmGX1w-i.es.js";
3
+ import { c as createImageFilePicker, d as DOM_CLASS_NAMES, f as closeInteractionHistory, g as recordInteraction, h as isWorkflowRecordingEnabled, i as registerFirstPartyCommandMutation, l as resolveImageSrc, m as getWorkflowRecording, n as executeFirstPartyCommandAsync, o as applyV2CommentInvalidationFromMutation, p as createInteractionHistory, r as readFirstPartyPageNumbers, s as getV2TrackedChangeMutationImpact, t as createSuperDocUI } from "./chunks/create-super-doc-ui-DHW9Toxn.es.js";
4
4
  import { t as import_eventemitter3 } from "./chunks/eventemitter3-DEIiXiH2.es.js";
5
5
  import { t as v4 } from "./chunks/uuid-H0Xcmmhy.es.js";
6
6
  import { $ as watch$1, A as onActivated, B as resolveDirective, C as isRef$1, D as normalizeClass, E as nextTick, F as openBlock, G as toRef, H as shallowRef$1, I as reactive, J as useAttrs, K as toRefs, L as ref, M as onDeactivated, N as onMounted, O as normalizeProps, P as onScopeDispose$1, Q as vModelText, R as renderList, S as isReactive$1, T as mergeProps, U as toDisplayString, V as resolveDynamicComponent, W as toRaw$2, X as vModelCheckbox, Y as useSlots, Z as vModelSelect, _ as getCurrentInstance, a as computed$1, b as hasInjectionContext, c as createCommentVNode, d as createStaticVNode, et as withCtx, f as createTextVNode, g as effectScope, h as defineComponent, i as Transition, j as onBeforeUnmount, k as normalizeStyle, l as createElementBlock, m as defineAsyncComponent, n as Fragment, nt as withKeys, o as createApp, p as createVNode, q as unref, r as Teleport, rt as withModifiers, s as createBlock, t as _plugin_vue_export_helper_default, tt as withDirectives, u as createElementVNode, v as getCurrentScope, w as markRaw, x as inject$1, y as h, z as renderSlot } from "./chunks/_plugin-vue_export-helper-DHiJKCsy.es.js";
@@ -297,24 +297,12 @@ var awarenessStatesToArray = (context, states) => {
297
297
  };
298
298
  });
299
299
  };
300
- /**
301
- * Shuffle an array of hex colors
302
- * @param array - List of hex colors
303
- * @returns Shuffled array of hex colors
304
- */
305
- var shuffleArray = (array) => {
306
- for (let i = array.length - 1; i > 0; i--) {
307
- const j = Math.floor(Math.random() * (i + 1));
308
- [array[i], array[j]] = [array[j], array[i]];
309
- }
310
- return array;
311
- };
312
300
  //#endregion
313
301
  //#region ../../shared/common/Telemetry.ts
314
302
  var DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
315
303
  function getSuperdocVersion() {
316
304
  try {
317
- return "2.22.1-next.2";
305
+ return "2.23.0-next.10";
318
306
  } catch {
319
307
  return "unknown";
320
308
  }
@@ -7612,6 +7600,7 @@ var getTrackedChangeIndex = () => null;
7612
7600
  var resolveTrackedChangeInStory = () => null;
7613
7601
  var makeTrackedChangeAnchorKey = ({ storyKey, rawId }) => `tc::${storyKey}::${rawId}`;
7614
7602
  var COMMENT_DRAFT_BR_TAG = /<br(?:\s[^>]*)?\s*\/?>/gi;
7603
+ var COMMENT_DRAFT_BLOCK_BOUNDARY = /(?:<\/(?:p|div|li|blockquote|pre|h[1-6])\s*>\s*)+(?:<(?:p|div|li|blockquote|pre|h[1-6])(?:\s[^>]*)?\s*\/?>)+/gi;
7615
7604
  var COMMENT_DRAFT_BLOCK_OPEN_TAG = /<(?:p|div|li|blockquote|pre|h[1-6])(?:\s[^>]*)?\s*\/?>/gi;
7616
7605
  var COMMENT_DRAFT_BLOCK_CLOSE_TAG = /<\/(?:p|div|li|blockquote|pre|h[1-6])\s*>/gi;
7617
7606
  var COMMENT_DRAFT_ANY_TAG = /<\/?[A-Za-z][A-Za-z0-9:-]*(?:\s[^>]*)?\s*\/?>/g;
@@ -7705,7 +7694,7 @@ var decodeCommentDraftEntities = (value) => value.replace(COMMENT_DRAFT_ENTITY,
7705
7694
  var normalizeV2CommentDraftText = (value) => {
7706
7695
  const html = String(value ?? "");
7707
7696
  if (!html || html === "<p></p>") return "";
7708
- return decodeCommentDraftEntities(html.replace(COMMENT_DRAFT_BR_TAG, "\n").replace(COMMENT_DRAFT_BLOCK_CLOSE_TAG, "\n").replace(COMMENT_DRAFT_BLOCK_OPEN_TAG, "").replace(COMMENT_DRAFT_ANY_TAG, "")).replace(/\n{3,}/g, "\n\n").replace(/^\n+/, "").replace(/\n+$/, "");
7697
+ return decodeCommentDraftEntities(html.replace(COMMENT_DRAFT_BLOCK_BOUNDARY, "\n").replace(COMMENT_DRAFT_BR_TAG, "\n").replace(COMMENT_DRAFT_BLOCK_CLOSE_TAG, "").replace(COMMENT_DRAFT_BLOCK_OPEN_TAG, "").replace(COMMENT_DRAFT_ANY_TAG, ""));
7709
7698
  };
7710
7699
  var cloneV2TrackedChangeStory = (story) => {
7711
7700
  if (!story || typeof story !== "object") return null;
@@ -7944,6 +7933,14 @@ var useCommentsStore = defineStore("comments", () => {
7944
7933
  if (!normalizedId) return null;
7945
7934
  return normalizedId.startsWith("imported:") ? normalizedId : `imported:${normalizedId}`;
7946
7935
  };
7936
+ const positionEntriesByAlias = computed$1(() => {
7937
+ const aliases = /* @__PURE__ */ new Map();
7938
+ for (const [key, entry] of Object.entries(editorCommentPositions.value || {})) for (const alias of [normalizeCommentId(entry?.key), normalizeCommentId(entry?.threadId)]) if (alias && !aliases.has(alias)) aliases.set(alias, {
7939
+ key,
7940
+ entry
7941
+ });
7942
+ return aliases;
7943
+ });
7947
7944
  const getPositionEntryByAlias = (id) => {
7948
7945
  const normalizedId = normalizeCommentId(id);
7949
7946
  if (!normalizedId) return {
@@ -7955,15 +7952,7 @@ var useCommentsStore = defineStore("comments", () => {
7955
7952
  key: normalizedId,
7956
7953
  entry: positions[normalizedId]
7957
7954
  };
7958
- for (const [key, entry] of Object.entries(positions)) {
7959
- const entryKey = normalizeCommentId(entry?.key);
7960
- const threadId = normalizeCommentId(entry?.threadId);
7961
- if (entryKey === normalizedId || threadId === normalizedId) return {
7962
- key,
7963
- entry
7964
- };
7965
- }
7966
- return {
7955
+ return positionEntriesByAlias.value.get(normalizedId) ?? {
7967
7956
  key: null,
7968
7957
  entry: null
7969
7958
  };
@@ -8012,6 +8001,41 @@ var useCommentsStore = defineStore("comments", () => {
8012
8001
  });
8013
8002
  return matches.length === 1 ? matches[0] : null;
8014
8003
  };
8004
+ const commentIdentityIndex = computed$1(() => {
8005
+ const list = commentsList.value;
8006
+ if (!isReactive$1(list)) return null;
8007
+ const primary = /* @__PURE__ */ new Map();
8008
+ const aliases = /* @__PURE__ */ new Map();
8009
+ for (const comment of list) {
8010
+ if (!isReactive$1(comment)) return null;
8011
+ for (const key of [
8012
+ "commentId",
8013
+ "importedId",
8014
+ "trackedChangeAnchorKey",
8015
+ "trackedChange"
8016
+ ]) {
8017
+ const descriptor = Object.getOwnPropertyDescriptor(comment, key);
8018
+ if (descriptor?.get || descriptor?.set || !descriptor && key in comment) return null;
8019
+ }
8020
+ const ids = [
8021
+ comment.commentId,
8022
+ comment.importedId,
8023
+ comment.trackedChangeAnchorKey
8024
+ ];
8025
+ if (ids.some((id) => id != null && typeof id !== "string")) return null;
8026
+ if (ids[0] != null && !primary.has(ids[0])) primary.set(ids[0], comment);
8027
+ const importedPositionId = comment.trackedChange ? buildTrackedChangeImportedPositionId(ids[1]) : null;
8028
+ for (const alias of [
8029
+ ids[1],
8030
+ ids[2],
8031
+ importedPositionId
8032
+ ]) if (alias != null && !aliases.has(alias)) aliases.set(alias, comment);
8033
+ }
8034
+ return {
8035
+ primary,
8036
+ aliases
8037
+ };
8038
+ });
8015
8039
  /**
8016
8040
  * Get a comment by either ID or imported ID
8017
8041
  *
@@ -8023,7 +8047,8 @@ var useCommentsStore = defineStore("comments", () => {
8023
8047
  const byPrimaryId = (c) => c.commentId == id;
8024
8048
  const byAliasId = (c) => c.importedId == id || c.trackedChangeAnchorKey == id || c?.trackedChange && buildTrackedChangeImportedPositionId(c.importedId) == id;
8025
8049
  const findIn = (list) => list.find(byPrimaryId) ?? list.find(byAliasId);
8026
- return findIn(commentsList.value) ?? findIn(reviewDirectoryList.value) ?? getTrackedChangeCommentByPositionAlias(id);
8050
+ const index = typeof id === "string" ? commentIdentityIndex.value : null;
8051
+ return (index ? index.primary.get(id) ?? index.aliases.get(id) : findIn(commentsList.value)) ?? findIn(reviewDirectoryList.value) ?? getTrackedChangeCommentByPositionAlias(id);
8027
8052
  };
8028
8053
  const getThreadParent = (comment) => {
8029
8054
  if (!comment?.parentCommentId) return comment;
@@ -9511,7 +9536,7 @@ var useCommentsStore = defineStore("comments", () => {
9511
9536
  reason: "parent-comment-id-missing"
9512
9537
  };
9513
9538
  const plainText = normalizeV2CommentDraftText(text);
9514
- if (plainText.length === 0) return {
9539
+ if (plainText.trim().length === 0) return {
9515
9540
  ok: false,
9516
9541
  reason: "comment-text-empty"
9517
9542
  };
@@ -9588,7 +9613,7 @@ var useCommentsStore = defineStore("comments", () => {
9588
9613
  reason: "comment-id-missing"
9589
9614
  };
9590
9615
  const plainText = normalizeV2CommentDraftText(text);
9591
- if (plainText.length === 0) return {
9616
+ if (plainText.trim().length === 0) return {
9592
9617
  ok: false,
9593
9618
  reason: "comment-text-empty"
9594
9619
  };
@@ -12521,6 +12546,19 @@ var pickResolver = (context = {}) => {
12521
12546
  if (typeof deprecatedResolver === "function") return deprecatedResolver;
12522
12547
  return null;
12523
12548
  };
12549
+ var BUILT_IN_PERMISSION_METHOD = Symbol.for("superdoc.internal.permission-method.builtin");
12550
+ var BUILT_IN_PERMISSION_RESOLVER = Symbol.for("superdoc.internal.permission-resolver.builtin");
12551
+ /** Create the shell's internal, live tracked-change permission shim. */
12552
+ var createTrackedChangePermissionResolver = (superdoc) => {
12553
+ const isBuiltInPolicy = () => superdoc.canPerformPermission?.[BUILT_IN_PERMISSION_METHOD] === true && pickResolver({ superdoc }) === null;
12554
+ const resolver = (payload = {}) => isBuiltInPolicy() ? defaultDecisionFor(payload.permission, superdoc.config.role, superdoc.config.isInternal) : superdoc.canPerformPermission({
12555
+ ...payload,
12556
+ role: superdoc.config.role,
12557
+ isInternal: superdoc.config.isInternal
12558
+ });
12559
+ Object.defineProperty(resolver, BUILT_IN_PERMISSION_RESOLVER, { value: isBuiltInPolicy });
12560
+ return resolver;
12561
+ };
12524
12562
  var defaultDecisionFor = (permission, role, isInternal) => {
12525
12563
  const internalExternal = isInternal ? "internal" : "external";
12526
12564
  return PERMISSION_MATRIX[permission]?.[internalExternal]?.includes(role) ?? false;
@@ -12979,15 +13017,19 @@ var CommentInput_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
12979
13017
  const htmlToText = (html) => {
12980
13018
  const value = String(html ?? "");
12981
13019
  if (!value || value === "<p></p>") return "";
12982
- if (typeof document === "undefined") return value.replace(/<br\s*\/?>/gi, "\n").replace(/<[^>]+>/g, "");
13020
+ if (typeof document === "undefined") return value.replace(/<\/p>\s*<p\b[^>]*>/gi, "\n").replace(/<br\s*\/?>/gi, "\n").replace(/<[^>]+>/g, "");
12983
13021
  const element = document.createElement("div");
12984
13022
  element.innerHTML = value;
12985
- return element.innerText || element.textContent || "";
13023
+ element.querySelectorAll("br").forEach((br) => br.replaceWith("\n"));
13024
+ element.querySelectorAll("p").forEach((paragraph, index) => {
13025
+ if (index > 0) paragraph.before("\n");
13026
+ });
13027
+ return element.textContent || "";
12986
13028
  };
12987
13029
  const textToHtml = (value) => {
12988
- const normalized = String(value ?? "").replace(/\r\n/g, "\n").trim();
13030
+ const normalized = String(value ?? "").replace(/\r\n/g, "\n");
12989
13031
  if (!normalized) return "<p></p>";
12990
- return normalized.split(/\n{2,}/).map((paragraph) => `<p>${escapeHtml(paragraph).replace(/\n/g, "<br>")}</p>`).join("");
13032
+ return `<p>${escapeHtml(normalized).replace(/\n/g, "<br>")}</p>`;
12991
13033
  };
12992
13034
  const commentDraft = computed$1({
12993
13035
  get: () => htmlToText(currentCommentText.value),
@@ -13115,7 +13157,7 @@ var CommentInput_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13115
13157
  }), 128))])) : createCommentVNode("", true)])], 2)]);
13116
13158
  };
13117
13159
  }
13118
- }, [["__scopeId", "data-v-87953125"]]);
13160
+ }, [["__scopeId", "data-v-0720a671"]]);
13119
13161
  //#endregion
13120
13162
  //#region src/components/CommentsLayer/CommentDialog.vue
13121
13163
  var _hoisted_1$27 = [
@@ -13615,7 +13657,7 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13615
13657
  return !suppressInternalExternal.value && !props.comment.trackedChange;
13616
13658
  });
13617
13659
  const hasTextContent = computed$1(() => {
13618
- return currentCommentText.value && currentCommentText.value !== "<p></p>";
13660
+ return Boolean(currentCommentText.value?.replace(/<[^>]*>/g, "").trim());
13619
13661
  });
13620
13662
  const setFocus = async () => {
13621
13663
  const editor = proxy.$superdoc.activeEditor;
@@ -14339,7 +14381,7 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14339
14381
  ], 64))], 14, _hoisted_1$27)), [[_directive_click_outside, handleClickOutside]]);
14340
14382
  };
14341
14383
  }
14342
- }, [["__scopeId", "data-v-21ad0f69"]]);
14384
+ }, [["__scopeId", "data-v-dcbcc0d4"]]);
14343
14385
  //#endregion
14344
14386
  //#region src/components/CommentsLayer/commentsList/ReviewDirectoryListItem.vue
14345
14387
  var _hoisted_1$26 = [
@@ -22723,7 +22765,8 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22723
22765
  documentId,
22724
22766
  commentsAdapter: commentsAdapter ?? null,
22725
22767
  trackedChangesAdapter: trackedChangesAdapter ?? null,
22726
- resolveReviewWindow: (input) => host.resolveReviewWindow(input)
22768
+ resolveReviewWindow: (input) => host.resolveReviewWindow(input),
22769
+ moveFragmentWordIds: (ids) => host.getHandles().trackChanges.moveFragmentWordIds(ids)
22727
22770
  });
22728
22771
  if (areDocumentsReady.value && !proxy.$superdoc.config.collaboration) isReady.value = true;
22729
22772
  isFloatingCommentsReady.value = true;
@@ -23482,11 +23525,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
23482
23525
  contentControlsChrome: proxy.$superdoc.uiConfig.contentControls.options.chrome,
23483
23526
  resolveTrackedChangeColor: composeAuthorColorResolver(proxy.$superdoc.config.modules?.trackChanges?.authorColors)
23484
23527
  } : void 0,
23485
- permissionResolver: (payload = {}) => proxy.$superdoc.canPerformPermission({
23486
- role: proxy.$superdoc.config.role,
23487
- isInternal: proxy.$superdoc.config.isInternal,
23488
- ...payload
23489
- })
23528
+ permissionResolver: createTrackedChangePermissionResolver(proxy.$superdoc)
23490
23529
  };
23491
23530
  };
23492
23531
  const REPLAY_MUTABLE_COMMENT_FIELDS = /* @__PURE__ */ new Set([
@@ -24529,7 +24568,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
24529
24568
  ], 38);
24530
24569
  };
24531
24570
  }
24532
- }, [["__scopeId", "data-v-99399849"]]);
24571
+ }, [["__scopeId", "data-v-3a8bc935"]]);
24533
24572
  //#endregion
24534
24573
  //#region src/core/create-app.js
24535
24574
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
@@ -40838,6 +40877,9 @@ var SdTooltip_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
40838
40877
  const handleEscape = (event) => {
40839
40878
  if (event.key === "Escape") close();
40840
40879
  };
40880
+ const handleTriggerKeydown = (event) => {
40881
+ if (event.key === "Enter" || event.key === " ") close();
40882
+ };
40841
40883
  watch$1(() => props.disabled, (disabled) => {
40842
40884
  if (disabled) close();
40843
40885
  });
@@ -40868,8 +40910,13 @@ var SdTooltip_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
40868
40910
  onMouseenter: handleTriggerMouseEnter,
40869
40911
  onMouseleave: handleTriggerMouseLeave,
40870
40912
  onFocusin: handleTriggerMouseEnter,
40871
- onFocusout: handleTriggerMouseLeave
40872
- }, [renderSlot(_ctx.$slots, "trigger", {}, void 0, true)], 544), (openBlock(), createBlock(Teleport, { to: "body" }, [createVNode(Transition, { name: "fade-in-scale-up-transition" }, {
40913
+ onFocusout: handleTriggerMouseLeave,
40914
+ onClickCapture: close,
40915
+ onKeydownCapture: handleTriggerKeydown
40916
+ }, [renderSlot(_ctx.$slots, "trigger", {}, void 0, true)], 544), (openBlock(), createBlock(Teleport, { to: "body" }, [createVNode(Transition, {
40917
+ name: "fade-in-scale-up-transition",
40918
+ css: isOpen.value
40919
+ }, {
40873
40920
  default: withCtx(() => [isOpen.value && !__props.disabled ? (openBlock(), createElementBlock("div", {
40874
40921
  key: 0,
40875
40922
  ref_key: "contentRef",
@@ -40884,10 +40931,10 @@ var SdTooltip_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
40884
40931
  "aria-hidden": "true"
40885
40932
  }, null, -1)), renderSlot(_ctx.$slots, "default", {}, void 0, true)], 46, _hoisted_1$11)) : createCommentVNode("", true)]),
40886
40933
  _: 3
40887
- })]))], 64);
40934
+ }, 8, ["css"])]))], 64);
40888
40935
  };
40889
40936
  }
40890
- }), [["__scopeId", "data-v-88d296cd"]]);
40937
+ }), [["__scopeId", "data-v-44bd03f9"]]);
40891
40938
  //#endregion
40892
40939
  //#region src/internal/toolbar/built-in/ButtonGroup.vue
40893
40940
  var _hoisted_1$10 = [
@@ -46313,13 +46360,13 @@ var SuperDoc = class extends import_eventemitter3.default {
46313
46360
  commentsBlock.allowResolve = this.#interactionConfig.comments.allowResolve;
46314
46361
  }
46315
46362
  }
46316
- this.config.colors = shuffleArray(this.config.colors);
46317
46363
  this.userColorMap = /* @__PURE__ */ new Map();
46318
46364
  this.colorIndex = 0;
46319
- this.version = "2.22.1-next.2";
46365
+ this.version = "2.23.0-next.10";
46320
46366
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
46321
46367
  this.superdocId = config.superdocId || v4();
46322
46368
  this.colors = this.config.colors ?? [];
46369
+ this.#assignUserColor();
46323
46370
  this.#initDocuments();
46324
46371
  await loadDefaultV2IntegrationOrFallback();
46325
46372
  if (this.#destroyed) return;
@@ -48728,6 +48775,7 @@ var SuperDoc = class extends import_eventemitter3.default {
48728
48775
  this.highContrastModeStore?.setHighContrastMode(isHighContrast);
48729
48776
  }
48730
48777
  };
48778
+ Object.defineProperty(SuperDoc.prototype.canPerformPermission, Symbol.for("superdoc.internal.permission-method.builtin"), { value: true });
48731
48779
  //#endregion
48732
48780
  //#region src/core/theme/create-theme.ts
48733
48781
  var COLORS_TO_VARS = {