superdoc 1.12.0-next.12 → 1.12.0-next.13

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
1
  "use strict";
2
- const superEditor_converter = require("./SuperConverter-C4uBfLso.cjs");
2
+ const superEditor_converter = require("./SuperConverter-BMjvGr5r.cjs");
3
3
  const helpers$1 = require("./helpers-OFep8CYR.cjs");
4
4
  const vue = require("./vue-BkoOkkmT.cjs");
5
5
  require("./jszip.min-oAFpNMh5.cjs");
@@ -993,7 +993,7 @@ const DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
993
993
  const COMMUNITY_LICENSE_KEY = "community-and-eval-agplv3";
994
994
  function getSuperdocVersion() {
995
995
  try {
996
- return true ? "1.12.0-next.12" : "unknown";
996
+ return true ? "1.12.0-next.13" : "unknown";
997
997
  } catch {
998
998
  return "unknown";
999
999
  }
@@ -17068,7 +17068,7 @@ const canUseDOM = () => {
17068
17068
  return false;
17069
17069
  }
17070
17070
  };
17071
- const summaryVersion = "1.12.0-next.12";
17071
+ const summaryVersion = "1.12.0-next.13";
17072
17072
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
17073
17073
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
17074
17074
  function mapAttributes(attrs) {
@@ -19872,7 +19872,7 @@ class Editor extends EventEmitter {
19872
19872
  * Process collaboration migrations
19873
19873
  */
19874
19874
  processCollaborationMigrations() {
19875
- console.debug("[checkVersionMigrations] Current editor version", "1.12.0-next.12");
19875
+ console.debug("[checkVersionMigrations] Current editor version", "1.12.0-next.13");
19876
19876
  if (!this.options.ydoc) return;
19877
19877
  const metaMap = this.options.ydoc.getMap("meta");
19878
19878
  let docVersion = metaMap.get("version");
@@ -20050,6 +20050,300 @@ class Editor extends EventEmitter {
20050
20050
  this.#renderer?.initDevTools?.(this);
20051
20051
  }
20052
20052
  }
20053
+ function getEditorSurfaceElement(editor) {
20054
+ if (!editor) return null;
20055
+ if (typeof editor.hitTest === "function" && editor.element instanceof HTMLElement) {
20056
+ return editor.element;
20057
+ }
20058
+ return editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element ?? null;
20059
+ }
20060
+ function getSurfaceRelativePoint(editor, eventLocation = {}) {
20061
+ const surface = getEditorSurfaceElement(editor);
20062
+ if (!surface) return null;
20063
+ const rect = surface.getBoundingClientRect();
20064
+ let left2;
20065
+ let top2;
20066
+ if (typeof eventLocation.clientX === "number" && typeof eventLocation.clientY === "number") {
20067
+ left2 = eventLocation.clientX - rect.left;
20068
+ top2 = eventLocation.clientY - rect.top;
20069
+ } else if (editor?.state?.selection) {
20070
+ const selectionFrom = editor.state.selection.from;
20071
+ const coords = editor.coordsAtPos?.(selectionFrom);
20072
+ if (coords) {
20073
+ left2 = coords.left - rect.left;
20074
+ top2 = coords.top - rect.top;
20075
+ }
20076
+ }
20077
+ if (!Number.isFinite(left2) || !Number.isFinite(top2)) {
20078
+ return null;
20079
+ }
20080
+ return { left: left2, top: top2 };
20081
+ }
20082
+ function findContainingBlockAncestor(element) {
20083
+ if (!element) return null;
20084
+ let current = element.parentElement;
20085
+ while (current && current !== document.body && current !== document.documentElement) {
20086
+ try {
20087
+ const style2 = window.getComputedStyle(current);
20088
+ const transform = style2.transform;
20089
+ const filter = style2.filter;
20090
+ const backdropFilter = style2.backdropFilter || style2.webkitBackdropFilter;
20091
+ const perspective = style2.perspective;
20092
+ const willChange = style2.willChange;
20093
+ const contain = style2.contain;
20094
+ if (transform && transform !== "none") {
20095
+ return current;
20096
+ }
20097
+ if (filter && filter !== "none") {
20098
+ return current;
20099
+ }
20100
+ if (backdropFilter && backdropFilter !== "none") {
20101
+ return current;
20102
+ }
20103
+ if (perspective && perspective !== "none") {
20104
+ return current;
20105
+ }
20106
+ if (willChange && willChange !== "auto") {
20107
+ const values = willChange.split(",").map((v) => v.trim());
20108
+ if (values.includes("transform") || values.includes("perspective")) {
20109
+ return current;
20110
+ }
20111
+ }
20112
+ if (contain && /paint|layout|strict|content/.test(contain)) {
20113
+ return current;
20114
+ }
20115
+ } catch (error) {
20116
+ console.warn("SlashMenu: Failed to get computed style for element", current, error);
20117
+ }
20118
+ current = current.parentElement;
20119
+ }
20120
+ return null;
20121
+ }
20122
+ const SlashMenuPluginKey = new superEditor_converter.PluginKey("slashMenu");
20123
+ const MENU_OFFSET_X = 100;
20124
+ const MENU_OFFSET_Y = 28;
20125
+ const CONTEXT_MENU_OFFSET_X = 10;
20126
+ const CONTEXT_MENU_OFFSET_Y = 10;
20127
+ const SLASH_COOLDOWN_MS = 5e3;
20128
+ const SlashMenu = Extension.create({
20129
+ name: "slashMenu",
20130
+ /**
20131
+ * Initialize default options for the SlashMenu extension
20132
+ * @returns {SlashMenuOptions} Empty options object (configuration is inherited from editor options)
20133
+ */
20134
+ addOptions() {
20135
+ return {};
20136
+ },
20137
+ addPmPlugins() {
20138
+ const editor = this.editor;
20139
+ if (editor.options?.isHeadless) {
20140
+ return [];
20141
+ }
20142
+ let slashCooldown = false;
20143
+ let slashCooldownTimeout = null;
20144
+ const isMenuDisabled = () => Boolean(editor.options?.disableContextMenu);
20145
+ const ensureStateShape = (value = {}) => ({
20146
+ open: false,
20147
+ selected: null,
20148
+ anchorPos: null,
20149
+ menuPosition: null,
20150
+ disabled: isMenuDisabled(),
20151
+ ...value
20152
+ });
20153
+ const slashMenuPlugin = new superEditor_converter.Plugin({
20154
+ key: SlashMenuPluginKey,
20155
+ state: {
20156
+ init: () => ensureStateShape(),
20157
+ /**
20158
+ * Apply transaction to update plugin state
20159
+ * Handles state transitions based on transaction metadata:
20160
+ * - 'open': Opens menu at specified position or cursor location
20161
+ * - 'select': Updates the selected menu item
20162
+ * - 'close': Closes the menu and clears anchor position
20163
+ * - 'updatePosition': Triggers menu position recalculation (no-op in apply)
20164
+ *
20165
+ * @param {import('prosemirror-state').Transaction} tr - The transaction
20166
+ * @param {SlashMenuState} value - Previous plugin state
20167
+ * @returns {SlashMenuState} New plugin state
20168
+ */
20169
+ apply(tr, value) {
20170
+ const meta = tr.getMeta(SlashMenuPluginKey);
20171
+ const disabled = isMenuDisabled();
20172
+ if (disabled) {
20173
+ if (value.open) {
20174
+ editor.emit("slashMenu:close");
20175
+ }
20176
+ return ensureStateShape({ disabled: true });
20177
+ }
20178
+ if (!meta) {
20179
+ if (value.disabled !== disabled) {
20180
+ return ensureStateShape({ ...value, disabled });
20181
+ }
20182
+ return value;
20183
+ }
20184
+ switch (meta.type) {
20185
+ case "open": {
20186
+ if (typeof meta.pos !== "number" || meta.pos < 0 || meta.pos > tr.doc.content.size) {
20187
+ console.warn("SlashMenu: Invalid position", meta.pos);
20188
+ return ensureStateShape(value);
20189
+ }
20190
+ let left2 = 0;
20191
+ let top2 = 0;
20192
+ let isContextMenu = false;
20193
+ if (typeof meta.clientX === "number" && typeof meta.clientY === "number") {
20194
+ left2 = meta.clientX;
20195
+ top2 = meta.clientY;
20196
+ isContextMenu = true;
20197
+ } else {
20198
+ const relativePoint = getSurfaceRelativePoint(editor, meta);
20199
+ if (relativePoint) {
20200
+ const surface = editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element;
20201
+ if (surface) {
20202
+ try {
20203
+ const rect = surface.getBoundingClientRect();
20204
+ left2 = rect.left + relativePoint.left;
20205
+ top2 = rect.top + relativePoint.top;
20206
+ } catch (error) {
20207
+ console.warn("SlashMenu: Failed to get surface bounds", error);
20208
+ return ensureStateShape(value);
20209
+ }
20210
+ }
20211
+ }
20212
+ }
20213
+ const menuSurface = editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element;
20214
+ const containingBlock = findContainingBlockAncestor(menuSurface);
20215
+ if (containingBlock) {
20216
+ try {
20217
+ const cbRect = containingBlock.getBoundingClientRect();
20218
+ left2 -= cbRect.left;
20219
+ top2 -= cbRect.top;
20220
+ left2 += containingBlock.scrollLeft || 0;
20221
+ top2 += containingBlock.scrollTop || 0;
20222
+ } catch (error) {
20223
+ console.warn("SlashMenu: Failed to adjust for containing block", error);
20224
+ }
20225
+ }
20226
+ const offsetX = isContextMenu ? CONTEXT_MENU_OFFSET_X : MENU_OFFSET_X;
20227
+ const offsetY = isContextMenu ? CONTEXT_MENU_OFFSET_Y : MENU_OFFSET_Y;
20228
+ const menuPosition = {
20229
+ left: `${left2 + offsetX}px`,
20230
+ top: `${top2 + offsetY}px`
20231
+ };
20232
+ const newState = {
20233
+ ...value,
20234
+ open: true,
20235
+ anchorPos: meta.pos,
20236
+ menuPosition
20237
+ };
20238
+ editor.emit("slashMenu:open", { menuPosition });
20239
+ return ensureStateShape(newState);
20240
+ }
20241
+ case "select": {
20242
+ return ensureStateShape({ ...value, selected: meta.id });
20243
+ }
20244
+ case "close": {
20245
+ editor.emit("slashMenu:close");
20246
+ return ensureStateShape({ ...value, open: false, anchorPos: null });
20247
+ }
20248
+ default:
20249
+ return ensureStateShape({ ...value, disabled });
20250
+ }
20251
+ }
20252
+ },
20253
+ /**
20254
+ * Create view plugin to handle window event listeners
20255
+ * @param {import('prosemirror-view').EditorView} editorView - The ProseMirror editor view
20256
+ * @returns {Object} View plugin with destroy method
20257
+ */
20258
+ view(editorView) {
20259
+ const updatePosition2 = () => {
20260
+ if (isMenuDisabled()) return;
20261
+ const state = SlashMenuPluginKey.getState(editorView.state);
20262
+ if (state.open) {
20263
+ editorView.dispatch(
20264
+ editorView.state.tr.setMeta(SlashMenuPluginKey, {
20265
+ type: "updatePosition"
20266
+ })
20267
+ );
20268
+ }
20269
+ };
20270
+ window.addEventListener("scroll", updatePosition2, true);
20271
+ window.addEventListener("resize", updatePosition2);
20272
+ return {
20273
+ destroy() {
20274
+ window.removeEventListener("scroll", updatePosition2, true);
20275
+ window.removeEventListener("resize", updatePosition2);
20276
+ if (slashCooldownTimeout) {
20277
+ clearTimeout(slashCooldownTimeout);
20278
+ slashCooldownTimeout = null;
20279
+ }
20280
+ }
20281
+ };
20282
+ },
20283
+ props: {
20284
+ /**
20285
+ * Handle keyboard events to open/close the slash menu
20286
+ * - '/': Opens menu at cursor if conditions are met (in paragraph, after space/start)
20287
+ * - 'Escape' or 'ArrowLeft': Closes menu and restores cursor position
20288
+ *
20289
+ * @param {import('prosemirror-view').EditorView} view - The ProseMirror editor view
20290
+ * @param {KeyboardEvent} event - The keyboard event
20291
+ * @returns {boolean} True if the event was handled, false otherwise
20292
+ */
20293
+ handleKeyDown(view, event) {
20294
+ if (isMenuDisabled()) {
20295
+ return false;
20296
+ }
20297
+ const pluginState = this.getState(view.state);
20298
+ if (event.key === "/" && slashCooldown) {
20299
+ return false;
20300
+ }
20301
+ if (event.key === "/" && !pluginState.open) {
20302
+ const { $cursor } = view.state.selection;
20303
+ if (!$cursor) return false;
20304
+ const isParagraph = $cursor.parent.type.name === "paragraph";
20305
+ if (!isParagraph) return false;
20306
+ const textBefore = $cursor.parent.textContent.slice(0, $cursor.parentOffset);
20307
+ const isEmptyOrAfterSpace = !textBefore || textBefore.endsWith(" ");
20308
+ if (!isEmptyOrAfterSpace) return false;
20309
+ event.preventDefault();
20310
+ slashCooldown = true;
20311
+ if (slashCooldownTimeout) clearTimeout(slashCooldownTimeout);
20312
+ slashCooldownTimeout = setTimeout(() => {
20313
+ slashCooldown = false;
20314
+ slashCooldownTimeout = null;
20315
+ }, SLASH_COOLDOWN_MS);
20316
+ view.dispatch(
20317
+ view.state.tr.setMeta(SlashMenuPluginKey, {
20318
+ type: "open",
20319
+ pos: $cursor.pos
20320
+ })
20321
+ );
20322
+ return true;
20323
+ }
20324
+ if (pluginState.open && (event.key === "Escape" || event.key === "ArrowLeft")) {
20325
+ const { anchorPos } = pluginState;
20326
+ view.dispatch(
20327
+ view.state.tr.setMeta(SlashMenuPluginKey, {
20328
+ type: "close"
20329
+ })
20330
+ );
20331
+ if (anchorPos !== null) {
20332
+ const tr = view.state.tr.setSelection(
20333
+ view.state.selection.constructor.near(view.state.doc.resolve(anchorPos))
20334
+ );
20335
+ view.dispatch(tr);
20336
+ view.focus();
20337
+ }
20338
+ return true;
20339
+ }
20340
+ return false;
20341
+ }
20342
+ }
20343
+ });
20344
+ return [slashMenuPlugin];
20345
+ }
20346
+ });
20053
20347
  let readFromCache;
20054
20348
  let addToCache;
20055
20349
  if (typeof WeakMap != "undefined") {
@@ -64367,7 +64661,8 @@ class PresentationEditor extends EventEmitter {
64367
64661
  }
64368
64662
  const activeEditor = this.getActiveEditor();
64369
64663
  const hasFocus = activeEditor?.view?.hasFocus?.() ?? false;
64370
- if (!hasFocus) {
64664
+ const slashMenuOpen = activeEditor?.state ? !!SlashMenuPluginKey.getState(activeEditor.state)?.open : false;
64665
+ if (!hasFocus && !slashMenuOpen) {
64371
64666
  try {
64372
64667
  this.#clearSelectedFieldAnnotationClass();
64373
64668
  this.#localSelectionLayer.innerHTML = "";
@@ -66604,300 +66899,6 @@ const processAiHighlights = (editor, doc2, highlightColor, customClass = null) =
66604
66899
  });
66605
66900
  return { decorations };
66606
66901
  };
66607
- function getEditorSurfaceElement(editor) {
66608
- if (!editor) return null;
66609
- if (typeof editor.hitTest === "function" && editor.element instanceof HTMLElement) {
66610
- return editor.element;
66611
- }
66612
- return editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element ?? null;
66613
- }
66614
- function getSurfaceRelativePoint(editor, eventLocation = {}) {
66615
- const surface = getEditorSurfaceElement(editor);
66616
- if (!surface) return null;
66617
- const rect = surface.getBoundingClientRect();
66618
- let left2;
66619
- let top2;
66620
- if (typeof eventLocation.clientX === "number" && typeof eventLocation.clientY === "number") {
66621
- left2 = eventLocation.clientX - rect.left;
66622
- top2 = eventLocation.clientY - rect.top;
66623
- } else if (editor?.state?.selection) {
66624
- const selectionFrom = editor.state.selection.from;
66625
- const coords = editor.coordsAtPos?.(selectionFrom);
66626
- if (coords) {
66627
- left2 = coords.left - rect.left;
66628
- top2 = coords.top - rect.top;
66629
- }
66630
- }
66631
- if (!Number.isFinite(left2) || !Number.isFinite(top2)) {
66632
- return null;
66633
- }
66634
- return { left: left2, top: top2 };
66635
- }
66636
- function findContainingBlockAncestor(element) {
66637
- if (!element) return null;
66638
- let current = element.parentElement;
66639
- while (current && current !== document.body && current !== document.documentElement) {
66640
- try {
66641
- const style2 = window.getComputedStyle(current);
66642
- const transform = style2.transform;
66643
- const filter = style2.filter;
66644
- const backdropFilter = style2.backdropFilter || style2.webkitBackdropFilter;
66645
- const perspective = style2.perspective;
66646
- const willChange = style2.willChange;
66647
- const contain = style2.contain;
66648
- if (transform && transform !== "none") {
66649
- return current;
66650
- }
66651
- if (filter && filter !== "none") {
66652
- return current;
66653
- }
66654
- if (backdropFilter && backdropFilter !== "none") {
66655
- return current;
66656
- }
66657
- if (perspective && perspective !== "none") {
66658
- return current;
66659
- }
66660
- if (willChange && willChange !== "auto") {
66661
- const values = willChange.split(",").map((v) => v.trim());
66662
- if (values.includes("transform") || values.includes("perspective")) {
66663
- return current;
66664
- }
66665
- }
66666
- if (contain && /paint|layout|strict|content/.test(contain)) {
66667
- return current;
66668
- }
66669
- } catch (error) {
66670
- console.warn("SlashMenu: Failed to get computed style for element", current, error);
66671
- }
66672
- current = current.parentElement;
66673
- }
66674
- return null;
66675
- }
66676
- const SlashMenuPluginKey = new superEditor_converter.PluginKey("slashMenu");
66677
- const MENU_OFFSET_X = 100;
66678
- const MENU_OFFSET_Y = 28;
66679
- const CONTEXT_MENU_OFFSET_X = 10;
66680
- const CONTEXT_MENU_OFFSET_Y = 10;
66681
- const SLASH_COOLDOWN_MS = 5e3;
66682
- const SlashMenu = Extension.create({
66683
- name: "slashMenu",
66684
- /**
66685
- * Initialize default options for the SlashMenu extension
66686
- * @returns {SlashMenuOptions} Empty options object (configuration is inherited from editor options)
66687
- */
66688
- addOptions() {
66689
- return {};
66690
- },
66691
- addPmPlugins() {
66692
- const editor = this.editor;
66693
- if (editor.options?.isHeadless) {
66694
- return [];
66695
- }
66696
- let slashCooldown = false;
66697
- let slashCooldownTimeout = null;
66698
- const isMenuDisabled = () => Boolean(editor.options?.disableContextMenu);
66699
- const ensureStateShape = (value = {}) => ({
66700
- open: false,
66701
- selected: null,
66702
- anchorPos: null,
66703
- menuPosition: null,
66704
- disabled: isMenuDisabled(),
66705
- ...value
66706
- });
66707
- const slashMenuPlugin = new superEditor_converter.Plugin({
66708
- key: SlashMenuPluginKey,
66709
- state: {
66710
- init: () => ensureStateShape(),
66711
- /**
66712
- * Apply transaction to update plugin state
66713
- * Handles state transitions based on transaction metadata:
66714
- * - 'open': Opens menu at specified position or cursor location
66715
- * - 'select': Updates the selected menu item
66716
- * - 'close': Closes the menu and clears anchor position
66717
- * - 'updatePosition': Triggers menu position recalculation (no-op in apply)
66718
- *
66719
- * @param {import('prosemirror-state').Transaction} tr - The transaction
66720
- * @param {SlashMenuState} value - Previous plugin state
66721
- * @returns {SlashMenuState} New plugin state
66722
- */
66723
- apply(tr, value) {
66724
- const meta = tr.getMeta(SlashMenuPluginKey);
66725
- const disabled = isMenuDisabled();
66726
- if (disabled) {
66727
- if (value.open) {
66728
- editor.emit("slashMenu:close");
66729
- }
66730
- return ensureStateShape({ disabled: true });
66731
- }
66732
- if (!meta) {
66733
- if (value.disabled !== disabled) {
66734
- return ensureStateShape({ ...value, disabled });
66735
- }
66736
- return value;
66737
- }
66738
- switch (meta.type) {
66739
- case "open": {
66740
- if (typeof meta.pos !== "number" || meta.pos < 0 || meta.pos > tr.doc.content.size) {
66741
- console.warn("SlashMenu: Invalid position", meta.pos);
66742
- return ensureStateShape(value);
66743
- }
66744
- let left2 = 0;
66745
- let top2 = 0;
66746
- let isContextMenu = false;
66747
- if (typeof meta.clientX === "number" && typeof meta.clientY === "number") {
66748
- left2 = meta.clientX;
66749
- top2 = meta.clientY;
66750
- isContextMenu = true;
66751
- } else {
66752
- const relativePoint = getSurfaceRelativePoint(editor, meta);
66753
- if (relativePoint) {
66754
- const surface = editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element;
66755
- if (surface) {
66756
- try {
66757
- const rect = surface.getBoundingClientRect();
66758
- left2 = rect.left + relativePoint.left;
66759
- top2 = rect.top + relativePoint.top;
66760
- } catch (error) {
66761
- console.warn("SlashMenu: Failed to get surface bounds", error);
66762
- return ensureStateShape(value);
66763
- }
66764
- }
66765
- }
66766
- }
66767
- const menuSurface = editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element;
66768
- const containingBlock = findContainingBlockAncestor(menuSurface);
66769
- if (containingBlock) {
66770
- try {
66771
- const cbRect = containingBlock.getBoundingClientRect();
66772
- left2 -= cbRect.left;
66773
- top2 -= cbRect.top;
66774
- left2 += containingBlock.scrollLeft || 0;
66775
- top2 += containingBlock.scrollTop || 0;
66776
- } catch (error) {
66777
- console.warn("SlashMenu: Failed to adjust for containing block", error);
66778
- }
66779
- }
66780
- const offsetX = isContextMenu ? CONTEXT_MENU_OFFSET_X : MENU_OFFSET_X;
66781
- const offsetY = isContextMenu ? CONTEXT_MENU_OFFSET_Y : MENU_OFFSET_Y;
66782
- const menuPosition = {
66783
- left: `${left2 + offsetX}px`,
66784
- top: `${top2 + offsetY}px`
66785
- };
66786
- const newState = {
66787
- ...value,
66788
- open: true,
66789
- anchorPos: meta.pos,
66790
- menuPosition
66791
- };
66792
- editor.emit("slashMenu:open", { menuPosition });
66793
- return ensureStateShape(newState);
66794
- }
66795
- case "select": {
66796
- return ensureStateShape({ ...value, selected: meta.id });
66797
- }
66798
- case "close": {
66799
- editor.emit("slashMenu:close");
66800
- return ensureStateShape({ ...value, open: false, anchorPos: null });
66801
- }
66802
- default:
66803
- return ensureStateShape({ ...value, disabled });
66804
- }
66805
- }
66806
- },
66807
- /**
66808
- * Create view plugin to handle window event listeners
66809
- * @param {import('prosemirror-view').EditorView} editorView - The ProseMirror editor view
66810
- * @returns {Object} View plugin with destroy method
66811
- */
66812
- view(editorView) {
66813
- const updatePosition2 = () => {
66814
- if (isMenuDisabled()) return;
66815
- const state = SlashMenuPluginKey.getState(editorView.state);
66816
- if (state.open) {
66817
- editorView.dispatch(
66818
- editorView.state.tr.setMeta(SlashMenuPluginKey, {
66819
- type: "updatePosition"
66820
- })
66821
- );
66822
- }
66823
- };
66824
- window.addEventListener("scroll", updatePosition2, true);
66825
- window.addEventListener("resize", updatePosition2);
66826
- return {
66827
- destroy() {
66828
- window.removeEventListener("scroll", updatePosition2, true);
66829
- window.removeEventListener("resize", updatePosition2);
66830
- if (slashCooldownTimeout) {
66831
- clearTimeout(slashCooldownTimeout);
66832
- slashCooldownTimeout = null;
66833
- }
66834
- }
66835
- };
66836
- },
66837
- props: {
66838
- /**
66839
- * Handle keyboard events to open/close the slash menu
66840
- * - '/': Opens menu at cursor if conditions are met (in paragraph, after space/start)
66841
- * - 'Escape' or 'ArrowLeft': Closes menu and restores cursor position
66842
- *
66843
- * @param {import('prosemirror-view').EditorView} view - The ProseMirror editor view
66844
- * @param {KeyboardEvent} event - The keyboard event
66845
- * @returns {boolean} True if the event was handled, false otherwise
66846
- */
66847
- handleKeyDown(view, event) {
66848
- if (isMenuDisabled()) {
66849
- return false;
66850
- }
66851
- const pluginState = this.getState(view.state);
66852
- if (event.key === "/" && slashCooldown) {
66853
- return false;
66854
- }
66855
- if (event.key === "/" && !pluginState.open) {
66856
- const { $cursor } = view.state.selection;
66857
- if (!$cursor) return false;
66858
- const isParagraph = $cursor.parent.type.name === "paragraph";
66859
- if (!isParagraph) return false;
66860
- const textBefore = $cursor.parent.textContent.slice(0, $cursor.parentOffset);
66861
- const isEmptyOrAfterSpace = !textBefore || textBefore.endsWith(" ");
66862
- if (!isEmptyOrAfterSpace) return false;
66863
- event.preventDefault();
66864
- slashCooldown = true;
66865
- if (slashCooldownTimeout) clearTimeout(slashCooldownTimeout);
66866
- slashCooldownTimeout = setTimeout(() => {
66867
- slashCooldown = false;
66868
- slashCooldownTimeout = null;
66869
- }, SLASH_COOLDOWN_MS);
66870
- view.dispatch(
66871
- view.state.tr.setMeta(SlashMenuPluginKey, {
66872
- type: "open",
66873
- pos: $cursor.pos
66874
- })
66875
- );
66876
- return true;
66877
- }
66878
- if (pluginState.open && (event.key === "Escape" || event.key === "ArrowLeft")) {
66879
- const { anchorPos } = pluginState;
66880
- view.dispatch(
66881
- view.state.tr.setMeta(SlashMenuPluginKey, {
66882
- type: "close"
66883
- })
66884
- );
66885
- if (anchorPos !== null) {
66886
- const tr = view.state.tr.setSelection(
66887
- view.state.selection.constructor.near(view.state.doc.resolve(anchorPos))
66888
- );
66889
- view.dispatch(tr);
66890
- view.focus();
66891
- }
66892
- return true;
66893
- }
66894
- return false;
66895
- }
66896
- }
66897
- });
66898
- return [slashMenuPlugin];
66899
- }
66900
- });
66901
66902
  class StructuredContentViewBase {
66902
66903
  node;
66903
66904
  view;
@@ -86720,18 +86721,25 @@ const _hoisted_3$8 = {
86720
86721
  };
86721
86722
  const _hoisted_4$4 = {
86722
86723
  key: 3,
86723
- class: "link-input-wrapper"
86724
+ class: "link-title"
86724
86725
  };
86725
- const _hoisted_5$2 = { class: "input-row text-input-row" };
86726
- const _hoisted_6$1 = ["onKeydown"];
86727
- const _hoisted_7$1 = { class: "input-row url-input-row" };
86728
- const _hoisted_8$1 = ["innerHTML"];
86729
- const _hoisted_9 = ["onKeydown"];
86730
- const _hoisted_10 = ["innerHTML"];
86731
- const _hoisted_11 = { class: "input-row link-buttons" };
86732
- const _hoisted_12 = ["innerHTML"];
86733
- const _hoisted_13 = {
86726
+ const _hoisted_5$2 = {
86734
86727
  key: 4,
86728
+ class: "link-input-wrapper"
86729
+ };
86730
+ const _hoisted_6$1 = { class: "input-row text-input-row" };
86731
+ const _hoisted_7$1 = ["readonly"];
86732
+ const _hoisted_8$1 = { class: "input-row url-input-row" };
86733
+ const _hoisted_9 = ["innerHTML"];
86734
+ const _hoisted_10 = ["readonly", "onKeydown"];
86735
+ const _hoisted_11 = ["innerHTML"];
86736
+ const _hoisted_12 = {
86737
+ key: 0,
86738
+ class: "input-row link-buttons"
86739
+ };
86740
+ const _hoisted_13 = ["innerHTML"];
86741
+ const _hoisted_14 = {
86742
+ key: 5,
86735
86743
  class: "input-row go-to-anchor clickable"
86736
86744
  };
86737
86745
  const _sfc_main$j = {
@@ -86825,6 +86833,7 @@ const _sfc_main$j = {
86825
86833
  });
86826
86834
  const isEditing = vue.computed(() => !isAnchor.value && !!getLinkHrefAtSelection());
86827
86835
  const isDisabled2 = vue.computed(() => !validUrl.value);
86836
+ const isViewingMode = vue.computed(() => props.editor?.options?.documentMode === "viewing");
86828
86837
  const openLink = () => {
86829
86838
  window.open(url.value, "_blank");
86830
86839
  };
@@ -86850,6 +86859,7 @@ const _sfc_main$j = {
86850
86859
  if (props.showInput) focusInput();
86851
86860
  });
86852
86861
  const handleSubmit = () => {
86862
+ if (isViewingMode.value) return;
86853
86863
  const editor = props.editor;
86854
86864
  if (!editor) return;
86855
86865
  if (!rawUrl.value) {
@@ -86880,36 +86890,38 @@ const _sfc_main$j = {
86880
86890
  return vue.openBlock(), vue.createElementBlock("div", {
86881
86891
  class: vue.normalizeClass(["link-input-ctn", { "high-contrast": vue.unref(isHighContrastMode2) }])
86882
86892
  }, [
86883
- isAnchor.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$g, "Page anchor")) : isEditing.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$b, "Edit link")) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$8, "Add link")),
86884
- __props.showInput && !isAnchor.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$4, [
86885
- vue.createBaseVNode("div", _hoisted_5$2, [
86886
- _cache[4] || (_cache[4] = vue.createBaseVNode("div", { class: "input-icon text-input-icon" }, "T", -1)),
86893
+ isAnchor.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$g, "Page anchor")) : isViewingMode.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$b, "Link details")) : isEditing.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$8, "Edit link")) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$4, "Add link")),
86894
+ __props.showInput && !isAnchor.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$2, [
86895
+ vue.createBaseVNode("div", _hoisted_6$1, [
86896
+ _cache[5] || (_cache[5] = vue.createBaseVNode("div", { class: "input-icon text-input-icon" }, "T", -1)),
86887
86897
  vue.withDirectives(vue.createBaseVNode("input", {
86888
86898
  type: "text",
86889
86899
  name: "text",
86890
86900
  placeholder: "Text",
86891
86901
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => text.value = $event),
86892
- onKeydown: vue.withKeys(vue.withModifiers(handleSubmit, ["stop", "prevent"]), ["enter"])
86893
- }, null, 40, _hoisted_6$1), [
86902
+ readonly: isViewingMode.value,
86903
+ onKeydown: _cache[1] || (_cache[1] = vue.withKeys(vue.withModifiers(($event) => !isViewingMode.value && handleSubmit, ["stop", "prevent"]), ["enter"]))
86904
+ }, null, 40, _hoisted_7$1), [
86894
86905
  [vue.vModelText, text.value]
86895
86906
  ])
86896
86907
  ]),
