@milkdown/plugin-slash 7.6.2 → 7.6.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/README.md CHANGED
@@ -4,7 +4,7 @@ The slash plugin of [milkdown](https://milkdown.dev/).
4
4
 
5
5
  # Official Documentation
6
6
 
7
- Documentation can be found on the [Milkdown website](https://milkdown.dev/docs/api/plugin-slash).
7
+ Documentation can be found on the [Milkdown website](https://milkdown.dev/).
8
8
 
9
9
  # License
10
10
 
package/lib/index.es.js CHANGED
@@ -1,11 +1,11 @@
1
1
  var H = (s) => {
2
2
  throw TypeError(s);
3
3
  };
4
- var C = (s, e, t) => e.has(s) || H("Cannot " + t);
5
- var o = (s, e, t) => (C(s, e, "read from private field"), t ? t.call(s) : e.get(s)), i = (s, e, t) => e.has(s) ? H("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(s) : e.set(s, t), a = (s, e, t, n) => (C(s, e, "write to private field"), n ? n.call(s, t) : e.set(s, t), t), A = (s, e, t) => (C(s, e, "access private method"), t);
4
+ var b = (s, e, t) => e.has(s) || H("Cannot " + t);
5
+ var n = (s, e, t) => (b(s, e, "read from private field"), t ? t.call(s) : e.get(s)), i = (s, e, t) => e.has(s) ? H("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(s) : e.set(s, t), a = (s, e, t, o) => (b(s, e, "write to private field"), o ? o.call(s, t) : e.set(s, t), t), A = (s, e, t) => (b(s, e, "access private method"), t);
6
6
  import { Plugin as N, PluginKey as T, TextSelection as _ } from "@milkdown/prose/state";
7
7
  import { $ctx as F, $prose as I } from "@milkdown/utils";
8
- import { findParentNode as R, posToDOMRect as U } from "@milkdown/prose";
8
+ import { posToDOMRect as R, findParentNode as U } from "@milkdown/prose";
9
9
  import q from "lodash.debounce";
10
10
  import { computePosition as K, flip as L, offset as j } from "@floating-ui/dom";
11
11
  function W(s) {
@@ -13,25 +13,25 @@ function W(s) {
13
13
  {},
14
14
  `${s}_SLASH_SPEC`
15
15
  ), t = I((r) => {
16
- const m = r.get(e.key);
16
+ const d = r.get(e.key);
17
17
  return new N({
18
18
  key: new T(`${s}_SLASH`),
19
- ...m
19
+ ...d
20
20
  });
21
- }), n = [e, t];
22
- return n.key = e.key, n.pluginKey = t.key, e.meta = {
21
+ }), o = [e, t];
22
+ return o.key = e.key, o.pluginKey = t.key, e.meta = {
23
23
  package: "@milkdown/plugin-slash",
24
24
  displayName: `Ctx<slashSpec>|${s}`
25
25
  }, t.meta = {
26
26
  package: "@milkdown/plugin-slash",
27
27
  displayName: `Prose<slash>|${s}`
28
- }, n;
28
+ }, o;
29
29
  }
30
- var c, p, u, f, h, g, y, S, x, B;
30
+ var m, p, u, f, g, h, y, S, k, $, B;
31
31
  class X {
32
32
  constructor(e) {
33
- i(this, x);
34
- i(this, c);
33
+ i(this, $);
34
+ i(this, m);
35
35
  /// @internal
36
36
  i(this, p);
37
37
  /// @internal
@@ -39,39 +39,40 @@ class X {
39
39
  /// @internal
40
40
  i(this, f);
41
41
  /// @internal
42
+ i(this, g);
43
+ /// @internal
42
44
  i(this, h);
43
45
  /// @internal
44
- i(this, g);
45
- /// The offset to get the block. Default is 0.
46
46
  i(this, y);
47
+ /// The offset to get the block. Default is 0.
47
48
  i(this, S);
48
- a(this, c, !1), this.onShow = () => {
49
+ i(this, k);
50
+ a(this, m, !1), this.onShow = () => {
49
51
  }, this.onHide = () => {
50
- }, a(this, S, (t, n) => {
51
- var E;
52
- const { state: r, composing: m } = t, { selection: l, doc: $ } = r, { ranges: k } = l, w = Math.min(...k.map((d) => d.$from.pos)), P = Math.max(...k.map((d) => d.$to.pos)), b = n && n.doc.eq($) && n.selection.eq(l);
53
- if (o(this, c) || ((E = t.dom.parentElement) == null || E.appendChild(this.element), a(this, c, !0)), m || b) return;
54
- if (!o(this, g).call(this, t, n)) {
52
+ }, a(this, k, (t, o) => {
53
+ const { state: r, composing: d } = t, { selection: l, doc: w } = r, { ranges: x } = l, P = Math.min(...x.map((c) => c.$from.pos)), C = Math.max(...x.map((c) => c.$to.pos)), O = o && o.doc.eq(w) && o.selection.eq(l);
54
+ if (n(this, m) || ((n(this, f) ?? t.dom.parentElement ?? document.body).appendChild(this.element), a(this, m, !0)), d || O) return;
55
+ if (!n(this, y).call(this, t, o)) {
55
56
  this.hide();
56
57
  return;
57
58
  }
58
59
  K({
59
- getBoundingClientRect: () => U(t, w, P)
60
+ getBoundingClientRect: () => R(t, P, C)
60
61
  }, this.element, {
61
62
  placement: "bottom-start",
62
- middleware: [L(), j(o(this, y)), ...o(this, p)],
63
- ...o(this, u)
64
- }).then(({ x: d, y: M }) => {
63
+ middleware: [L(), j(n(this, S)), ...n(this, p)],
64
+ ...n(this, u)
65
+ }).then(({ x: c, y: M }) => {
65
66
  Object.assign(this.element.style, {
66
- left: `${d}px`,
67
+ left: `${c}px`,
67
68
  top: `${M}px`
68
69
  });
69
70
  }), this.show();
70
- }), this.update = (t, n) => {
71
- q(o(this, S), o(this, f))(t, n);
72
- }, this.getContent = (t, n = (r) => r.type.name === "paragraph") => {
73
- const { selection: r } = t.state, { empty: m, $from: l } = r, $ = t.state.selection instanceof _, k = this.element.contains(document.activeElement), w = !t.hasFocus() && !k, P = !t.editable, O = !R(n)(t.state.selection);
74
- if (!(w || P || !m || !$ || O))
71
+ }), this.update = (t, o) => {
72
+ q(n(this, k), n(this, g))(t, o);
73
+ }, this.getContent = (t, o = (r) => r.type.name === "paragraph") => {
74
+ const { selection: r } = t.state, { empty: d, $from: l } = r, w = t.state.selection instanceof _, x = this.element.contains(document.activeElement), P = !t.hasFocus() && !x, C = !t.editable, E = !U(o)(t.state.selection);
75
+ if (!(P || C || !d || !w || E))
75
76
  return l.parent.textBetween(
76
77
  Math.max(0, l.parentOffset - 500),
77
78
  l.parentOffset,
@@ -83,15 +84,15 @@ class X {
83
84
  this.element.dataset.show = "true", this.onShow();
84
85
  }, this.hide = () => {
85
86
  this.element.dataset.show = "false", this.onHide();
86
- }, this.element = e.content, a(this, f, e.debounce ?? 200), a(this, g, e.shouldShow ?? A(this, x, B)), a(this, h, e.trigger ?? "/"), a(this, y, e.offset), a(this, p, e.middleware ?? []), a(this, u, e.floatingUIOptions ?? {});
87
+ }, this.element = e.content, a(this, g, e.debounce ?? 200), a(this, y, e.shouldShow ?? A(this, $, B)), a(this, h, e.trigger ?? "/"), a(this, S, e.offset), a(this, p, e.middleware ?? []), a(this, u, e.floatingUIOptions ?? {}), a(this, f, e.root);
87
88
  }
88
89
  }
89
- c = new WeakMap(), p = new WeakMap(), u = new WeakMap(), f = new WeakMap(), h = new WeakMap(), g = new WeakMap(), y = new WeakMap(), S = new WeakMap(), x = new WeakSet(), /// @internal
90
+ m = new WeakMap(), p = new WeakMap(), u = new WeakMap(), f = new WeakMap(), g = new WeakMap(), h = new WeakMap(), y = new WeakMap(), S = new WeakMap(), k = new WeakMap(), $ = new WeakSet(), /// @internal
90
91
  B = function(e) {
91
92
  const t = this.getContent(e);
92
93
  if (!t) return !1;
93
- const n = t.at(-1);
94
- return n ? Array.isArray(o(this, h)) ? o(this, h).includes(n) : o(this, h) === n : !1;
94
+ const o = t.at(-1);
95
+ return o ? Array.isArray(n(this, h)) ? n(this, h).includes(o) : n(this, h) === o : !1;
95
96
  };
96
97
  export {
97
98
  X as SlashProvider,
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","sources":["../src/slash-plugin.ts","../src/slash-provider.ts"],"sourcesContent":["import type { SliceType } from '@milkdown/ctx'\nimport type { PluginSpec } from '@milkdown/prose/state'\nimport { Plugin, PluginKey } from '@milkdown/prose/state'\nimport type { $Ctx, $Prose } from '@milkdown/utils'\nimport { $ctx, $prose } from '@milkdown/utils'\n\n/// @internal\nexport type SlashPluginSpecId<Id extends string> = `${Id}_SLASH_SPEC`\n\n/// @internal\nexport type SlashPlugin<Id extends string, State = any> = [\n $Ctx<PluginSpec<State>, SlashPluginSpecId<Id>>,\n $Prose,\n] & {\n key: SliceType<PluginSpec<State>, SlashPluginSpecId<Id>>\n pluginKey: $Prose['key']\n}\n\n/// Create a slash plugin with a unique id.\nexport function slashFactory<Id extends string, State = any>(id: Id) {\n const slashSpec = $ctx<PluginSpec<State>, SlashPluginSpecId<Id>>(\n {},\n `${id}_SLASH_SPEC`\n )\n const slashPlugin = $prose((ctx) => {\n const spec = ctx.get(slashSpec.key)\n return new Plugin({\n key: new PluginKey(`${id}_SLASH`),\n ...spec,\n })\n })\n const result = [slashSpec, slashPlugin] as SlashPlugin<Id>\n result.key = slashSpec.key\n result.pluginKey = slashPlugin.key\n slashSpec.meta = {\n package: '@milkdown/plugin-slash',\n displayName: `Ctx<slashSpec>|${id}`,\n }\n slashPlugin.meta = {\n package: '@milkdown/plugin-slash',\n displayName: `Prose<slash>|${id}`,\n }\n\n return result\n}\n","import { findParentNode, posToDOMRect } from '@milkdown/prose'\nimport type { EditorState } from '@milkdown/prose/state'\nimport type { Node } from '@milkdown/prose/model'\nimport { TextSelection } from '@milkdown/prose/state'\nimport type { EditorView } from '@milkdown/prose/view'\nimport debounce from 'lodash.debounce'\nimport type {\n ComputePositionConfig,\n Middleware,\n VirtualElement,\n} from '@floating-ui/dom'\nimport { computePosition, flip, offset } from '@floating-ui/dom'\n\n/// Options for slash provider.\nexport interface SlashProviderOptions {\n /// The slash content.\n content: HTMLElement\n /// The debounce time for updating slash, 200ms by default.\n debounce?: number\n /// The function to determine whether the tooltip should be shown.\n shouldShow?: (view: EditorView, prevState?: EditorState) => boolean\n /// The key trigger for shouldShow, '/' by default.\n trigger?: string | string[]\n /// The offset to get the block. Default is 0.\n offset?:\n | number\n | {\n mainAxis?: number\n crossAxis?: number\n alignmentAxis?: number | null\n }\n /// Other middlewares for floating ui. This will be added after the internal middlewares.\n middleware?: Middleware[]\n /// Options for floating ui. If you pass `middleware` or `placement`, it will override the internal settings.\n floatingUIOptions?: Partial<ComputePositionConfig>\n}\n\n/// A provider for creating slash.\nexport class SlashProvider {\n /// The root element of the slash.\n element: HTMLElement\n\n /// @internal\n #initialized = false\n\n /// @internal\n readonly #middleware: Middleware[]\n\n /// @internal\n readonly #floatingUIOptions: Partial<ComputePositionConfig>\n\n /// @internal\n readonly #debounce: number\n\n /// @internal\n readonly #trigger: string | string[]\n\n /// @internal\n readonly #shouldShow: (view: EditorView, prevState?: EditorState) => boolean\n\n /// The offset to get the block. Default is 0.\n readonly #offset?:\n | number\n | {\n mainAxis?: number\n crossAxis?: number\n alignmentAxis?: number | null\n }\n\n /// On show callback.\n onShow = () => {}\n\n /// On hide callback.\n onHide = () => {}\n\n constructor(options: SlashProviderOptions) {\n this.element = options.content\n this.#debounce = options.debounce ?? 200\n this.#shouldShow = options.shouldShow ?? this.#_shouldShow\n this.#trigger = options.trigger ?? '/'\n this.#offset = options.offset\n this.#middleware = options.middleware ?? []\n this.#floatingUIOptions = options.floatingUIOptions ?? {}\n }\n\n /// @internal\n #onUpdate = (view: EditorView, prevState?: EditorState): void => {\n const { state, composing } = view\n const { selection, doc } = state\n const { ranges } = selection\n const from = Math.min(...ranges.map((range) => range.$from.pos))\n const to = Math.max(...ranges.map((range) => range.$to.pos))\n const isSame =\n prevState && prevState.doc.eq(doc) && prevState.selection.eq(selection)\n\n if (!this.#initialized) {\n view.dom.parentElement?.appendChild(this.element)\n this.#initialized = true\n }\n\n if (composing || isSame) return\n\n if (!this.#shouldShow(view, prevState)) {\n this.hide()\n return\n }\n\n const virtualEl: VirtualElement = {\n getBoundingClientRect: () => posToDOMRect(view, from, to),\n }\n computePosition(virtualEl, this.element, {\n placement: 'bottom-start',\n middleware: [flip(), offset(this.#offset), ...this.#middleware],\n ...this.#floatingUIOptions,\n }).then(({ x, y }) => {\n Object.assign(this.element.style, {\n left: `${x}px`,\n top: `${y}px`,\n })\n })\n\n this.show()\n }\n\n /// @internal\n #_shouldShow(view: EditorView): boolean {\n const currentTextBlockContent = this.getContent(view)\n\n if (!currentTextBlockContent) return false\n\n const target = currentTextBlockContent.at(-1)\n\n if (!target) return false\n\n return Array.isArray(this.#trigger)\n ? this.#trigger.includes(target)\n : this.#trigger === target\n }\n\n /// Update provider state by editor view.\n update = (view: EditorView, prevState?: EditorState): void => {\n const updater = debounce(this.#onUpdate, this.#debounce)\n\n updater(view, prevState)\n }\n\n /// Get the content of the current text block.\n /// Pass the `matchNode` function to determine whether the current node should be matched, by default, it will match the paragraph node.\n getContent = (\n view: EditorView,\n matchNode: (node: Node) => boolean = (node) =>\n node.type.name === 'paragraph'\n ): string | undefined => {\n const { selection } = view.state\n const { empty, $from } = selection\n const isTextBlock = view.state.selection instanceof TextSelection\n\n const isSlashChildren = this.element.contains(document.activeElement)\n\n const notHasFocus = !view.hasFocus() && !isSlashChildren\n\n const isReadonly = !view.editable\n\n const paragraph = findParentNode(matchNode)(view.state.selection)\n\n const isNotInParagraph = !paragraph\n\n if (notHasFocus || isReadonly || !empty || !isTextBlock || isNotInParagraph)\n return\n\n return $from.parent.textBetween(\n Math.max(0, $from.parentOffset - 500),\n $from.parentOffset,\n undefined,\n '\\uFFFC'\n )\n }\n\n /// Destroy the slash.\n destroy = () => {}\n\n /// Show the slash.\n show = () => {\n this.element.dataset.show = 'true'\n this.onShow()\n }\n\n /// Hide the slash.\n hide = () => {\n this.element.dataset.show = 'false'\n this.onHide()\n }\n}\n"],"names":["slashFactory","id","slashSpec","$ctx","slashPlugin","$prose","ctx","spec","Plugin","PluginKey","result","SlashProvider","options","__privateAdd","_SlashProvider_instances","_initialized","_middleware","_floatingUIOptions","_debounce","_trigger","_shouldShow","_offset","_onUpdate","__privateSet","view","prevState","state","composing","selection","doc","ranges","from","range","to","isSame","__privateGet","_a","computePosition","posToDOMRect","flip","offset","x","y","debounce","matchNode","node","empty","$from","isTextBlock","TextSelection","isSlashChildren","notHasFocus","isReadonly","isNotInParagraph","findParentNode","__privateMethod","_shouldShow_fn","currentTextBlockContent","target"],"mappings":"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"}
1
+ {"version":3,"file":"index.es.js","sources":["../src/slash-plugin.ts","../src/slash-provider.ts"],"sourcesContent":["import type { SliceType } from '@milkdown/ctx'\nimport type { PluginSpec } from '@milkdown/prose/state'\nimport { Plugin, PluginKey } from '@milkdown/prose/state'\nimport type { $Ctx, $Prose } from '@milkdown/utils'\nimport { $ctx, $prose } from '@milkdown/utils'\n\n/// @internal\nexport type SlashPluginSpecId<Id extends string> = `${Id}_SLASH_SPEC`\n\n/// @internal\nexport type SlashPlugin<Id extends string, State = any> = [\n $Ctx<PluginSpec<State>, SlashPluginSpecId<Id>>,\n $Prose,\n] & {\n key: SliceType<PluginSpec<State>, SlashPluginSpecId<Id>>\n pluginKey: $Prose['key']\n}\n\n/// Create a slash plugin with a unique id.\nexport function slashFactory<Id extends string, State = any>(id: Id) {\n const slashSpec = $ctx<PluginSpec<State>, SlashPluginSpecId<Id>>(\n {},\n `${id}_SLASH_SPEC`\n )\n const slashPlugin = $prose((ctx) => {\n const spec = ctx.get(slashSpec.key)\n return new Plugin({\n key: new PluginKey(`${id}_SLASH`),\n ...spec,\n })\n })\n const result = [slashSpec, slashPlugin] as SlashPlugin<Id>\n result.key = slashSpec.key\n result.pluginKey = slashPlugin.key\n slashSpec.meta = {\n package: '@milkdown/plugin-slash',\n displayName: `Ctx<slashSpec>|${id}`,\n }\n slashPlugin.meta = {\n package: '@milkdown/plugin-slash',\n displayName: `Prose<slash>|${id}`,\n }\n\n return result\n}\n","import { findParentNode, posToDOMRect } from '@milkdown/prose'\nimport type { EditorState } from '@milkdown/prose/state'\nimport type { Node } from '@milkdown/prose/model'\nimport { TextSelection } from '@milkdown/prose/state'\nimport type { EditorView } from '@milkdown/prose/view'\nimport debounce from 'lodash.debounce'\nimport type {\n ComputePositionConfig,\n Middleware,\n VirtualElement,\n} from '@floating-ui/dom'\nimport { computePosition, flip, offset } from '@floating-ui/dom'\n\n/// Options for slash provider.\nexport interface SlashProviderOptions {\n /// The slash content.\n content: HTMLElement\n /// The debounce time for updating slash, 200ms by default.\n debounce?: number\n /// The function to determine whether the tooltip should be shown.\n shouldShow?: (view: EditorView, prevState?: EditorState) => boolean\n /// The key trigger for shouldShow, '/' by default.\n trigger?: string | string[]\n /// The offset to get the block. Default is 0.\n offset?:\n | number\n | {\n mainAxis?: number\n crossAxis?: number\n alignmentAxis?: number | null\n }\n /// Other middlewares for floating ui. This will be added after the internal middlewares.\n middleware?: Middleware[]\n /// Options for floating ui. If you pass `middleware` or `placement`, it will override the internal settings.\n floatingUIOptions?: Partial<ComputePositionConfig>\n /// The root element that the slash will be appended to.\n root?: HTMLElement\n}\n\n/// A provider for creating slash.\nexport class SlashProvider {\n /// The root element of the slash.\n element: HTMLElement\n\n /// @internal\n #initialized = false\n\n /// @internal\n readonly #middleware: Middleware[]\n\n /// @internal\n readonly #floatingUIOptions: Partial<ComputePositionConfig>\n\n /// @internal\n readonly #root?: HTMLElement\n\n /// @internal\n readonly #debounce: number\n\n /// @internal\n readonly #trigger: string | string[]\n\n /// @internal\n readonly #shouldShow: (view: EditorView, prevState?: EditorState) => boolean\n\n /// The offset to get the block. Default is 0.\n readonly #offset?:\n | number\n | {\n mainAxis?: number\n crossAxis?: number\n alignmentAxis?: number | null\n }\n\n /// On show callback.\n onShow = () => {}\n\n /// On hide callback.\n onHide = () => {}\n\n constructor(options: SlashProviderOptions) {\n this.element = options.content\n this.#debounce = options.debounce ?? 200\n this.#shouldShow = options.shouldShow ?? this.#_shouldShow\n this.#trigger = options.trigger ?? '/'\n this.#offset = options.offset\n this.#middleware = options.middleware ?? []\n this.#floatingUIOptions = options.floatingUIOptions ?? {}\n this.#root = options.root\n }\n\n /// @internal\n #onUpdate = (view: EditorView, prevState?: EditorState): void => {\n const { state, composing } = view\n const { selection, doc } = state\n const { ranges } = selection\n const from = Math.min(...ranges.map((range) => range.$from.pos))\n const to = Math.max(...ranges.map((range) => range.$to.pos))\n const isSame =\n prevState && prevState.doc.eq(doc) && prevState.selection.eq(selection)\n\n if (!this.#initialized) {\n const root = this.#root ?? view.dom.parentElement ?? document.body\n root.appendChild(this.element)\n this.#initialized = true\n }\n\n if (composing || isSame) return\n\n if (!this.#shouldShow(view, prevState)) {\n this.hide()\n return\n }\n\n const virtualEl: VirtualElement = {\n getBoundingClientRect: () => posToDOMRect(view, from, to),\n }\n computePosition(virtualEl, this.element, {\n placement: 'bottom-start',\n middleware: [flip(), offset(this.#offset), ...this.#middleware],\n ...this.#floatingUIOptions,\n }).then(({ x, y }) => {\n Object.assign(this.element.style, {\n left: `${x}px`,\n top: `${y}px`,\n })\n })\n\n this.show()\n }\n\n /// @internal\n #_shouldShow(view: EditorView): boolean {\n const currentTextBlockContent = this.getContent(view)\n\n if (!currentTextBlockContent) return false\n\n const target = currentTextBlockContent.at(-1)\n\n if (!target) return false\n\n return Array.isArray(this.#trigger)\n ? this.#trigger.includes(target)\n : this.#trigger === target\n }\n\n /// Update provider state by editor view.\n update = (view: EditorView, prevState?: EditorState): void => {\n const updater = debounce(this.#onUpdate, this.#debounce)\n\n updater(view, prevState)\n }\n\n /// Get the content of the current text block.\n /// Pass the `matchNode` function to determine whether the current node should be matched, by default, it will match the paragraph node.\n getContent = (\n view: EditorView,\n matchNode: (node: Node) => boolean = (node) =>\n node.type.name === 'paragraph'\n ): string | undefined => {\n const { selection } = view.state\n const { empty, $from } = selection\n const isTextBlock = view.state.selection instanceof TextSelection\n\n const isSlashChildren = this.element.contains(document.activeElement)\n\n const notHasFocus = !view.hasFocus() && !isSlashChildren\n\n const isReadonly = !view.editable\n\n const paragraph = findParentNode(matchNode)(view.state.selection)\n\n const isNotInParagraph = !paragraph\n\n if (notHasFocus || isReadonly || !empty || !isTextBlock || isNotInParagraph)\n return\n\n return $from.parent.textBetween(\n Math.max(0, $from.parentOffset - 500),\n $from.parentOffset,\n undefined,\n '\\uFFFC'\n )\n }\n\n /// Destroy the slash.\n destroy = () => {}\n\n /// Show the slash.\n show = () => {\n this.element.dataset.show = 'true'\n this.onShow()\n }\n\n /// Hide the slash.\n hide = () => {\n this.element.dataset.show = 'false'\n this.onHide()\n }\n}\n"],"names":["slashFactory","id","slashSpec","$ctx","slashPlugin","$prose","ctx","spec","Plugin","PluginKey","result","SlashProvider","options","__privateAdd","_SlashProvider_instances","_initialized","_middleware","_floatingUIOptions","_root","_debounce","_trigger","_shouldShow","_offset","_onUpdate","__privateSet","view","prevState","state","composing","selection","doc","ranges","from","range","to","isSame","__privateGet","computePosition","posToDOMRect","flip","offset","x","y","debounce","matchNode","node","empty","$from","isTextBlock","TextSelection","isSlashChildren","notHasFocus","isReadonly","isNotInParagraph","findParentNode","__privateMethod","_shouldShow_fn","currentTextBlockContent","target"],"mappings":"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"}
@@ -14,6 +14,7 @@ export interface SlashProviderOptions {
14
14
  };
15
15
  middleware?: Middleware[];
16
16
  floatingUIOptions?: Partial<ComputePositionConfig>;
17
+ root?: HTMLElement;
17
18
  }
18
19
  export declare class SlashProvider {
19
20
  #private;
@@ -1 +1 @@
1
- {"version":3,"file":"slash-provider.d.ts","sourceRoot":"","sources":["../src/slash-provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAEjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEtD,OAAO,KAAK,EACV,qBAAqB,EACrB,UAAU,EAEX,MAAM,kBAAkB,CAAA;AAIzB,MAAM,WAAW,oBAAoB;IAEnC,OAAO,EAAE,WAAW,CAAA;IAEpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,WAAW,KAAK,OAAO,CAAA;IAEnE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAE3B,MAAM,CAAC,EACH,MAAM,GACN;QACE,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAC9B,CAAA;IAEL,UAAU,CAAC,EAAE,UAAU,EAAE,CAAA;IAEzB,iBAAiB,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAA;CACnD;AAGD,qBAAa,aAAa;;IAExB,OAAO,EAAE,WAAW,CAAA;IA8BpB,MAAM,aAAW;IAGjB,MAAM,aAAW;gBAEL,OAAO,EAAE,oBAAoB;IAiEzC,MAAM,SAAU,UAAU,cAAc,WAAW,KAAG,IAAI,CAIzD;IAID,UAAU,SACF,UAAU,cACL,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,KAEjC,MAAM,GAAG,SAAS,CAwBpB;IAGD,OAAO,aAAW;IAGlB,IAAI,aAGH;IAGD,IAAI,aAGH;CACF"}
1
+ {"version":3,"file":"slash-provider.d.ts","sourceRoot":"","sources":["../src/slash-provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAEjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEtD,OAAO,KAAK,EACV,qBAAqB,EACrB,UAAU,EAEX,MAAM,kBAAkB,CAAA;AAIzB,MAAM,WAAW,oBAAoB;IAEnC,OAAO,EAAE,WAAW,CAAA;IAEpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,WAAW,KAAK,OAAO,CAAA;IAEnE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAE3B,MAAM,CAAC,EACH,MAAM,GACN;QACE,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAC9B,CAAA;IAEL,UAAU,CAAC,EAAE,UAAU,EAAE,CAAA;IAEzB,iBAAiB,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAElD,IAAI,CAAC,EAAE,WAAW,CAAA;CACnB;AAGD,qBAAa,aAAa;;IAExB,OAAO,EAAE,WAAW,CAAA;IAiCpB,MAAM,aAAW;IAGjB,MAAM,aAAW;gBAEL,OAAO,EAAE,oBAAoB;IAmEzC,MAAM,SAAU,UAAU,cAAc,WAAW,KAAG,IAAI,CAIzD;IAID,UAAU,SACF,UAAU,cACL,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,KAEjC,MAAM,GAAG,SAAS,CAwBpB;IAGD,OAAO,aAAW;IAGlB,IAAI,aAGH;IAGD,IAAI,aAGH;CACF"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@milkdown/plugin-slash",
3
3
  "type": "module",
4
- "version": "7.6.2",
4
+ "version": "7.6.3",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -34,13 +34,13 @@
34
34
  "@types/lodash.debounce": "^4.0.7",
35
35
  "lodash.debounce": "^4.0.8",
36
36
  "tslib": "^2.8.1",
37
- "@milkdown/exception": "7.6.2",
38
- "@milkdown/utils": "7.6.2"
37
+ "@milkdown/exception": "7.6.3",
38
+ "@milkdown/utils": "7.6.3"
39
39
  },
40
40
  "devDependencies": {
41
- "@milkdown/ctx": "7.6.2",
42
- "@milkdown/core": "7.6.2",
43
- "@milkdown/prose": "7.6.2"
41
+ "@milkdown/ctx": "7.6.3",
42
+ "@milkdown/core": "7.6.3",
43
+ "@milkdown/prose": "7.6.3"
44
44
  },
45
45
  "nx": {
46
46
  "targets": {
@@ -33,6 +33,8 @@ export interface SlashProviderOptions {
33
33
  middleware?: Middleware[]
34
34
  /// Options for floating ui. If you pass `middleware` or `placement`, it will override the internal settings.
35
35
  floatingUIOptions?: Partial<ComputePositionConfig>
36
+ /// The root element that the slash will be appended to.
37
+ root?: HTMLElement
36
38
  }
37
39
 
38
40
  /// A provider for creating slash.
@@ -49,6 +51,9 @@ export class SlashProvider {
49
51
  /// @internal
50
52
  readonly #floatingUIOptions: Partial<ComputePositionConfig>
51
53
 
54
+ /// @internal
55
+ readonly #root?: HTMLElement
56
+
52
57
  /// @internal
53
58
  readonly #debounce: number
54
59
 
@@ -81,6 +86,7 @@ export class SlashProvider {
81
86
  this.#offset = options.offset
82
87
  this.#middleware = options.middleware ?? []
83
88
  this.#floatingUIOptions = options.floatingUIOptions ?? {}
89
+ this.#root = options.root
84
90
  }
85
91
 
86
92
  /// @internal
@@ -94,7 +100,8 @@ export class SlashProvider {
94
100
  prevState && prevState.doc.eq(doc) && prevState.selection.eq(selection)
95
101
 
96
102
  if (!this.#initialized) {
97
- view.dom.parentElement?.appendChild(this.element)
103
+ const root = this.#root ?? view.dom.parentElement ?? document.body
104
+ root.appendChild(this.element)
98
105
  this.#initialized = true
99
106
  }
100
107