@llui/markdown-editor 0.3.0 → 0.5.0

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 (54) hide show
  1. package/dist/editor.d.ts +15 -2
  2. package/dist/editor.d.ts.map +1 -1
  3. package/dist/editor.js +12 -2
  4. package/dist/editor.js.map +1 -1
  5. package/dist/index.d.ts +6 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +15 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/plugins/block-drag.d.ts +74 -0
  10. package/dist/plugins/block-drag.d.ts.map +1 -0
  11. package/dist/plugins/block-drag.js +983 -0
  12. package/dist/plugins/block-drag.js.map +1 -0
  13. package/dist/plugins/code-language.d.ts +60 -0
  14. package/dist/plugins/code-language.d.ts.map +1 -0
  15. package/dist/plugins/code-language.js +308 -0
  16. package/dist/plugins/code-language.js.map +1 -0
  17. package/dist/plugins/frontmatter.d.ts +45 -0
  18. package/dist/plugins/frontmatter.d.ts.map +1 -0
  19. package/dist/plugins/frontmatter.js +281 -0
  20. package/dist/plugins/frontmatter.js.map +1 -0
  21. package/dist/plugins/overlay.d.ts +1 -0
  22. package/dist/plugins/overlay.d.ts.map +1 -1
  23. package/dist/plugins/overlay.js +7 -0
  24. package/dist/plugins/overlay.js.map +1 -1
  25. package/dist/plugins/wikilink.d.ts +110 -0
  26. package/dist/plugins/wikilink.d.ts.map +1 -0
  27. package/dist/plugins/wikilink.js +692 -0
  28. package/dist/plugins/wikilink.js.map +1 -0
  29. package/dist/styles/block-drag.css +118 -0
  30. package/dist/styles/editor.css +112 -0
  31. package/dist/transformers/code.d.ts +24 -0
  32. package/dist/transformers/code.d.ts.map +1 -0
  33. package/dist/transformers/code.js +167 -0
  34. package/dist/transformers/code.js.map +1 -0
  35. package/dist/transformers/gfm.d.ts.map +1 -1
  36. package/dist/transformers/gfm.js +7 -2
  37. package/dist/transformers/gfm.js.map +1 -1
  38. package/dist/transformers/registry.d.ts +3 -0
  39. package/dist/transformers/registry.d.ts.map +1 -1
  40. package/dist/transformers/registry.js +26 -0
  41. package/dist/transformers/registry.js.map +1 -1
  42. package/package.json +42 -28
  43. package/src/editor.ts +27 -4
  44. package/src/index.ts +58 -1
  45. package/src/plugins/block-drag.ts +1175 -0
  46. package/src/plugins/code-language.ts +378 -0
  47. package/src/plugins/frontmatter.ts +324 -0
  48. package/src/plugins/overlay.ts +7 -0
  49. package/src/plugins/wikilink.ts +843 -0
  50. package/src/styles/block-drag.css +118 -0
  51. package/src/styles/editor.css +112 -0
  52. package/src/transformers/code.ts +174 -0
  53. package/src/transformers/gfm.ts +6 -2
  54. package/src/transformers/registry.ts +27 -0
