@lexical/html 0.44.1-nightly.20260518.0 → 0.45.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/{DOMRenderExtension.d.ts → dist/DOMRenderExtension.d.ts} +12 -1
- package/dist/DOMRenderRuntime.d.ts +51 -0
- package/dist/LexicalHtml.dev.js +3192 -0
- package/dist/LexicalHtml.dev.mjs +3146 -0
- package/{LexicalHtml.js.flow → dist/LexicalHtml.js.flow} +16 -16
- package/dist/LexicalHtml.mjs +56 -0
- package/dist/LexicalHtml.node.mjs +54 -0
- package/dist/LexicalHtml.prod.js +9 -0
- package/dist/LexicalHtml.prod.mjs +9 -0
- package/dist/RenderContext.d.ts +68 -0
- package/{compileDOMRenderConfigOverrides.d.ts → dist/compileDOMRenderConfigOverrides.d.ts} +1 -1
- package/{constants.d.ts → dist/constants.d.ts} +2 -0
- package/dist/domOverride.d.ts +23 -0
- package/dist/import/CoreImportExtension.d.ts +11 -0
- package/dist/import/DOMImportExtension.d.ts +82 -0
- package/dist/import/HorizontalRuleImportExtension.d.ts +27 -0
- package/dist/import/ImportContext.d.ts +208 -0
- package/dist/import/compileImportRules.d.ts +50 -0
- package/dist/import/coreImportRules.d.ts +25 -0
- package/dist/import/defineImportRule.d.ts +32 -0
- package/dist/import/defineOverlayRules.d.ts +66 -0
- package/dist/import/index.d.ts +38 -0
- package/dist/import/inlineStylesFromStyleSheets.d.ts +28 -0
- package/dist/import/parseCss.d.ts +18 -0
- package/dist/import/runImport.d.ts +19 -0
- package/dist/import/schemas.d.ts +91 -0
- package/dist/import/sel.d.ts +74 -0
- package/dist/import/types.d.ts +394 -0
- package/dist/index.d.ts +44 -0
- package/{types.d.ts → dist/types.d.ts} +96 -8
- package/package.json +33 -18
- package/src/ContextRecord.ts +243 -0
- package/src/DOMRenderExtension.ts +96 -0
- package/src/DOMRenderRuntime.ts +265 -0
- package/src/RenderContext.ts +168 -0
- package/src/compileDOMRenderConfigOverrides.ts +416 -0
- package/src/constants.ts +18 -0
- package/src/domOverride.ts +46 -0
- package/src/import/CoreImportExtension.ts +26 -0
- package/src/import/DOMImportExtension.ts +221 -0
- package/src/import/HorizontalRuleImportExtension.ts +53 -0
- package/src/import/ImportContext.ts +339 -0
- package/src/import/compileImportRules.ts +178 -0
- package/src/import/coreImportRules.ts +485 -0
- package/src/import/defineImportRule.ts +40 -0
- package/src/import/defineOverlayRules.ts +105 -0
- package/src/import/index.ts +96 -0
- package/src/import/inlineStylesFromStyleSheets.ts +104 -0
- package/src/import/parseCss.ts +219 -0
- package/src/import/runImport.ts +245 -0
- package/src/import/schemas.ts +236 -0
- package/src/import/sel.ts +314 -0
- package/src/import/types.ts +471 -0
- package/src/index.ts +555 -0
- package/src/types.ts +470 -0
- package/LexicalHtml.dev.js +0 -914
- package/LexicalHtml.dev.mjs +0 -900
- package/LexicalHtml.mjs +0 -24
- package/LexicalHtml.node.mjs +0 -22
- package/LexicalHtml.prod.js +0 -9
- package/LexicalHtml.prod.mjs +0 -9
- package/RenderContext.d.ts +0 -32
- package/domOverride.d.ts +0 -18
- package/index.d.ts +0 -32
- /package/{ContextRecord.d.ts → dist/ContextRecord.d.ts} +0 -0
- /package/{LexicalHtml.js → dist/LexicalHtml.js} +0 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type {
|
|
9
|
+
ChildSchema,
|
|
10
|
+
DOMImportContext,
|
|
11
|
+
ImportChildrenOpts,
|
|
12
|
+
ImportNodeOpts,
|
|
13
|
+
ImportSession,
|
|
14
|
+
ImportStateConfig,
|
|
15
|
+
} from './types';
|
|
16
|
+
|
|
17
|
+
import {isDOMDocumentNode, type LexicalEditor, type LexicalNode} from 'lexical';
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
type CompiledDispatch,
|
|
21
|
+
type CompiledRule,
|
|
22
|
+
getDispatchIndices,
|
|
23
|
+
} from './compileImportRules';
|
|
24
|
+
import {
|
|
25
|
+
$getImportContextValue,
|
|
26
|
+
$withImportContext,
|
|
27
|
+
ImportOverlays,
|
|
28
|
+
} from './ImportContext';
|
|
29
|
+
import {$applySchema, RootSchema} from './schemas';
|
|
30
|
+
|
|
31
|
+
const __DEV__ = process.env.NODE_ENV !== 'production';
|
|
32
|
+
|
|
33
|
+
const NO_CAPTURES: Record<string, RegExpMatchArray> = Object.freeze(
|
|
34
|
+
{} as Record<string, RegExpMatchArray>,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
interface Runtime {
|
|
38
|
+
readonly dispatch: CompiledDispatch;
|
|
39
|
+
readonly editor: LexicalEditor;
|
|
40
|
+
readonly session: ImportSession;
|
|
41
|
+
/**
|
|
42
|
+
* Stack of overlay dispatchers installed via `$importChildren({rules})`.
|
|
43
|
+
* The most recently pushed overlay is at the highest index and is
|
|
44
|
+
* tried first; rules within an overlay are dispatched in their own
|
|
45
|
+
* registration order. When all overlay rules for a node have been
|
|
46
|
+
* exhausted (or have called `$next()` to defer), the main dispatcher
|
|
47
|
+
* is consulted. This lets app rules scope cost-bearing predicates to
|
|
48
|
+
* the subtrees where they apply.
|
|
49
|
+
*/
|
|
50
|
+
readonly overlays: CompiledDispatch[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function makeContext(
|
|
54
|
+
runtime: Runtime,
|
|
55
|
+
captures: Readonly<Record<string, RegExpMatchArray>>,
|
|
56
|
+
): DOMImportContext<Record<string, RegExpMatchArray>> {
|
|
57
|
+
const ctx: DOMImportContext<Record<string, RegExpMatchArray>> = {
|
|
58
|
+
$importChildren: (parent, opts) =>
|
|
59
|
+
$importChildrenInternal(runtime, parent, opts),
|
|
60
|
+
$importOne: (node, opts) => $importOneInternal(runtime, node, opts),
|
|
61
|
+
captures,
|
|
62
|
+
get<V>(cfg: ImportStateConfig<V>): V {
|
|
63
|
+
return $getImportContextValue(cfg, runtime.editor);
|
|
64
|
+
},
|
|
65
|
+
session: runtime.session,
|
|
66
|
+
};
|
|
67
|
+
return ctx;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function $importChildrenInternal(
|
|
71
|
+
runtime: Runtime,
|
|
72
|
+
parent: ParentNode,
|
|
73
|
+
opts: ImportChildrenOpts | undefined,
|
|
74
|
+
): LexicalNode[] {
|
|
75
|
+
const overlay = opts && opts.rules ? opts.rules.dispatch : undefined;
|
|
76
|
+
if (overlay) {
|
|
77
|
+
runtime.overlays.push(overlay);
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const run = () => $importChildrenRun(runtime, parent, opts);
|
|
81
|
+
return opts && opts.context
|
|
82
|
+
? $withImportContext(opts.context, runtime.editor)(run)
|
|
83
|
+
: run();
|
|
84
|
+
} finally {
|
|
85
|
+
if (overlay) {
|
|
86
|
+
runtime.overlays.pop();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function $importChildrenRun(
|
|
92
|
+
runtime: Runtime,
|
|
93
|
+
parent: ParentNode,
|
|
94
|
+
opts: ImportChildrenOpts | undefined,
|
|
95
|
+
): LexicalNode[] {
|
|
96
|
+
const onChild = opts && opts.$onChild;
|
|
97
|
+
const collected: LexicalNode[] = [];
|
|
98
|
+
for (const child of Array.from(parent.childNodes)) {
|
|
99
|
+
const produced = $importOneInternal(runtime, child, undefined);
|
|
100
|
+
for (const lex of produced) {
|
|
101
|
+
const result = onChild ? onChild(lex) : lex;
|
|
102
|
+
if (result != null) {
|
|
103
|
+
collected.push(result);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const afterApplied = opts && opts.$after ? opts.$after(collected) : collected;
|
|
108
|
+
const schema: ChildSchema | undefined = opts && opts.schema;
|
|
109
|
+
if (!schema) {
|
|
110
|
+
return afterApplied;
|
|
111
|
+
}
|
|
112
|
+
return $applySchema(schema, afterApplied, null, parent);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function $importOneInternal(
|
|
116
|
+
runtime: Runtime,
|
|
117
|
+
node: Node,
|
|
118
|
+
opts: ImportNodeOpts | undefined,
|
|
119
|
+
): LexicalNode[] {
|
|
120
|
+
const run = () => $dispatch(runtime, node);
|
|
121
|
+
const out =
|
|
122
|
+
opts && opts.context
|
|
123
|
+
? $withImportContext(opts.context, runtime.editor)(run)
|
|
124
|
+
: run();
|
|
125
|
+
// Surface to callers as a mutable array per the DOMImportContext contract.
|
|
126
|
+
return out as LexicalNode[];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Build the candidate (dispatch, indices) list for `node`. Overlays are
|
|
131
|
+
* tried first in top-of-stack order; the main dispatcher comes last. The
|
|
132
|
+
* `$next()` chain walks through all of them in sequence — an overlay rule
|
|
133
|
+
* can defer to a lower overlay rule, or all the way through to a main
|
|
134
|
+
* rule, just by calling `$next()`.
|
|
135
|
+
*/
|
|
136
|
+
function getCandidates(
|
|
137
|
+
runtime: Runtime,
|
|
138
|
+
node: Node,
|
|
139
|
+
): readonly {dispatch: CompiledDispatch; indices: readonly number[]}[] {
|
|
140
|
+
const candidates: {
|
|
141
|
+
dispatch: CompiledDispatch;
|
|
142
|
+
indices: readonly number[];
|
|
143
|
+
}[] = [];
|
|
144
|
+
for (let i = runtime.overlays.length - 1; i >= 0; i--) {
|
|
145
|
+
const d = runtime.overlays[i];
|
|
146
|
+
const idx = getDispatchIndices(d, node);
|
|
147
|
+
if (idx.length > 0) {
|
|
148
|
+
candidates.push({dispatch: d, indices: idx});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const mainIdx = getDispatchIndices(runtime.dispatch, node);
|
|
152
|
+
if (mainIdx.length > 0) {
|
|
153
|
+
candidates.push({dispatch: runtime.dispatch, indices: mainIdx});
|
|
154
|
+
}
|
|
155
|
+
return candidates;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function $dispatch(runtime: Runtime, node: Node): readonly LexicalNode[] {
|
|
159
|
+
const candidates = getCandidates(runtime, node);
|
|
160
|
+
if (candidates.length === 0) {
|
|
161
|
+
return $hoistChildrenOf(runtime, node);
|
|
162
|
+
}
|
|
163
|
+
let groupCursor = 0;
|
|
164
|
+
let ruleCursor = 0;
|
|
165
|
+
const $next = (): readonly LexicalNode[] => {
|
|
166
|
+
while (groupCursor < candidates.length) {
|
|
167
|
+
const {dispatch, indices} = candidates[groupCursor];
|
|
168
|
+
while (ruleCursor < indices.length) {
|
|
169
|
+
const idx = indices[ruleCursor++];
|
|
170
|
+
const rule: CompiledRule = dispatch.rules[idx];
|
|
171
|
+
const captures: Record<string, RegExpMatchArray> = {};
|
|
172
|
+
if (rule.predicate(node, captures)) {
|
|
173
|
+
const ctx = makeContext(
|
|
174
|
+
runtime,
|
|
175
|
+
Object.keys(captures).length === 0 ? NO_CAPTURES : captures,
|
|
176
|
+
);
|
|
177
|
+
try {
|
|
178
|
+
return rule.$import(ctx, node, $next);
|
|
179
|
+
} catch (e) {
|
|
180
|
+
if (__DEV__) {
|
|
181
|
+
console.error(
|
|
182
|
+
`[lexical] DOM import rule "${rule.name}" threw on node`,
|
|
183
|
+
node,
|
|
184
|
+
e,
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
throw e;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
groupCursor++;
|
|
192
|
+
ruleCursor = 0;
|
|
193
|
+
}
|
|
194
|
+
return $hoistChildrenOf(runtime, node);
|
|
195
|
+
};
|
|
196
|
+
return $next();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Fallback when no rule matched and `$next()` was called past the end of the
|
|
201
|
+
* chain: hoist the element's children to take its place, recursively. Pure
|
|
202
|
+
* elements with no rule become invisible, matching the legacy
|
|
203
|
+
* `$createNodesFromDOM` hoisting behavior.
|
|
204
|
+
*/
|
|
205
|
+
function $hoistChildrenOf(runtime: Runtime, node: Node): LexicalNode[] {
|
|
206
|
+
if (node.childNodes.length === 0) {
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
const collected: LexicalNode[] = [];
|
|
210
|
+
for (const child of Array.from(node.childNodes)) {
|
|
211
|
+
const produced = $importOneInternal(runtime, child, undefined);
|
|
212
|
+
for (const lex of produced) {
|
|
213
|
+
collected.push(lex);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return collected;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Top-level walker for a compiled dispatcher. Iterates the DOM children of
|
|
221
|
+
* `dom` (using the document body if a {@link Document} is passed) and
|
|
222
|
+
* applies `RootSchema` to the produced lexical nodes so runs of inlines are
|
|
223
|
+
* wrapped in paragraphs — same shape as the legacy `$generateNodesFromDOM`.
|
|
224
|
+
*
|
|
225
|
+
* @internal
|
|
226
|
+
*/
|
|
227
|
+
export function $runImport(
|
|
228
|
+
dispatch: CompiledDispatch,
|
|
229
|
+
editor: LexicalEditor,
|
|
230
|
+
dom: Document | ParentNode,
|
|
231
|
+
session: ImportSession,
|
|
232
|
+
): LexicalNode[] {
|
|
233
|
+
// Prime the overlay stack with any overlays a preprocess wrote to
|
|
234
|
+
// ImportOverlays. These remain in effect for the entire walk; nested
|
|
235
|
+
// `$importChildren({rules})` calls push on top.
|
|
236
|
+
const installed = session.get(ImportOverlays);
|
|
237
|
+
const runtime: Runtime = {
|
|
238
|
+
dispatch,
|
|
239
|
+
editor,
|
|
240
|
+
overlays: installed.map(o => o.dispatch),
|
|
241
|
+
session,
|
|
242
|
+
};
|
|
243
|
+
const rootParent: ParentNode = isDOMDocumentNode(dom) ? dom.body : dom;
|
|
244
|
+
return $importChildrenRun(runtime, rootParent, {schema: RootSchema});
|
|
245
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type {ChildSchema} from './types';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
$createParagraphNode,
|
|
12
|
+
$isBlockElementNode,
|
|
13
|
+
$isDecoratorNode,
|
|
14
|
+
$isElementNode,
|
|
15
|
+
type ElementNode,
|
|
16
|
+
isHTMLElement,
|
|
17
|
+
type LexicalNode,
|
|
18
|
+
} from 'lexical';
|
|
19
|
+
|
|
20
|
+
import {isAlignmentValue} from './coreImportRules';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* True if the node fills a block slot at the root or inside another
|
|
24
|
+
* block — covers both ElementNode-style blocks (paragraph, heading,
|
|
25
|
+
* quote) and block-level DecoratorNodes (HorizontalRuleNode,
|
|
26
|
+
* ImageNode-as-block, etc.). Used by {@link BlockSchema},
|
|
27
|
+
* {@link RootSchema}, and {@link NestedBlockSchema}.
|
|
28
|
+
*
|
|
29
|
+
* @experimental
|
|
30
|
+
*/
|
|
31
|
+
export function $isBlockLevel(node: LexicalNode): boolean {
|
|
32
|
+
return (
|
|
33
|
+
$isBlockElementNode(node) || ($isDecoratorNode(node) && !node.isInline())
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Distribute an inline wrapper (`LinkNode`, `MarkNode`, …) across a
|
|
39
|
+
* heterogeneous run of children produced by `$importChildren`, lifting
|
|
40
|
+
* any block children to the top level while keeping the wrapper around
|
|
41
|
+
* the leaf inline content.
|
|
42
|
+
*
|
|
43
|
+
* Use from a rule whose DOM source is an inline element that the
|
|
44
|
+
* browser permitted to enclose block elements — the canonical case is
|
|
45
|
+
* `<a href="…"><h1>title</h1><div>body</div></a>`, which a link rule
|
|
46
|
+
* wants to surface as two block siblings (heading + paragraph), each
|
|
47
|
+
* with its own link wrapping the original inline content. Schemas
|
|
48
|
+
* can't express this because they reason about a parent's children
|
|
49
|
+
* only — they cannot lift the parent out of itself.
|
|
50
|
+
*
|
|
51
|
+
* For each top-level child:
|
|
52
|
+
* - **Inline children** are collected into runs; each run is wrapped
|
|
53
|
+
* in a single fresh wrapper (from `$makeWrapper()`).
|
|
54
|
+
* - **Block children** are descended into: their own children are
|
|
55
|
+
* recursively distributed with `$makeWrapper`, then re-attached so
|
|
56
|
+
* the block keeps its position at the top level.
|
|
57
|
+
*
|
|
58
|
+
* The returned list will contain a mix of blocks and wrapped inline
|
|
59
|
+
* runs. The enclosing schema (typically {@link BlockSchema}) will
|
|
60
|
+
* then package those inline wrappers into paragraphs as usual.
|
|
61
|
+
*
|
|
62
|
+
* @experimental
|
|
63
|
+
*/
|
|
64
|
+
export function $distributeInlineWrapper(
|
|
65
|
+
children: readonly LexicalNode[],
|
|
66
|
+
$makeWrapper: () => ElementNode,
|
|
67
|
+
): LexicalNode[] {
|
|
68
|
+
const out: LexicalNode[] = [];
|
|
69
|
+
let inlineRun: LexicalNode[] = [];
|
|
70
|
+
|
|
71
|
+
const flushInline = () => {
|
|
72
|
+
if (inlineRun.length === 0) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
out.push($makeWrapper().splice(0, 0, inlineRun));
|
|
76
|
+
inlineRun = [];
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
for (const child of children) {
|
|
80
|
+
if ($isBlockLevel(child)) {
|
|
81
|
+
flushInline();
|
|
82
|
+
// Recursively distribute the wrapper into the block's own
|
|
83
|
+
// children. A block DecoratorNode (no children) is left alone.
|
|
84
|
+
if ($isElementNode(child)) {
|
|
85
|
+
const wrapped = $distributeInlineWrapper(
|
|
86
|
+
child.getChildren(),
|
|
87
|
+
$makeWrapper,
|
|
88
|
+
);
|
|
89
|
+
child.splice(0, child.getChildrenSize(), wrapped);
|
|
90
|
+
}
|
|
91
|
+
out.push(child);
|
|
92
|
+
} else {
|
|
93
|
+
inlineRun.push(child);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
flushInline();
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Apply a {@link ChildSchema} to a flat list of children produced by
|
|
102
|
+
* `$importChildren`. Walks the list once, partitions into accepted vs.
|
|
103
|
+
* rejected runs, packages or drops rejected runs, then runs `$finalize`.
|
|
104
|
+
*
|
|
105
|
+
* @internal
|
|
106
|
+
*/
|
|
107
|
+
export function $applySchema(
|
|
108
|
+
schema: ChildSchema,
|
|
109
|
+
children: LexicalNode[],
|
|
110
|
+
parent: LexicalNode | null,
|
|
111
|
+
domParent: Node | null,
|
|
112
|
+
): LexicalNode[] {
|
|
113
|
+
const out: LexicalNode[] = [];
|
|
114
|
+
let run: LexicalNode[] | null = null;
|
|
115
|
+
|
|
116
|
+
const flushRun = () => {
|
|
117
|
+
if (run === null) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const rejected = run;
|
|
121
|
+
run = null;
|
|
122
|
+
if (schema.$packageRun) {
|
|
123
|
+
const packaged = schema.$packageRun(rejected, parent, domParent);
|
|
124
|
+
if (packaged.length > 0) {
|
|
125
|
+
for (const n of packaged) {
|
|
126
|
+
out.push(n);
|
|
127
|
+
}
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// No $packageRun (or it returned []) — apply onReject. 'drop' (default)
|
|
132
|
+
// discards the run. 'hoist' lets it through unchanged at this level.
|
|
133
|
+
if (schema.onReject === 'hoist') {
|
|
134
|
+
for (const n of rejected) {
|
|
135
|
+
out.push(n);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
for (const child of children) {
|
|
141
|
+
if (schema.$accepts(child, parent)) {
|
|
142
|
+
flushRun();
|
|
143
|
+
out.push(child);
|
|
144
|
+
} else {
|
|
145
|
+
if (run === null) {
|
|
146
|
+
run = [];
|
|
147
|
+
}
|
|
148
|
+
run.push(child);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
flushRun();
|
|
152
|
+
|
|
153
|
+
return schema.$finalize ? schema.$finalize(out, parent) : out;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Wrap a run of inline lexical nodes in a fresh paragraph, propagating the
|
|
158
|
+
* `text-align` of `domParent` as the paragraph's format type (matching the
|
|
159
|
+
* legacy `wrapContinuousInlines` behavior).
|
|
160
|
+
*/
|
|
161
|
+
function $paragraphPackageRun(
|
|
162
|
+
run: LexicalNode[],
|
|
163
|
+
_parent: LexicalNode | null,
|
|
164
|
+
domParent: Node | null,
|
|
165
|
+
): LexicalNode[] {
|
|
166
|
+
const paragraph = $createParagraphNode();
|
|
167
|
+
if (isHTMLElement(domParent)) {
|
|
168
|
+
const textAlign = domParent.style.textAlign;
|
|
169
|
+
if (isAlignmentValue(textAlign)) {
|
|
170
|
+
paragraph.setFormat(textAlign);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return [paragraph.splice(0, 0, run)];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Default schema for block-level positions (root of the document, the body
|
|
178
|
+
* of a block element node). Accepts block lexical nodes; packages runs of
|
|
179
|
+
* inline children into fresh paragraph nodes.
|
|
180
|
+
*
|
|
181
|
+
* @experimental
|
|
182
|
+
*/
|
|
183
|
+
export const BlockSchema: ChildSchema = {
|
|
184
|
+
$accepts: $isBlockLevel,
|
|
185
|
+
$packageRun: $paragraphPackageRun,
|
|
186
|
+
name: 'BlockSchema',
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Schema for inline-only positions (the body of an inline lexical node such
|
|
191
|
+
* as a link). Accepts non-block lexical nodes; runs of block children are
|
|
192
|
+
* dropped (`onReject: 'drop'` is the default).
|
|
193
|
+
*
|
|
194
|
+
* @experimental
|
|
195
|
+
*/
|
|
196
|
+
export const InlineSchema: ChildSchema = {
|
|
197
|
+
$accepts: child => !$isBlockLevel(child),
|
|
198
|
+
name: 'InlineSchema',
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Schema for nested block positions — the equivalent of the legacy
|
|
203
|
+
* `ArtificialNode__DO_NOT_USE` flow used when a block DOM element appears
|
|
204
|
+
* inside another block lexical ancestor. Accepts block nodes; runs of inline
|
|
205
|
+
* children are emitted with a line break between consecutive runs (instead
|
|
206
|
+
* of being wrapped in a paragraph, which would introduce an extra level of
|
|
207
|
+
* nesting).
|
|
208
|
+
*
|
|
209
|
+
* @experimental
|
|
210
|
+
*/
|
|
211
|
+
export const NestedBlockSchema: ChildSchema = {
|
|
212
|
+
$accepts: $isBlockLevel,
|
|
213
|
+
/**
|
|
214
|
+
* Pass an inline run through unchanged. Because the schema iterator only
|
|
215
|
+
* groups *maximal* rejected runs (each separated from the next by an
|
|
216
|
+
* accepted block child), the legacy "linebreak between adjacent inline
|
|
217
|
+
* groups" case never arises — adjacent inline siblings are already
|
|
218
|
+
* coalesced into one run.
|
|
219
|
+
*/
|
|
220
|
+
$packageRun: run => run,
|
|
221
|
+
name: 'NestedBlockSchema',
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Schema for the topmost level of `$generateNodesFromDOM`. Identical to
|
|
226
|
+
* {@link BlockSchema}; aliased for clarity at the entry point and so it can
|
|
227
|
+
* be overridden separately in the future (e.g. to synthesize a `ListNode`
|
|
228
|
+
* around runs of orphan `ListItemNode`s).
|
|
229
|
+
*
|
|
230
|
+
* @experimental
|
|
231
|
+
*/
|
|
232
|
+
export const RootSchema: ChildSchema = {
|
|
233
|
+
$accepts: $isBlockLevel,
|
|
234
|
+
$packageRun: $paragraphPackageRun,
|
|
235
|
+
name: 'RootSchema',
|
|
236
|
+
};
|