superdoc 2.23.0-next.1 → 2.23.0-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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.23.0-next.1";
307
+ return "2.23.0-next.3";
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 = [
@@ -23523,11 +23565,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
23523
23565
  contentControlsChrome: proxy.$superdoc.uiConfig.contentControls.options.chrome,
23524
23566
  resolveTrackedChangeColor: composeAuthorColorResolver(proxy.$superdoc.config.modules?.trackChanges?.authorColors)
23525
23567
  } : void 0,
23526
- permissionResolver: (payload = {}) => proxy.$superdoc.canPerformPermission({
23527
- role: proxy.$superdoc.config.role,
23528
- isInternal: proxy.$superdoc.config.isInternal,
23529
- ...payload
23530
- })
23568
+ permissionResolver: createTrackedChangePermissionResolver(proxy.$superdoc)
23531
23569
  };
23532
23570
  };
23533
23571
  const REPLAY_MUTABLE_COMMENT_FIELDS = /* @__PURE__ */ new Set([
@@ -24570,7 +24608,7 @@ var SuperDoc_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_v
24570
24608
  ], 38);
24571
24609
  };
24572
24610
  }
24573
- }, [["__scopeId", "data-v-99399849"]]);
24611
+ }, [["__scopeId", "data-v-3a8081b4"]]);
24574
24612
  //#endregion
24575
24613
  //#region src/core/create-app.js
24576
24614
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
@@ -40887,6 +40925,9 @@ var _sfc_main$12 = /*@__PURE__*/ Object.assign({ inheritAttrs: false }, {
40887
40925
  const handleEscape = (event) => {
40888
40926
  if (event.key === "Escape") close();
40889
40927
  };
40928
+ const handleTriggerKeydown = (event) => {
40929
+ if (event.key === "Enter" || event.key === " ") close();
40930
+ };
40890
40931
  require__plugin_vue_export_helper.watch(() => props.disabled, (disabled) => {
40891
40932
  if (disabled) close();
40892
40933
  });
@@ -40917,8 +40958,13 @@ var _sfc_main$12 = /*@__PURE__*/ Object.assign({ inheritAttrs: false }, {
40917
40958
  onMouseenter: handleTriggerMouseEnter,
40918
40959
  onMouseleave: handleTriggerMouseLeave,
40919
40960
  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" }, {
40961
+ onFocusout: handleTriggerMouseLeave,
40962
+ onClickCapture: close,
40963
+ onKeydownCapture: handleTriggerKeydown
40964
+ }, [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, {
40965
+ name: "fade-in-scale-up-transition",
40966
+ css: isOpen.value
40967
+ }, {
40922
40968
  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
40969
  key: 0,
40924
40970
  ref_key: "contentRef",
@@ -40933,11 +40979,11 @@ var _sfc_main$12 = /*@__PURE__*/ Object.assign({ inheritAttrs: false }, {
40933
40979
  "aria-hidden": "true"
40934
40980
  }, 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
40981
  _: 3
40936
- })]))], 64);
40982
+ }, 8, ["css"])]))], 64);
40937
40983
  };
40938
40984
  }
40939
40985
  });
40940
- var SdTooltip_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(_sfc_main$12, [["__scopeId", "data-v-88d296cd"]]);
40986
+ var SdTooltip_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(_sfc_main$12, [["__scopeId", "data-v-44bd03f9"]]);
40941
40987
  //#endregion
40942
40988
  //#region src/internal/toolbar/built-in/ButtonGroup.vue
40943
40989
  var _hoisted_1$10 = [
@@ -46384,13 +46430,13 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46384
46430
  commentsBlock.allowResolve = this.#interactionConfig.comments.allowResolve;
46385
46431
  }
46386
46432
  }
46387
- this.config.colors = shuffleArray(this.config.colors);
46388
46433
  this.userColorMap = /* @__PURE__ */ new Map();
46389
46434
  this.colorIndex = 0;
46390
- this.version = "2.23.0-next.1";
46435
+ this.version = "2.23.0-next.3";
46391
46436
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
46392
46437
  this.superdocId = config.superdocId || require_uuid.v4();
46393
46438
  this.colors = this.config.colors ?? [];
46439
+ this.#assignUserColor();
46394
46440
  this.#initDocuments();
46395
46441
  await loadDefaultV2IntegrationOrFallback();
46396
46442
  if (this.#destroyed) return;
@@ -48799,6 +48845,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
48799
48845
  this.highContrastModeStore?.setHighContrastMode(isHighContrast);
48800
48846
  }
48801
48847
  };
48848
+ Object.defineProperty(SuperDoc.prototype.canPerformPermission, Symbol.for("superdoc.internal.permission-method.builtin"), { value: true });
48802
48849
  //#endregion
48803
48850
  //#region src/core/theme/create-theme.ts
48804
48851
  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.23.0-next.1";