@@ -0,0 +1,281 @@
1
+ // YAML frontmatter plugin — the leading `---` … `---` metadata block.
2
+ //
3
+ // ## Why the block is an OPAQUE STRING, not parsed YAML
4
+ //
5
+ // Deliberate choice, and the requirement that drove it is round-trip fidelity:
6
+ // what the author wrote must come back out byte-for-byte. Two options exist —
7
+ // parse YAML properly, or don't parse it at all — and only the second is
8
+ // achievable here:
9
+ //
10
+ // - Parsing correctly means a real YAML 1.2 implementation (anchors, aliases,
11
+ // tags, flow/block collections, the five scalar styles, folded/literal block
12
+ // scalars with their indentation-indicator and chomping rules). Nothing
13
+ // smaller is *correct*, and a correct parser is not enough by itself: a
14
+ // round-trip also needs a comment- and style-preserving EMITTER, because
15
+ // `parse` → `stringify` normalizes quoting, key order, indentation and drops
16
+ // comments outright. That is a large dependency (this package deliberately
17
+ // dropped Prism from `@lexical/code` for exactly this reason — see
18
+ // `code-language.ts`) to buy a feature the editor does not need: it never
19
+ // interprets frontmatter, it only has to preserve it.
20
+ //
21
+ // - The naive middle ground — split each line on the first `:` into a
22
+ // `Record<string, string>` — is what the reference implementation this was
23
+ // modelled on does, and it is strictly WORSE than not parsing. Nested maps,
24
+ // sequences, block scalars, quoted values containing `:`, comments and blank
25
+ // lines are all silently flattened or destroyed. A lossy parse presented as
26
+ // structured data is a data-loss bug wearing a feature's clothes.
27
+ //
28
+ // So the block is stored verbatim as a single `source` string and re-emitted
29
+ // between two fences. Consumers that *want* structure own that choice: hand
30
+ // `$getFrontmatter()` to whatever YAML library they already ship, or supply
31
+ // `render` to draw a preview. The editor stays honest about not understanding it.
32
+ //
33
+ // The one unavoidable deviation from byte-for-byte: `$convertFromMarkdownString`
34
+ // runs `normalizeMarkdown`, which `trimEnd()`s every line BEFORE any transformer
35
+ // is consulted, so trailing whitespace inside the block is lost. That happens
36
+ // upstream of every transformer and cannot be intercepted from one. YAML treats
37
+ // trailing spaces as insignificant, so nothing meaningful changes. Likewise a
38
+ // body that is empty or only blank lines normalizes to the canonical `---\n---`.
39
+ //
40
+ // ## The `---` collision with `hrPlugin`
41
+ //
42
+ // `hrPlugin`'s ELEMENT transformer matches `/^(---|\*\*\*|___)\s*$/`, so before
43
+ // this plugin existed a leading frontmatter block parsed as a horizontal rule
44
+ // followed by loose prose. Telling consumers to drop `hrPlugin` is not a fix:
45
+ // `---` is legitimately both things, and which one it is depends on POSITION and
46
+ // CLOSURE, not on which plugin is loaded.
47
+ //
48
+ // The resolution is structural, not ordering-based. `@lexical/markdown`'s
49
+ // importer tries EVERY multiline-element transformer on a line before ANY
50
+ // element transformer (`$importMultiline` runs first in `$importMarkdownNodes`;
51
+ // export mirrors it with `[...multilineElement, ...element]`). This is therefore
52
+ // a `multiline-element` transformer, which means it is consulted ahead of the
53
+ // `hr` element transformer no matter where the two plugins sit in the array —
54
+ // plugin ORDER cannot change the outcome, and neither can loading or omitting
55
+ // `hrPlugin`.
56
+ //
57
+ // Claiming the line is then narrowed by `handleImportAfterStartMatch`, which
58
+ // returns `null` — "not mine, try the next transformer" — unless BOTH hold:
59
+ //
60
+ // 1. the fence is on line 0 (frontmatter is only frontmatter at the very top
61
+ // of the document), and
62
+ // 2. a closing `---` line exists somewhere below it.
63
+ //
64
+ // Declining falls through to `hrPlugin` (when loaded), so a `---` that is
65
+ // genuinely a thematic break — mid-document, or an unclosed one on line 1 —
66
+ // still becomes an `<hr>`. `replace` returns `false` so that TYPING `---` in the
67
+ // editor is likewise left to the hr shortcut; frontmatter is only ever created
68
+ // by importing markdown or by calling `$setFrontmatter`.
69
+ //
70
+ // The block closes at the FIRST subsequent line that is exactly `---`, which is
71
+ // the rule Jekyll / gray-matter / Hugo apply. A `---` *inside* a value (e.g.
72
+ // `title: a --- b`) is not a whole line and is preserved untouched.
73
+ import { $getRoot } from 'lexical';
74
+ import { $createLLuiDecoratorNode, $isLLuiDecoratorNode, LLuiDecoratorNode, decoratorBridge, } from '@llui/lexical';
75
+ import { div, textarea } from '@llui/dom';
76
+ import { renderedPreview } from './_preview.js';
77
+ /** The decorator bridge id for the frontmatter block. */
78
+ export const FRONTMATTER_BRIDGE_TYPE = 'frontmatter';
79
+ function isFrontmatterData(value) {
80
+ return (typeof value === 'object' &&
81
+ value !== null &&
82
+ typeof value.source === 'string');
83
+ }
84
+ /** A line consisting solely of `---` (trailing tabs/spaces tolerated — they are
85
+ * not content, and `normalizeMarkdown` has usually already trimmed them). */
86
+ const FENCE = /^---[ \t]*$/;
87
+ /** Render the fences back around an opaque body. An empty (or blank-only) body
88
+ * collapses to the canonical two-line form so the result stays idempotent. */
89
+ export function serializeFrontmatter(source) {
90
+ return source === '' ? '---\n---' : `---\n${source}\n---`;
91
+ }
92
+ /**
93
+ * The index of the closing fence, or `-1` when `lines` does not open a
94
+ * frontmatter block (no fence on line 0) or never closes one.
95
+ *
96
+ * The single definition of "is this frontmatter?", shared by the importer and
97
+ * {@link splitFrontmatter} so the two can never disagree. A returned index is
98
+ * always `>= 1`, which is the property the importer's anti-rewind invariant
99
+ * rests on (see `handleImportAfterStartMatch`).
100
+ */
101
+ function closingFenceIndex(lines) {
102
+ const first = lines[0];
103
+ if (first === undefined || !FENCE.test(first))
104
+ return -1;
105
+ for (let i = 1; i < lines.length; i++) {
106
+ const line = lines[i];
107
+ if (line !== undefined && FENCE.test(line))
108
+ return i;
109
+ }
110
+ return -1;
111
+ }
112
+ /**
113
+ * Split a leading frontmatter block off a markdown string: `[body, rest]`, or
114
+ * `null` when the document has none (no line-0 fence, or no closing fence).
115
+ * Exported because a consumer often needs the metadata BEFORE building an
116
+ * editor — the same predicate the importer uses, so the two never disagree.
117
+ */
118
+ export function splitFrontmatter(markdown) {
119
+ const lines = markdown.split('\n');
120
+ const end = closingFenceIndex(lines);
121
+ if (end === -1)
122
+ return null;
123
+ return [lines.slice(1, end).join('\n'), lines.slice(end + 1).join('\n')];
124
+ }
125
+ // ── Document accessors (run inside `editor.read` / `editor.update`) ──────────
126
+ /** The frontmatter node, if the document starts with one. */
127
+ function $frontmatterNode() {
128
+ const first = $getRoot().getFirstChild();
129
+ return $isLLuiDecoratorNode(first) && first.getBridgeType() === FRONTMATTER_BRIDGE_TYPE
130
+ ? first
131
+ : null;
132
+ }
133
+ /** The document's frontmatter body, or `null` when it has none. */
134
+ export function $getFrontmatter() {
135
+ const node = $frontmatterNode();
136
+ if (!node || !$isLLuiDecoratorNode(node))
137
+ return null;
138
+ const data = node.getData();
139
+ return isFrontmatterData(data) ? data.source : null;
140
+ }
141
+ /**
142
+ * Set (or, with `null`, remove) the document's frontmatter. The block is always
143
+ * kept as the FIRST child of the root — it is only frontmatter there, and the
144
+ * exporter relies on that position (see the transformer's `export`).
145
+ */
146
+ export function $setFrontmatter(source) {
147
+ const existing = $frontmatterNode();
148
+ if (source === null) {
149
+ existing?.remove();
150
+ return;
151
+ }
152
+ if (existing && $isLLuiDecoratorNode(existing)) {
153
+ existing.setData({ source });
154
+ return;
155
+ }
156
+ const node = $createLLuiDecoratorNode(FRONTMATTER_BRIDGE_TYPE, { source });
157
+ const root = $getRoot();
158
+ const first = root.getFirstChild();
159
+ if (first)
160
+ first.insertBefore(node);
161
+ else
162
+ root.append(node);
163
+ }
164
+ // ── Transformer ─────────────────────────────────────────────────────────────
165
+ const FRONTMATTER_TRANSFORMER = {
166
+ dependencies: [LLuiDecoratorNode],
167
+ export: (node) => {
168
+ if (!$isLLuiDecoratorNode(node) || node.getBridgeType() !== FRONTMATTER_BRIDGE_TYPE)
169
+ return null;
170
+ const data = node.getData();
171
+ if (!isFrontmatterData(data))
172
+ return null;
173
+ // Only the document's FIRST block can be emitted as fences: `---` anywhere
174
+ // else re-imports as a thematic break, which would silently destroy the
175
+ // metadata on the next round-trip. A stray block (dragged out of position,
176
+ // pasted into a quote, …) degrades to a visible ```yaml code fence instead —
177
+ // lossy in node type, but the text survives and the author can see why.
178
+ if ($getRoot().getFirstChild() !== node)
179
+ return '```yaml\n' + data.source + '\n```';
180
+ return serializeFrontmatter(data.source);
181
+ },
182
+ regExpStart: FENCE,
183
+ // Never consulted: `handleImportAfterStartMatch` below always returns a
184
+ // decision, so the default open/close scan is not reached. Declared because
185
+ // the shape requires the pair to be meaningful together.
186
+ regExpEnd: FENCE,
187
+ handleImportAfterStartMatch: ({ lines, rootNode, startLineIndex }) => {
188
+ // Frontmatter exists only at the very top of the document. Anywhere else a
189
+ // `---` is a thematic break — decline so `hrPlugin` (or plain prose) gets it.
190
+ //
191
+ // INVARIANT — do not relax this guard without also fixing the scan below.
192
+ // `$importMarkdownNodes` assigns `i = shiftedIndex` from the returned tuple,
193
+ // so a returned index <= `startLineIndex` REWINDS its loop and the importer
194
+ // spins forever (not a wrong parse — a hang). The scan starts at line 1, so
195
+ // pinning `startLineIndex` to 0 is what makes every returned index strictly
196
+ // greater. A positional relaxation must start the scan at `startLineIndex + 1`.
197
+ if (startLineIndex !== 0)
198
+ return null;
199
+ const end = closingFenceIndex(lines);
200
+ if (end !== -1) {
201
+ // Verbatim body: no trimming, no interpretation, blank lines preserved.
202
+ const source = lines.slice(1, end).join('\n');
203
+ rootNode.append($createLLuiDecoratorNode(FRONTMATTER_BRIDGE_TYPE, { source }));
204
+ return [true, end];
205
+ }
206
+ // Unclosed: this is a lone `---` on line 1, i.e. a horizontal rule.
207
+ return null;
208
+ },
209
+ // Typing `---` must never produce frontmatter — returning false hands the
210
+ // markdown shortcut back to `hrPlugin`. Use `$setFrontmatter` to create one.
211
+ replace: () => false,
212
+ type: 'multiline-element',
213
+ };
214
+ export { FRONTMATTER_TRANSFORMER };
215
+ /** Keep editor-level key/paste handling out of the frontmatter island. */
216
+ const stop = (e) => e.stopPropagation();
217
+ export function frontmatterPlugin(opts = {}) {
218
+ const editable = opts.editable ?? true;
219
+ const bridge = decoratorBridge(FRONTMATTER_BRIDGE_TYPE, (data, api) => {
220
+ const children = [];
221
+ if (editable) {
222
+ children.push(
223
+ // A <textarea>, NOT a contenteditable div: newlines are load-bearing in
224
+ // YAML, and a contenteditable's `textContent` drops the <br>/<div> line
225
+ // structure the browser inserts, so committing from one silently
226
+ // flattens a multi-line block into a single line.
227
+ textarea({
228
+ 'data-scope': 'md-frontmatter',
229
+ 'data-part': 'source',
230
+ 'aria-label': opts.label ?? 'Frontmatter',
231
+ placeholder: opts.placeholder ?? 'key: value',
232
+ spellcheck: 'false',
233
+ autocapitalize: 'off',
234
+ autocomplete: 'off',
235
+ value: data.at('source'),
236
+ // Grow with the content so the whole block stays visible.
237
+ rows: data.at('source').map((source) => String(Math.max(1, source.split('\n').length))),
238
+ onKeyDown: stop,
239
+ onBeforeInput: stop,
240
+ onPaste: stop,
241
+ // Commit on blur only: while the caret is inside, the node data is
242
+ // deliberately stale so the reactive `value` binding cannot rewrite
243
+ // what is being typed.
244
+ onBlur: (e) => {
245
+ const source = e.target.value;
246
+ if (source !== data.peek().source)
247
+ api.update({ source });
248
+ },
249
+ }));
250
+ }
251
+ if (opts.render) {
252
+ children.push(renderedPreview(data.at('source'), opts.render));
253
+ }
254
+ return [
255
+ div({ 'data-scope': 'md-frontmatter', 'data-part': 'root', contenteditable: 'false' }, children),
256
+ ];
257
+ });
258
+ return {
259
+ name: 'frontmatter',
260
+ nodes: [LLuiDecoratorNode],
261
+ decorators: [bridge],
262
+ transformers: [FRONTMATTER_TRANSFORMER],
263
+ items: [
264
+ {
265
+ id: 'frontmatter',
266
+ label: 'Frontmatter',
267
+ icon: 'frontmatter',
268
+ group: 'insert',
269
+ keywords: ['frontmatter', 'yaml', 'metadata', 'front matter'],
270
+ // Idempotent: a document already carrying frontmatter is left alone
271
+ // rather than having its metadata blanked.
272
+ run: (editor) => editor.update(() => {
273
+ if ($getFrontmatter() === null)
274
+ $setFrontmatter('');
275
+ }),
276
+ surfaces: ['slash', 'context'],
277
+ },
278
+ ],
279
+ };
280
+ }
281
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/plugins/frontmatter.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ export declare const OVERLAY_Z: {
4
4
  readonly contextMenu: 61;
5
5
  readonly floatingToolbar: 62;
6
6
  readonly tableTools: 63;
7
+ readonly codeLanguage: 64;
7
8
  };
