@harbour-enterprises/superdoc 1.5.0-next.7 → 1.5.0-next.8

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.
@@ -1,5 +1,5 @@
1
- import { B as BIT8, M as MAX_SAFE_INTEGER, c as create, a as BITS7, u as utf8TextDecoder, b as create$1, s as setIfUndefined, d as create$2, f as from, e as floor$1, g as equalityDeep, w as writeVarUint, h as writeVarString, t as toUint8Array, i as createEncoder, j as createInjectionKey, k as toString, l as throwError, m as useSsrAdapter, n as configProviderInjectionKey, o as cssrAnchorMetaName, p as globalStyle, q as cB, r as c, v as isMounted, x as commonVariables$2, y as cM, z as cNotM, A as cE, C as derived, D as changeColor, E as insideModal, F as insidePopover, G as resolveWrappedSlot, H as on, I as warnOnce, J as useConfig, K as useMergedState, L as useMemo, N as useTheme, O as useRtl, P as createKey, Q as useThemeClass, R as createId, S as call, T as render, U as messageProviderInjectionKey, V as messageApiInjectionKey, W as fromBase64, X as onChange, Y as varStorage, Z as toBase64, _ as createUint8ArrayFromArrayBuffer, $ as offChange, a0 as writeVarUint8Array, a1 as map, a2 as length, a3 as isNode, a4 as min, a5 as pow, a6 as comments_module_events, a7 as getFileObject, a8 as getTrackChanges, a9 as CommentsPluginKey, aa as TrackChangesBasePluginKey, ab as Editor, ac as getRichTextExtensions, ad as ellipsisVerticalSvg, ae as xmarkIconSvg, af as checkIconSvg, ag as caretDownIconSvg, ah as commentIconSvg, ai as _export_sfc, aj as NDropdown, ak as SuperInput, al as vClickOutside, am as PresentationEditor, an as SuperEditor, ao as AIWriter, ap as NConfigProvider, aq as SuperToolbar } from "./index-7ebfCUN0.es.js";
2
- import "./SuperConverter-S5AfMnkn.es.js";
1
+ import { B as BIT8, M as MAX_SAFE_INTEGER, c as create, a as BITS7, u as utf8TextDecoder, b as create$1, s as setIfUndefined, d as create$2, f as from, e as floor$1, g as equalityDeep, w as writeVarUint, h as writeVarString, t as toUint8Array, i as createEncoder, j as createInjectionKey, k as toString, l as throwError, m as useSsrAdapter, n as configProviderInjectionKey, o as cssrAnchorMetaName, p as globalStyle, q as cB, r as c, v as isMounted, x as commonVariables$2, y as cM, z as cNotM, A as cE, C as derived, D as changeColor, E as insideModal, F as insidePopover, G as resolveWrappedSlot, H as on, I as warnOnce, J as useConfig, K as useMergedState, L as useMemo, N as useTheme, O as useRtl, P as createKey, Q as useThemeClass, R as createId, S as call, T as render, U as messageProviderInjectionKey, V as messageApiInjectionKey, W as fromBase64, X as onChange, Y as varStorage, Z as toBase64, _ as createUint8ArrayFromArrayBuffer, $ as offChange, a0 as writeVarUint8Array, a1 as map, a2 as length, a3 as isNode, a4 as min, a5 as pow, a6 as comments_module_events, a7 as getFileObject, a8 as getTrackChanges, a9 as CommentsPluginKey, aa as TrackChangesBasePluginKey, ab as Editor, ac as getRichTextExtensions, ad as ellipsisVerticalSvg, ae as xmarkIconSvg, af as checkIconSvg, ag as caretDownIconSvg, ah as commentIconSvg, ai as _export_sfc, aj as NDropdown, ak as SuperInput, al as vClickOutside, am as PresentationEditor, an as SuperEditor, ao as AIWriter, ap as NConfigProvider, aq as SuperToolbar } from "./index-DIb368iJ.es.js";
2
+ import "./SuperConverter-CXmwt666.es.js";
3
3
  import { B as BlankDOCX } from "./blank-docx-ABm6XYAA.es.js";
4
4
  import { E as EventEmitter } from "./eventemitter3-CwrdEv8r.es.js";
5
5
  import { HocuspocusProvider, HocuspocusProviderWebsocket } from "@hocuspocus/provider";