305
+ return "2.23.0-next.3";
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 = [
@@ -23482,11 +23524,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
23482
23524
  contentControlsChrome: proxy.$superdoc.uiConfig.contentControls.options.chrome,
23483
23525
  resolveTrackedChangeColor: composeAuthorColorResolver(proxy.$superdoc.config.modules?.trackChanges?.authorColors)
23484
23526
  } : void 0,
23485
- permissionResolver: (payload = {}) => proxy.$superdoc.canPerformPermission({
23486
- role: proxy.$superdoc.config.role,
23487
- isInternal: proxy.$superdoc.config.isInternal,
23488
- ...payload
23489
- })
23527
+ permissionResolver: createTrackedChangePermissionResolver(proxy.$superdoc)
23490
23528
  };
23491
23529
  };
23492
23530
  const REPLAY_MUTABLE_COMMENT_FIELDS = /* @__PURE__ */ new Set([
@@ -24529,7 +24567,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
24529
24567
  ], 38);
24530
24568
  };
24531
24569
  }
24532
- }, [["__scopeId", "data-v-99399849"]]);
24570
+ }, [["__scopeId", "data-v-3a8081b4"]]);
24533
24571
  //#endregion
24534
24572
  //#region src/core/create-app.js
24535
24573
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
@@ -40838,6 +40876,9 @@ var SdTooltip_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
40838
40876
  const handleEscape = (event) => {
40839
40877
  if (event.key === "Escape") close();
40840
40878
  };
40879
+ const handleTriggerKeydown = (event) => {
40880
+ if (event.key === "Enter" || event.key === " ") close();
40881
+ };
40841
40882
  watch$1(() => props.disabled, (disabled) => {
40842
40883
  if (disabled) close();
40843
40884
  });
@@ -40868,8 +40909,13 @@ var SdTooltip_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
40868
40909
  onMouseenter: handleTriggerMouseEnter,
40869
40910
  onMouseleave: handleTriggerMouseLeave,
40870
40911
  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" }, {
40912
+ onFocusout: handleTriggerMouseLeave,
40913
+ onClickCapture: close,
40914
+ onKeydownCapture: handleTriggerKeydown
40915
+ }, [renderSlot(_ctx.$slots, "trigger", {}, void 0, true)], 544), (openBlock(), createBlock(Teleport, { to: "body" }, [createVNode(Transition, {
40916
+ name: "fade-in-scale-up-transition",
40917
+ css: isOpen.value
40918
+ }, {
40873
40919
  default: withCtx(() => [isOpen.value && !__props.disabled ? (openBlock(), createElementBlock("div", {
40874
40920
  key: 0,
40875
40921
  ref_key: "contentRef",
@@ -40884,10 +40930,10 @@ var SdTooltip_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
40884
40930
  "aria-hidden": "true"
40885
40931
  }, null, -1)), renderSlot(_ctx.$slots, "default", {}, void 0, true)], 46, _hoisted_1$11)) : createCommentVNode("", true)]),
40886
40932
  _: 3
40887
- })]))], 64);
40933
+ }, 8, ["css"])]))], 64);
40888
40934
  };
40889
40935
  }
40890
- }), [["__scopeId", "data-v-88d296cd"]]);
40936
+ }), [["__scopeId", "data-v-44bd03f9"]]);
40891
40937
  //#endregion
40892
40938
  //#region src/internal/toolbar/built-in/ButtonGroup.vue
40893
40939
  var _hoisted_1$10 = [
@@ -46313,13 +46359,13 @@ var SuperDoc = class extends import_eventemitter3.default {
46313
46359
  commentsBlock.allowResolve = this.#interactionConfig.comments.allowResolve;
46314
46360
  }
46315
46361
  }
46316
- this.config.colors = shuffleArray(this.config.colors);
46317
46362
  this.userColorMap = /* @__PURE__ */ new Map();
46318
46363
  this.colorIndex = 0;
46319
- this.version = "2.23.0-next.1";
46364
+ this.version = "2.23.0-next.3";
46320
46365
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
46321
46366
  this.superdocId = config.superdocId || v4();
46322
46367
  this.colors = this.config.colors ?? [];
46368
+ this.#assignUserColor();
46323
46369
  this.#initDocuments();
46324
46370
  await loadDefaultV2IntegrationOrFallback();
46325
46371
  if (this.#destroyed) return;
@@ -48728,6 +48774,7 @@ var SuperDoc = class extends import_eventemitter3.default {
48728
48774
  this.highContrastModeStore?.setHighContrastMode(isHighContrast);
48729
48775
  }
48730
48776
  };
48777
+ Object.defineProperty(SuperDoc.prototype.canPerformPermission, Symbol.for("superdoc.internal.permission-method.builtin"), { value: true });
48731
48778
  //#endregion
48732
48779
  //#region src/core/theme/create-theme.ts
48733
48780
  var COLORS_TO_VARS = {