8
9
  export interface OverlayRootConfig {
9
10
  /** Whether the overlay is shown. */
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/plugins/overlay.ts"],"names":[],"mappings":"AAsBA,OAAO,EAOL,KAAK,UAAU,EACf,KAAK,MAAM,EACZ,MAAM,WAAW,CAAA;AAGlB,eAAO,MAAM,SAAS;;;;;CAKZ,CAAA;AAWV,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;IACrB,2CAA2C;IAC3C,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACjB,2CAA2C;IAC3C,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACjB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAA;IACd,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,UAAU,CAAA;IACzB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,UAAU,CAAA;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,UAAU,CA2B9D;AAED;mDACmD;AACnD,wBAAgB,WAAW,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAEpE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAoB5D"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/plugins/overlay.ts"],"names":[],"mappings":"AAwBA,OAAO,EAOL,KAAK,UAAU,EACf,KAAK,MAAM,EACZ,MAAM,WAAW,CAAA;AAGlB,eAAO,MAAM,SAAS;;;;;;CAUZ,CAAA;AAWV,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;IACrB,2CAA2C;IAC3C,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACjB,2CAA2C;IAC3C,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACjB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAA;IACd,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,UAAU,CAAA;IACzB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,UAAU,CAAA;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,UAAU,CA2B9D;AAED;mDACmD;AACnD,wBAAgB,WAAW,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAEpE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAoB5D"}
@@ -18,6 +18,8 @@
18
18
  // 61 — context menu — pointer-anchored