@@ -7513,7 +7513,7 @@ const _sfc_main = {
7513
7513
  __name: "SuperDoc",
7514
7514
  emits: ["selection-update"],
7515
7515
  setup(__props, { emit: __emit }) {
7516
- const PdfViewer = defineAsyncComponent(() => import("./PdfViewer-ClST5VR6.es.js"));
7516
+ const PdfViewer = defineAsyncComponent(() => import("./PdfViewer-ChE3uW6-.es.js"));
7517
7517
  const superdocStore = useSuperdocStore();
7518
7518
  const commentsStore = useCommentsStore();
7519
7519
  const {
@@ -8467,7 +8467,7 @@ class SuperDoc extends EventEmitter {
8467
8467
  this.config.colors = shuffleArray(this.config.colors);
8468
8468
  this.userColorMap = /* @__PURE__ */ new Map();
8469
8469
  this.colorIndex = 0;
8470
- this.version = "1.5.0-next.7";
8470
+ this.version = "1.5.0-next.8";
8471
8471
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
8472
8472
  this.superdocId = config.superdocId || v4();
8473
8473
  this.colors = this.config.colors;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  const jszip = require("./jszip-C8_CqJxM.cjs");
3
3
  const helpers$1 = require("./helpers-nOdwpmwb.cjs");
4
- const superEditor_converter = require("./SuperConverter-CIjArITT.cjs");
4
+ const superEditor_converter = require("./SuperConverter-iLb7JzYI.cjs");
5
5
  const vue = require("./vue-De9wkgLl.cjs");
6
6
  require("./jszip.min-BPh2MMAa.cjs");
7
7
  const eventemitter3 = require("./eventemitter3-BQuRcMPI.cjs");
@@ -15524,7 +15524,7 @@ const canUseDOM = () => {
15524
15524
  return false;
15525
15525
  }
15526
15526
  };
15527
- const summaryVersion = "1.5.0-next.7";
15527
+ const summaryVersion = "1.5.0-next.8";
15528
15528
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
15529
15529
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
15530
15530
  function mapAttributes(attrs) {
@@ -18181,7 +18181,7 @@ class Editor extends EventEmitter {
18181
18181
  * Process collaboration migrations
18182
18182
  */
18183
18183
  processCollaborationMigrations() {
18184
- console.debug("[checkVersionMigrations] Current editor version", "1.5.0-next.7");
18184
+ console.debug("[checkVersionMigrations] Current editor version", "1.5.0-next.8");
18185
18185
  if (!this.options.ydoc) return;
18186
18186
  const metaMap = this.options.ydoc.getMap("meta");
18187
18187
  let docVersion = metaMap.get("version");
@@ -23469,7 +23469,8 @@ const lineStyles = (lineHeight2) => ({
23469
23469
  // The primary fix uses accurate font metrics from Canvas API, but this
23470
23470
  // provides defense-in-depth against any remaining sub-pixel rendering
23471
23471
  // differences between measurement and display.
23472
- overflow: "visible"
23472
+ overflow: "visible",
23473
+ zIndex: "10"
23473
23474
  });
23474
23475
  const PRINT_STYLES = `
23475
23476
  @media print {
@@ -23775,6 +23776,7 @@ const SDT_CONTAINER_STYLES = `
23775
23776
  border: 1px solid #629be7;
23776
23777
  position: relative;
23777
23778
  display: inline;
23779
+ z-index: 10;
23778
23780
  }
23779
23781
 
23780
23782
  /* Hover effect for inline structured content */
@@ -49108,8 +49110,6 @@ class EditorOverlayManager {
49108
49110
  #activeRegion = null;
49109
49111
  /** Full-width border line element (MS Word style) */
49110
49112
  #borderLine = null;
49111
- /** Dimming overlay element (for dimming body content during editing) */
49112
- #dimmingOverlay = null;
49113
49113
  /**
49114
49114
  * Creates a new EditorOverlayManager instance.
49115
49115
  *
@@ -49403,17 +49403,6 @@ class EditorOverlayManager {
49403
49403
  }
49404
49404
  }
49405
49405
  }
49406
- /**
49407
- * Hides and removes the dimming overlay.
49408
- * @internal Reserved for future implementation of body dimming during header/footer editing.
49409
- */
49410
- // eslint-disable-next-line no-unused-private-class-members
49411
- #hideDimmingOverlay() {
49412
- if (this.#dimmingOverlay) {
49413
- this.#dimmingOverlay.remove();
49414
- this.#dimmingOverlay = null;
49415
- }
49416
- }
49417
49406
  /**
49418
49407
  * Shows a full-width border line at the bottom of the header or top of the footer.
49419
49408
  * This creates the MS Word style visual indicator spanning edge-to-edge of the page.
@@ -51586,6 +51575,7 @@ class PresentationEditor extends EventEmitter {
51586
51575
  #viewportHost;
51587
51576
  #painterHost;
51588
51577
  #selectionOverlay;
51578
+ #permissionOverlay = null;
51589
51579
  #hiddenHost;
51590
51580
  #layoutOptions;
51591
51581
  #layoutState = { blocks: [], measures: [], layout: null, bookmarks: /* @__PURE__ */ new Map() };
@@ -51745,6 +51735,16 @@ class PresentationEditor extends EventEmitter {
51745
51735
  });
51746
51736
  this.#domIndexObserverManager.setup();
51747
51737
  this.#selectionSync.on("render", () => this.#updateSelection());
51738
+ this.#selectionSync.on("render", () => this.#updatePermissionOverlay());
51739
+ this.#permissionOverlay = doc2.createElement("div");
51740
+ this.#permissionOverlay.className = "presentation-editor__permission-overlay";
51741
+ Object.assign(this.#permissionOverlay.style, {
51742
+ position: "absolute",
51743
+ inset: "0",
51744
+ pointerEvents: "none",
51745
+ zIndex: "5"
51746
+ });
51747
+ this.#viewportHost.appendChild(this.#permissionOverlay);
51748
51748
  this.#selectionOverlay = doc2.createElement("div");
51749
51749
  this.#selectionOverlay.className = "presentation-editor__selection-overlay";
51750
51750
  this.#selectionOverlay.id = `presentation-overlay-${options.documentId || "default"}`;
@@ -51830,7 +51830,7 @@ class PresentationEditor extends EventEmitter {
51830
51830
  const normalizedEditorProps = {
51831
51831
  ...editorOptions.editorProps ?? {},
51832
51832
  editable: () => {
51833
- return this.#documentMode !== "viewing";
51833
+ return !this.#isViewLocked();
51834
51834
  }
51835
51835
  };
51836
51836
  try {
@@ -52272,6 +52272,7 @@ class PresentationEditor extends EventEmitter {
52272
52272
  this.#pendingDocChange = true;
52273
52273
  this.#scheduleRerender();
52274
52274
  }
52275
+ this.#updatePermissionOverlay();
52275
52276
  }
52276
52277
  #syncDocumentModeClass() {
52277
52278
  if (!this.#visibleHost) return;
@@ -53661,7 +53662,7 @@ class PresentationEditor extends EventEmitter {
53661
53662
  win,
53662
53663
  this.#visibleHost,
53663
53664
  () => this.#getActiveDomTarget(),
53664
- () => this.#documentMode !== "viewing"
53665
+ () => !this.#isViewLocked()
53665
53666
  );
53666
53667
  this.#inputBridge.bind();
53667
53668
  }
@@ -54586,7 +54587,7 @@ class PresentationEditor extends EventEmitter {
54586
54587
  this.#dragUsedPageNotMountedFallback = false;
54587
54588
  return;
54588
54589
  }
54589
- if (this.#session.mode !== "body" || this.#documentMode === "viewing") {
54590
+ if (this.#session.mode !== "body" || this.#isViewLocked()) {
54590
54591
  this.#dragLastPointer = null;
54591
54592
  this.#dragLastRawHit = null;
54592
54593
  this.#dragUsedPageNotMountedFallback = false;
@@ -54936,6 +54937,7 @@ class PresentationEditor extends EventEmitter {
54936
54937
  this.#epochMapper.onLayoutComplete(layoutEpoch);
54937
54938
  this.#selectionSync.onLayoutComplete(layoutEpoch);
54938
54939
  layoutCompleted = true;
54940
+ this.#updatePermissionOverlay();
54939
54941
  this.#layoutError = null;
54940
54942
  this.#layoutErrorState = "healthy";
54941
54943
  this.#dismissErrorBanner();
@@ -55024,7 +55026,7 @@ class PresentationEditor extends EventEmitter {
55024
55026
  if (!this.#localSelectionLayer) {
55025
55027
  return;
55026
55028
  }
55027
- if (this.#documentMode === "viewing") {
55029
+ if (this.#isViewLocked()) {
55028
55030
  try {
55029
55031
  this.#localSelectionLayer.innerHTML = "";
55030
55032
  } catch (error) {
@@ -55106,6 +55108,76 @@ class PresentationEditor extends EventEmitter {
55106
55108
  }
55107
55109
  }
55108
55110
  }
55111
+ /**
55112
+ * Updates the permission overlay (w:permStart/w:permEnd) to match the current editor permission ranges.
55113
+ *
55114
+ * This method is called after layout completes to ensure permission overlay
55115
+ * is based on stable permission ranges data.
55116
+ */
55117
+ #updatePermissionOverlay() {
55118
+ const overlay2 = this.#permissionOverlay;
55119
+ if (!overlay2) {
55120
+ return;
55121
+ }
55122
+ if (this.#session.mode !== "body") {
55123
+ overlay2.innerHTML = "";
55124
+ return;
55125
+ }
55126
+ const permissionStorage = this.#editor?.storage?.permissionRanges;
55127
+ const ranges = permissionStorage?.ranges ?? [];
55128
+ const shouldRender = ranges.length > 0;
55129
+ if (!shouldRender) {
55130
+ overlay2.innerHTML = "";
55131
+ return;
55132
+ }
55133
+ const layout = this.#layoutState.layout;
55134
+ if (!layout) {
55135
+ overlay2.innerHTML = "";
55136
+ return;
55137
+ }
55138
+ const docEpoch = this.#epochMapper.getCurrentEpoch();
55139
+ if (this.#layoutEpoch < docEpoch) {
55140
+ return;
55141
+ }
55142
+ const pageHeight = this.#getBodyPageHeight();
55143
+ const pageGap = layout.pageGap ?? this.#getEffectivePageGap();
55144
+ const fragment = overlay2.ownerDocument?.createDocumentFragment();
55145
+ if (!fragment) {
55146
+ overlay2.innerHTML = "";
55147
+ return;
55148
+ }
55149
+ ranges.forEach(({ from: from3, to }) => {
55150
+ const rects = this.#computeSelectionRectsFromDom(from3, to);
55151
+ if (!rects?.length) {
55152
+ return;
55153
+ }
55154
+ rects.forEach((rect) => {
55155
+ const pageLocalY = rect.y - rect.pageIndex * (pageHeight + pageGap);
55156
+ const coords = this.#convertPageLocalToOverlayCoords(rect.pageIndex, rect.x, pageLocalY);
55157
+ if (!coords) {
55158
+ return;
55159
+ }
55160
+ const highlight = overlay2.ownerDocument?.createElement("div");
55161
+ if (!highlight) {
55162
+ return;
55163
+ }
55164
+ highlight.className = "presentation-editor__permission-highlight";
55165
+ Object.assign(highlight.style, {
55166
+ position: "absolute",
55167
+ left: `${coords.x}px`,
55168
+ top: `${coords.y}px`,
55169
+ width: `${Math.max(1, rect.width)}px`,
55170
+ height: `${Math.max(1, rect.height)}px`,
55171
+ borderRadius: "2px",
55172
+ pointerEvents: "none",
55173
+ zIndex: 1
55174
+ });
55175
+ fragment.appendChild(highlight);
55176
+ });
55177
+ });
55178
+ overlay2.innerHTML = "";
55179
+ overlay2.appendChild(fragment);
55180
+ }
55109
55181
  #resolveLayoutOptions(blocks, sectionMetadata) {
55110
55182
  const defaults = this.#computeDefaultLayoutDefaults();
55111
55183
  const firstSection = blocks?.find(
@@ -55851,7 +55923,7 @@ class PresentationEditor extends EventEmitter {
55851
55923
  this.#announce(announcement.message);
55852
55924
  }
55853
55925
  #validateHeaderFooterEditPermission() {
55854
- if (this.#documentMode === "viewing") {
55926
+ if (this.#isViewLocked()) {
55855
55927
  return { allowed: false, reason: "documentMode" };
55856
55928
  }
55857
55929
  if (!this.#editor.isEditable) {
@@ -56714,6 +56786,17 @@ class PresentationEditor extends EventEmitter {
56714
56786
  this.#errorBanner = null;
56715
56787
  this.#errorBannerMessage = null;
56716
56788
  }
56789
+ /**
56790
+ * Determines whether the current viewing mode should block edits.
56791
+ * When documentMode is viewing but the active editor has been toggled
56792
+ * back to editable (e.g. permission ranges), we treat the view as editable.
56793
+ */
56794
+ #isViewLocked() {
56795
+ if (this.#documentMode !== "viewing") return false;
56796
+ const hasPermissionOverride = !!this.#editor?.storage?.permissionRanges?.hasAllowedRanges;
56797
+ if (hasPermissionOverride) return false;
56798
+ return this.#documentMode === "viewing";
56799
+ }
56717
56800
  /**
56718
56801
  * Applies vertical alignment and font scaling to layout DOM elements for subscript/superscript rendering.
56719
56802
  *
@@ -58593,6 +58676,11 @@ const structuredContentHelpers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ O
58593
58676
  parseTagObject
58594
58677
  }, Symbol.toStringTag, { value: "Module" }));
58595
58678
  const STRUCTURED_CONTENT_NAMES = ["structuredContent", "structuredContentBlock"];
58679
+ function isValidIntegerId(id) {
58680
+ if (id === null || id === void 0) return true;
58681
+ const str = String(id);
58682
+ return /^-?\d+$/.test(str);
58683
+ }
58596
58684
  const findFirstTextNode = (node) => {
58597
58685
  let firstTextNode = null;
58598
58686
  node.descendants((child) => {
@@ -58634,6 +58722,9 @@ const StructuredContentCommands = Extension.create({
58634
58722
  * });
58635
58723
  */
58636
58724
  insertStructuredContentInline: (options = {}) => ({ editor, dispatch, state, tr }) => {
58725
+ if (options.attrs?.id !== void 0 && !isValidIntegerId(options.attrs.id)) {
58726
+ throw new Error("Invalid structured content id - must be an integer, got: " + options.attrs.id);
58727
+ }
58637
58728
  const { schema } = editor;
58638
58729
  let { from: from3, to } = state.selection;
58639
58730
  if (dispatch) {
@@ -58696,6 +58787,9 @@ const StructuredContentCommands = Extension.create({
58696
58787
  * });
58697
58788
  */
58698
58789
  insertStructuredContentBlock: (options = {}) => ({ editor, dispatch, state, tr }) => {
58790
+ if (options.attrs?.id !== void 0 && !isValidIntegerId(options.attrs.id)) {
58791
+ throw new Error("Invalid structured content id - must be an integer, got: " + options.attrs.id);
58792
+ }
58699
58793
  const { schema } = editor;
58700
58794
  let { from: from3, to } = state.selection;
58701
58795
  if (dispatch) {
@@ -58753,6 +58847,9 @@ const StructuredContentCommands = Extension.create({
58753
58847
  * });
58754
58848
  */
58755
58849
  updateStructuredContentById: (id, options = {}) => ({ editor, dispatch, state, tr }) => {
58850
+ if (options.attrs?.id !== void 0 && !isValidIntegerId(options.attrs.id)) {
58851
+ throw new Error("Invalid structured content id - must be an integer, got: " + options.attrs.id);
58852
+ }
58756
58853
  const structuredContentTags = getStructuredContentTagsById(id, state);
58757
58854
  if (!structuredContentTags.length) {
58758
58855
  return true;
@@ -58880,6 +58977,9 @@ const StructuredContentCommands = Extension.create({
58880
58977
  * });
58881
58978
  */
58882
58979
  updateStructuredContentByGroup: (group, options = {}) => ({ editor, dispatch, state, tr }) => {
58980
+ if (options.attrs?.id !== void 0 && !isValidIntegerId(options.attrs.id)) {
58981
+ throw new Error("Invalid structured content id - must be an integer, got: " + options.attrs.id);
58982
+ }
58883
58983
  const structuredContentTags = getStructuredContentByGroup(group, state);
58884
58984
  if (!structuredContentTags.length) {
58885
58985
  return true;
@@ -59557,7 +59657,7 @@ const mergeRanges$2 = (ranges, docSize) => {
59557
59657
  }
59558
59658
  return merged;
59559
59659
  };
59560
- const collectChangedRanges = (trs, docSize) => {
59660
+ const collectChangedRanges$1 = (trs, docSize) => {
59561
59661
  const ranges = [];
59562
59662
  trs.forEach((tr) => {
59563
59663
  if (!tr.docChanged) return;
@@ -59760,7 +59860,7 @@ const wrapTextInRunsPlugin = (editor) => {
59760
59860
  const runType = newState.schema.nodes.run;
59761
59861
  if (!runType) return null;
59762
59862
  pendingRanges = mapRangesThroughTransactions(pendingRanges, transactions, docSize);
59763
- const changedRanges = collectChangedRanges(transactions, docSize);
59863
+ const changedRanges = collectChangedRanges$1(transactions, docSize);
59764
59864
  pendingRanges = mergeRanges$2([...pendingRanges, ...changedRanges], docSize);
59765
59865
  if (view?.composing) {
59766
59866
  return null;
@@ -74635,6 +74735,283 @@ const NodeResizer = Extension.create({
74635
74735
  return [nodeResizer(["image"], this.editor)];
74636
74736
  }
74637
74737
  });
74738
+ const PERMISSION_PLUGIN_KEY = new superEditor_converter.PluginKey("permissionRanges");
74739
+ const EVERYONE_GROUP = "everyone";
74740
+ const EMPTY_IDENTIFIER_SET = Object.freeze(/* @__PURE__ */ new Set());
74741
+ const normalizeIdentifier = (value) => typeof value === "string" ? value.trim().toLowerCase() : "";
74742
+ const buildAllowedIdentifierSet = (editor) => {
74743
+ const email = normalizeIdentifier(editor?.options?.user?.email);
74744
+ if (!email) {
74745
+ return EMPTY_IDENTIFIER_SET;
74746
+ }
74747
+ const [localPart, domain] = email.split("@");
74748
+ if (!localPart || !domain) {
74749
+ return EMPTY_IDENTIFIER_SET;
74750
+ }
74751
+ const formatted = `${domain}\\${localPart}`;
74752
+ return formatted ? /* @__PURE__ */ new Set([formatted]) : EMPTY_IDENTIFIER_SET;
74753
+ };
74754
+ const isEveryoneGroup = (value) => normalizeIdentifier(value) === EVERYONE_GROUP;
74755
+ const isRangeAllowedForUser = (attrs, allowedIdentifiers) => {
74756
+ if (!attrs) return false;
74757
+ if (isEveryoneGroup(attrs.edGrp)) {
74758
+ return true;
74759
+ }
74760
+ if (!allowedIdentifiers?.size) {
74761
+ return false;
74762
+ }
74763
+ const normalizedEd = normalizeIdentifier(attrs.ed);
74764
+ return normalizedEd && allowedIdentifiers.has(normalizedEd);
74765
+ };
74766
+ const getPermissionNodeId = (node, pos, fallbackPrefix) => String(node.attrs?.id ?? `${fallbackPrefix}-${pos}`);
74767
+ const buildPermissionState = (doc2, allowedIdentifiers = EMPTY_IDENTIFIER_SET) => {
74768
+ const ranges = [];
74769
+ const openRanges = /* @__PURE__ */ new Map();
74770
+ doc2.descendants((node, pos) => {
74771
+ if (node.type?.name === "permStart") {
74772
+ const id = getPermissionNodeId(node, pos, "permStart");
74773
+ openRanges.set(id, {
74774
+ from: pos + node.nodeSize,
74775
+ attrs: node.attrs ?? {}
74776
+ });
74777
+ return false;
74778
+ }
74779
+ if (node.type?.name === "permEnd") {
74780
+ const id = getPermissionNodeId(node, pos, "permEnd");
74781
+ const start2 = openRanges.get(id);
74782
+ if (start2 && isRangeAllowedForUser(start2.attrs, allowedIdentifiers)) {
74783
+ const to = Math.max(pos, start2.from);
74784
+ if (to > start2.from) {
74785
+ ranges.push({
74786
+ id,
74787
+ from: start2.from,
74788
+ to
74789
+ });
74790
+ }
74791
+ }
74792
+ if (start2) {
74793
+ openRanges.delete(id);
74794
+ }
74795
+ return false;
74796
+ }
74797
+ });
74798
+ return {
74799
+ ranges,
74800
+ hasAllowedRanges: ranges.length > 0
74801
+ };
74802
+ };
74803
+ const collectPermissionTags = (doc2, permStartType, permEndType) => {
74804
+ const tags = /* @__PURE__ */ new Map();
74805
+ doc2.descendants((node, pos) => {
74806
+ if (node.type !== permStartType && node.type !== permEndType) {
74807
+ return;
74808
+ }
74809
+ const id = node.attrs?.id;
74810
+ if (!id) {
74811
+ return;
74812
+ }
74813
+ const entry = tags.get(id) ?? {};
74814
+ if (node.type === permStartType) {
74815
+ entry.start = { pos, attrs: node.attrs ?? {} };
74816
+ } else if (node.type === permEndType) {
74817
+ entry.end = { pos, attrs: node.attrs ?? {} };
74818
+ }
74819
+ tags.set(id, entry);
74820
+ });
74821
+ return tags;
74822
+ };
74823
+ const clampPosition = (pos, size2) => {
74824
+ if (Number.isNaN(pos) || !Number.isFinite(pos)) {
74825
+ return 0;
74826
+ }
74827
+ return Math.max(0, Math.min(pos, size2));
74828
+ };
74829
+ const trimPermissionTagsFromRange = (doc2, range, permStartType, permEndType) => {
74830
+ let from3 = range.from;
74831
+ let to = range.to;
74832
+ while (from3 < to) {
74833
+ const node = doc2.nodeAt(from3);
74834
+ if (!node || node.type !== permStartType && node.type !== permEndType) {
74835
+ break;
74836
+ }
74837
+ from3 += node.nodeSize;
74838
+ }
74839
+ while (to > from3) {
74840
+ const $pos = doc2.resolve(to);
74841
+ const nodeBefore = $pos.nodeBefore;
74842
+ if (!nodeBefore || nodeBefore.type !== permStartType && nodeBefore.type !== permEndType) {
74843
+ break;
74844
+ }
74845
+ to -= nodeBefore.nodeSize;
74846
+ }
74847
+ return { from: from3, to };
74848
+ };
74849
+ const collectChangedRanges = (tr) => {
74850
+ const ranges = [];
74851
+ tr.mapping.maps.forEach((map3) => {
74852
+ map3.forEach((oldStart, oldEnd) => {
74853
+ const from3 = Math.min(oldStart, oldEnd);
74854
+ const to = Math.max(oldStart, oldEnd);
74855
+ ranges.push({ from: from3, to });
74856
+ });
74857
+ });
74858
+ return ranges;
74859
+ };
74860
+ const isRangeAllowed = (range, allowedRanges) => {
74861
+ if (!allowedRanges?.length) return false;
74862
+ return allowedRanges.some((allowed) => range.from >= allowed.from && range.to <= allowed.to);
74863
+ };
74864
+ const PermissionRanges = Extension.create({
74865
+ name: "permissionRanges",
74866
+ addStorage() {
74867
+ return {
74868
+ ranges: [],
74869
+ hasAllowedRanges: false
74870
+ };
74871
+ },
74872
+ addPmPlugins() {
74873
+ const editor = this.editor;
74874
+ const storage = this.storage;
74875
+ let originalSetDocumentMode = null;
74876
+ const getAllowedIdentifiers = () => buildAllowedIdentifierSet(editor);
74877
+ const toggleEditableIfAllowed = (hasAllowedRanges) => {
74878
+ if (!editor || editor.isDestroyed) return;
74879
+ if (editor.options.documentMode !== "viewing") return;
74880
+ if (hasAllowedRanges && !editor.isEditable) {
74881
+ editor.setEditable(true, false);
74882
+ } else if (!hasAllowedRanges && editor.isEditable) {
74883
+ editor.setEditable(false, false);
74884
+ }
74885
+ };
74886
+ const updateEditableState = (hasAllowedRanges) => {
74887
+ const nextValue = Boolean(hasAllowedRanges);
74888
+ const previousValue = storage.hasAllowedRanges;
74889
+ storage.hasAllowedRanges = nextValue;
74890
+ if (previousValue === nextValue) {
74891
+ return;
74892
+ }
74893
+ toggleEditableIfAllowed(nextValue);
74894
+ };
74895
+ if (editor && typeof editor.setDocumentMode === "function") {
74896
+ originalSetDocumentMode = editor.setDocumentMode.bind(editor);
74897
+ editor.setDocumentMode = (mode, caller) => {
74898
+ originalSetDocumentMode(mode, caller);
74899
+ const state = editor.state;
74900
+ if (!state) return;
74901
+ const pluginState = PERMISSION_PLUGIN_KEY.getState(state);
74902
+ if (pluginState) {
74903
+ toggleEditableIfAllowed(pluginState.hasAllowedRanges);
74904
+ }
74905
+ };
74906
+ }
74907
+ return [
74908
+ new superEditor_converter.Plugin({
74909
+ key: PERMISSION_PLUGIN_KEY,
74910
+ state: {
74911
+ init(_2, state) {
74912
+ const permissionState = buildPermissionState(state.doc, getAllowedIdentifiers());
74913
+ storage.ranges = permissionState.ranges;
74914
+ updateEditableState(permissionState.hasAllowedRanges);
74915
+ return permissionState;
74916
+ },
74917
+ apply(tr, value, _oldState, newState) {
74918
+ let permissionState = value;
74919
+ if (tr.docChanged) {
74920
+ permissionState = buildPermissionState(newState.doc, getAllowedIdentifiers());
74921
+ storage.ranges = permissionState.ranges;
74922
+ updateEditableState(permissionState.hasAllowedRanges);
74923
+ }
74924
+ return permissionState;
74925
+ }
74926
+ },
74927
+ view() {
74928
+ return {
74929
+ destroy() {
74930
+ if (editor && originalSetDocumentMode) {
74931
+ editor.setDocumentMode = originalSetDocumentMode;
74932
+ }
74933
+ }
74934
+ };
74935
+ },
74936
+ // Appends transactions to the document to ensure permission ranges are updated.
74937
+ appendTransaction(transactions, oldState, newState) {
74938
+ if (!transactions.some((tr2) => tr2.docChanged)) return null;
74939
+ const permStartType = newState.schema.nodes["permStart"];
74940
+ const permEndType = newState.schema.nodes["permEnd"];
74941
+ if (!permStartType || !permEndType) return null;
74942
+ const oldTags = collectPermissionTags(oldState.doc, permStartType, permEndType);
74943
+ if (!oldTags.size) {
74944
+ return null;
74945
+ }
74946
+ const newTags = collectPermissionTags(newState.doc, permStartType, permEndType);
74947
+ const mappingToNew = new superEditor_converter.Mapping();
74948
+ transactions.forEach((tr2) => {
74949
+ mappingToNew.appendMapping(tr2.mapping);
74950
+ });
74951
+ const pendingInsertions = [];
74952
+ oldTags.forEach((tag, id) => {
74953
+ const current = newTags.get(id);
74954
+ if (tag.start && !current?.start) {
74955
+ const mapped = mappingToNew.mapResult(tag.start.pos, -1);
74956
+ pendingInsertions.push({
74957
+ pos: mapped.pos,
74958
+ nodeType: permStartType,
74959
+ attrs: tag.start.attrs,
74960
+ priority: 0
74961
+ });
74962
+ }
74963
+ if (tag.end && !current?.end) {
74964
+ const mapped = mappingToNew.mapResult(tag.end.pos, 1);
74965
+ pendingInsertions.push({
74966
+ pos: mapped.pos,
74967
+ nodeType: permEndType,
74968
+ attrs: tag.end.attrs,
74969
+ priority: 1
74970
+ });
74971
+ }
74972
+ });
74973
+ if (!pendingInsertions.length) {
74974
+ return null;
74975
+ }
74976
+ pendingInsertions.sort((a, b2) => {
74977
+ if (a.pos === b2.pos) {
74978
+ return a.priority - b2.priority;
74979
+ }
74980
+ return a.pos - b2.pos;
74981
+ });
74982
+ const tr = newState.tr;
74983
+ let offset2 = 0;
74984
+ pendingInsertions.forEach((item) => {
74985
+ const node = item.nodeType.create(item.attrs);
74986
+ const insertPos = clampPosition(item.pos + offset2, tr.doc.content.size);
74987
+ tr.insert(insertPos, node);
74988
+ offset2 += node.nodeSize;
74989
+ });
74990
+ return tr.docChanged ? tr : null;
74991
+ },
74992
+ // Filters transactions to ensure only allowed edits are applied.
74993
+ filterTransaction(tr, state) {
74994
+ if (!tr.docChanged) return true;
74995
+ if (!editor || editor.options.documentMode !== "viewing") return true;
74996
+ const pluginState = PERMISSION_PLUGIN_KEY.getState(state);
74997
+ if (!pluginState?.hasAllowedRanges) {
74998
+ return true;
74999
+ }
75000
+ const changedRanges = collectChangedRanges(tr);
75001
+ if (!changedRanges.length) return true;
75002
+ const permStartType = state.schema.nodes["permStart"];
75003
+ const permEndType = state.schema.nodes["permEnd"];
75004
+ if (!permStartType || !permEndType) return true;
75005
+ const allRangesAllowed = changedRanges.every((range) => {
75006
+ const trimmed = trimPermissionTagsFromRange(state.doc, range, permStartType, permEndType);
75007
+ return isRangeAllowed(trimmed, pluginState.ranges);
75008
+ });
75009
+ return allRangesAllowed;
75010
+ }
75011
+ })
75012
+ ];
75013
+ }
75014
+ });
74638
75015
  const PermStart = Node$1.create({
74639
75016
  name: "permStart",
74640
75017
  group: "inline",
@@ -74794,6 +75171,7 @@ const getStarterExtensions = () => {
74794
75171
  ShapeGroup,
74795
75172
  PermStart,
74796
75173
  PermEnd,
75174
+ PermissionRanges,
74797
75175
  PassthroughInline,
74798
75176
  PassthroughBlock
74799
75177
  ];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
- const index = require("./index-LpMObyDy.cjs");
3
- require("./SuperConverter-CIjArITT.cjs");
2
+ const index = require("./index-CJcGqc_k.cjs");
3
+ require("./SuperConverter-iLb7JzYI.cjs");
4
4
  const blankDocx = require("./blank-docx-DfW3Eeh2.cjs");
5
5
  const eventemitter3 = require("./eventemitter3-BQuRcMPI.cjs");
6
6
  const provider = require("@hocuspocus/provider");
@@ -7530,7 +7530,7 @@ const _sfc_main = {
7530
7530
  __name: "SuperDoc",
7531
7531
  emits: ["selection-update"],
7532
7532
  setup(__props, { emit: __emit }) {
7533
- const PdfViewer = vue.defineAsyncComponent(() => Promise.resolve().then(() => require("./PdfViewer-Cli6IR-X.cjs")));
7533
+ const PdfViewer = vue.defineAsyncComponent(() => Promise.resolve().then(() => require("./PdfViewer-DKfNDdEk.cjs")));
7534
7534
  const superdocStore = useSuperdocStore();
7535
7535
  const commentsStore = useCommentsStore();
7536
7536
  const {
@@ -8484,7 +8484,7 @@ class SuperDoc extends eventemitter3.EventEmitter {
8484
8484
  this.config.colors = shuffleArray(this.config.colors);
8485
8485
  this.userColorMap = /* @__PURE__ */ new Map();
8486
8486
  this.colorIndex = 0;
8487
- this.version = "1.5.0-next.7";
8487
+ this.version = "1.5.0-next.8";
8488
8488
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
8489
8489
  this.superdocId = config.superdocId || uuid.v4();
8490
8490
  this.colors = this.config.colors;