@llui/markdown-editor 0.2.14 → 0.4.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.
- package/dist/editor.d.ts +22 -2
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +45 -6
- package/dist/editor.js.map +1 -1
- package/dist/effects.d.ts +0 -1
- package/dist/effects.d.ts.map +1 -1
- package/dist/effects.js +4 -1
- package/dist/effects.js.map +1 -1
- package/dist/index.d.ts +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -4
- package/dist/index.js.map +1 -1
- package/dist/plugins/block-drag.d.ts +73 -0
- package/dist/plugins/block-drag.d.ts.map +1 -0
- package/dist/plugins/block-drag.js +760 -0
- package/dist/plugins/block-drag.js.map +1 -0
- package/dist/plugins/code-language.d.ts +60 -0
- package/dist/plugins/code-language.d.ts.map +1 -0
- package/dist/plugins/code-language.js +308 -0
- package/dist/plugins/code-language.js.map +1 -0
- package/dist/plugins/frontmatter.d.ts +45 -0
- package/dist/plugins/frontmatter.d.ts.map +1 -0
- package/dist/plugins/frontmatter.js +281 -0
- package/dist/plugins/frontmatter.js.map +1 -0
- package/dist/plugins/overlay.d.ts +1 -0
- package/dist/plugins/overlay.d.ts.map +1 -1
- package/dist/plugins/overlay.js +7 -0
- package/dist/plugins/overlay.js.map +1 -1
- package/dist/plugins/table.d.ts.map +1 -1
- package/dist/plugins/table.js +77 -15
- package/dist/plugins/table.js.map +1 -1
- package/dist/plugins/wikilink.d.ts +91 -0
- package/dist/plugins/wikilink.d.ts.map +1 -0
- package/dist/plugins/wikilink.js +467 -0
- package/dist/plugins/wikilink.js.map +1 -0
- package/dist/styles/block-drag.css +63 -0
- package/dist/styles/editor.css +64 -6
- package/dist/theme.d.ts +2 -5
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +15 -11
- package/dist/theme.js.map +1 -1
- package/dist/transformers/code.d.ts +24 -0
- package/dist/transformers/code.d.ts.map +1 -0
- package/dist/transformers/code.js +167 -0
- package/dist/transformers/code.js.map +1 -0
- package/dist/transformers/gfm.d.ts +9 -1
- package/dist/transformers/gfm.d.ts.map +1 -1
- package/dist/transformers/gfm.js +16 -4
- package/dist/transformers/gfm.js.map +1 -1
- package/dist/transformers/registry.d.ts +3 -0
- package/dist/transformers/registry.d.ts.map +1 -1
- package/dist/transformers/registry.js +26 -0
- package/dist/transformers/registry.js.map +1 -1
- package/package.json +45 -31
- package/src/editor.ts +77 -9
- package/src/effects.ts +4 -2
- package/src/index.ts +61 -9
- package/src/plugins/block-drag.ts +912 -0
- package/src/plugins/code-language.ts +378 -0
- package/src/plugins/frontmatter.ts +324 -0
- package/src/plugins/overlay.ts +7 -0
- package/src/plugins/table.ts +87 -13
- package/src/plugins/wikilink.ts +553 -0
- package/src/styles/block-drag.css +63 -0
- package/src/styles/editor.css +64 -6
- package/src/theme.ts +15 -11
- package/src/transformers/code.ts +174 -0
- package/src/transformers/gfm.ts +16 -4
- package/src/transformers/registry.ts +27 -0
- package/dist/__llui_deps.json +0 -274
package/dist/styles/editor.css
CHANGED
|
@@ -83,12 +83,6 @@
|
|
|
83
83
|
[data-lexical-editor] .md-strikethrough {
|
|
84
84
|
text-decoration: line-through;
|
|
85
85
|
}
|
|
86
|
-
[data-lexical-editor] .md-underline {
|
|
87
|
-
text-decoration: underline;
|
|
88
|
-
}
|
|
89
|
-
[data-lexical-editor] .md-underline-strikethrough {
|
|
90
|
-
text-decoration: underline line-through;
|
|
91
|
-
}
|
|
92
86
|
|
|
93
87
|
/* Task-list items (li[role="checkbox"]) with a clickable checkbox. */
|
|
94
88
|
[data-lexical-editor] li[role='checkbox'] {
|
|
@@ -351,6 +345,40 @@
|
|
|
351
345
|
background: var(--md-surface-2);
|
|
352
346
|
}
|
|
353
347
|
|
|
348
|
+
/* ── Code-block language badge ────────────────────────────────────────── */
|
|
349
|
+
[data-scope='md-code-language'][data-part='bar'] {
|
|
350
|
+
padding: 0.15rem;
|
|
351
|
+
background: var(--md-surface);
|
|
352
|
+
border: 1px solid var(--md-border);
|
|
353
|
+
border-radius: 6px;
|
|
354
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
|
|
355
|
+
}
|
|
356
|
+
[data-scope='md-code-language'][data-part='input'] {
|
|
357
|
+
font: inherit;
|
|
358
|
+
font-family: var(--md-mono);
|
|
359
|
+
font-size: 0.72rem;
|
|
360
|
+
width: 8rem;
|
|
361
|
+
padding: 0.1rem 0.3rem;
|
|
362
|
+
color: var(--md-text);
|
|
363
|
+
background: transparent;
|
|
364
|
+
border: none;
|
|
365
|
+
outline: none;
|
|
366
|
+
}
|
|
367
|
+
[data-scope='md-code-language'][data-part='input']::placeholder {
|
|
368
|
+
color: var(--md-muted);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/* ── Wiki links ───────────────────────────────────────────────────────── */
|
|
372
|
+
[data-scope='md-wikilink'][data-part='link'] {
|
|
373
|
+
color: var(--md-primary);
|
|
374
|
+
text-decoration: none;
|
|
375
|
+
border-bottom: 1px solid var(--md-primary-soft);
|
|
376
|
+
cursor: pointer;
|
|
377
|
+
}
|
|
378
|
+
[data-scope='md-wikilink'][data-part='link']:hover {
|
|
379
|
+
border-bottom-color: var(--md-primary);
|
|
380
|
+
}
|
|
381
|
+
|
|
354
382
|
/* ── Math block ───────────────────────────────────────────────────────── */
|
|
355
383
|
[data-scope='md-math'][data-part='root'] {
|
|
356
384
|
display: flex;
|
|
@@ -375,6 +403,36 @@
|
|
|
375
403
|
text-align: center;
|
|
376
404
|
}
|
|
377
405
|
|
|
406
|
+
/* ── Frontmatter block ────────────────────────────────────────────────── */
|
|
407
|
+
[data-scope='md-frontmatter'][data-part='root'] {
|
|
408
|
+
display: flex;
|
|
409
|
+
flex-direction: column;
|
|
410
|
+
gap: 0.4rem;
|
|
411
|
+
margin: 0 0 0.9rem;
|
|
412
|
+
padding: 0.6rem 0.8rem;
|
|
413
|
+
border: 1px dashed var(--md-border);
|
|
414
|
+
border-radius: 8px;
|
|
415
|
+
background: var(--md-surface-2);
|
|
416
|
+
}
|
|
417
|
+
[data-scope='md-frontmatter'] [data-part='source'] {
|
|
418
|
+
width: 100%;
|
|
419
|
+
box-sizing: border-box;
|
|
420
|
+
border: 0;
|
|
421
|
+
padding: 0;
|
|
422
|
+
resize: vertical;
|
|
423
|
+
background: transparent;
|
|
424
|
+
font-family: var(--md-mono);
|
|
425
|
+
font-size: 0.82rem;
|
|
426
|
+
line-height: 1.5;
|
|
427
|
+
white-space: pre;
|
|
428
|
+
overflow-x: auto;
|
|
429
|
+
color: var(--md-muted);
|
|
430
|
+
outline: none;
|
|
431
|
+
}
|
|
432
|
+
[data-scope='md-frontmatter'] [data-part='source']:focus {
|
|
433
|
+
color: var(--md-text);
|
|
434
|
+
}
|
|
435
|
+
|
|
378
436
|
/* ── Mermaid block ────────────────────────────────────────────────────── */
|
|
379
437
|
[data-scope='md-mermaid'][data-part='root'] {
|
|
380
438
|
display: flex;
|
package/dist/theme.d.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import type { EditorThemeClasses } from 'lexical';
|
|
2
2
|
export declare const STRIKETHROUGH_CLASS = "md-strikethrough";
|
|
3
|
-
export declare const UNDERLINE_CLASS = "md-underline";
|
|
4
|
-
export declare const UNDERLINE_STRIKETHROUGH_CLASS = "md-underline-strikethrough";
|
|
5
3
|
/** The class hooks Lexical needs for text-decoration formats it renders as a
|
|
6
|
-
* plain <span>.
|
|
7
|
-
* the case where both apply — both want `text-decoration`.) */
|
|
4
|
+
* plain <span>. */
|
|
8
5
|
export declare const defaultTheme: EditorThemeClasses;
|
|
9
6
|
/** Merge a consumer theme over the default. `text` is merged per-key so a
|
|
10
|
-
* consumer overriding (say) `strikethrough` keeps the default
|
|
7
|
+
* consumer overriding (say) `strikethrough` keeps the other default entries.
|
|
11
8
|
*
|
|
12
9
|
* Always returns a FRESH theme (never the shared `defaultTheme` singleton):
|
|
13
10
|
* Lexical caches resolved class arrays by MUTATING the `text` object it is
|
package/dist/theme.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEjD,eAAO,MAAM,mBAAmB,qBAAqB,CAAA;AAErD;mBACmB;AACnB,eAAO,MAAM,YAAY,EAAE,kBAI1B,CAAA;AAED;;;;;;;8EAO8E;AAC9E,wBAAgB,UAAU,CAAC,KAAK,CAAC,EAAE,kBAAkB,GAAG,kBAAkB,CAIzE"}
|
package/dist/theme.js
CHANGED
|
@@ -2,28 +2,32 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Lexical styles most inline formats through semantic tags that carry
|
|
4
4
|
// browser-default styling — bold→<strong>, italic→<em>, code→<code>. But
|
|
5
|
-
// `strikethrough`
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
5
|
+
// `strikethrough` renders as a bare <span> whose ONLY styling hook is a
|
|
6
|
+
// `theme.text.strikethrough` class. With no theme the format is applied to the
|
|
7
|
+
// model but is visually invisible. This default theme supplies that class name;
|
|
8
|
+
// the bundled `styles/editor.css` gives it its `text-decoration`.
|
|
9
|
+
//
|
|
10
|
+
// `underline` is deliberately NOT themed here: the GFM markdown dialect this
|
|
11
|
+
// editor serializes has no underline representation (Lexical's text-format
|
|
12
|
+
// transformers require a SYMMETRIC delimiter, and there is no standard symmetric
|
|
13
|
+
// underline syntax), so an applied underline would be silently stripped on save.
|
|
14
|
+
// To keep the WYSIWYG surface and the serialized dialect in lock-step, the
|
|
15
|
+
// underline command is also intercepted at the editor seam (see editor.ts) — so
|
|
16
|
+
// underline can be neither applied nor lost. Add it back (theme + transformer +
|
|
17
|
+
// command) only alongside a dialect that can round-trip it.
|
|
9
18
|
//
|
|
10
19
|
// Consumers can override any entry via `markdownEditor({ theme })` — the user's
|
|
11
20
|
// theme is merged over this default (see `mergeTheme`).
|
|
12
21
|
export const STRIKETHROUGH_CLASS = 'md-strikethrough';
|
|
13
|
-
export const UNDERLINE_CLASS = 'md-underline';
|
|
14
|
-
export const UNDERLINE_STRIKETHROUGH_CLASS = 'md-underline-strikethrough';
|
|
15
22
|
/** The class hooks Lexical needs for text-decoration formats it renders as a
|
|
16
|
-
* plain <span>.
|
|
17
|
-
* the case where both apply — both want `text-decoration`.) */
|
|
23
|
+
* plain <span>. */
|
|
18
24
|
export const defaultTheme = {
|
|
19
25
|
text: {
|
|
20
26
|
strikethrough: STRIKETHROUGH_CLASS,
|
|
21
|
-
underline: UNDERLINE_CLASS,
|
|
22
|
-
underlineStrikethrough: UNDERLINE_STRIKETHROUGH_CLASS,
|
|
23
27
|
},
|
|
24
28
|
};
|
|
25
29
|
/** Merge a consumer theme over the default. `text` is merged per-key so a
|
|
26
|
-
* consumer overriding (say) `strikethrough` keeps the default
|
|
30
|
+
* consumer overriding (say) `strikethrough` keeps the other default entries.
|
|
27
31
|
*
|
|
28
32
|
* Always returns a FRESH theme (never the shared `defaultTheme` singleton):
|
|
29
33
|
* Lexical caches resolved class arrays by MUTATING the `text` object it is
|
package/dist/theme.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,yEAAyE;AACzE,+EAA+E;AAC/E,gFAAgF;AAChF
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,yEAAyE;AACzE,wEAAwE;AACxE,+EAA+E;AAC/E,gFAAgF;AAChF,kEAAkE;AAClE,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,iFAAiF;AACjF,iFAAiF;AACjF,2EAA2E;AAC3E,gFAAgF;AAChF,gFAAgF;AAChF,4DAA4D;AAC5D,EAAE;AACF,gFAAgF;AAChF,wDAAwD;AAIxD,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,CAAA;AAErD;mBACmB;AACnB,MAAM,CAAC,MAAM,YAAY,GAAuB;IAC9C,IAAI,EAAE;QACJ,aAAa,EAAE,mBAAmB;KACnC;CACF,CAAA;AAED;;;;;;;8EAO8E;AAC9E,MAAM,UAAU,UAAU,CAAC,KAA0B;IACnD,MAAM,IAAI,GAAG,EAAE,GAAG,YAAY,CAAC,IAAI,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,CAAA;IACrD,OAAQ,IAA8C,CAAC,uBAAuB,CAAA;IAC9E,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,CAAA;AAC3B,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { MultilineElementTransformer } from '@lexical/markdown';
|
|
2
|
+
/**
|
|
3
|
+
* Canonicalize a fence info string.
|
|
4
|
+
*
|
|
5
|
+
* CommonMark's info string is the remainder of the opening-fence line with the
|
|
6
|
+
* surrounding whitespace stripped; a blank one means "no language". Two
|
|
7
|
+
* characters are removed rather than preserved, because keeping them would emit
|
|
8
|
+
* markdown that no longer re-imports to the same block:
|
|
9
|
+
*
|
|
10
|
+
* - a backtick — illegal in a backtick-fenced info string (it would terminate
|
|
11
|
+
* or corrupt the fence);
|
|
12
|
+
* - a newline — it would end the fence line entirely.
|
|
13
|
+
*
|
|
14
|
+
* Everything else survives verbatim, including spaces (`'lance table'`) and
|
|
15
|
+
* punctuation (`'c++'`, `'objective-c'`).
|
|
16
|
+
*/
|
|
17
|
+
export declare function normalizeCodeInfo(raw: string | null | undefined): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* A drop-in replacement for `@lexical/markdown`'s `CODE` that treats the whole
|
|
20
|
+
* remainder of the opening-fence line as the info string (CommonMark's rule)
|
|
21
|
+
* instead of a single `[\w-]+` token.
|
|
22
|
+
*/
|
|
23
|
+
export declare const CODE_INFO_TRANSFORMER: MultilineElementTransformer;
|
|
24
|
+
//# sourceMappingURL=code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../src/transformers/code.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAA;AAEpE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAO/E;AAkDD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,2BA8DnC,CAAA"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// The fenced-code-block transformer.
|
|
2
|
+
//
|
|
3
|
+
// ## Why this package does not use `@lexical/markdown`'s `CODE`
|
|
4
|
+
//
|
|
5
|
+
// Upstream's `CODE_START_REGEX` captures the info string with `([\w-]+)?`, i.e.
|
|
6
|
+
// a SINGLE word-ish token. Everything after that token stays on the line and is
|
|
7
|
+
// pushed into the code block's CONTENT:
|
|
8
|
+
//
|
|
9
|
+
// ```lance table → language 'lance', body 'table\nsum(x)' (corrupt)
|
|
10
|
+
// ```c++ → language 'c', body '++\nint main()' (corrupt)
|
|
11
|
+
//
|
|
12
|
+
// That is silent data loss on perfectly ordinary markdown. CommonMark defines
|
|
13
|
+
// the info string as *the rest of the line*, trimmed — so
|
|
14
|
+
// {@link CODE_INFO_TRANSFORMER} captures exactly that and hands it to
|
|
15
|
+
// `CodeNode.setLanguage` untouched.
|
|
16
|
+
//
|
|
17
|
+
// This lives in `transformers/` (not in `plugins/code-language.ts`) so that it
|
|
18
|
+
// is the DEFAULT in `GFM_TRANSFORMERS` rather than an opt-in a consumer has to
|
|
19
|
+
// remember to order ahead of `corePlugin()`. `codeLanguagePlugin()` contributes
|
|
20
|
+
// this same object reference, so the registry's reference de-duplication
|
|
21
|
+
// collapses the two contributions into one and plugin order cannot change the
|
|
22
|
+
// parse. See `test/composition.test.ts`.
|
|
23
|
+
//
|
|
24
|
+
// ## The language is an opaque label
|
|
25
|
+
//
|
|
26
|
+
// The package depends on `@lexical/code-core`, not `@lexical/code`, to keep
|
|
27
|
+
// Prism out of the bundle. Nothing interprets the info string — it is stored,
|
|
28
|
+
// shown, edited, and re-emitted verbatim. That opacity is precisely what lets an
|
|
29
|
+
// arbitrary token like `lance table` survive a round-trip.
|
|
30
|
+
import { $createTextNode } from 'lexical';
|
|
31
|
+
import { $createCodeNode, $isCodeNode, CodeNode } from '@lexical/code-core';
|
|
32
|
+
/**
|
|
33
|
+
* Canonicalize a fence info string.
|
|
34
|
+
*
|
|
35
|
+
* CommonMark's info string is the remainder of the opening-fence line with the
|
|
36
|
+
* surrounding whitespace stripped; a blank one means "no language". Two
|
|
37
|
+
* characters are removed rather than preserved, because keeping them would emit
|
|
38
|
+
* markdown that no longer re-imports to the same block:
|
|
39
|
+
*
|
|
40
|
+
* - a backtick — illegal in a backtick-fenced info string (it would terminate
|
|
41
|
+
* or corrupt the fence);
|
|
42
|
+
* - a newline — it would end the fence line entirely.
|
|
43
|
+
*
|
|
44
|
+
* Everything else survives verbatim, including spaces (`'lance table'`) and
|
|
45
|
+
* punctuation (`'c++'`, `'objective-c'`).
|
|
46
|
+
*/
|
|
47
|
+
export function normalizeCodeInfo(raw) {
|
|
48
|
+
if (raw === null || raw === undefined)
|
|
49
|
+
return null;
|
|
50
|
+
const cleaned = raw
|
|
51
|
+
.replace(/`/g, '')
|
|
52
|
+
.replace(/[\r\n]+/g, ' ')
|
|
53
|
+
.trim();
|
|
54
|
+
return cleaned === '' ? null : cleaned;
|
|
55
|
+
}
|
|
56
|
+
/** The opening fence: its backtick run, then the raw info string (rest of line). */
|
|
57
|
+
const FENCE_START = /^([ \t]*`{3,})(.*)$/;
|
|
58
|
+
/** A closing fence of at least `length` backticks on a line of its own. */
|
|
59
|
+
const fenceEndFor = (length) => new RegExp(`^[ \\t]*\`{${length},}[ \\t]*$`);
|
|
60
|
+
/**
|
|
61
|
+
* The narrowest fence that can enclose `code` without being terminated early:
|
|
62
|
+
* one backtick longer than the longest fence-like run inside it.
|
|
63
|
+
*/
|
|
64
|
+
function fenceFor(code) {
|
|
65
|
+
const runs = code.match(/`{3,}/g);
|
|
66
|
+
const longest = runs ? Math.max(...runs.map((run) => run.length)) : 0;
|
|
67
|
+
return '`'.repeat(Math.max(3, longest + 1));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A self-closing opening fence (```` ```code``` ````): the closing run sits on
|
|
71
|
+
* the SAME line, so the span between the fences is CONTENT and there is no info
|
|
72
|
+
* string. Returns that content, or `null` when the line is an ordinary opening
|
|
73
|
+
* fence.
|
|
74
|
+
*
|
|
75
|
+
* Shared by BOTH directions on purpose. It used to live only in
|
|
76
|
+
* `handleImportAfterStartMatch`, so the import path and the typed-shortcut
|
|
77
|
+
* `replace` path parsed the same text two different ways: importing
|
|
78
|
+
* '```inline```' gave a language-less block containing `inline`, while TYPING it
|
|
79
|
+
* and pressing Enter gave an EMPTY block labelled 'inline' — the word was gone.
|
|
80
|
+
* The divergence was reachable because `FENCE_START`'s `(.*)$` consumes the
|
|
81
|
+
* whole line, which always satisfies the shortcut engine's `match[0].length ===
|
|
82
|
+
* matchLength` gate. (Upstream's narrower `CODE_START_REGEX` never matched this
|
|
83
|
+
* shape, so widening the capture is what introduced it.)
|
|
84
|
+
*/
|
|
85
|
+
function singleLineFenceContent(fence, rest) {
|
|
86
|
+
const closing = rest.match(new RegExp(`\`{${fence.length},}[ \t]*$`));
|
|
87
|
+
return closing && closing.index !== undefined ? rest.slice(0, closing.index) : null;
|
|
88
|
+
}
|
|
89
|
+
/** Append a code block carrying `language` and `lines` to `parent`. */
|
|
90
|
+
function $appendCodeNode(parent, language, lines) {
|
|
91
|
+
const node = $createCodeNode(language ?? undefined);
|
|
92
|
+
const code = lines.join('\n');
|
|
93
|
+
if (code !== '')
|
|
94
|
+
node.append($createTextNode(code));
|
|
95
|
+
parent.append(node);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A drop-in replacement for `@lexical/markdown`'s `CODE` that treats the whole
|
|
99
|
+
* remainder of the opening-fence line as the info string (CommonMark's rule)
|
|
100
|
+
* instead of a single `[\w-]+` token.
|
|
101
|
+
*/
|
|
102
|
+
export const CODE_INFO_TRANSFORMER = {
|
|
103
|
+
dependencies: [CodeNode],
|
|
104
|
+
export: (node) => {
|
|
105
|
+
if (!$isCodeNode(node))
|
|
106
|
+
return null;
|
|
107
|
+
const code = node.getTextContent();
|
|
108
|
+
const fence = fenceFor(code);
|
|
109
|
+
const info = normalizeCodeInfo(node.getLanguage()) ?? '';
|
|
110
|
+
return fence + info + (code === '' ? '' : '\n' + code) + '\n' + fence;
|
|
111
|
+
},
|
|
112
|
+
handleImportAfterStartMatch: ({ lines, rootNode, startLineIndex, startMatch }) => {
|
|
113
|
+
const fence = (startMatch[1] ?? '```').trim();
|
|
114
|
+
const rest = startMatch[2] ?? '';
|
|
115
|
+
// Single-line form (```code```) — see `singleLineFenceContent`. Matches
|
|
116
|
+
// `@lexical/markdown`, and matches CommonMark, which forbids a backtick
|
|
117
|
+
// inside the info string.
|
|
118
|
+
const inline = singleLineFenceContent(fence, rest);
|
|
119
|
+
if (inline !== null) {
|
|
120
|
+
$appendCodeNode(rootNode, null, [inline]);
|
|
121
|
+
return [true, startLineIndex];
|
|
122
|
+
}
|
|
123
|
+
const language = normalizeCodeInfo(rest);
|
|
124
|
+
const fenceEnd = fenceEndFor(fence.length);
|
|
125
|
+
for (let i = startLineIndex + 1; i < lines.length; i++) {
|
|
126
|
+
if (fenceEnd.test(lines[i])) {
|
|
127
|
+
$appendCodeNode(rootNode, language, lines.slice(startLineIndex + 1, i));
|
|
128
|
+
return [true, i];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Unterminated fence: consume to the end of the document.
|
|
132
|
+
$appendCodeNode(rootNode, language, lines.slice(startLineIndex + 1));
|
|
133
|
+
return [true, lines.length - 1];
|
|
134
|
+
},
|
|
135
|
+
regExpEnd: { optional: true, regExp: /^[ \t]*`{3,}[ \t]*$/ },
|
|
136
|
+
regExpStart: FENCE_START,
|
|
137
|
+
// Import is fully handled above; `replace` serves the typed-shortcut path
|
|
138
|
+
// (`registerMarkdownShortcuts` calls it with the trailing siblings) and the
|
|
139
|
+
// paste path (`children === null`, lines supplied).
|
|
140
|
+
replace: (rootNode, children, startMatch, _endMatch, linesInBetween, isImport) => {
|
|
141
|
+
const fence = (startMatch[1] ?? '```').trim();
|
|
142
|
+
const rest = startMatch[2] ?? '';
|
|
143
|
+
// The SAME single-line rule the import path applies, so the two agree.
|
|
144
|
+
const inline = singleLineFenceContent(fence, rest);
|
|
145
|
+
if (inline !== null) {
|
|
146
|
+
const node = $createCodeNode();
|
|
147
|
+
if (inline !== '')
|
|
148
|
+
node.append($createTextNode(inline));
|
|
149
|
+
rootNode.replace(node);
|
|
150
|
+
if (!isImport)
|
|
151
|
+
node.select(0, 0);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const language = normalizeCodeInfo(rest);
|
|
155
|
+
if (!children) {
|
|
156
|
+
$appendCodeNode(rootNode, language, linesInBetween ?? []);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const node = $createCodeNode(language ?? undefined);
|
|
160
|
+
node.append(...children);
|
|
161
|
+
rootNode.replace(node);
|
|
162
|
+
if (!isImport)
|
|
163
|
+
node.select(0, 0);
|
|
164
|
+
},
|
|
165
|
+
type: 'multiline-element',
|
|
166
|
+
};
|
|
167
|
+
//# sourceMappingURL=code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code.js","sourceRoot":"","sources":["../../src/transformers/code.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,9 +2,17 @@ import type { Klass, LexicalNode } from 'lexical';
|
|
|
2
2
|
import { type Transformer } from '@lexical/markdown';
|
|
3
3
|
/** Node classes required to render the GFM superset. */
|
|
4
4
|
export declare const GFM_NODES: ReadonlyArray<Klass<LexicalNode>>;
|
|
5
|
+
/** The `==highlight==` transformer. NOT part of the default GFM set: `==..==` is
|
|
6
|
+
* not GFM, so exporting it produces non-standard markdown other renderers won't
|
|
7
|
+
* understand. Offered as an opt-in a consumer can add to a plugin's transformers. */
|
|
8
|
+
export declare const HIGHLIGHT_TRANSFORMER: Transformer;
|
|
5
9
|
/** Inline text-format transformers (no block nodes, no node registration). These
|
|
6
10
|
* are the only transformers a single-block / inline-only editor needs; `LINK` is
|
|
7
|
-
* kept separate since it requires `LinkNode` to be registered.
|
|
11
|
+
* kept separate since it requires `LinkNode` to be registered.
|
|
12
|
+
*
|
|
13
|
+
* `HIGHLIGHT` is deliberately excluded: it round-trips as the non-GFM `==..==`
|
|
14
|
+
* syntax, so it would silently emit markdown outside the editor's stated dialect.
|
|
15
|
+
* Opt in with {@link HIGHLIGHT_TRANSFORMER}. */
|
|
8
16
|
export declare const INLINE_TEXT_TRANSFORMERS: readonly Transformer[];
|
|
9
17
|
/** Markdown ↔ node transformers for the GFM superset. */
|
|
10
18
|
export declare const GFM_TRANSFORMERS: readonly Transformer[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gfm.d.ts","sourceRoot":"","sources":["../../src/transformers/gfm.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAOjD,OAAO,EACL,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"gfm.d.ts","sourceRoot":"","sources":["../../src/transformers/gfm.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAOjD,OAAO,EACL,KAAK,WAAW,EAgBjB,MAAM,mBAAmB,CAAA;AAG1B,wDAAwD;AACxD,eAAO,MAAM,SAAS,EAAE,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAQvD,CAAA;AAED;;qFAEqF;AACrF,eAAO,MAAM,qBAAqB,EAAE,WAAuB,CAAA;AAE3D;;;;;;gDAMgD;AAChD,eAAO,MAAM,wBAAwB,EAAE,SAAS,WAAW,EAS1D,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,gBAAgB,EAAE,SAAS,WAAW,EAelD,CAAA"}
|
package/dist/transformers/gfm.js
CHANGED
|
@@ -6,7 +6,8 @@ import { LinkNode } from '@lexical/link';
|
|
|
6
6
|
// `@lexical/code-core` (not `@lexical/code`) keeps Prism out of the bundle — we
|
|
7
7
|
// never register syntax highlighting, so plain CodeNode is all we need.
|
|
8
8
|
import { CodeNode, CodeHighlightNode } from '@lexical/code-core';
|
|
9
|
-
import { HEADING, QUOTE, UNORDERED_LIST, ORDERED_LIST, CHECK_LIST,
|
|
9
|
+
import { HEADING, QUOTE, UNORDERED_LIST, ORDERED_LIST, CHECK_LIST, BOLD_ITALIC_STAR, BOLD_ITALIC_UNDERSCORE, BOLD_STAR, BOLD_UNDERSCORE, ITALIC_STAR, ITALIC_UNDERSCORE, STRIKETHROUGH, INLINE_CODE, HIGHLIGHT, LINK, } from '@lexical/markdown';
|
|
10
|
+
import { CODE_INFO_TRANSFORMER } from './code.js';
|
|
10
11
|
/** Node classes required to render the GFM superset. */
|
|
11
12
|
export const GFM_NODES = [
|
|
12
13
|
HeadingNode,
|
|
@@ -17,9 +18,17 @@ export const GFM_NODES = [
|
|
|
17
18
|
CodeHighlightNode,
|
|
18
19
|
LinkNode,
|
|
19
20
|
];
|
|
21
|
+
/** The `==highlight==` transformer. NOT part of the default GFM set: `==..==` is
|
|
22
|
+
* not GFM, so exporting it produces non-standard markdown other renderers won't
|
|
23
|
+
* understand. Offered as an opt-in a consumer can add to a plugin's transformers. */
|
|
24
|
+
export const HIGHLIGHT_TRANSFORMER = HIGHLIGHT;
|
|
20
25
|
/** Inline text-format transformers (no block nodes, no node registration). These
|
|
21
26
|
* are the only transformers a single-block / inline-only editor needs; `LINK` is
|
|
22
|
-
* kept separate since it requires `LinkNode` to be registered.
|
|
27
|
+
* kept separate since it requires `LinkNode` to be registered.
|
|
28
|
+
*
|
|
29
|
+
* `HIGHLIGHT` is deliberately excluded: it round-trips as the non-GFM `==..==`
|
|
30
|
+
* syntax, so it would silently emit markdown outside the editor's stated dialect.
|
|
31
|
+
* Opt in with {@link HIGHLIGHT_TRANSFORMER}. */
|
|
23
32
|
export const INLINE_TEXT_TRANSFORMERS = [
|
|
24
33
|
BOLD_ITALIC_STAR,
|
|
25
34
|
BOLD_ITALIC_UNDERSCORE,
|
|
@@ -29,7 +38,6 @@ export const INLINE_TEXT_TRANSFORMERS = [
|
|
|
29
38
|
ITALIC_UNDERSCORE,
|
|
30
39
|
STRIKETHROUGH,
|
|
31
40
|
INLINE_CODE,
|
|
32
|
-
HIGHLIGHT,
|
|
33
41
|
];
|
|
34
42
|
/** Markdown ↔ node transformers for the GFM superset. */
|
|
35
43
|
export const GFM_TRANSFORMERS = [
|
|
@@ -40,7 +48,11 @@ export const GFM_TRANSFORMERS = [
|
|
|
40
48
|
CHECK_LIST,
|
|
41
49
|
UNORDERED_LIST,
|
|
42
50
|
ORDERED_LIST,
|
|
43
|
-
CODE
|
|
51
|
+
// NOT `@lexical/markdown`'s `CODE`: that one captures the info string as a
|
|
52
|
+
// single `[\w-]+` token and pushes the remainder of the fence line into the
|
|
53
|
+
// code body, silently corrupting ```c++ and ```lance table. See
|
|
54
|
+
// `transformers/code.ts`.
|
|
55
|
+
CODE_INFO_TRANSFORMER,
|
|
44
56
|
...INLINE_TEXT_TRANSFORMERS,
|
|
45
57
|
LINK,
|
|
46
58
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gfm.js","sourceRoot":"","sources":["../../src/transformers/gfm.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,kFAAkF;AAGlF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,gFAAgF;AAChF,wEAAwE;AACxE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAChE,OAAO,EAEL,OAAO,EACP,KAAK,EACL,cAAc,EACd,YAAY,EACZ,UAAU,EACV,
|
|
1
|
+
{"version":3,"file":"gfm.js","sourceRoot":"","sources":["../../src/transformers/gfm.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,kFAAkF;AAGlF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,gFAAgF;AAChF,wEAAwE;AACxE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAChE,OAAO,EAEL,OAAO,EACP,KAAK,EACL,cAAc,EACd,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,SAAS,EACT,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,SAAS,EACT,IAAI,GACL,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAA;AAEjD,wDAAwD;AACxD,MAAM,CAAC,MAAM,SAAS,GAAsC;IAC1D,WAAW;IACX,SAAS;IACT,QAAQ;IACR,YAAY;IACZ,QAAQ;IACR,iBAAiB;IACjB,QAAQ;CACT,CAAA;AAED;;qFAEqF;AACrF,MAAM,CAAC,MAAM,qBAAqB,GAAgB,SAAS,CAAA;AAE3D;;;;;;gDAMgD;AAChD,MAAM,CAAC,MAAM,wBAAwB,GAA2B;IAC9D,gBAAgB;IAChB,sBAAsB;IACtB,SAAS;IACT,eAAe;IACf,WAAW;IACX,iBAAiB;IACjB,aAAa;IACb,WAAW;CACZ,CAAA;AAED,yDAAyD;AACzD,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACtD,OAAO;IACP,KAAK;IACL,4EAA4E;IAC5E,2EAA2E;IAC3E,UAAU;IACV,cAAc;IACd,YAAY;IACZ,2EAA2E;IAC3E,4EAA4E;IAC5E,gEAAgE;IAChE,0BAA0B;IAC1B,qBAAqB;IACrB,GAAG,wBAAwB;IAC3B,IAAI;CACL,CAAA"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { Transformer } from '@lexical/markdown';
|
|
2
2
|
import type { MarkdownPlugin } from '../plugins/types.js';
|
|
3
|
+
/** Declare that `transformer` must be consulted before same-rank peers with a
|
|
4
|
+
* higher value. Call at module scope, beside the transformer's definition. */
|
|
5
|
+
export declare function setTransformerPrecedence(transformer: Transformer, value: number): void;
|
|
3
6
|
/** Stable-sort transformers into the order Lexical expects. */
|
|
4
7
|
export declare function orderTransformers(transformers: readonly Transformer[]): Transformer[];
|
|
5
8
|
/** Collect every plugin's transformers (de-duplicated by reference) and order
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/transformers/registry.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/transformers/registry.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AA4BzD;8EAC8E;AAC9E,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEtF;AAED,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,EAAE,CAgBrF;AAED;;kCAEkC;AAClC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,GAAG,WAAW,EAAE,CAYnF"}
|
|
@@ -10,6 +10,26 @@ const TYPE_RANK = {
|
|
|
10
10
|
'text-format': 2,
|
|
11
11
|
'text-match': 3,
|
|
12
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Explicit ordering between transformers of the SAME rank.
|
|
15
|
+
*
|
|
16
|
+
* Within a rank Lexical falls back to array position, which for text-match
|
|
17
|
+
* transformers means `findOutermostTextMatchTransformer` breaks a tie — two
|
|
18
|
+
* transformers matching at the SAME start index — by plugin array order. That
|
|
19
|
+
* makes round-trip fidelity depend on the order a consumer happens to list
|
|
20
|
+
* plugins in, which is exactly the failure mode the registry exists to prevent.
|
|
21
|
+
*
|
|
22
|
+
* A transformer that must be consulted ahead of a same-rank peer declares a
|
|
23
|
+
* LOWER precedence here (default 0). This is a side table rather than a field on
|
|
24
|
+
* the transformer because the colliding peers include upstream's `LINK`, which
|
|
25
|
+
* this package does not own and cannot annotate.
|
|
26
|
+
*/
|
|
27
|
+
const precedence = new WeakMap();
|
|
28
|
+
/** Declare that `transformer` must be consulted before same-rank peers with a
|
|
29
|
+
* higher value. Call at module scope, beside the transformer's definition. */
|
|
30
|
+
export function setTransformerPrecedence(transformer, value) {
|
|
31
|
+
precedence.set(transformer, value);
|
|
32
|
+
}
|
|
13
33
|
/** Stable-sort transformers into the order Lexical expects. */
|
|
14
34
|
export function orderTransformers(transformers) {
|
|
15
35
|
return [...transformers].sort((a, b) => {
|
|
@@ -21,6 +41,12 @@ export function orderTransformers(transformers) {
|
|
|
21
41
|
// Longer trigger (`***`) before shorter (`**`, `*`).
|
|
22
42
|
return b.tag.length - a.tag.length;
|
|
23
43
|
}
|
|
44
|
+
const pa = precedence.get(a) ?? 0;
|
|
45
|
+
const pb = precedence.get(b) ?? 0;
|
|
46
|
+
if (pa !== pb)
|
|
47
|
+
return pa - pb;
|
|
48
|
+
// Equal precedence: `Array.prototype.sort` is specified stable, so the
|
|
49
|
+
// plugin array order is preserved — the documented default.
|
|
24
50
|
return 0;
|
|
25
51
|
});
|
|
26
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/transformers/registry.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,+EAA+E;AAC/E,kDAAkD;AAKlD,6EAA6E;AAC7E,6EAA6E;AAC7E,mEAAmE;AACnE,MAAM,SAAS,GAA2B;IACxC,mBAAmB,EAAE,CAAC;IACtB,OAAO,EAAE,CAAC;IACV,aAAa,EAAE,CAAC;IAChB,YAAY,EAAE,CAAC;CAChB,CAAA;AAED,+DAA+D;AAC/D,MAAM,UAAU,iBAAiB,CAAC,YAAoC;IACpE,OAAO,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACrC,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjC,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE,CAAA;QAC7B,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACzD,qDAAqD;YACrD,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAA;QACpC,CAAC;QACD,OAAO,CAAC,CAAA;IACV,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;kCAEkC;AAClC,MAAM,UAAU,iBAAiB,CAAC,OAAkC;IAClE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAe,CAAA;IACnC,MAAM,SAAS,GAAkB,EAAE,CAAA;IACnC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC;YACpD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC3B,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;gBACrB,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,iBAAiB,CAAC,SAAS,CAAC,CAAA;AACrC,CAAC"}
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/transformers/registry.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,+EAA+E;AAC/E,kDAAkD;AAKlD,6EAA6E;AAC7E,6EAA6E;AAC7E,mEAAmE;AACnE,MAAM,SAAS,GAA2B;IACxC,mBAAmB,EAAE,CAAC;IACtB,OAAO,EAAE,CAAC;IACV,aAAa,EAAE,CAAC;IAChB,YAAY,EAAE,CAAC;CAChB,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,GAAG,IAAI,OAAO,EAAuB,CAAA;AAErD;8EAC8E;AAC9E,MAAM,UAAU,wBAAwB,CAAC,WAAwB,EAAE,KAAa;IAC9E,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAA;AACpC,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,iBAAiB,CAAC,YAAoC;IACpE,OAAO,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACrC,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjC,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE,CAAA;QAC7B,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACzD,qDAAqD;YACrD,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAA;QACpC,CAAC;QACD,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACjC,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACjC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE,CAAA;QAC7B,uEAAuE;QACvE,4DAA4D;QAC5D,OAAO,CAAC,CAAA;IACV,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;kCAEkC;AAClC,MAAM,UAAU,iBAAiB,CAAC,OAAkC;IAClE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAe,CAAA;IACnC,MAAM,SAAS,GAAkB,EAAE,CAAA;IACnC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC;YACpD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC3B,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;gBACrB,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,iBAAiB,CAAC,SAAS,CAAC,CAAA;AACrC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llui/markdown-editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -21,43 +21,57 @@
|
|
|
21
21
|
"types": "./dist/surfaces/toolbar.d.ts",
|
|
22
22
|
"import": "./dist/surfaces/toolbar.js"
|
|
23
23
|
},
|
|
24
|
-
"./
|
|
24
|
+
"./plugins/block-drag": {
|
|
25
|
+
"types": "./dist/plugins/block-drag.d.ts",
|
|
26
|
+
"import": "./dist/plugins/block-drag.js"
|
|
27
|
+
},
|
|
28
|
+
"./plugins/code-language": {
|
|
29
|
+
"types": "./dist/plugins/code-language.d.ts",
|
|
30
|
+
"import": "./dist/plugins/code-language.js"
|
|
31
|
+
},
|
|
32
|
+
"./plugins/wikilink": {
|
|
33
|
+
"types": "./dist/plugins/wikilink.d.ts",
|
|
34
|
+
"import": "./dist/plugins/wikilink.js"
|
|
35
|
+
},
|
|
36
|
+
"./styles/editor.css": "./dist/styles/editor.css",
|
|
37
|
+
"./styles/block-drag.css": "./dist/styles/block-drag.css"
|
|
25
38
|
},
|
|
26
39
|
"peerDependencies": {
|
|
27
|
-
"lexical": "^0.
|
|
28
|
-
"@lexical/markdown": "^0.
|
|
29
|
-
"@lexical/rich-text": "^0.
|
|
30
|
-
"@lexical/list": "^0.
|
|
31
|
-
"@lexical/link": "^0.
|
|
32
|
-
"@lexical/table": "^0.
|
|
33
|
-
"@lexical/selection": "^0.
|
|
34
|
-
"@lexical/utils": "^0.
|
|
35
|
-
"@lexical/code-core": "^0.
|
|
36
|
-
"@llui/dom": "^0.
|
|
37
|
-
"@llui/lexical": "^0.
|
|
38
|
-
"@llui/markdown": "^0.
|
|
39
|
-
"@llui/components": "^0.
|
|
40
|
+
"lexical": "^0.48.0",
|
|
41
|
+
"@lexical/markdown": "^0.48.0",
|
|
42
|
+
"@lexical/rich-text": "^0.48.0",
|
|
43
|
+
"@lexical/list": "^0.48.0",
|
|
44
|
+
"@lexical/link": "^0.48.0",
|
|
45
|
+
"@lexical/table": "^0.48.0",
|
|
46
|
+
"@lexical/selection": "^0.48.0",
|
|
47
|
+
"@lexical/utils": "^0.48.0",
|
|
48
|
+
"@lexical/code-core": "^0.48.0",
|
|
49
|
+
"@llui/dom": "^0.12.0",
|
|
50
|
+
"@llui/lexical": "^0.4.0",
|
|
51
|
+
"@llui/markdown": "^0.12.0",
|
|
52
|
+
"@llui/components": "^0.13.0"
|
|
40
53
|
},
|
|
41
54
|
"devDependencies": {
|
|
42
|
-
"lexical": "^0.
|
|
43
|
-
"@lexical/headless": "^0.
|
|
44
|
-
"@lexical/markdown": "^0.
|
|
45
|
-
"@lexical/rich-text": "^0.
|
|
46
|
-
"@lexical/list": "^0.
|
|
47
|
-
"@lexical/link": "^0.
|
|
48
|
-
"@lexical/table": "^0.
|
|
49
|
-
"@lexical/selection": "^0.
|
|
50
|
-
"@lexical/utils": "^0.
|
|
55
|
+
"lexical": "^0.48.0",
|
|
56
|
+
"@lexical/headless": "^0.48.0",
|
|
57
|
+
"@lexical/markdown": "^0.48.0",
|
|
58
|
+
"@lexical/rich-text": "^0.48.0",
|
|
59
|
+
"@lexical/list": "^0.48.0",
|
|
60
|
+
"@lexical/link": "^0.48.0",
|
|
61
|
+
"@lexical/table": "^0.48.0",
|
|
62
|
+
"@lexical/selection": "^0.48.0",
|
|
63
|
+
"@lexical/utils": "^0.48.0",
|
|
51
64
|
"typescript": "^6.0.0",
|
|
52
65
|
"vitest": "^4.1.2",
|
|
53
|
-
"@lexical/code-core": "^0.
|
|
54
|
-
"@llui/dom": "0.
|
|
55
|
-
"@llui/
|
|
56
|
-
"@llui/
|
|
57
|
-
"@llui/lexical": "0.
|
|
66
|
+
"@lexical/code-core": "^0.48.0",
|
|
67
|
+
"@llui/dom": "0.12.0",
|
|
68
|
+
"@llui/components": "0.13.0",
|
|
69
|
+
"@llui/markdown": "0.12.0",
|
|
70
|
+
"@llui/lexical": "0.4.0"
|
|
58
71
|
},
|
|
59
72
|
"sideEffects": [
|
|
60
|
-
"./dist/styles/editor.css"
|
|
73
|
+
"./dist/styles/editor.css",
|
|
74
|
+
"./dist/styles/block-drag.css"
|
|
61
75
|
],
|
|
62
76
|
"description": "WYSIWYG Markdown editor for LLui — hides Markdown behind a rich, pluggable editing widget built on Lexical",
|
|
63
77
|
"keywords": [
|
|
@@ -87,7 +101,7 @@
|
|
|
87
101
|
"access": "public"
|
|
88
102
|
},
|
|
89
103
|
"scripts": {
|
|
90
|
-
"build": "tsc -p tsconfig.build.json && mkdir -p dist/styles && cp src/styles
|
|
104
|
+
"build": "tsc -p tsconfig.build.json && mkdir -p dist/styles && cp src/styles/*.css dist/styles/",
|
|
91
105
|
"check": "tsc --noEmit -p tsconfig.check.json",
|
|
92
106
|
"lint": "eslint src",
|
|
93
107
|
"test": "vitest run"
|