86897
- vue.createBaseVNode("div", _hoisted_7$1, [
86908
+ vue.createBaseVNode("div", _hoisted_8$1, [
86898
86909
  vue.createBaseVNode("div", {
86899
86910
  class: "input-icon",
86900
86911
  innerHTML: vue.unref(toolbarIcons).linkInput
86901
- }, null, 8, _hoisted_8$1),
86912
+ }, null, 8, _hoisted_9),
86902
86913
  vue.withDirectives(vue.createBaseVNode("input", {
86903
86914
  type: "text",
86904
86915
  name: "link",
86905
86916
  placeholder: "Type or paste a link",
86906
86917
  class: vue.normalizeClass({ error: urlError.value }),
86907
- "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => rawUrl.value = $event),
86918
+ "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => rawUrl.value = $event),
86919
+ readonly: isViewingMode.value,
86908
86920
  onKeydown: [
86909
86921
  vue.withKeys(vue.withModifiers(handleSubmit, ["stop", "prevent"]), ["enter"]),
86910
- _cache[2] || (_cache[2] = ($event) => urlError.value = false)
86922
+ _cache[3] || (_cache[3] = ($event) => urlError.value = false)
86911
86923
  ]
86912
- }, null, 42, _hoisted_9), [
86924
+ }, null, 42, _hoisted_10), [
86913
86925
  [vue.vModelText, rawUrl.value]
86914
86926
  ]),
86915
86927
  vue.createBaseVNode("div", {
@@ -86917,9 +86929,9 @@ const _sfc_main$j = {
86917
86929
  innerHTML: vue.unref(toolbarIcons).openLink,
86918
86930
  onClick: openLink,
86919
86931
  "data-item": "btn-link-open"
86920
- }, null, 10, _hoisted_10)
86932
+ }, null, 10, _hoisted_11)
86921
86933
  ]),
