@llui/markdown-editor 0.2.12 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +44 -0
  2. package/dist/editor.d.ts.map +1 -1
  3. package/dist/editor.js +34 -8
  4. package/dist/editor.js.map +1 -1
  5. package/dist/effects.d.ts +5 -3
  6. package/dist/effects.d.ts.map +1 -1
  7. package/dist/effects.js +7 -5
  8. package/dist/effects.js.map +1 -1
  9. package/dist/format.js.map +1 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/paste.d.ts.map +1 -1
  12. package/dist/paste.js +5 -0
  13. package/dist/paste.js.map +1 -1
  14. package/dist/plugins/_preview.js.map +1 -1
  15. package/dist/plugins/callout.d.ts.map +1 -1
  16. package/dist/plugins/callout.js +37 -45
  17. package/dist/plugins/callout.js.map +1 -1
  18. package/dist/plugins/context-menu.js.map +1 -1
  19. package/dist/plugins/core.js.map +1 -1
  20. package/dist/plugins/emoji.js.map +1 -1
  21. package/dist/plugins/floating-toolbar.js.map +1 -1
  22. package/dist/plugins/hr.d.ts.map +1 -1
  23. package/dist/plugins/hr.js +4 -7
  24. package/dist/plugins/hr.js.map +1 -1
  25. package/dist/plugins/image.d.ts.map +1 -1
  26. package/dist/plugins/image.js +28 -20
  27. package/dist/plugins/image.js.map +1 -1
  28. package/dist/plugins/inline.js.map +1 -1
  29. package/dist/plugins/link.d.ts.map +1 -1
  30. package/dist/plugins/link.js +16 -9
  31. package/dist/plugins/link.js.map +1 -1
  32. package/dist/plugins/math.d.ts.map +1 -1
  33. package/dist/plugins/math.js +25 -34
  34. package/dist/plugins/math.js.map +1 -1
  35. package/dist/plugins/mention.js.map +1 -1
  36. package/dist/plugins/mermaid.d.ts.map +1 -1
  37. package/dist/plugins/mermaid.js +25 -34
  38. package/dist/plugins/mermaid.js.map +1 -1
  39. package/dist/plugins/overlay.js.map +1 -1
  40. package/dist/plugins/single-block.js.map +1 -1
  41. package/dist/plugins/slash.js.map +1 -1
  42. package/dist/plugins/table.d.ts.map +1 -1
  43. package/dist/plugins/table.js +7 -4
  44. package/dist/plugins/table.js.map +1 -1
  45. package/dist/plugins/types.js.map +1 -1
  46. package/dist/plugins/ui.js.map +1 -1
  47. package/dist/security.d.ts +26 -0
  48. package/dist/security.d.ts.map +1 -0
  49. package/dist/security.js +87 -0
  50. package/dist/security.js.map +1 -0
  51. package/dist/state.js.map +1 -1
  52. package/dist/surfaces/link-dialog.js.map +1 -1
  53. package/dist/surfaces/toolbar.js.map +1 -1
  54. package/dist/theme.js.map +1 -1
  55. package/dist/transformers/gfm.js.map +1 -1
  56. package/dist/transformers/registry.js.map +1 -1
  57. package/package.json +23 -17
  58. package/src/editor.ts +339 -0
  59. package/src/effects.ts +53 -0
  60. package/src/format.ts +57 -0
  61. package/src/index.ts +93 -0
  62. package/src/paste.ts +96 -0
  63. package/src/plugins/_preview.ts +51 -0
  64. package/src/plugins/callout.ts +180 -0
  65. package/src/plugins/context-menu.ts +118 -0
  66. package/src/plugins/core.ts +179 -0
  67. package/src/plugins/emoji.ts +59 -0
  68. package/src/plugins/floating-toolbar.ts +180 -0
  69. package/src/plugins/hr.ts +56 -0
  70. package/src/plugins/image.ts +240 -0
  71. package/src/plugins/inline.ts +76 -0
  72. package/src/plugins/link.ts +143 -0
  73. package/src/plugins/math.ts +102 -0
  74. package/src/plugins/mention.ts +224 -0
  75. package/src/plugins/mermaid.ts +115 -0
  76. package/src/plugins/overlay.ts +138 -0
  77. package/src/plugins/single-block.ts +193 -0
  78. package/src/plugins/slash.ts +224 -0
  79. package/src/plugins/table.ts +284 -0
  80. package/src/plugins/types.ts +50 -0
  81. package/src/plugins/ui.ts +79 -0
  82. package/src/security.ts +89 -0
  83. package/src/state.ts +220 -0
  84. package/src/styles/editor.css +554 -0
  85. package/src/surfaces/link-dialog.ts +67 -0
  86. package/src/surfaces/toolbar.ts +246 -0
  87. package/src/theme.ts +42 -0
  88. package/src/transformers/gfm.ts +69 -0
  89. package/src/transformers/registry.ts +47 -0
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # @llui/markdown-editor
2
+
3
+ WYSIWYG Markdown editor for [LLui](https://github.com/fponticelli/llui) — hides Markdown behind a rich, pluggable editing widget built on Lexical.
4
+
5
+ ```bash
6
+ pnpm add @llui/markdown-editor @llui/lexical @llui/components lexical
7
+ ```
8
+
9
+ ## Usage
10
+
11
+ ```ts
12
+ import { mountApp } from '@llui/dom'
13
+ import { markdownEditor } from '@llui/markdown-editor'
14
+ import '@llui/markdown-editor/styles/editor.css'
15
+
16
+ // `markdownEditor()` returns a component definition; mount it (or compose it).
17
+ mountApp(
18
+ document.getElementById('editor')!,
19
+ markdownEditor({
20
+ defaultValue: '# Hello\n\nStart typing…',
21
+ toolbar: true,
22
+ onChange: (markdown) => console.log(markdown),
23
+ }),
24
+ )
25
+ ```
26
+
27
+ ## What it provides
28
+
29
+ - **`markdownEditor()`** — the editor component, built on the [`@llui/lexical`](https://www.npmjs.com/package/@llui/lexical) seam.
30
+ - **Transformer registry** — GFM and callout plugins (`./plugins/core`, `./plugins/callout`) that map Markdown constructs to Lexical nodes.
31
+ - **Toolbar surface** — an optional formatting toolbar (`./surfaces/toolbar`).
32
+ - **`collab` seam** — opt-in collaborative editing via [`@llui/lexical-collab`](https://www.npmjs.com/package/@llui/lexical-collab).
33
+
34
+ ## Entry points
35
+
36
+ | Import | Purpose |
37
+ | ----------------------------------------- | ------------------------------ |
38
+ | `@llui/markdown-editor` | `markdownEditor()` component |
39
+ | `@llui/markdown-editor/plugins/core` | Core GFM transformers |
40
+ | `@llui/markdown-editor/plugins/callout` | Callout/admonition transformer |
41
+ | `@llui/markdown-editor/surfaces/toolbar` | Toolbar surface |
42
+ | `@llui/markdown-editor/styles/editor.css` | Editor styles |
43
+
44
+ Peers on `@llui/dom`, `@llui/lexical`, `@llui/components`, `lexical`, and the relevant `@lexical/*` packages (`^0.46`).
@@ -1 +1 @@
1
- {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"AAMA,OAAO,EAA2B,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAA;AAM9F,OAAO,EAAmC,KAAK,MAAM,EAAE,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAWjG,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAMrE,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,SAAS,EAEd,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,YAAY;IAC3B;2FACuF;IACvF,OAAO,CAAC,EAAE,SAAS,cAAc,EAAE,CAAA;IACnC,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACtB,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,kBAAkB,CAAA;IAC1B,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,uEAAuE;IACvE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;IAC9C,mFAAmF;IACnF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAA;IACzC,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;+EAE2E;IAC3E,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;wEAIoE;IACpE,MAAM,CAAC,EAAE,aAAa,CAAA;CACvB;AAED;;iEAEiE;AACjE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,IAAI,CAAA;CAChD;AAED;;;yEAGyE;AACzE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAA;IACrC,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IACjC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC;AAED,gEAAgE;AAChE,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,aAAa,CAAA;AAEjE,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,KAAK,EAAE,SAAS,WAAW,EAAE,CAAA;IAC7B,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;CAC5B;AAOD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,GAAE,YAAiB,GACxB,kBAAkB,CAAC,WAAW,EAAE,SAAS,EAAE,YAAY,CAAC,CA0L1D"}
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"AAMA,OAAO,EAA2B,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAA;AAM9F,OAAO,EAAmC,KAAK,MAAM,EAAE,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAYjG,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAMrE,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,SAAS,EAEd,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,YAAY;IAC3B;2FACuF;IACvF,OAAO,CAAC,EAAE,SAAS,cAAc,EAAE,CAAA;IACnC,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACtB,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,kBAAkB,CAAA;IAC1B,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,uEAAuE;IACvE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;IAC9C,mFAAmF;IACnF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAA;IACzC,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;+EAE2E;IAC3E,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;wEAIoE;IACpE,MAAM,CAAC,EAAE,aAAa,CAAA;CACvB;AAED;;iEAEiE;AACjE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,IAAI,CAAA;CAChD;AAED;;;yEAGyE;AACzE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAA;IACrC,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IACjC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC;AAED,gEAAgE;AAChE,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,aAAa,CAAA;AAEjE,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,KAAK,EAAE,SAAS,WAAW,EAAE,CAAA;IAC7B,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;CAC5B;AAgBD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,GAAE,YAAiB,GACxB,kBAAkB,CAAC,WAAW,EAAE,SAAS,EAAE,YAAY,CAAC,CAoN1D"}
package/dist/editor.js CHANGED
@@ -10,6 +10,7 @@ import { lexicalForeign, registerDecoratorBridges, PROGRAMMATIC_TAG, } from '@ll
10
10
  import { corePlugin } from './plugins/core.js';
11
11
  import { linkPlugin } from './plugins/link.js';
12
12
  import { registerMarkdownPaste } from './paste.js';
13
+ import { registerLinkSanitizer } from './security.js';
13
14
  import { toolbar as renderToolbar } from './surfaces/toolbar.js';
14
15
  import { buildTransformers } from './transformers/registry.js';
15
16
  import { mergeTheme } from './theme.js';
@@ -37,10 +38,22 @@ export function markdownEditor(config = {}) {
37
38
  .filter((p) => p.ui !== undefined)
38
39
  .map((p) => ({ name: p.name, ui: p.ui }));
39
40
  const pluginUIByName = new Map(pluginUIs.map((p) => [p.name, p.ui]));
40
- // The live editor, captured at mount; effects dispatch through it.
41
- let editorRef = null;
42
- const getEditor = () => editorRef;
43
- const baseOnEffect = makeOnEffect(getEditor, itemsById, {
41
+ // Per-MOUNT live-editor context, keyed by the mount's stable `send` closure
42
+ // the SAME object the runtime hands to both `view` and `onEffect`. A single
43
+ // definition can be mounted more than once (or re-mounted); each mount gets its
44
+ // own editor reference here, so effects and plugin handlers dispatch to their
45
+ // own editor and unmount clears only that mount's reference (no cross-wiring,
46
+ // no leaked disposed editor). Entries are collected with their `send` key.
47
+ const mountContexts = new WeakMap();
48
+ const contextFor = (send) => {
49
+ let ctx = mountContexts.get(send);
50
+ if (!ctx) {
51
+ ctx = { editor: null };
52
+ mountContexts.set(send, ctx);
53
+ }
54
+ return ctx;
55
+ };
56
+ const baseOnEffect = makeOnEffect((api) => contextFor(api.send).editor, itemsById, {
44
57
  onChange: config.onChange,
45
58
  onFormatChange: config.onFormatChange,
46
59
  applyValue: (editor, value) => editor.update(() => {
@@ -85,9 +98,10 @@ export function markdownEditor(config = {}) {
85
98
  };
86
99
  const composedOnEffect = (effect, api) => {
87
100
  if (effect.type === 'pluginEffect') {
101
+ const mount = contextFor(api.send);
88
102
  const ui = pluginUIByName.get(effect.name);
89
103
  ui?.onEffect?.(effect.effect, {
90
- editor: getEditor,
104
+ editor: () => mount.editor,
91
105
  send: (msg) => api.send({ type: 'plugin', name: effect.name, msg }),
92
106
  emit: (msg) => api.send(msg),
93
107
  });
@@ -96,6 +110,9 @@ export function markdownEditor(config = {}) {
96
110
  baseOnEffect(effect, api);
97
111
  };
98
112
  const view = ({ state, send, }) => {
113
+ // This mount's live-editor slot (keyed by this mount's `send`). `onReady`
114
+ // fills it; effects/plugins read it through `contextFor(api.send)`.
115
+ const mount = contextFor(send);
99
116
  // Build the collab binding (once, at mount) from the consumer's factory,
100
117
  // injecting the markdown seed + status sinks that mirror into `state.collab`.
101
118
  const collabBinding = config.collab
@@ -129,7 +146,13 @@ export function markdownEditor(config = {}) {
129
146
  ? { changeDebounceMs: config.changeDebounceMs }
130
147
  : {}),
131
148
  register: (editor) => {
132
- const disposers = [registerMarkdownShortcuts(editor, transformers)];
149
+ const disposers = [
150
+ registerMarkdownShortcuts(editor, transformers),
151
+ // Global scheme allowlist for links: the single backstop covering the
152
+ // link dialog, pasted/imported markdown, and the typed `[x](url)`
153
+ // shortcut. Image src is enforced in the image transformer.
154
+ registerLinkSanitizer(editor),
155
+ ];
133
156
  if (config.pasteMarkdown !== false)
134
157
  disposers.push(registerMarkdownPaste(editor, transformers));
135
158
  if (decorators.length > 0)
@@ -139,10 +162,13 @@ export function markdownEditor(config = {}) {
139
162
  return () => {
140
163
  for (const dispose of disposers)
141
164
  dispose();
165
+ // Release this mount's editor reference so a disposed editor never
166
+ // leaks and stale effects can't reach a torn-down editor.
167
+ mount.editor = null;
142
168
  };
143
169
  },
144
170
  onReady: (editor) => {
145
- editorRef = editor;
171
+ mount.editor = editor;
146
172
  if (config.placeholder) {
147
173
  editor.getRootElement()?.setAttribute('data-placeholder', config.placeholder);
148
174
  }
@@ -165,7 +191,7 @@ export function markdownEditor(config = {}) {
165
191
  const rendered = ui.view({
166
192
  state: state.at(`plugins.${name}`),
167
193
  send: (msg) => send({ type: 'plugin', name, msg }),
168
- editor: getEditor,
194
+ editor: () => mount.editor,
169
195
  });
170
196
  return Array.isArray(rendered) ? rendered : [rendered];
171
197
  });
@@ -1 +1 @@
1
- {"version":3,"file":"editor.js","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"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","sourcesContent":["// `markdownEditor(config)` — the high-level component. Lexical owns the live\n// document; this wires the foreign seam to the markdown transformer converters,\n// surfaces the format state for the chrome, routes command intents back to the\n// live editor through effects, and COMPOSES plugin UI extensions (each plugin's\n// state slice + reducer + view + effects) into the single component.\n\nimport { $getRoot, $setSelection, type EditorThemeClasses, type LexicalEditor } from 'lexical'\nimport {\n $convertFromMarkdownString,\n $convertToMarkdownString,\n registerMarkdownShortcuts,\n} from '@lexical/markdown'\nimport { component, div, type Renderable, type Signal, type SignalComponentDef } from '@llui/dom'\nimport {\n lexicalForeign,\n registerDecoratorBridges,\n PROGRAMMATIC_TAG,\n type DecoratorBridge,\n} from '@llui/lexical'\nimport { corePlugin } from './plugins/core.js'\nimport { linkPlugin } from './plugins/link.js'\nimport { registerMarkdownPaste } from './paste.js'\nimport { toolbar as renderToolbar } from './surfaces/toolbar.js'\nimport type { CommandItem, MarkdownPlugin } from './plugins/types.js'\nimport type { PluginUI } from './plugins/ui.js'\nimport { buildTransformers } from './transformers/registry.js'\nimport { mergeTheme } from './theme.js'\nimport { computeFormatState } from './format.js'\nimport { makeOnEffect } from './effects.js'\nimport {\n countWords,\n init,\n update,\n type EditorEffect,\n type EditorMsg,\n type EditorOutMsg,\n type EditorState,\n type FormatState,\n} from './state.js'\n\nexport interface EditorConfig {\n /** Plugins composing the feature set; order defines transformer precedence.\n * Defaults to `[corePlugin(), linkPlugin()]` so the minimal editor has GFM + links. */\n plugins?: readonly MarkdownPlugin[]\n /** Initial markdown (uncontrolled seed). */\n defaultValue?: string\n /** Controlled: the consumer owns this signal; the editor follows it. */\n value?: Signal<string>\n /** Debounced markdown-emission window (ms). Default 300. */\n changeDebounceMs?: number\n placeholder?: string\n readonly?: boolean\n /** Lexical theme class map. */\n theme?: EditorThemeClasses\n /** Editor namespace (instance isolation). */\n namespace?: string\n /** Outbound markdown (after debounce). */\n onChange?: (markdown: string) => void\n /** Outbound format surface (for chrome built outside this package). */\n onFormatChange?: (format: FormatState) => void\n /** Receives the live Lexical editor at mount (imperative access, collab hooks). */\n onReady?: (editor: LexicalEditor) => void\n /** Render the built-in toolbar above the editor. Default false (minimal). */\n toolbar?: boolean\n /** Convert plain-text Markdown to rich content on paste. Default true.\n * Pastes that carry `text/html` are always left to Lexical's HTML import,\n * regardless of this flag. Set false to paste Markdown as literal text. */\n pasteMarkdown?: boolean\n /** Enable collaborative editing. The editor hands you a markdown `seed` and\n * status sinks; return a binding (build it with `yjsCollab` from\n * `@llui/lexical-collab`, wiring your own provider). Mutually exclusive with\n * `value` — the shared CRDT document, not a markdown signal, owns the content.\n * `defaultValue` becomes the seed the bootstrapping peer writes. */\n collab?: CollabFactory\n}\n\n/** Disposer-returning binding the collab layer installs on the live editor.\n * `@llui/lexical-collab`'s `YjsCollab` satisfies this structurally, so\n * `@llui/markdown-editor` needs no Yjs dependency of its own. */\nexport interface CollabBinding {\n register: (editor: LexicalEditor) => () => void\n}\n\n/** Hooks the editor injects into the {@link CollabFactory}: a markdown `seed`\n * (run once by the bootstrapping peer to fill an empty shared doc from\n * `defaultValue`) plus status sinks the editor mirrors into `state.collab`.\n * Spread straight into `yjsCollab({ id, provider, user, ...hooks })`. */\nexport interface CollabHooks {\n seed: (editor: LexicalEditor) => void\n onStatus: (connected: boolean) => void\n onSync: (synced: boolean) => void\n onPeers: (count: number) => void\n}\n\n/** Builds the collab binding from the editor-supplied hooks. */\nexport type CollabFactory = (hooks: CollabHooks) => CollabBinding\n\n/** Hooks the chrome layer (toolbar/menus) uses to compose around the editor. */\nexport interface EditorParts {\n /** The merged, surface-filtered command items. */\n items: readonly CommandItem[]\n /** Reactive format signal for `connect`-style toolbars. */\n format: Signal<FormatState>\n}\n\n/** Default plugin set when the consumer supplies none. */\nfunction defaultPlugins(): MarkdownPlugin[] {\n return [corePlugin(), linkPlugin()]\n}\n\n/**\n * Build the markdown editor component. Embed it with `mountApp(el, markdownEditor(...))`\n * or compose it inside a larger component.\n */\nexport function markdownEditor(\n config: EditorConfig = {},\n): SignalComponentDef<EditorState, EditorMsg, EditorEffect> {\n const plugins = config.plugins && config.plugins.length > 0 ? config.plugins : defaultPlugins()\n const transformers = buildTransformers(plugins)\n\n const items: CommandItem[] = plugins.flatMap((p) => p.items ?? [])\n const itemsById = new Map(items.map((i) => [i.id, i]))\n // Share the merged item list with plugins that want it (e.g. the slash menu).\n for (const plugin of plugins) plugin.onItems?.(items)\n const decorators: DecoratorBridge[] = plugins.flatMap((p) => p.decorators ?? [])\n const pluginUIs: Array<{ name: string; ui: PluginUI }> = plugins\n .filter((p): p is MarkdownPlugin & { ui: PluginUI } => p.ui !== undefined)\n .map((p) => ({ name: p.name, ui: p.ui }))\n const pluginUIByName = new Map(pluginUIs.map((p) => [p.name, p.ui]))\n\n // The live editor, captured at mount; effects dispatch through it.\n let editorRef: LexicalEditor | null = null\n const getEditor = (): LexicalEditor | null => editorRef\n\n const baseOnEffect = makeOnEffect(getEditor, itemsById, {\n onChange: config.onChange,\n onFormatChange: config.onFormatChange,\n applyValue: (editor, value) =>\n editor.update(\n () => {\n $convertFromMarkdownString(value, transformers)\n // Clear selection so the reconciler doesn't pull DOM focus into the\n // editor on an external push (e.g. typing in a bound source textarea).\n $setSelection(null)\n },\n { tag: PROGRAMMATIC_TAG },\n ),\n })\n\n if (config.collab && config.value) {\n throw new Error(\n 'markdownEditor: `collab` and `value` are mutually exclusive — in a collaborative ' +\n 'session the shared CRDT document owns the content, not a markdown signal. ' +\n 'Use `defaultValue` as the bootstrap seed instead.',\n )\n }\n\n const collabEnabled = !!config.collab\n const seedValue = config.value ? config.value.peek() : (config.defaultValue ?? '')\n\n // ── Composed TEA: core + plugin UI slices ──────────────────────────────────\n const composedInit = (): [EditorState, EditorEffect[]] => {\n const [core, effects] = init({\n value: seedValue,\n readonly: config.readonly ?? false,\n collab: collabEnabled,\n })\n const slices: Record<string, unknown> = {}\n for (const { name, ui } of pluginUIs) slices[name] = ui.init()\n return [{ ...core, plugins: slices }, effects]\n }\n\n const composedUpdate = (state: EditorState, msg: EditorMsg): [EditorState, EditorEffect[]] => {\n if (msg.type === 'plugin') {\n const ui = pluginUIByName.get(msg.name)\n if (!ui?.update) return [state, []]\n const result = ui.update(state.plugins[msg.name], msg.msg)\n const [slice, effects] = (Array.isArray(result) ? result : [result, []]) as [\n unknown,\n unknown[],\n ]\n return [\n { ...state, plugins: { ...state.plugins, [msg.name]: slice } },\n effects.map((effect) => ({ type: 'pluginEffect' as const, name: msg.name, effect })),\n ]\n }\n return update(state, msg)\n }\n\n const composedOnEffect = (\n effect: EditorEffect,\n api: { send: (msg: EditorMsg) => void; state: Signal<EditorState> },\n ): void => {\n if (effect.type === 'pluginEffect') {\n const ui = pluginUIByName.get(effect.name)\n ui?.onEffect?.(effect.effect, {\n editor: getEditor,\n send: (msg) => api.send({ type: 'plugin', name: effect.name, msg }),\n emit: (msg) => api.send(msg as EditorMsg),\n })\n return\n }\n baseOnEffect(effect, api)\n }\n\n const view = ({\n state,\n send,\n }: {\n state: Signal<EditorState>\n send: (msg: EditorMsg) => void\n }): Renderable => {\n // Build the collab binding (once, at mount) from the consumer's factory,\n // injecting the markdown seed + status sinks that mirror into `state.collab`.\n const collabBinding: CollabBinding | null = config.collab\n ? config.collab({\n seed: () => {\n $convertFromMarkdownString(seedValue, transformers)\n $setSelection(null)\n },\n onStatus: (connected) => send({ type: 'collabStatus', connected }),\n onSync: (synced) => send({ type: 'collabSync', synced }),\n onPeers: (peers) => send({ type: 'collabPeers', peers }),\n })\n : null\n\n const host = lexicalForeign<EditorOutMsg>({\n namespace: config.namespace ?? 'llui-markdown',\n theme: mergeTheme(config.theme),\n plugins,\n serialize: (editor) =>\n editor.getEditorState().read(() => $convertToMarkdownString(transformers)),\n deserialize: (_editor, value) => {\n $convertFromMarkdownString(value, transformers)\n $setSelection(null)\n },\n // In collab mode the shared CRDT owns the document: the local undo stack\n // and the boot-time seed are disabled — the binding supplies a scoped undo\n // manager and a sync-gated bootstrap instead.\n ...(collabBinding ? { history: false, seedMode: 'deferred' as const } : {}),\n defaultValue: collabBinding || config.value ? undefined : (config.defaultValue ?? ''),\n ...(config.value && !collabBinding ? { value: config.value } : {}),\n readonly: state.at('readonly'),\n ...(config.changeDebounceMs !== undefined\n ? { changeDebounceMs: config.changeDebounceMs }\n : {}),\n register: (editor) => {\n const disposers = [registerMarkdownShortcuts(editor, transformers)]\n if (config.pasteMarkdown !== false)\n disposers.push(registerMarkdownPaste(editor, transformers))\n if (decorators.length > 0) disposers.push(registerDecoratorBridges(editor, decorators))\n if (collabBinding) disposers.push(collabBinding.register(editor))\n return () => {\n for (const dispose of disposers) dispose()\n }\n },\n onReady: (editor) => {\n editorRef = editor\n if (config.placeholder) {\n editor.getRootElement()?.setAttribute('data-placeholder', config.placeholder)\n }\n config.onReady?.(editor)\n },\n onChange: (value) => send({ type: 'markdownChanged', value }),\n onSelectionChange: (ctx) => {\n const format = computeFormatState(ctx.editor, ctx)\n const text = ctx.editor.getEditorState().read(() => $getRoot().getTextContent())\n // Toggle an empty marker so CSS can show the placeholder.\n ctx.editor.getRootElement()?.setAttribute('data-empty', text === '' ? 'true' : 'false')\n send({ type: 'formatChanged', format, wordCount: countWords(text), charCount: text.length })\n },\n emit: (msg) => send(msg),\n })\n\n // Plugin view contributions (overlays/panels) — each gets its own slice + send.\n const pluginViews: Renderable = pluginUIs.flatMap(({ name, ui }) => {\n if (!ui.view) return []\n const rendered = ui.view({\n state: state.at(`plugins.${name}`),\n send: (msg) => send({ type: 'plugin', name, msg }),\n editor: getEditor,\n })\n return Array.isArray(rendered) ? rendered : [rendered]\n })\n\n if (!config.toolbar) return [host, ...pluginViews]\n return [\n div({ 'data-scope': 'md-editor', 'data-part': 'root' }, [\n renderToolbar({ format: state.at('format'), send, items, collab: state.at('collab') }),\n div({ 'data-scope': 'md-editor', 'data-part': 'surface' }, [host]),\n ]),\n ...pluginViews,\n ]\n }\n\n return component<EditorState, EditorMsg, EditorEffect>({\n name: 'MarkdownEditor',\n init: composedInit,\n update: composedUpdate,\n view,\n onEffect: composedOnEffect,\n })\n}\n"]}
1
+ {"version":3,"file":"editor.js","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"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"}
package/dist/effects.d.ts CHANGED
@@ -11,7 +11,9 @@ export interface EffectConfig {
11
11
  /** Push markdown into the live editor (deserialize), without echoing onChange. */
12
12
  applyValue: (editor: LexicalEditor, value: string) => void;
13
13
  }
14
- /** Build the component's `onEffect`. `getEditor` returns the live editor (set at
15
- * mount via the foreign `onReady`); `items` is the merged id command map. */
16
- export declare function makeOnEffect(getEditor: () => LexicalEditor | null, items: ReadonlyMap<string, CommandItem>, config: EffectConfig): (effect: EditorEffect, api: EffectApi) => void;
14
+ /** Build the component's `onEffect`. `resolveEditor` maps the per-mount effect
15
+ * `api` (whose `send` identifies the mount) to that mount's live editor — so two
16
+ * mounts of one definition dispatch to their own editors; `items` is the merged
17
+ * id → command map. */
18
+ export declare function makeOnEffect(resolveEditor: (api: EffectApi) => LexicalEditor | null, items: ReadonlyMap<string, CommandItem>, config: EffectConfig): (effect: EditorEffect, api: EffectApi) => void;
17
19
  //# sourceMappingURL=effects.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"effects.d.ts","sourceRoot":"","sources":["../src/effects.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAEtE,iEAAiE;AACjE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAA;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;IAC9C,kFAAkF;IAClF,UAAU,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAC3D;AAED;+EAC+E;AAC/E,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,aAAa,GAAG,IAAI,EACrC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,EACvC,MAAM,EAAE,YAAY,GACnB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,KAAK,IAAI,CAwBhD"}
1
+ {"version":3,"file":"effects.d.ts","sourceRoot":"","sources":["../src/effects.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAEtE,iEAAiE;AACjE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAA;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;IAC9C,kFAAkF;IAClF,UAAU,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAC3D;AAED;;;uBAGuB;AACvB,wBAAgB,YAAY,CAC1B,aAAa,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,aAAa,GAAG,IAAI,EACvD,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,EACvC,MAAM,EAAE,YAAY,GACnB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,KAAK,IAAI,CAwBhD"}
package/dist/effects.js CHANGED
@@ -1,20 +1,22 @@
1
1
  // Effect handler: the only place TEA reaches back into the live Lexical editor.
2
2
  // `execCommand` looks an id up in the merged command-item map and runs it on the
3
3
  // editor captured at mount; emit* forward to the consumer's callbacks.
4
- /** Build the component's `onEffect`. `getEditor` returns the live editor (set at
5
- * mount via the foreign `onReady`); `items` is the merged id command map. */
6
- export function makeOnEffect(getEditor, items, config) {
4
+ /** Build the component's `onEffect`. `resolveEditor` maps the per-mount effect
5
+ * `api` (whose `send` identifies the mount) to that mount's live editor — so two
6
+ * mounts of one definition dispatch to their own editors; `items` is the merged
7
+ * id → command map. */
8
+ export function makeOnEffect(resolveEditor, items, config) {
7
9
  return (effect, api) => {
8
10
  switch (effect.type) {
9
11
  case 'execCommand': {
10
- const editor = getEditor();
12
+ const editor = resolveEditor(api);
11
13
  const item = items.get(effect.id);
12
14
  if (editor && item)
13
15
  item.run(editor, { send: api.send });
14
16
  return;
15
17
  }
16
18
  case 'applyValue': {
17
- const editor = getEditor();
19
+ const editor = resolveEditor(api);
18
20
  if (editor)
19
21
  config.applyValue(editor, effect.value);
20
22
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"effects.js","sourceRoot":"","sources":["../src/effects.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,iFAAiF;AACjF,uEAAuE;AAkBvE;+EAC+E;AAC/E,MAAM,UAAU,YAAY,CAC1B,SAAqC,EACrC,KAAuC,EACvC,MAAoB;IAEpB,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;QACrB,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;gBAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;gBACjC,IAAI,MAAM,IAAI,IAAI;oBAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YACD,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;gBAC1B,IAAI,MAAM;oBAAE,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;gBACnD,OAAM;YACR,CAAC;YACD,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBAC/B,OAAM;YACR,CAAC;YACD,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;gBACtC,OAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC,CAAA;AACH,CAAC","sourcesContent":["// Effect handler: the only place TEA reaches back into the live Lexical editor.\n// `execCommand` looks an id up in the merged command-item map and runs it on the\n// editor captured at mount; emit* forward to the consumer's callbacks.\n\nimport type { LexicalEditor } from 'lexical'\nimport type { CommandItem } from './plugins/types.js'\nimport type { EditorEffect, EditorMsg, FormatState } from './state.js'\n\n/** The api the component passes to `onEffect` (send + state). */\nexport interface EffectApi {\n send: (msg: EditorMsg) => void\n}\n\nexport interface EffectConfig {\n onChange?: (markdown: string) => void\n onFormatChange?: (format: FormatState) => void\n /** Push markdown into the live editor (deserialize), without echoing onChange. */\n applyValue: (editor: LexicalEditor, value: string) => void\n}\n\n/** Build the component's `onEffect`. `getEditor` returns the live editor (set at\n * mount via the foreign `onReady`); `items` is the merged id → command map. */\nexport function makeOnEffect(\n getEditor: () => LexicalEditor | null,\n items: ReadonlyMap<string, CommandItem>,\n config: EffectConfig,\n): (effect: EditorEffect, api: EffectApi) => void {\n return (effect, api) => {\n switch (effect.type) {\n case 'execCommand': {\n const editor = getEditor()\n const item = items.get(effect.id)\n if (editor && item) item.run(editor, { send: api.send })\n return\n }\n case 'applyValue': {\n const editor = getEditor()\n if (editor) config.applyValue(editor, effect.value)\n return\n }\n case 'emitChange': {\n config.onChange?.(effect.value)\n return\n }\n case 'emitFormat': {\n config.onFormatChange?.(effect.format)\n return\n }\n }\n }\n}\n"]}
1
+ {"version":3,"file":"effects.js","sourceRoot":"","sources":["../src/effects.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,iFAAiF;AACjF,uEAAuE;AAkBvE;;;uBAGuB;AACvB,MAAM,UAAU,YAAY,CAC1B,aAAuD,EACvD,KAAuC,EACvC,MAAoB;IAEpB,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;QACrB,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;gBACjC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;gBACjC,IAAI,MAAM,IAAI,IAAI;oBAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YACD,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;gBACjC,IAAI,MAAM;oBAAE,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;gBACnD,OAAM;YACR,CAAC;YACD,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBAC/B,OAAM;YACR,CAAC;YACD,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;gBACtC,OAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC,CAAA;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,8EAA8E;AAC9E,mEAAmE;AAEnE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAsB,MAAM,SAAS,CAAA;AAC9E,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAC3E,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/C,OAAO,EAAE,YAAY,EAAoC,MAAM,YAAY,CAAA;AAE3E,gFAAgF;AAChF,MAAM,UAAU,kBAAkB,CAChC,MAAqB,EACrB,OAAsD;IAEtD,OAAO,MAAM,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;QACvC,MAAM,IAAI,GAAG,eAAe,EAAE,CAAA;QAC9B,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,OAAO,EAAE,GAAG,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAA;QAChF,CAAC;QAED,IAAI,SAAS,GAAc,IAAI,CAAC,SAAS,CAAA;QACzC,IAAI,IAAI,GAAG,KAAK,CAAA;QAEhB,MAAM,SAAS,GAAG,aAAa,EAAE,CAAA;QACjC,IAAI,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;YACjC,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,CAAA;YAC7C,IAAI,GAAG,mBAAmB,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAA;YAE5E,IAAI,IAAI,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;gBAC/B,MAAM,QAAQ,GAAG,mBAAmB,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAA;gBACjF,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,IAAI,GAAG,qBAAqB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;oBACxD,IAAI,IAAI;wBAAE,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAA;gBAC1C,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAA;oBACnF,IAAI,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC;wBAAE,SAAS,GAAG,MAAM,CAAA;gBACjD,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI;YACJ,SAAS;YACT,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["// Compute the full toolbar FormatState from a Lexical selection — the base\n// rich-text format (from @llui/lexical) refined with list/code/link detection\n// (which needs the list/code/link packages this layer depends on).\n\nimport { $getSelection, $isRangeSelection, type LexicalEditor } from 'lexical'\nimport { $findMatchingParent, $getNearestNodeOfType } from '@lexical/utils'\nimport { ListNode, $isListItemNode } from '@lexical/list'\nimport { $isCodeNode } from '@lexical/code-core'\nimport { $isLinkNode } from '@lexical/link'\nimport { $readBaseFormat } from '@llui/lexical'\nimport type { SelectionContext } from '@llui/lexical'\nimport { EMPTY_FORMAT, type BlockType, type FormatState } from './state.js'\n\n/** Read the full format surface at the current selection (opens a read ctx). */\nexport function computeFormatState(\n editor: LexicalEditor,\n history: Pick<SelectionContext, 'canUndo' | 'canRedo'>,\n): FormatState {\n return editor.getEditorState().read(() => {\n const base = $readBaseFormat()\n if (!base.hasSelection) {\n return { ...EMPTY_FORMAT, canUndo: history.canUndo, canRedo: history.canRedo }\n }\n\n let blockType: BlockType = base.blockType\n let link = false\n\n const selection = $getSelection()\n if ($isRangeSelection(selection)) {\n const anchorNode = selection.anchor.getNode()\n link = $findMatchingParent(anchorNode, (node) => $isLinkNode(node)) !== null\n\n if (base.blockType === 'other') {\n const listItem = $findMatchingParent(anchorNode, (node) => $isListItemNode(node))\n if (listItem) {\n const list = $getNearestNodeOfType(anchorNode, ListNode)\n if (list) blockType = list.getListType()\n } else {\n const top = anchorNode.getKey() === 'root' ? null : anchorNode.getTopLevelElement()\n if (top && $isCodeNode(top)) blockType = 'code'\n }\n }\n }\n\n return {\n bold: base.bold,\n italic: base.italic,\n strikethrough: base.strikethrough,\n code: base.code,\n link,\n blockType,\n alignment: base.alignment,\n canUndo: history.canUndo,\n canRedo: history.canRedo,\n }\n })\n}\n"]}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,8EAA8E;AAC9E,mEAAmE;AAEnE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAsB,MAAM,SAAS,CAAA;AAC9E,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAC3E,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/C,OAAO,EAAE,YAAY,EAAoC,MAAM,YAAY,CAAA;AAE3E,gFAAgF;AAChF,MAAM,UAAU,kBAAkB,CAChC,MAAqB,EACrB,OAAsD;IAEtD,OAAO,MAAM,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;QACvC,MAAM,IAAI,GAAG,eAAe,EAAE,CAAA;QAC9B,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,OAAO,EAAE,GAAG,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAA;QAChF,CAAC;QAED,IAAI,SAAS,GAAc,IAAI,CAAC,SAAS,CAAA;QACzC,IAAI,IAAI,GAAG,KAAK,CAAA;QAEhB,MAAM,SAAS,GAAG,aAAa,EAAE,CAAA;QACjC,IAAI,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;YACjC,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,CAAA;YAC7C,IAAI,GAAG,mBAAmB,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAA;YAE5E,IAAI,IAAI,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;gBAC/B,MAAM,QAAQ,GAAG,mBAAmB,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAA;gBACjF,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,IAAI,GAAG,qBAAqB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;oBACxD,IAAI,IAAI;wBAAE,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAA;gBAC1C,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAA;oBACnF,IAAI,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC;wBAAE,SAAS,GAAG,MAAM,CAAA;gBACjD,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI;YACJ,SAAS;YACT,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,EAML,cAAc,GACf,MAAM,aAAa,CAAA;AAEpB,OAAO,EAUL,YAAY,EACZ,UAAU,EACV,IAAI,EACJ,MAAM,EACN,UAAU,GACX,MAAM,YAAY,CAAA;AAEnB,OAAO,EAKN,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAKL,cAAc,GACf,MAAM,iBAAiB,CAAA;AAExB,OAAO,EAA0B,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAGL,iBAAiB,GAClB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAA0B,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAIL,aAAa,EACb,cAAc,GACf,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAA0B,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAA6B,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC/E,OAAO,EAA2C,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC7F,OAAO,EAA2B,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACxF,OAAO,EAA2B,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAE9E,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAEjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,6BAA6B,EAC7B,YAAY,EACZ,UAAU,GACX,MAAM,YAAY,CAAA;AAEnB,OAAO,EAIL,cAAc,EACd,cAAc,EACd,OAAO,GACR,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAA0B,UAAU,EAAE,MAAM,2BAA2B,CAAA","sourcesContent":["// `@llui/markdown-editor` — WYSIWYG Markdown editor for LLui, built on Lexical.\n\nexport {\n type EditorConfig,\n type EditorParts,\n type CollabBinding,\n type CollabHooks,\n type CollabFactory,\n markdownEditor,\n} from './editor.js'\n\nexport {\n type BlockType,\n type FormatState,\n type OverlayKind,\n type CollabStatus,\n type EditorState,\n type EditorMsg,\n type EditorOutMsg,\n type EditorEffect,\n type InitOptions,\n EMPTY_FORMAT,\n COLLAB_OFF,\n init,\n update,\n countWords,\n} from './state.js'\n\nexport {\n type ItemSurface,\n type CommandItem,\n type CommandContext,\n type MarkdownPlugin,\n} from './plugins/types.js'\n\nexport {\n type PluginUI,\n type PluginUISpec,\n type PluginViewArgs,\n type PluginEffectContext,\n definePluginUI,\n} from './plugins/ui.js'\n\nexport { type CorePluginOptions, corePlugin } from './plugins/core.js'\nexport {\n type InlineFormat,\n type SingleBlockPluginOptions,\n singleBlockPlugin,\n} from './plugins/single-block.js'\nexport { type LinkPluginOptions, linkPlugin } from './plugins/link.js'\nexport {\n type CalloutKind,\n type CalloutData,\n type CalloutPluginOptions,\n calloutPlugin,\n $insertCallout,\n} from './plugins/callout.js'\nexport { hrPlugin, $insertHorizontalRule } from './plugins/hr.js'\nexport { slashPlugin } from './plugins/slash.js'\nexport { contextMenuPlugin } from './plugins/context-menu.js'\nexport { floatingToolbarPlugin } from './plugins/floating-toolbar.js'\nexport { type MathPluginOptions, mathPlugin } from './plugins/math.js'\nexport { type MermaidPluginOptions, mermaidPlugin } from './plugins/mermaid.js'\nexport { type Mention, type MentionPluginOptions, mentionPlugin } from './plugins/mention.js'\nexport { type EmojiPluginOptions, DEFAULT_EMOJI, emojiPlugin } from './plugins/emoji.js'\nexport { type ImagePluginOptions, imagePlugin } from './plugins/image.js'\nexport { tablePlugin } from './plugins/table.js'\n\nexport { $insertMarkdownAtSelection, registerMarkdownPaste } from './paste.js'\n\nexport { GFM_NODES, GFM_TRANSFORMERS } from './transformers/gfm.js'\nexport { buildTransformers, orderTransformers } from './transformers/registry.js'\n\nexport { computeFormatState } from './format.js'\n\nexport {\n STRIKETHROUGH_CLASS,\n UNDERLINE_CLASS,\n UNDERLINE_STRIKETHROUGH_CLASS,\n defaultTheme,\n mergeTheme,\n} from './theme.js'\n\nexport {\n type ToolbarItemParts,\n type ToolbarParts,\n type ToolbarOptions,\n DEFAULT_GLYPHS,\n connectToolbar,\n toolbar,\n} from './surfaces/toolbar.js'\n\nexport { type LinkDialogOptions, linkDialog } from './surfaces/link-dialog.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,EAML,cAAc,GACf,MAAM,aAAa,CAAA;AAEpB,OAAO,EAUL,YAAY,EACZ,UAAU,EACV,IAAI,EACJ,MAAM,EACN,UAAU,GACX,MAAM,YAAY,CAAA;AAEnB,OAAO,EAKN,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAKL,cAAc,GACf,MAAM,iBAAiB,CAAA;AAExB,OAAO,EAA0B,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAGL,iBAAiB,GAClB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAA0B,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAIL,aAAa,EACb,cAAc,GACf,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAA0B,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAA6B,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC/E,OAAO,EAA2C,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC7F,OAAO,EAA2B,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACxF,OAAO,EAA2B,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAE9E,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAEjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,6BAA6B,EAC7B,YAAY,EACZ,UAAU,GACX,MAAM,YAAY,CAAA;AAEnB,OAAO,EAIL,cAAc,EACd,cAAc,EACd,OAAO,GACR,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAA0B,UAAU,EAAE,MAAM,2BAA2B,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"paste.d.ts","sourceRoot":"","sources":["../src/paste.ts"],"names":[],"mappings":"AAMA,OAAO,EAUL,KAAK,aAAa,EACnB,MAAM,SAAS,CAAA;AAChB,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEhF;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,GAC/B,OAAO,CAiBT;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,GAC/B,MAAM,IAAI,CA6BZ"}
1
+ {"version":3,"file":"paste.d.ts","sourceRoot":"","sources":["../src/paste.ts"],"names":[],"mappings":"AAMA,OAAO,EAUL,KAAK,aAAa,EACnB,MAAM,SAAS,CAAA;AAChB,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAGhF;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,GAC/B,OAAO,CAqBT;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,GAC/B,MAAM,IAAI,CA6BZ"}
package/dist/paste.js CHANGED
@@ -5,6 +5,7 @@
5
5
  // per-editor via the `pasteMarkdown: false` config option.
6
6
  import { $createParagraphNode, $getSelection, $insertNodes, $isRangeSelection, $setSelection, COMMAND_PRIORITY_HIGH, PASTE_COMMAND, isDOMNode, isSelectionCapturedInDecoratorInput, } from 'lexical';
7
7
  import { $convertFromMarkdownString } from '@lexical/markdown';
8
+ import { $sanitizeLinkNodes } from './security.js';
8
9
  /**
9
10
  * Parse `markdown` with `transformers` and insert the produced nodes at the
10
11
  * current range selection. The document is parsed into a detached scratch
@@ -24,6 +25,10 @@ export function $insertMarkdownAtSelection(markdown, transformers) {
24
25
  // touches the scratch node, not the live document.
25
26
  const scratch = $createParagraphNode();
26
27
  $convertFromMarkdownString(markdown, transformers, scratch);
28
+ // Untrusted source: neutralize any `javascript:`/`data:` link the markdown
29
+ // carried BEFORE the nodes are spliced into the live document. (Image src is
30
+ // enforced in the image transformer; links go through here.)
31
+ $sanitizeLinkNodes(scratch);
27
32
  const nodes = scratch.getChildren();
28
33
  if (nodes.length === 0)
29
34
  return false;
package/dist/paste.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"paste.js","sourceRoot":"","sources":["../src/paste.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,gFAAgF;AAChF,2DAA2D;AAE3D,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,SAAS,EACT,mCAAmC,GAEpC,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,0BAA0B,EAAoB,MAAM,mBAAmB,CAAA;AAEhF;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAAgB,EAChB,YAAgC;IAEhC,MAAM,SAAS,GAAG,aAAa,EAAE,CAAA;IACjC,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAA;IAC/C,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,CAAA;IAE/B,kFAAkF;IAClF,mDAAmD;IACnD,MAAM,OAAO,GAAG,oBAAoB,EAAE,CAAA;IACtC,0BAA0B,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,CAAA;IAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAA;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAEpC,6EAA6E;IAC7E,4EAA4E;IAC5E,aAAa,CAAC,KAAK,CAAC,CAAA;IACpB,YAAY,CAAC,KAAK,CAAC,CAAA;IACnB,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAqB,EACrB,YAAgC;IAEhC,OAAO,MAAM,CAAC,eAAe,CAC3B,aAAa,EACb,CAAC,KAAqB,EAAE,EAAE;QACxB,qEAAqE;QACrE,wCAAwC;QACxC,IAAI,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,mCAAmC,CAAC,KAAK,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAA;QAC9F,MAAM,SAAS,GAAG,KAAK,CAAC,aAAa,CAAA;QACrC,IAAI,CAAC,SAAS;YAAE,OAAO,KAAK,CAAA;QAC5B,wEAAwE;QACxE,IAAI,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,OAAO,KAAK,CAAA;QACvD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;QAC5C,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAA;QAEvB,qEAAqE;QACrE,sEAAsE;QACtE,wEAAwE;QACxE,sEAAsE;QACtE,wBAAwB;QACxB,IAAI,CAAC,iBAAiB,CAAC,aAAa,EAAE,CAAC;YAAE,OAAO,KAAK,CAAA;QAErD,KAAK,CAAC,cAAc,EAAE,CAAA;QACtB,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE;YACjB,0BAA0B,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;QACF,OAAO,IAAI,CAAA;IACb,CAAC,EACD,qBAAqB,CACtB,CAAA;AACH,CAAC","sourcesContent":["// Markdown-on-paste: when the user pastes plain text into the editor, parse it\n// as Markdown and insert the resulting rich nodes at the caret instead of the\n// literal source. Rich pastes (clipboards carrying `text/html`) are left to\n// Lexical's own HTML import so copy-from-the-web keeps its formatting. Disabled\n// per-editor via the `pasteMarkdown: false` config option.\n\nimport {\n $createParagraphNode,\n $getSelection,\n $insertNodes,\n $isRangeSelection,\n $setSelection,\n COMMAND_PRIORITY_HIGH,\n PASTE_COMMAND,\n isDOMNode,\n isSelectionCapturedInDecoratorInput,\n type LexicalEditor,\n} from 'lexical'\nimport { $convertFromMarkdownString, type Transformer } from '@lexical/markdown'\n\n/**\n * Parse `markdown` with `transformers` and insert the produced nodes at the\n * current range selection. The document is parsed into a detached scratch\n * container (so the live root is never cleared) and the selection captured\n * before the import — which moves the caret into the scratch node — is restored\n * before the nodes are spliced in. Returns `true` only when nodes were actually\n * inserted; `false` (a no-op) when there is no range selection to insert into or\n * the markdown parsed to nothing — letting the caller fall back to the default\n * paste behaviour instead of silently swallowing the event.\n */\nexport function $insertMarkdownAtSelection(\n markdown: string,\n transformers: Array<Transformer>,\n): boolean {\n const selection = $getSelection()\n if (!$isRangeSelection(selection)) return false\n const saved = selection.clone()\n\n // Import into a detached element so `$convertFromMarkdownString`'s `root.clear()`\n // touches the scratch node, not the live document.\n const scratch = $createParagraphNode()\n $convertFromMarkdownString(markdown, transformers, scratch)\n const nodes = scratch.getChildren()\n if (nodes.length === 0) return false\n\n // The import re-homes the selection to the scratch node's start; restore the\n // real caret, then splice the parsed nodes in (splitting blocks as needed).\n $setSelection(saved)\n $insertNodes(nodes)\n return true\n}\n\n/**\n * Register the markdown-on-paste handler on `editor`. Returns a disposer.\n *\n * Plain-text pastes are converted as Markdown. Pastes that also carry\n * `text/html` are ignored so Lexical's richer HTML import handles them.\n */\nexport function registerMarkdownPaste(\n editor: LexicalEditor,\n transformers: Array<Transformer>,\n): () => void {\n return editor.registerCommand(\n PASTE_COMMAND,\n (event: ClipboardEvent) => {\n // Let native inputs inside a DecoratorNode paste themselves (mirrors\n // Lexical's own rich-text paste guard).\n if (isDOMNode(event.target) && isSelectionCapturedInDecoratorInput(event.target)) return false\n const clipboard = event.clipboardData\n if (!clipboard) return false\n // Defer to Lexical's HTML import when the source provides rich content.\n if (clipboard.types.includes('text/html')) return false\n const text = clipboard.getData('text/plain')\n if (!text) return false\n\n // Command listeners run inside a read context, so we can inspect the\n // selection synchronously. Only claim the event when there is a range\n // selection to insert into; otherwise fall through to Lexical's default\n // paste handler (e.g. a selected decorator/NodeSelection) rather than\n // swallowing the paste.\n if (!$isRangeSelection($getSelection())) return false\n\n event.preventDefault()\n editor.update(() => {\n $insertMarkdownAtSelection(text, transformers)\n })\n return true\n },\n COMMAND_PRIORITY_HIGH,\n )\n}\n"]}
1
+ {"version":3,"file":"paste.js","sourceRoot":"","sources":["../src/paste.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,gFAAgF;AAChF,2DAA2D;AAE3D,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,SAAS,EACT,mCAAmC,GAEpC,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,0BAA0B,EAAoB,MAAM,mBAAmB,CAAA;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAElD;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAAgB,EAChB,YAAgC;IAEhC,MAAM,SAAS,GAAG,aAAa,EAAE,CAAA;IACjC,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAA;IAC/C,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,CAAA;IAE/B,kFAAkF;IAClF,mDAAmD;IACnD,MAAM,OAAO,GAAG,oBAAoB,EAAE,CAAA;IACtC,0BAA0B,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,CAAA;IAC3D,2EAA2E;IAC3E,6EAA6E;IAC7E,6DAA6D;IAC7D,kBAAkB,CAAC,OAAO,CAAC,CAAA;IAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAA;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAEpC,6EAA6E;IAC7E,4EAA4E;IAC5E,aAAa,CAAC,KAAK,CAAC,CAAA;IACpB,YAAY,CAAC,KAAK,CAAC,CAAA;IACnB,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAqB,EACrB,YAAgC;IAEhC,OAAO,MAAM,CAAC,eAAe,CAC3B,aAAa,EACb,CAAC,KAAqB,EAAE,EAAE;QACxB,qEAAqE;QACrE,wCAAwC;QACxC,IAAI,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,mCAAmC,CAAC,KAAK,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAA;QAC9F,MAAM,SAAS,GAAG,KAAK,CAAC,aAAa,CAAA;QACrC,IAAI,CAAC,SAAS;YAAE,OAAO,KAAK,CAAA;QAC5B,wEAAwE;QACxE,IAAI,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,OAAO,KAAK,CAAA;QACvD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;QAC5C,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAA;QAEvB,qEAAqE;QACrE,sEAAsE;QACtE,wEAAwE;QACxE,sEAAsE;QACtE,wBAAwB;QACxB,IAAI,CAAC,iBAAiB,CAAC,aAAa,EAAE,CAAC;YAAE,OAAO,KAAK,CAAA;QAErD,KAAK,CAAC,cAAc,EAAE,CAAA;QACtB,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE;YACjB,0BAA0B,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;QACF,OAAO,IAAI,CAAA;IACb,CAAC,EACD,qBAAqB,CACtB,CAAA;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"_preview.js","sourceRoot":"","sources":["../../src/plugins/_preview.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,uEAAuE;AACvE,yEAAyE;AACzE,qEAAqE;AACrE,EAAE;AACF,qEAAqE;AACrE,sEAAsE;AACtE,oCAAoC;AACpC,mEAAmE;AACnE,wEAAwE;AACxE,yEAAyE;AACzE,2DAA2D;AAE3D,OAAO,EAAE,OAAO,EAA+B,MAAM,WAAW,CAAA;AAShE;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAsB,EACtB,MAAqB,EACrB,GAAG,GAAG,KAAK;IAEX,OAAO,OAAO,CAA8C;QAC1D,GAAG;QACH,KAAK,EAAE,EAAE,MAAM,EAAE;QACjB,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YACvB,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;YACvC,EAAE,CAAC,YAAY,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAA;YAC3C,MAAM,KAAK,GAAG,CAAC,KAAa,EAAQ,EAAE;gBACpC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;gBACzB,IAAI,OAAO,GAAG,KAAK,QAAQ;oBAAE,EAAE,CAAC,SAAS,GAAG,GAAG,CAAA;;oBAC1C,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAA;YAC9B,CAAC,CAAA;YACD,mEAAmE;YACnE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACvC,OAAO,EAAE,MAAM,EAAE,CAAA;QACnB,CAAC;QACD,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE;KACzC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["// Shared rendered-preview seam for the math / mermaid decorator plugins.\n//\n// SECURITY: a consumer-supplied `render` turns editor-document content\n// (TeX / mermaid source the user typed) into a preview. To avoid forcing\n// that through an unsanitized HTML sink, `render` may return EITHER:\n//\n// - a DOM `Node` — mounted directly with no HTML round-trip and NO\n// sanitization needed (prefer this: hand back the element KaTeX /\n// mermaid already produced); or\n// - a `string` — injected as **trusted HTML**. The renderer owns\n// sanitization in this branch; document content flows into it, so a\n// vulnerable/misconfigured renderer is an XSS sink. Return sanitized\n// markup (e.g. via DOMPurify) or prefer the Node form.\n\nimport { foreign, type Mountable, type Signal } from '@llui/dom'\n\n/** A preview renderer: source string → safe DOM node, or trusted HTML string. */\nexport type PreviewRender = (source: string) => string | Node\n\ninterface PreviewInstance {\n unbind: () => void\n}\n\n/**\n * Build a reactive `data-part=\"preview\"` region that re-renders whenever\n * `source` changes. String results are set as trusted HTML; Node results\n * are mounted directly (no sanitization). See the module header.\n */\nexport function renderedPreview(\n source: Signal<string>,\n render: PreviewRender,\n tag = 'div',\n): Mountable {\n return foreign<PreviewInstance, { source: Signal<string> }>({\n tag,\n state: { source },\n mount: ({ el, state }) => {\n el.setAttribute('data-part', 'preview')\n el.setAttribute('contenteditable', 'false')\n const apply = (value: string): void => {\n const out = render(value)\n if (typeof out === 'string') el.innerHTML = out\n else el.replaceChildren(out)\n }\n // `bind` fires immediately with the current value, then on change.\n const unbind = state.source.bind(apply)\n return { unbind }\n },\n unmount: (instance) => instance.unbind(),\n })\n}\n"]}
1
+ {"version":3,"file":"_preview.js","sourceRoot":"","sources":["../../src/plugins/_preview.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,uEAAuE;AACvE,yEAAyE;AACzE,qEAAqE;AACrE,EAAE;AACF,qEAAqE;AACrE,sEAAsE;AACtE,oCAAoC;AACpC,mEAAmE;AACnE,wEAAwE;AACxE,yEAAyE;AACzE,2DAA2D;AAE3D,OAAO,EAAE,OAAO,EAA+B,MAAM,WAAW,CAAA;AAShE;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAsB,EACtB,MAAqB,EACrB,GAAG,GAAG,KAAK;IAEX,OAAO,OAAO,CAA8C;QAC1D,GAAG;QACH,KAAK,EAAE,EAAE,MAAM,EAAE;QACjB,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YACvB,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;YACvC,EAAE,CAAC,YAAY,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAA;YAC3C,MAAM,KAAK,GAAG,CAAC,KAAa,EAAQ,EAAE;gBACpC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;gBACzB,IAAI,OAAO,GAAG,KAAK,QAAQ;oBAAE,EAAE,CAAC,SAAS,GAAG,GAAG,CAAA;;oBAC1C,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAA;YAC9B,CAAC,CAAA;YACD,mEAAmE;YACnE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACvC,OAAO,EAAE,MAAM,EAAE,CAAA;QACnB,CAAC;QACD,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE;KACzC,CAAC,CAAA;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"callout.d.ts","sourceRoot":"","sources":["../../src/plugins/callout.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,iBAAiB,EAElB,MAAM,eAAe,CAAA;AAEtB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAA;AAE/D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb;AA8GD,iFAAiF;AACjF,wBAAgB,cAAc,CAC5B,IAAI,GAAE,WAAoB,EAC1B,SAAS,SAAgB,GACxB,iBAAiB,CAEnB;AAyBD,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED,wBAAgB,aAAa,CAAC,IAAI,GAAE,oBAAyB,GAAG,cAAc,CA0B7E"}
1
+ {"version":3,"file":"callout.d.ts","sourceRoot":"","sources":["../../src/plugins/callout.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,iBAAiB,EAElB,MAAM,eAAe,CAAA;AAEtB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAA;AAE/D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb;AA+FD,iFAAiF;AACjF,wBAAgB,cAAc,CAC5B,IAAI,GAAE,WAAoB,EAC1B,SAAS,SAAgB,GACxB,iBAAiB,CAEnB;AAyBD,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED,wBAAgB,aAAa,CAAC,IAAI,GAAE,oBAAyB,GAAG,cAAc,CA0B7E"}
@@ -5,7 +5,7 @@
5
5
  import {} from 'lexical';
6
6
  import { $insertNodeToNearestRoot } from '@lexical/utils';
7
7
  import { $createLLuiDecoratorNode, $isLLuiDecoratorNode, LLuiDecoratorNode, decoratorBridge, } from '@llui/lexical';
8
- import { button, component, div, span, text } from '@llui/dom';
8
+ import { button, div, span, text } from '@llui/dom';
9
9
  const KIND_CYCLE = ['note', 'tip', 'warning', 'danger'];
10
10
  const KIND_LABEL = {
11
11
  note: 'Note',
@@ -29,50 +29,42 @@ function isCalloutData(value) {
29
29
  const stop = (e) => e.stopPropagation();
30
30
  /** The LLui sub-view rendered inside a callout DecoratorNode. The badge cycles
31
31
  * the kind; the text is an editable island that persists into the Lexical node
32
- * on blur (both round-trip to markdown). */
33
- const calloutBridge = decoratorBridge(BRIDGE_TYPE, (data, api) => component({
34
- name: 'Callout',
35
- init: () => ({ kind: data.kind, text: data.text }),
36
- update: (state, msg) => {
37
- if (msg.type === 'cycle') {
38
- const kind = nextKind(state.kind);
39
- api.update({ kind, text: state.text });
40
- return { ...state, kind };
41
- }
42
- if (msg.type === 'commitText') {
43
- if (msg.text === state.text)
44
- return state;
45
- api.update({ kind: state.kind, text: msg.text });
46
- return { ...state, text: msg.text };
47
- }
48
- return state;
49
- },
50
- view: ({ state, send }) => [
51
- div({
52
- 'data-scope': 'md-callout',
53
- 'data-part': 'root',
54
- 'data-kind': state.at('kind'),
55
- contenteditable: 'false',
56
- onKeyDown: stop,
57
- onBeforeInput: stop,
58
- onPaste: stop,
59
- }, [
60
- button({
61
- type: 'button',
62
- 'data-part': 'badge',
63
- 'aria-label': 'Change callout kind',
64
- onClick: () => send({ type: 'cycle' }),
65
- }, [text(state.at('kind').map((k) => KIND_LABEL[k]))]),
66
- span({
67
- 'data-part': 'text',
68
- contenteditable: 'true',
69
- role: 'textbox',
70
- 'aria-label': 'Callout text',
71
- onBlur: (e) => send({ type: 'commitText', text: e.target.textContent ?? '' }),
72
- }, [text(state.at('text'))]),
73
- ]),
74
- ],
75
- }));
32
+ * on blur (both round-trip to markdown). `data` is a reactive signal fed by the
33
+ * bridge, so a data commit updates the view IN PLACE — the editable island keeps
34
+ * its focus/caret instead of the whole sub-app remounting. */
35
+ const calloutBridge = decoratorBridge(BRIDGE_TYPE, (data, api) => [
36
+ div({
37
+ 'data-scope': 'md-callout',
38
+ 'data-part': 'root',
39
+ 'data-kind': data.at('kind'),
40
+ contenteditable: 'false',
41
+ onKeyDown: stop,
42
+ onBeforeInput: stop,
43
+ onPaste: stop,
44
+ }, [
45
+ button({
46
+ type: 'button',
47
+ 'data-part': 'badge',
48
+ 'aria-label': 'Change callout kind',
49
+ onClick: () => {
50
+ const cur = data.peek();
51
+ api.update({ kind: nextKind(cur.kind), text: cur.text });
52
+ },
53
+ }, [text(data.at('kind').map((k) => KIND_LABEL[k]))]),
54
+ span({
55
+ 'data-part': 'text',
56
+ contenteditable: 'true',
57
+ role: 'textbox',
58
+ 'aria-label': 'Callout text',
59
+ onBlur: (e) => {
60
+ const cur = data.peek();
61
+ const value = e.target.textContent ?? '';
62
+ if (value !== cur.text)
63
+ api.update({ kind: cur.kind, text: value });
64
+ },
65
+ }, [text(data.at('text'))]),
66
+ ]),
67
+ ]);
76
68
  /** `:::kind text` element transformer (single-line admonition). */
77
69
  const CALLOUT_TRANSFORMER = {
78
70
  dependencies: [LLuiDecoratorNode],
@@ -1 +1 @@
1
- {"version":3,"file":"callout.js","sourceRoot":"","sources":["../../src/plugins/callout.ts"],"names":[],"mappings":"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","sourcesContent":["// Callout (admonition) plugin — the custom-rendering showcase. A callout is a\n// block decorator: it stores `{ kind, text }`, renders an LLui sub-view (its own\n// TEA loop) with a clickable kind badge, and round-trips to `:::kind text`\n// markdown via a contributed element transformer.\n\nimport { type ElementNode, type LexicalEditor, type LexicalNode } from 'lexical'\nimport { $insertNodeToNearestRoot } from '@lexical/utils'\nimport type { ElementTransformer } from '@lexical/markdown'\nimport {\n $createLLuiDecoratorNode,\n $isLLuiDecoratorNode,\n LLuiDecoratorNode,\n decoratorBridge,\n} from '@llui/lexical'\nimport { button, component, div, span, text, type Signal } from '@llui/dom'\nimport type { MarkdownPlugin } from './types.js'\n\nexport type CalloutKind = 'note' | 'tip' | 'warning' | 'danger'\n\nexport interface CalloutData {\n kind: CalloutKind\n text: string\n}\n\nconst KIND_CYCLE: readonly CalloutKind[] = ['note', 'tip', 'warning', 'danger']\nconst KIND_LABEL: Readonly<Record<CalloutKind, string>> = {\n note: 'Note',\n tip: 'Tip',\n warning: 'Warning',\n danger: 'Danger',\n}\n\nconst BRIDGE_TYPE = 'callout'\n\nfunction nextKind(kind: CalloutKind): CalloutKind {\n const idx = KIND_CYCLE.indexOf(kind)\n return KIND_CYCLE[(idx + 1) % KIND_CYCLE.length]!\n}\n\nfunction isCalloutData(value: unknown): value is CalloutData {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as CalloutData).kind === 'string' &&\n typeof (value as CalloutData).text === 'string'\n )\n}\n\ntype CalloutMsg = { type: 'cycle' } | { type: 'commitText'; text: string }\n\n// Keep keyboard/input/paste events from bubbling to the outer Lexical editor so\n// the nested editable text island edits natively without Lexical intercepting.\nconst stop = (e: Event): void => e.stopPropagation()\n\n/** The LLui sub-view rendered inside a callout DecoratorNode. The badge cycles\n * the kind; the text is an editable island that persists into the Lexical node\n * on blur (both round-trip to markdown). */\nconst calloutBridge = decoratorBridge<CalloutData, CalloutData, CalloutMsg, never>(\n BRIDGE_TYPE,\n (data, api) =>\n component<CalloutData, CalloutMsg, never>({\n name: 'Callout',\n init: () => ({ kind: data.kind, text: data.text }),\n update: (state, msg) => {\n if (msg.type === 'cycle') {\n const kind = nextKind(state.kind)\n api.update({ kind, text: state.text })\n return { ...state, kind }\n }\n if (msg.type === 'commitText') {\n if (msg.text === state.text) return state\n api.update({ kind: state.kind, text: msg.text })\n return { ...state, text: msg.text }\n }\n return state\n },\n view: ({ state, send }) => [\n div(\n {\n 'data-scope': 'md-callout',\n 'data-part': 'root',\n 'data-kind': state.at('kind') as Signal<string>,\n contenteditable: 'false',\n onKeyDown: stop,\n onBeforeInput: stop,\n onPaste: stop,\n },\n [\n button(\n {\n type: 'button',\n 'data-part': 'badge',\n 'aria-label': 'Change callout kind',\n onClick: () => send({ type: 'cycle' }),\n },\n [text(state.at('kind').map((k) => KIND_LABEL[k]))],\n ),\n span(\n {\n 'data-part': 'text',\n contenteditable: 'true',\n role: 'textbox',\n 'aria-label': 'Callout text',\n onBlur: (e: FocusEvent) =>\n send({ type: 'commitText', text: (e.target as HTMLElement).textContent ?? '' }),\n },\n [text(state.at('text') as Signal<string>)],\n ),\n ],\n ),\n ],\n }),\n)\n\n/** `:::kind text` element transformer (single-line admonition). */\nconst CALLOUT_TRANSFORMER: ElementTransformer = {\n dependencies: [LLuiDecoratorNode],\n export: (node: LexicalNode): string | null => {\n if (!$isLLuiDecoratorNode(node) || node.getBridgeType() !== BRIDGE_TYPE) return null\n const data = node.getData()\n if (!isCalloutData(data)) return null\n return `:::${data.kind} ${data.text}`\n },\n regExp: /^:::(note|tip|warning|danger)[ \\t]+(.+)$/,\n replace: (parentNode: ElementNode, _children, match): void => {\n const kind = match[1] as CalloutKind\n const callout = $createLLuiDecoratorNode(BRIDGE_TYPE, { kind, text: match[2] ?? '' })\n parentNode.replace(callout)\n },\n type: 'element',\n}\n\n/** Insert a fresh callout at the current selection; returns the created node. */\nexport function $insertCallout(\n kind: CalloutKind = 'note',\n textValue = 'New callout',\n): LLuiDecoratorNode {\n return $insertNodeToNearestRoot($createLLuiDecoratorNode(BRIDGE_TYPE, { kind, text: textValue }))\n}\n\n/** Move focus into a callout's editable text island once it has decorated, and\n * select its placeholder text so the next keystroke replaces it. */\nfunction focusCalloutText(editor: LexicalEditor, key: string, attempt = 0): void {\n if (typeof requestAnimationFrame !== 'function') return\n requestAnimationFrame(() => {\n const span = editor.getElementByKey(key)?.querySelector('[data-part=\"text\"]')\n if (span instanceof HTMLElement) {\n span.focus()\n try {\n const range = document.createRange()\n range.selectNodeContents(span)\n const sel = window.getSelection()\n sel?.removeAllRanges()\n sel?.addRange(range)\n } catch {\n /* selection API unavailable */\n }\n } else if (attempt < 3) {\n focusCalloutText(editor, key, attempt + 1)\n }\n })\n}\n\nexport interface CalloutPluginOptions {\n /** Default kind for the toolbar/slash insert action. */\n defaultKind?: CalloutKind\n}\n\nexport function calloutPlugin(opts: CalloutPluginOptions = {}): MarkdownPlugin {\n const defaultKind = opts.defaultKind ?? 'note'\n return {\n name: 'callout',\n nodes: [LLuiDecoratorNode],\n decorators: [calloutBridge],\n transformers: [CALLOUT_TRANSFORMER],\n items: [\n {\n id: 'callout',\n label: 'Callout',\n icon: 'callout',\n group: 'insert',\n keywords: ['note', 'admonition', 'aside', 'tip', 'warning'],\n run: (editor) => {\n let key = ''\n editor.update(() => {\n key = $insertCallout(defaultKind).getKey()\n })\n // Land the caret inside the new callout's text, not after the block.\n focusCalloutText(editor, key)\n },\n surfaces: ['toolbar', 'slash', 'context'],\n },\n ],\n }\n}\n"]}
1
+ {"version":3,"file":"callout.js","sourceRoot":"","sources":["../../src/plugins/callout.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"context-menu.js","sourceRoot":"","sources":["../../src/plugins/context-menu.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,+EAA+E;AAC/E,8DAA8D;AAE9D,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAe,MAAM,WAAW,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAsBlE,MAAM,UAAU,iBAAiB;IAC/B,IAAI,YAAY,GAAkB,EAAE,CAAA;IAEpC,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjB,wEAAwE;YACxE,yEAAyE;YACzE,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,CAAA;QAC9E,CAAC;QACD,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;YACxB,MAAM,SAAS,GAAG,CAAC,CAAQ,EAAQ,EAAE;gBACnC,MAAM,EAAE,GAAG,CAAe,CAAA;gBAC1B,CAAC,CAAC,cAAc,EAAE,CAAA;gBAClB,GAAG,CAAC,IAAI,CAAC;oBACP,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,aAAa;oBACnB,GAAG,EAAE;wBACH,IAAI,EAAE,MAAM;wBACZ,CAAC,EAAE,EAAE,CAAC,OAAO;wBACb,CAAC,EAAE,EAAE,CAAC,OAAO;wBACb,KAAK,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;qBAC/D;iBACF,CAAC,CAAA;YACJ,CAAC,CAAA;YACD,MAAM,IAAI,GAAG,MAAM,CAAC,cAAc,EAAE,CAAA;YACpC,IAAI,EAAE,gBAAgB,CAAC,aAAa,EAAE,SAAS,CAAC,CAAA;YAChD,OAAO,GAAG,EAAE;gBACV,MAAM,CAAC,cAAc,EAAE,EAAE,mBAAmB,CAAC,aAAa,EAAE,SAAS,CAAC,CAAA;YACxE,CAAC,CAAA;QACH,CAAC;QACD,EAAE,EAAE,cAAc,CAA0C;YAC1D,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;YACpD,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;gBACrB,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;oBACjB,KAAK,MAAM;wBACT,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAA;oBAC7E,KAAK,OAAO;wBACV,OAAO,WAAW,CAAC,KAAK,CAAC,CAAA;oBAC3B,KAAK,QAAQ,CAAC,CAAC,CAAC;wBACd,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;wBACnC,IAAI,CAAC,IAAI;4BAAE,OAAO,WAAW,CAAC,KAAK,CAAC,CAAA;wBACpC,OAAO,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;oBACpE,CAAC;gBACH,CAAC;YACH,CAAC;YACD,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;gBACxB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAA;YACjD,CAAC;YACD,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CACxB,WAAW,CAAC;gBACV,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;gBACtB,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC;gBAChB,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC;gBAChB,MAAM,EAAE,SAAS,CAAC,WAAW;gBAC7B,KAAK,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE;gBAC1D,uDAAuD;gBACvD,MAAM,EAAE,GAAG,EAAE,CAAC;oBACZ,GAAG,CAAC;wBACF,YAAY,EAAE,YAAY;wBAC1B,WAAW,EAAE,UAAU;wBACvB,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;wBAC1C,aAAa,EAAE,CAAC,CAAQ,EAAE,EAAE;4BAC1B,CAAC,CAAC,cAAc,EAAE,CAAA;4BAClB,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;wBACzB,CAAC;qBACF,CAAC;iBACH;gBACD,QAAQ,EAAE,GAAG,EAAE,CAAC;oBACd,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAuB,EAAE;wBAC5C,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE;wBAClB,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;4BACvB,GAAG,CACD;gCACE,YAAY,EAAE,YAAY;gCAC1B,WAAW,EAAE,QAAQ;gCACrB,WAAW,EAAE,CAAC,CAAa,EAAE,EAAE;oCAC7B,CAAC,CAAC,cAAc,EAAE,CAAA;oCAClB,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;gCAC/C,CAAC;6BACF,EACD,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CACnC;yBACF;qBACF,CAAC;iBACH;aACF,CAAC;SACL,CAAC;KACH,CAAA;AACH,CAAC","sourcesContent":["// Right-click context menu — a plugin-UI overlay. `register` installs a\n// `contextmenu` listener on the editor root and opens the menu at the pointer;\n// the plugin-UI renders the menu and runs the chosen command.\n\nimport { div, each, text, type Signal } from '@llui/dom'\nimport { definePluginUI } from './ui.js'\nimport { OVERLAY_Z, hideOverlay, overlayRoot } from './overlay.js'\nimport type { CommandItem, MarkdownPlugin } from './types.js'\n\ninterface MenuItem {\n id: string\n label: string\n}\n\ninterface ContextState {\n open: boolean\n x: number\n y: number\n items: MenuItem[]\n}\n\ntype ContextMsg =\n | { type: 'open'; x: number; y: number; items: MenuItem[] }\n | { type: 'close' }\n | { type: 'choose'; index: number }\n\ntype ContextEffect = { type: 'run'; id: string }\n\nexport function contextMenuPlugin(): MarkdownPlugin {\n let contextItems: CommandItem[] = []\n\n return {\n name: 'contextMenu',\n onItems: (items) => {\n // Curated: only items that explicitly opt into the context menu (insert\n // actions, links, history). Inline formatting lives in the floating bar.\n contextItems = items.filter((i) => i.surfaces?.includes('context') ?? false)\n },\n register: (editor, ctx) => {\n const onContext = (e: Event): void => {\n const me = e as MouseEvent\n e.preventDefault()\n ctx.emit({\n type: 'plugin',\n name: 'contextMenu',\n msg: {\n type: 'open',\n x: me.clientX,\n y: me.clientY,\n items: contextItems.map((i) => ({ id: i.id, label: i.label })),\n },\n })\n }\n const root = editor.getRootElement()\n root?.addEventListener('contextmenu', onContext)\n return () => {\n editor.getRootElement()?.removeEventListener('contextmenu', onContext)\n }\n },\n ui: definePluginUI<ContextState, ContextMsg, ContextEffect>({\n init: () => ({ open: false, x: 0, y: 0, items: [] }),\n update: (state, msg) => {\n switch (msg.type) {\n case 'open':\n return { open: msg.items.length > 0, x: msg.x, y: msg.y, items: msg.items }\n case 'close':\n return hideOverlay(state)\n case 'choose': {\n const item = state.items[msg.index]\n if (!item) return hideOverlay(state)\n return [{ ...state, open: false }, [{ type: 'run', id: item.id }]]\n }\n }\n },\n onEffect: (effect, ctx) => {\n ctx.emit({ type: 'runCommand', id: effect.id })\n },\n view: ({ state, send }) =>\n overlayRoot({\n open: state.at('open'),\n x: state.at('x'),\n y: state.at('y'),\n zIndex: OVERLAY_Z.contextMenu,\n attrs: { 'data-scope': 'md-context', 'data-part': 'root' },\n // Backdrop closes the menu on any outside interaction.\n before: () => [\n div({\n 'data-scope': 'md-context',\n 'data-part': 'backdrop',\n onMouseDown: () => send({ type: 'close' }),\n onContextMenu: (e: Event) => {\n e.preventDefault()\n send({ type: 'close' })\n },\n }),\n ],\n children: () => [\n each(state.at('items') as Signal<MenuItem[]>, {\n key: (it) => it.id,\n render: (item, index) => [\n div(\n {\n 'data-scope': 'md-context',\n 'data-part': 'option',\n onMouseDown: (e: MouseEvent) => {\n e.preventDefault()\n send({ type: 'choose', index: index.peek() })\n },\n },\n [text(item.map((it) => it.label))],\n ),\n ],\n }),\n ],\n }),\n }),\n }\n}\n"]}
1
+ {"version":3,"file":"context-menu.js","sourceRoot":"","sources":["../../src/plugins/context-menu.ts"],"names":[],"mappings":"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"}