19
19
  // 62 — floating selection toolbar — selection-anchored bubble
20
20
  // 63 — table tools — element-anchored, sits over a table
21
+ // 64 — code-block language badge — element-anchored, may sit INSIDE a
22
+ // table cell, so it must clear 63
21
23
  // The values live with each plugin's view; this comment is the source of truth.
22
24
  import { div, derived, onMount, portal, show, } from '@llui/dom';
23
25
  import { registerNestedLayer } from '@llui/components/utils';
@@ -26,6 +28,11 @@ export const OVERLAY_Z = {
26
28
  contextMenu: 61,
27
29
  floatingToolbar: 62,
28
30
  tableTools: 63,
31
+ // Strictly above `tableTools`: a fenced code block can live inside a table
32
+ // cell, in which case both surfaces are open at once. At an equal z-index the
33
+ // clickable one was decided by portal insertion order — i.e. by plugin array
34
+ // order — which is exactly the no-tie rule this scale exists to prevent.
35
+ codeLanguage: 64,
29
36
  };
30
37
  const toMountables = (r) => [...r];
31
38
  // Unique marker per overlay instance so its portal root can be located while
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../src/plugins/overlay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../src/plugins/overlay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ import { TextNode, type EditorConfig, type LexicalEditor, type LexicalNode, type LexicalUpdateJSON, type NodeKey, type SerializedTextNode, type Spread } from 'lexical';
2
+ import type { MarkdownPlugin } from './types.js';
3
+ /** A parsed wikilink. `alias` is `null` when the target is shown verbatim. */
4
+ export interface WikiLink {
5
+ target: string;
6
+ alias: string | null;
7
+ }
8
+ /**
9
+ * Parse the content BETWEEN the brackets. Returns `null` when the content is not
10
+ * a valid wikilink body.
11
+ *
12
+ * Deliberate choices, each load-bearing for exact round-tripping:
13
+ * * split on the FIRST `|` only, so `[[a|b|c]]` has alias `b|c` and re-exports
14
+ * byte-identically;
15
+ * * an EMPTY alias (`[[a|]]`) normalizes to no alias — the alternative
16
+ * (keeping `alias: ''`) would render a zero-width, unclickable node;
17
+ * * NO trimming. `[[ a ]]` keeps its spaces, because trimming would make
18
+ * import→export lossy. Presentation trimming is the host's call in
19
+ * `onNavigate`/`resolve`, not the document's.
20
+ */
21
+ export declare function parseWikiLinkInner(inner: string): WikiLink | null;
22
+ /** Sanitize a target. Returns `null` when nothing usable survives. */
23
+ export declare function sanitizeWikiLinkTarget(raw: string): string | null;
24
+ /** Sanitize an alias. Returns `null` when nothing usable survives. */
25
+ export declare function sanitizeWikiLinkAlias(raw: string | null): string | null;
26
+ /**
27
+ * Serialize a wikilink back to markdown. Inverse of {@link parseWikiLinkInner}
28
+ * for every link built through this module's constructors — see
29
+ * {@link sanitizeWikiLinkTarget} for why that qualifier is load-bearing.
30
+ */
31
+ export declare function formatWikiLink(link: WikiLink): string;
32
+ export type SerializedWikiLinkNode = Spread<{
33
+ target: string;
34
+ alias: string | null;
35
+ }, SerializedTextNode>;
36
+ /**
37
+ * An atomic inline wikilink. Extends `TextNode` so the caret, selection and
38
+ * text formats behave exactly as they do for prose, while `token` mode keeps it
39
+ * indivisible: the user can delete it or move past it, but never edit its
40
+ * interior into a state where the visible alias disagrees with `__target`.
41
+ */
42
+ export declare class WikiLinkNode extends TextNode {
43
+ __target: string;
44
+ __alias: string | null;
45
+ static getType(): string;
46
+ static clone(node: WikiLinkNode): WikiLinkNode;
47
+ constructor(target: string, alias: string | null, text?: string, key?: NodeKey);
48
+ static importJSON(serializedNode: SerializedWikiLinkNode): WikiLinkNode;
49
+ updateFromJSON(serializedNode: LexicalUpdateJSON<SerializedWikiLinkNode>): this;
50
+ exportJSON(): SerializedWikiLinkNode;
51
+ createDOM(config: EditorConfig, editor?: LexicalEditor): HTMLElement;
52
+ updateDOM(prevNode: this, dom: HTMLElement, config: EditorConfig): boolean;
53
+ getTarget(): string;
54
+ /**
55
+ * Repoint the link. The display text follows only when there is no alias.
56
+ * The value is sanitized (see {@link sanitizeWikiLinkTarget}); a target with
57
+ * nothing representable in it leaves the link untouched rather than producing
58
+ * one that corrupts the document on export.
59
+ */
60
+ setTarget(target: string): this;
61
+ getAlias(): string | null;
62
+ /** Set (or clear, with `null`) the alias; the display text follows. */
63
+ setAlias(alias: string | null): this;
64
+ getLink(): WikiLink;
65
+ canInsertTextBefore(): boolean;
66
+ canInsertTextAfter(): boolean;
67
+ }
68
+ /**
69
+ * Build a wikilink node. `target`/`alias` are sanitized to values the `[[…]]`
70
+ * syntax can express (see {@link sanitizeWikiLinkTarget}); a target with nothing
71
+ * usable left falls back to the literal text `Page` rather than yielding an
72
+ * invisible token.
73
+ */
74
+ export declare function $createWikiLinkNode(target: string, alias?: string | null): WikiLinkNode;
75
+ export declare function $isWikiLinkNode(node: LexicalNode | null | undefined): node is WikiLinkNode;
76
+ /** A document the host offers as a link target while the user types `[[…`. */
77
+ export interface DocCandidate {
78
+ /** The link target written into the document (`[[target]]`). */
79
+ readonly target: string;
80
+ /** Human-facing title shown in the results list (defaults to `target`). */
81
+ readonly title?: string;
82
+ /** A short one-line snippet shown under the title. */
83
+ readonly snippet?: string;
84
+ /** A longer content excerpt shown in the reference/preview pane. */
85
+ readonly preview?: string;
86
+ }
87
+ export interface WikiLinkPluginOptions {
88
+ /**
89
+ * Called when the user activates a wikilink. This is the host's resolution
90
+ * seam: `@llui/markdown-editor` knows nothing about what a target names.
91
+ *
92
+ * The notification travels the same route as every other plugin event —
93
+ * `ctx.emit` → the editor's update loop → this plugin's reducer → an effect —
94
+ * rather than a raw DOM event, so an activation is an ordinary TEA message
95
+ * that shows up in devtools, replay and agent traces.
96
+ */
97
+ onNavigate?: (link: WikiLink) => void;
98
+ /** Text used as the target when the insert command runs with no selection. */
99
+ placeholderTarget?: string;
100
+ /**
101
+ * Document-search seam: as the user types `[[query`, resolve matching
102
+ * documents to offer as link targets, with an optional content preview shown in
103
+ * the panel's reference pane. Sync or async (async is debounced; a stale
104
+ * response for a superseded query is dropped). When omitted, the panel never
105
+ * opens and `[[target]]` still works by typing the closing `]]`.
106
+ */
107
+ search?: (query: string) => readonly DocCandidate[] | Promise<readonly DocCandidate[]>;
108
+ }
109
+ export declare function wikilinkPlugin(opts?: WikiLinkPluginOptions): MarkdownPlugin;
110
+ //# sourceMappingURL=wikilink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wikilink.d.ts","sourceRoot":"","sources":["../../src/plugins/wikilink.ts"],"names":[],"mappings":"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"}