86922
- vue.createBaseVNode("div", _hoisted_11, [
86934
+ !isViewingMode.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12, [
86923
86935
  isEditing.value ? (vue.openBlock(), vue.createElementBlock("button", {
86924
86936
  key: 0,
86925
86937
  class: "remove-btn",
@@ -86929,25 +86941,25 @@ const _sfc_main$j = {
86929
86941
  vue.createBaseVNode("div", {
86930
86942
  class: "remove-btn__icon",
86931
86943
  innerHTML: vue.unref(toolbarIcons).removeLink
86932
- }, null, 8, _hoisted_12),
86933
- _cache[5] || (_cache[5] = vue.createTextVNode(" Remove ", -1))
86944
+ }, null, 8, _hoisted_13),
86945
+ _cache[6] || (_cache[6] = vue.createTextVNode(" Remove ", -1))
86934
86946
  ])) : vue.createCommentVNode("", true),
86935
86947
  vue.createBaseVNode("button", {
86936
86948
  class: vue.normalizeClass(["submit-btn", { "disable-btn": isDisabled2.value }]),
86937
86949
  onClick: handleSubmit,
86938
86950
  "data-item": "btn-link-apply"
86939
86951
  }, " Apply ", 2)
86940
- ])
86941
- ])) : isAnchor.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_13, [
86952
+ ])) : vue.createCommentVNode("", true)
86953
+ ])) : isAnchor.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_14, [
86942
86954
  vue.createBaseVNode("a", {
86943
- onClick: _cache[3] || (_cache[3] = vue.withModifiers((...args) => __props.goToAnchor && __props.goToAnchor(...args), ["stop", "prevent"]))
86955
+ onClick: _cache[4] || (_cache[4] = vue.withModifiers((...args) => __props.goToAnchor && __props.goToAnchor(...args), ["stop", "prevent"]))
86944
86956
  }, "Go to " + vue.toDisplayString(rawUrl.value.startsWith("#_") ? rawUrl.value.substring(2) : rawUrl.value), 1)
86945
86957
  ])) : vue.createCommentVNode("", true)
86946
86958
  ], 2);
86947
86959
  };
86948
86960
  }
86949
86961
  };
86950
- const LinkInput = /* @__PURE__ */ _export_sfc(_sfc_main$j, [["__scopeId", "data-v-f64d35e8"]]);
86962
+ const LinkInput = /* @__PURE__ */ _export_sfc(_sfc_main$j, [["__scopeId", "data-v-198fc596"]]);
86951
86963
  const _hoisted_1$f = ["aria-label", "onClick", "onKeydown"];
86952
86964
  const _hoisted_2$a = ["innerHTML"];
86953
86965
  const _hoisted_3$7 = ["innerHTML"];