@astryxdesign/lab 0.2.0-canary.c366298 → 0.2.0-canary.c75407e
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/RichTextEditor/RichTextEditor.d.ts.map +1 -1
- package/dist/RichTextEditor/RichTextEditor.js +1 -7
- package/dist/RichTextEditor/editorNodes.d.ts +8 -0
- package/dist/RichTextEditor/editorNodes.d.ts.map +1 -0
- package/dist/RichTextEditor/editorNodes.js +23 -0
- package/dist/RichTextEditor/index.d.ts +2 -0
- package/dist/RichTextEditor/index.d.ts.map +1 -1
- package/dist/RichTextEditor/index.js +2 -1
- package/dist/RichTextEditor/markdownSerializers.d.ts +40 -0
- package/dist/RichTextEditor/markdownSerializers.d.ts.map +1 -0
- package/dist/RichTextEditor/markdownSerializers.js +85 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +7 -2
- package/src/RichTextEditor/RichTextEditor.doc.mjs +5 -0
- package/src/RichTextEditor/RichTextEditor.test.tsx +43 -0
- package/src/RichTextEditor/RichTextEditor.tsx +1 -16
- package/src/RichTextEditor/editorNodes.ts +34 -0
- package/src/RichTextEditor/index.ts +6 -0
- package/src/RichTextEditor/markdownSerializers.ts +105 -0
- package/src/index.ts +3 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../src/RichTextEditor/RichTextEditor.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAQL,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAgBf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAElD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAkBxD,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../src/RichTextEditor/RichTextEditor.tsx"],"names":[],"mappings":"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"}
|
|
@@ -44,11 +44,8 @@ import { TabIndentationPlugin } from '@lexical/react/LexicalTabIndentationPlugin
|
|
|
44
44
|
import { MarkdownShortcutPlugin } from '@lexical/react/LexicalMarkdownShortcutPlugin';
|
|
45
45
|
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
|
|
46
46
|
import { TRANSFORMERS, $convertToMarkdownString } from '@lexical/markdown';
|
|
47
|
-
import { ListNode, ListItemNode } from '@lexical/list';
|
|
48
|
-
import { HeadingNode, QuoteNode } from '@lexical/rich-text';
|
|
49
|
-
import { LinkNode, AutoLinkNode } from '@lexical/link';
|
|
50
|
-
import { CodeNode, CodeHighlightNode } from '@lexical/code';
|
|
51
47
|
import { $generateHtmlFromNodes } from '@lexical/html';
|
|
48
|
+
import { DEFAULT_NODES } from "./editorNodes.js";
|
|
52
49
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
53
50
|
/**
|
|
54
51
|
* Serialized state for an empty editor: a root containing a single empty
|
|
@@ -107,9 +104,6 @@ const sizeStyles = {
|
|
|
107
104
|
}
|
|
108
105
|
};
|
|
109
106
|
|
|
110
|
-
/** The default OSS node set registered with the editor. */
|
|
111
|
-
const DEFAULT_NODES = [HeadingNode, QuoteNode, ListNode, ListItemNode, LinkNode, AutoLinkNode, CodeNode, CodeHighlightNode];
|
|
112
|
-
|
|
113
107
|
/**
|
|
114
108
|
* Fraction of `maxLength` at which the character counter begins announcing
|
|
115
109
|
* remaining/over-limit characters to screen readers. Matches TextArea.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Klass, LexicalNode } from 'lexical';
|
|
2
|
+
/**
|
|
3
|
+
* The default OSS node set registered with the editor: headings, quotes,
|
|
4
|
+
* lists, links, and code. Extend via the `nodes` prop / option rather than
|
|
5
|
+
* editing this list.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_NODES: ReadonlyArray<Klass<LexicalNode>>;
|
|
8
|
+
//# sourceMappingURL=editorNodes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editorNodes.d.ts","sourceRoot":"","sources":["../../src/RichTextEditor/editorNodes.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAC,KAAK,EAAE,WAAW,EAAC,MAAM,SAAS,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAS3D,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file editorNodes.ts
|
|
5
|
+
* @input Imports the default Lexical node classes registered by the editor.
|
|
6
|
+
* @output Exports DEFAULT_NODES — the base OSS node set.
|
|
7
|
+
* @position Shared by RichTextEditor.tsx (editor config) and
|
|
8
|
+
* markdownSerializers.ts (headless conversion), so both register the same
|
|
9
|
+
* nodes and Markdown round-trips consistently.
|
|
10
|
+
*
|
|
11
|
+
* SYNC: When the default node set changes, both consumers pick it up here.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { ListNode, ListItemNode } from '@lexical/list';
|
|
15
|
+
import { HeadingNode, QuoteNode } from '@lexical/rich-text';
|
|
16
|
+
import { LinkNode, AutoLinkNode } from '@lexical/link';
|
|
17
|
+
import { CodeNode, CodeHighlightNode } from '@lexical/code';
|
|
18
|
+
/**
|
|
19
|
+
* The default OSS node set registered with the editor: headings, quotes,
|
|
20
|
+
* lists, links, and code. Extend via the `nodes` prop / option rather than
|
|
21
|
+
* editing this list.
|
|
22
|
+
*/
|
|
23
|
+
export const DEFAULT_NODES = [HeadingNode, QuoteNode, ListNode, ListItemNode, LinkNode, AutoLinkNode, CodeNode, CodeHighlightNode];
|
|
@@ -12,4 +12,6 @@ export type { RichTextEditorProps, RichTextEditorRef, RichTextEditorStatus, Rich
|
|
|
12
12
|
export { RichTextView } from './RichTextView';
|
|
13
13
|
export type { RichTextViewProps } from './RichTextView';
|
|
14
14
|
export { sharedEditorTheme } from './editorTheme';
|
|
15
|
+
export { markdownToEditorStateJSON, editorStateJSONToMarkdown, } from './markdownSerializers';
|
|
16
|
+
export type { MarkdownSerializerOptions } from './markdownSerializers';
|
|
15
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/RichTextEditor/index.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,YAAY,EACV,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,kBAAkB,EAClB,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAC5C,YAAY,EAAC,iBAAiB,EAAC,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAC,iBAAiB,EAAC,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/RichTextEditor/index.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,YAAY,EACV,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,kBAAkB,EAClB,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAC5C,YAAY,EAAC,iBAAiB,EAAC,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAC,iBAAiB,EAAC,MAAM,eAAe,CAAC;AAEhD,OAAO,EACL,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAC,yBAAyB,EAAC,MAAM,uBAAuB,CAAC"}
|
|
@@ -13,4 +13,5 @@
|
|
|
13
13
|
*/
|
|
14
14
|
export { RichTextEditor } from "./RichTextEditor.js";
|
|
15
15
|
export { RichTextView } from "./RichTextView.js";
|
|
16
|
-
export { sharedEditorTheme } from "./editorTheme.js";
|
|
16
|
+
export { sharedEditorTheme } from "./editorTheme.js";
|
|
17
|
+
export { markdownToEditorStateJSON, editorStateJSONToMarkdown } from "./markdownSerializers.js";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type Transformer } from '@lexical/markdown';
|
|
2
|
+
import type { Klass, LexicalNode } from 'lexical';
|
|
3
|
+
/** Options shared by the Markdown serializer helpers. */
|
|
4
|
+
export interface MarkdownSerializerOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Markdown transformers to use. Defaults to the standard `@lexical/markdown`
|
|
7
|
+
* `TRANSFORMERS`. Pass the same array you give `RichTextEditor`'s
|
|
8
|
+
* `transformers` prop so content round-trips consistently.
|
|
9
|
+
*/
|
|
10
|
+
transformers?: ReadonlyArray<Transformer>;
|
|
11
|
+
/**
|
|
12
|
+
* Extra Lexical nodes to register beyond the default OSS set, mirroring the
|
|
13
|
+
* editor's `nodes` prop. Required for custom node types to serialize.
|
|
14
|
+
*/
|
|
15
|
+
nodes?: ReadonlyArray<Klass<LexicalNode>>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Convert a Markdown string to a serialized Lexical `EditorState` JSON string
|
|
19
|
+
* — the same shape `RichTextEditor`'s `defaultValue` expects. Runs headless
|
|
20
|
+
* (no DOM), so it is safe in Node / SSR.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```
|
|
24
|
+
* const value = markdownToEditorStateJSON('# Title\n\nHello');
|
|
25
|
+
* <RichTextEditor label="Notes" defaultValue={value} />
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function markdownToEditorStateJSON(markdown: string, options?: MarkdownSerializerOptions): string;
|
|
29
|
+
/**
|
|
30
|
+
* Convert a serialized Lexical `EditorState` JSON string (e.g. the value
|
|
31
|
+
* produced by `RichTextEditor`'s `onChange` or `defaultValue`) to a Markdown
|
|
32
|
+
* string. Runs headless (no DOM), so it is safe in Node / SSR.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```
|
|
36
|
+
* const md = editorStateJSONToMarkdown(savedJson);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function editorStateJSONToMarkdown(editorStateJSON: string, options?: MarkdownSerializerOptions): string;
|
|
40
|
+
//# sourceMappingURL=markdownSerializers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdownSerializers.d.ts","sourceRoot":"","sources":["../../src/RichTextEditor/markdownSerializers.ts"],"names":[],"mappings":"AA0BA,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAC,KAAK,EAAE,WAAW,EAAC,MAAM,SAAS,CAAC;AAEhD,yDAAyD;AACzD,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,YAAY,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC1C;;;OAGG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;CAC3C;AAYD;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,yBAA8B,GACtC,MAAM,CAUR;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,yBAA8B,GACtC,MAAM,CAKR"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file markdownSerializers.ts
|
|
5
|
+
* @input Uses @lexical/headless (createHeadlessEditor), @lexical/markdown
|
|
6
|
+
* ($convertFromMarkdownString / $convertToMarkdownString), and the shared
|
|
7
|
+
* DEFAULT_NODES set.
|
|
8
|
+
* @output Standalone Markdown <-> serialized EditorState helpers:
|
|
9
|
+
* markdownToEditorStateJSON, editorStateJSONToMarkdown.
|
|
10
|
+
* @position Re-exported from RichTextEditor/index.ts and the @astryxdesign/lab
|
|
11
|
+
* barrel. Complements the ref's getMarkdown() by working WITHOUT a mounted
|
|
12
|
+
* editor (e.g. to produce a `defaultValue` from Markdown on the server).
|
|
13
|
+
*
|
|
14
|
+
* SYNC: When modified, update:
|
|
15
|
+
* - /packages/lab/src/RichTextEditor/index.ts (exports)
|
|
16
|
+
* - /packages/lab/src/index.ts (barrel re-export)
|
|
17
|
+
* - /packages/lab/src/RichTextEditor/RichTextEditor.doc.mjs (usage notes)
|
|
18
|
+
* - /packages/lab/src/RichTextEditor/RichTextEditor.test.tsx (tests)
|
|
19
|
+
*
|
|
20
|
+
* NOTE: `@lexical/headless`, `@lexical/markdown`, and `lexical` are OPTIONAL
|
|
21
|
+
* peer dependencies (this is a canary lab module). Install them to use these
|
|
22
|
+
* helpers. `@lexical/headless` runs Lexical without a DOM, so these work in
|
|
23
|
+
* Node / SSR contexts.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { createHeadlessEditor } from '@lexical/headless';
|
|
27
|
+
import { TRANSFORMERS, $convertFromMarkdownString, $convertToMarkdownString } from '@lexical/markdown';
|
|
28
|
+
import { DEFAULT_NODES } from "./editorNodes.js";
|
|
29
|
+
|
|
30
|
+
/** Options shared by the Markdown serializer helpers. */
|
|
31
|
+
|
|
32
|
+
function createSerializerEditor(nodes) {
|
|
33
|
+
return createHeadlessEditor({
|
|
34
|
+
namespace: 'astryx-editor-serializer',
|
|
35
|
+
nodes: nodes ? [...DEFAULT_NODES, ...nodes] : [...DEFAULT_NODES],
|
|
36
|
+
onError(error) {
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Convert a Markdown string to a serialized Lexical `EditorState` JSON string
|
|
44
|
+
* — the same shape `RichTextEditor`'s `defaultValue` expects. Runs headless
|
|
45
|
+
* (no DOM), so it is safe in Node / SSR.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```
|
|
49
|
+
* const value = markdownToEditorStateJSON('# Title\n\nHello');
|
|
50
|
+
* <RichTextEditor label="Notes" defaultValue={value} />
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function markdownToEditorStateJSON(markdown, options = {}) {
|
|
54
|
+
const {
|
|
55
|
+
transformers = TRANSFORMERS,
|
|
56
|
+
nodes
|
|
57
|
+
} = options;
|
|
58
|
+
const editor = createSerializerEditor(nodes);
|
|
59
|
+
editor.update(() => {
|
|
60
|
+
$convertFromMarkdownString(markdown, [...transformers]);
|
|
61
|
+
}, {
|
|
62
|
+
discrete: true
|
|
63
|
+
});
|
|
64
|
+
return JSON.stringify(editor.getEditorState().toJSON());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Convert a serialized Lexical `EditorState` JSON string (e.g. the value
|
|
69
|
+
* produced by `RichTextEditor`'s `onChange` or `defaultValue`) to a Markdown
|
|
70
|
+
* string. Runs headless (no DOM), so it is safe in Node / SSR.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```
|
|
74
|
+
* const md = editorStateJSONToMarkdown(savedJson);
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function editorStateJSONToMarkdown(editorStateJSON, options = {}) {
|
|
78
|
+
const {
|
|
79
|
+
transformers = TRANSFORMERS,
|
|
80
|
+
nodes
|
|
81
|
+
} = options;
|
|
82
|
+
const editor = createSerializerEditor(nodes);
|
|
83
|
+
const state = editor.parseEditorState(editorStateJSON);
|
|
84
|
+
return state.read(() => $convertToMarkdownString([...transformers]));
|
|
85
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -28,5 +28,5 @@ export { SankeyChart, type SankeyChartProps, SankeyLink, type SankeyLinkProps, S
|
|
|
28
28
|
export * from './Stepper';
|
|
29
29
|
export * from './CircularProgress';
|
|
30
30
|
export { LogStream, type LogStreamProps, type LogEntry, type LogStreamLevel, } from './LogStream';
|
|
31
|
-
export { RichTextEditor, type RichTextEditorProps, type RichTextEditorRef, type RichTextEditorStatus, type RichTextEditorStatusType, type RichTextEditorSize, type Transformer, RichTextView, type RichTextViewProps, sharedEditorTheme, } from './RichTextEditor';
|
|
31
|
+
export { RichTextEditor, type RichTextEditorProps, type RichTextEditorRef, type RichTextEditorStatus, type RichTextEditorStatusType, type RichTextEditorSize, type Transformer, RichTextView, type RichTextViewProps, sharedEditorTheme, markdownToEditorStateJSON, editorStateJSONToMarkdown, type MarkdownSerializerOptions, } from './RichTextEditor';
|
|
32
32
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -64,4 +64,4 @@ export { LogStream } from "./LogStream/index.js";
|
|
|
64
64
|
|
|
65
65
|
// RichTextEditor — experimental Lexical WYSIWYG editor (RFC facebook/astryx#3899)
|
|
66
66
|
// Optional peer deps: lexical + @lexical/*. Read-only rendering via RichTextView.
|
|
67
|
-
export { RichTextEditor, RichTextView, sharedEditorTheme } from "./RichTextEditor/index.js";
|
|
67
|
+
export { RichTextEditor, RichTextView, sharedEditorTheme, markdownToEditorStateJSON, editorStateJSONToMarkdown } from "./RichTextEditor/index.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/lab",
|
|
3
|
-
"version": "0.2.0-canary.
|
|
3
|
+
"version": "0.2.0-canary.c75407e",
|
|
4
4
|
"description": "Experimental Astryx components — published to npm only under the @canary dist-tag for early testing; never released as a stable (latest) version.",
|
|
5
5
|
"author": "Meta Open Source",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,12 +45,13 @@
|
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@stylexjs/stylex": ">=0.10.0",
|
|
48
|
-
"@astryxdesign/core": "0.2.0-canary.
|
|
48
|
+
"@astryxdesign/core": "0.2.0-canary.c75407e",
|
|
49
49
|
"react": ">=19.0.0",
|
|
50
50
|
"react-dom": ">=19.0.0",
|
|
51
51
|
"lexical": "^0.46.0",
|
|
52
52
|
"@lexical/react": "^0.46.0",
|
|
53
53
|
"@lexical/markdown": "^0.46.0",
|
|
54
|
+
"@lexical/headless": "^0.46.0",
|
|
54
55
|
"@lexical/html": "^0.46.0",
|
|
55
56
|
"@lexical/link": "^0.46.0",
|
|
56
57
|
"@lexical/list": "^0.46.0",
|
|
@@ -65,6 +66,7 @@
|
|
|
65
66
|
},
|
|
66
67
|
"devDependencies": {
|
|
67
68
|
"@lexical/code": "^0.46.0",
|
|
69
|
+
"@lexical/headless": "^0.46.0",
|
|
68
70
|
"@lexical/html": "^0.46.0",
|
|
69
71
|
"@lexical/link": "^0.46.0",
|
|
70
72
|
"@lexical/list": "^0.46.0",
|
|
@@ -87,6 +89,9 @@
|
|
|
87
89
|
"@lexical/markdown": {
|
|
88
90
|
"optional": true
|
|
89
91
|
},
|
|
92
|
+
"@lexical/headless": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
90
95
|
"@lexical/html": {
|
|
91
96
|
"optional": true
|
|
92
97
|
},
|
|
@@ -155,6 +155,11 @@ export const docs = {
|
|
|
155
155
|
description:
|
|
156
156
|
'Use a ref (RichTextEditorRef) to imperatively focus(), clear(), read the state via getEditorState(), serialize to Markdown via getMarkdown() or HTML via getHTML(), or reach the LexicalEditor via getEditor(). The handle is available after mount. getMarkdown() uses the same transformers prop the editor is configured with. focus() and clear() are no-ops when the editor is read-only or disabled, and clear() resets to a single empty paragraph.',
|
|
157
157
|
},
|
|
158
|
+
{
|
|
159
|
+
guidance: true,
|
|
160
|
+
description:
|
|
161
|
+
'To produce a defaultValue from Markdown without mounting an editor (e.g. on the server), use markdownToEditorStateJSON(markdown). Convert the other way with editorStateJSONToMarkdown(json). Both run headless via @lexical/headless and accept the same transformers/nodes options as the editor.',
|
|
162
|
+
},
|
|
158
163
|
{
|
|
159
164
|
guidance: false,
|
|
160
165
|
description:
|
|
@@ -22,6 +22,10 @@ import {
|
|
|
22
22
|
} from '@lexical/markdown';
|
|
23
23
|
import {RichTextEditor, type RichTextEditorRef} from './RichTextEditor';
|
|
24
24
|
import {RichTextView} from './RichTextView';
|
|
25
|
+
import {
|
|
26
|
+
markdownToEditorStateJSON,
|
|
27
|
+
editorStateJSONToMarkdown,
|
|
28
|
+
} from './markdownSerializers';
|
|
25
29
|
|
|
26
30
|
// Small plugin that captures the editor instance so tests can drive real
|
|
27
31
|
// Lexical updates (jsdom does not implement contenteditable editing).
|
|
@@ -661,3 +665,42 @@ describe('RichTextView', () => {
|
|
|
661
665
|
expect(screen.queryByRole('textbox')).not.toBeInTheDocument();
|
|
662
666
|
});
|
|
663
667
|
});
|
|
668
|
+
|
|
669
|
+
describe('markdown serializers', () => {
|
|
670
|
+
it('markdownToEditorStateJSON produces a heading node from "# "', () => {
|
|
671
|
+
const json = markdownToEditorStateJSON('# Title');
|
|
672
|
+
const parsed = JSON.parse(json);
|
|
673
|
+
const first = parsed.root.children[0];
|
|
674
|
+
expect(first.type).toBe('heading');
|
|
675
|
+
expect(first.tag).toBe('h1');
|
|
676
|
+
expect(first.children[0].text).toBe('Title');
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
it('editorStateJSONToMarkdown round-trips a heading back to "# "', () => {
|
|
680
|
+
const json = markdownToEditorStateJSON('# Title');
|
|
681
|
+
expect(editorStateJSONToMarkdown(json)).toBe('# Title');
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
it('markdown round-trips through both helpers', () => {
|
|
685
|
+
const md = '# Heading\n\nSome **bold** text';
|
|
686
|
+
const json = markdownToEditorStateJSON(md);
|
|
687
|
+
expect(editorStateJSONToMarkdown(json)).toBe(md);
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
it('honors a custom (empty) transformers set — no heading syntax', () => {
|
|
691
|
+
// With no transformers, "# Title" is not recognized as a heading; it stays
|
|
692
|
+
// a plain paragraph, so serializing back yields the literal text.
|
|
693
|
+
const json = markdownToEditorStateJSON('# Title', {transformers: []});
|
|
694
|
+
const parsed = JSON.parse(json);
|
|
695
|
+
expect(parsed.root.children[0].type).toBe('paragraph');
|
|
696
|
+
expect(parsed.root.children[0].children[0].text).toBe('# Title');
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
it('produces JSON consumable as RichTextEditor defaultValue', async () => {
|
|
700
|
+
const value = markdownToEditorStateJSON('Hello world');
|
|
701
|
+
render(<RichTextEditor label="Notes" defaultValue={value} />);
|
|
702
|
+
await waitFor(() =>
|
|
703
|
+
expect(screen.getByRole('textbox').textContent).toContain('Hello world'),
|
|
704
|
+
);
|
|
705
|
+
});
|
|
706
|
+
});
|
|
@@ -76,11 +76,8 @@ import {
|
|
|
76
76
|
type Transformer,
|
|
77
77
|
} from '@lexical/markdown';
|
|
78
78
|
export type {Transformer} from '@lexical/markdown';
|
|
79
|
-
import {ListNode, ListItemNode} from '@lexical/list';
|
|
80
|
-
import {HeadingNode, QuoteNode} from '@lexical/rich-text';
|
|
81
|
-
import {LinkNode, AutoLinkNode} from '@lexical/link';
|
|
82
|
-
import {CodeNode, CodeHighlightNode} from '@lexical/code';
|
|
83
79
|
import {$generateHtmlFromNodes} from '@lexical/html';
|
|
80
|
+
import {DEFAULT_NODES} from './editorNodes';
|
|
84
81
|
import type {
|
|
85
82
|
EditorState,
|
|
86
83
|
Klass,
|
|
@@ -185,18 +182,6 @@ const sizeStyles = stylex.create({
|
|
|
185
182
|
},
|
|
186
183
|
});
|
|
187
184
|
|
|
188
|
-
/** The default OSS node set registered with the editor. */
|
|
189
|
-
const DEFAULT_NODES: ReadonlyArray<Klass<LexicalNode>> = [
|
|
190
|
-
HeadingNode,
|
|
191
|
-
QuoteNode,
|
|
192
|
-
ListNode,
|
|
193
|
-
ListItemNode,
|
|
194
|
-
LinkNode,
|
|
195
|
-
AutoLinkNode,
|
|
196
|
-
CodeNode,
|
|
197
|
-
CodeHighlightNode,
|
|
198
|
-
];
|
|
199
|
-
|
|
200
185
|
/**
|
|
201
186
|
* Fraction of `maxLength` at which the character counter begins announcing
|
|
202
187
|
* remaining/over-limit characters to screen readers. Matches TextArea.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file editorNodes.ts
|
|
5
|
+
* @input Imports the default Lexical node classes registered by the editor.
|
|
6
|
+
* @output Exports DEFAULT_NODES — the base OSS node set.
|
|
7
|
+
* @position Shared by RichTextEditor.tsx (editor config) and
|
|
8
|
+
* markdownSerializers.ts (headless conversion), so both register the same
|
|
9
|
+
* nodes and Markdown round-trips consistently.
|
|
10
|
+
*
|
|
11
|
+
* SYNC: When the default node set changes, both consumers pick it up here.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {ListNode, ListItemNode} from '@lexical/list';
|
|
15
|
+
import {HeadingNode, QuoteNode} from '@lexical/rich-text';
|
|
16
|
+
import {LinkNode, AutoLinkNode} from '@lexical/link';
|
|
17
|
+
import {CodeNode, CodeHighlightNode} from '@lexical/code';
|
|
18
|
+
import type {Klass, LexicalNode} from 'lexical';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The default OSS node set registered with the editor: headings, quotes,
|
|
22
|
+
* lists, links, and code. Extend via the `nodes` prop / option rather than
|
|
23
|
+
* editing this list.
|
|
24
|
+
*/
|
|
25
|
+
export const DEFAULT_NODES: ReadonlyArray<Klass<LexicalNode>> = [
|
|
26
|
+
HeadingNode,
|
|
27
|
+
QuoteNode,
|
|
28
|
+
ListNode,
|
|
29
|
+
ListItemNode,
|
|
30
|
+
LinkNode,
|
|
31
|
+
AutoLinkNode,
|
|
32
|
+
CodeNode,
|
|
33
|
+
CodeHighlightNode,
|
|
34
|
+
];
|
|
@@ -26,3 +26,9 @@ export {RichTextView} from './RichTextView';
|
|
|
26
26
|
export type {RichTextViewProps} from './RichTextView';
|
|
27
27
|
|
|
28
28
|
export {sharedEditorTheme} from './editorTheme';
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
markdownToEditorStateJSON,
|
|
32
|
+
editorStateJSONToMarkdown,
|
|
33
|
+
} from './markdownSerializers';
|
|
34
|
+
export type {MarkdownSerializerOptions} from './markdownSerializers';
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file markdownSerializers.ts
|
|
5
|
+
* @input Uses @lexical/headless (createHeadlessEditor), @lexical/markdown
|
|
6
|
+
* ($convertFromMarkdownString / $convertToMarkdownString), and the shared
|
|
7
|
+
* DEFAULT_NODES set.
|
|
8
|
+
* @output Standalone Markdown <-> serialized EditorState helpers:
|
|
9
|
+
* markdownToEditorStateJSON, editorStateJSONToMarkdown.
|
|
10
|
+
* @position Re-exported from RichTextEditor/index.ts and the @astryxdesign/lab
|
|
11
|
+
* barrel. Complements the ref's getMarkdown() by working WITHOUT a mounted
|
|
12
|
+
* editor (e.g. to produce a `defaultValue` from Markdown on the server).
|
|
13
|
+
*
|
|
14
|
+
* SYNC: When modified, update:
|
|
15
|
+
* - /packages/lab/src/RichTextEditor/index.ts (exports)
|
|
16
|
+
* - /packages/lab/src/index.ts (barrel re-export)
|
|
17
|
+
* - /packages/lab/src/RichTextEditor/RichTextEditor.doc.mjs (usage notes)
|
|
18
|
+
* - /packages/lab/src/RichTextEditor/RichTextEditor.test.tsx (tests)
|
|
19
|
+
*
|
|
20
|
+
* NOTE: `@lexical/headless`, `@lexical/markdown`, and `lexical` are OPTIONAL
|
|
21
|
+
* peer dependencies (this is a canary lab module). Install them to use these
|
|
22
|
+
* helpers. `@lexical/headless` runs Lexical without a DOM, so these work in
|
|
23
|
+
* Node / SSR contexts.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import {createHeadlessEditor} from '@lexical/headless';
|
|
27
|
+
import {
|
|
28
|
+
TRANSFORMERS,
|
|
29
|
+
$convertFromMarkdownString,
|
|
30
|
+
$convertToMarkdownString,
|
|
31
|
+
type Transformer,
|
|
32
|
+
} from '@lexical/markdown';
|
|
33
|
+
import {DEFAULT_NODES} from './editorNodes';
|
|
34
|
+
import type {Klass, LexicalNode} from 'lexical';
|
|
35
|
+
|
|
36
|
+
/** Options shared by the Markdown serializer helpers. */
|
|
37
|
+
export interface MarkdownSerializerOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Markdown transformers to use. Defaults to the standard `@lexical/markdown`
|
|
40
|
+
* `TRANSFORMERS`. Pass the same array you give `RichTextEditor`'s
|
|
41
|
+
* `transformers` prop so content round-trips consistently.
|
|
42
|
+
*/
|
|
43
|
+
transformers?: ReadonlyArray<Transformer>;
|
|
44
|
+
/**
|
|
45
|
+
* Extra Lexical nodes to register beyond the default OSS set, mirroring the
|
|
46
|
+
* editor's `nodes` prop. Required for custom node types to serialize.
|
|
47
|
+
*/
|
|
48
|
+
nodes?: ReadonlyArray<Klass<LexicalNode>>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function createSerializerEditor(nodes?: ReadonlyArray<Klass<LexicalNode>>) {
|
|
52
|
+
return createHeadlessEditor({
|
|
53
|
+
namespace: 'astryx-editor-serializer',
|
|
54
|
+
nodes: nodes ? [...DEFAULT_NODES, ...nodes] : [...DEFAULT_NODES],
|
|
55
|
+
onError(error: Error) {
|
|
56
|
+
throw error;
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Convert a Markdown string to a serialized Lexical `EditorState` JSON string
|
|
63
|
+
* — the same shape `RichTextEditor`'s `defaultValue` expects. Runs headless
|
|
64
|
+
* (no DOM), so it is safe in Node / SSR.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```
|
|
68
|
+
* const value = markdownToEditorStateJSON('# Title\n\nHello');
|
|
69
|
+
* <RichTextEditor label="Notes" defaultValue={value} />
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export function markdownToEditorStateJSON(
|
|
73
|
+
markdown: string,
|
|
74
|
+
options: MarkdownSerializerOptions = {},
|
|
75
|
+
): string {
|
|
76
|
+
const {transformers = TRANSFORMERS, nodes} = options;
|
|
77
|
+
const editor = createSerializerEditor(nodes);
|
|
78
|
+
editor.update(
|
|
79
|
+
() => {
|
|
80
|
+
$convertFromMarkdownString(markdown, [...transformers]);
|
|
81
|
+
},
|
|
82
|
+
{discrete: true},
|
|
83
|
+
);
|
|
84
|
+
return JSON.stringify(editor.getEditorState().toJSON());
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Convert a serialized Lexical `EditorState` JSON string (e.g. the value
|
|
89
|
+
* produced by `RichTextEditor`'s `onChange` or `defaultValue`) to a Markdown
|
|
90
|
+
* string. Runs headless (no DOM), so it is safe in Node / SSR.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```
|
|
94
|
+
* const md = editorStateJSONToMarkdown(savedJson);
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export function editorStateJSONToMarkdown(
|
|
98
|
+
editorStateJSON: string,
|
|
99
|
+
options: MarkdownSerializerOptions = {},
|
|
100
|
+
): string {
|
|
101
|
+
const {transformers = TRANSFORMERS, nodes} = options;
|
|
102
|
+
const editor = createSerializerEditor(nodes);
|
|
103
|
+
const state = editor.parseEditorState(editorStateJSON);
|
|
104
|
+
return state.read(() => $convertToMarkdownString([...transformers]));
|
|
105
|
+
}
|