@lexical/html 0.44.1-nightly.20260519.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.
Files changed (66) hide show
  1. package/{DOMRenderExtension.d.ts → dist/DOMRenderExtension.d.ts} +12 -1
  2. package/dist/DOMRenderRuntime.d.ts +51 -0
  3. package/dist/LexicalHtml.dev.js +3192 -0
  4. package/dist/LexicalHtml.dev.mjs +3146 -0
  5. package/{LexicalHtml.js.flow → dist/LexicalHtml.js.flow} +16 -16
  6. package/dist/LexicalHtml.mjs +56 -0
  7. package/dist/LexicalHtml.node.mjs +54 -0
  8. package/dist/LexicalHtml.prod.js +9 -0
  9. package/dist/LexicalHtml.prod.mjs +9 -0
  10. package/dist/RenderContext.d.ts +68 -0
  11. package/{compileDOMRenderConfigOverrides.d.ts → dist/compileDOMRenderConfigOverrides.d.ts} +1 -1
  12. package/{constants.d.ts → dist/constants.d.ts} +2 -0
  13. package/dist/domOverride.d.ts +23 -0
  14. package/dist/import/CoreImportExtension.d.ts +11 -0
  15. package/dist/import/DOMImportExtension.d.ts +82 -0
  16. package/dist/import/HorizontalRuleImportExtension.d.ts +27 -0
  17. package/dist/import/ImportContext.d.ts +208 -0
  18. package/dist/import/compileImportRules.d.ts +50 -0
  19. package/dist/import/coreImportRules.d.ts +25 -0
  20. package/dist/import/defineImportRule.d.ts +32 -0
  21. package/dist/import/defineOverlayRules.d.ts +66 -0
  22. package/dist/import/index.d.ts +38 -0
  23. package/dist/import/inlineStylesFromStyleSheets.d.ts +28 -0
  24. package/dist/import/parseCss.d.ts +18 -0
  25. package/dist/import/runImport.d.ts +19 -0
  26. package/dist/import/schemas.d.ts +91 -0
  27. package/dist/import/sel.d.ts +74 -0
  28. package/dist/import/types.d.ts +394 -0
  29. package/dist/index.d.ts +44 -0
  30. package/{types.d.ts → dist/types.d.ts} +96 -8
  31. package/package.json +33 -18
  32. package/src/ContextRecord.ts +243 -0
  33. package/src/DOMRenderExtension.ts +96 -0
  34. package/src/DOMRenderRuntime.ts +265 -0
  35. package/src/RenderContext.ts +168 -0
  36. package/src/compileDOMRenderConfigOverrides.ts +416 -0
  37. package/src/constants.ts +18 -0
  38. package/src/domOverride.ts +46 -0
  39. package/src/import/CoreImportExtension.ts +26 -0
  40. package/src/import/DOMImportExtension.ts +221 -0
  41. package/src/import/HorizontalRuleImportExtension.ts +53 -0
  42. package/src/import/ImportContext.ts +339 -0
  43. package/src/import/compileImportRules.ts +178 -0
  44. package/src/import/coreImportRules.ts +485 -0
  45. package/src/import/defineImportRule.ts +40 -0
  46. package/src/import/defineOverlayRules.ts +105 -0
  47. package/src/import/index.ts +96 -0
  48. package/src/import/inlineStylesFromStyleSheets.ts +104 -0
  49. package/src/import/parseCss.ts +219 -0
  50. package/src/import/runImport.ts +245 -0
  51. package/src/import/schemas.ts +236 -0
  52. package/src/import/sel.ts +314 -0
  53. package/src/import/types.ts +471 -0
  54. package/src/index.ts +555 -0
  55. package/src/types.ts +470 -0
  56. package/LexicalHtml.dev.js +0 -914
  57. package/LexicalHtml.dev.mjs +0 -900
  58. package/LexicalHtml.mjs +0 -24
  59. package/LexicalHtml.node.mjs +0 -22
  60. package/LexicalHtml.prod.js +0 -9
  61. package/LexicalHtml.prod.mjs +0 -9
  62. package/RenderContext.d.ts +0 -32
  63. package/domOverride.d.ts +0 -18
  64. package/index.d.ts +0 -32
  65. /package/{ContextRecord.d.ts → dist/ContextRecord.d.ts} +0 -0
  66. /package/{LexicalHtml.js → dist/LexicalHtml.js} +0 -0
@@ -0,0 +1,168 @@
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 {EditorDOMRenderConfig} from 'lexical';
9
+
10
+ import {getPeerDependencyFromEditor} from '@lexical/extension';
11
+ import {$getEditor, $getEditorDOMRenderConfig, LexicalEditor} from 'lexical';
12
+
13
+ import {DOMRenderContextSymbol, DOMRenderExtensionName} from './constants';
14
+ import {
15
+ $withContext,
16
+ createContextState,
17
+ getContextRecord,
18
+ getContextValue,
19
+ } from './ContextRecord';
20
+ import {DOMRenderExtension} from './DOMRenderExtension';
21
+ import {
22
+ AnyRenderStateConfigPairOrUpdater,
23
+ ContextRecord,
24
+ RenderStateConfig,
25
+ } from './types';
26
+
27
+ /**
28
+ * Create a context state to be used during render.
29
+ *
30
+ * Note that to support the ValueOrUpdater pattern you can not use a
31
+ * function for V (but you may wrap it in an array or object).
32
+ *
33
+ * @experimental
34
+ * @__NO_SIDE_EFFECTS__
35
+ */
36
+ export function createRenderState<V>(
37
+ name: string,
38
+ getDefaultValue: () => V,
39
+ isEqual?: (a: V, b: V) => boolean,
40
+ ): RenderStateConfig<V> {
41
+ return createContextState(
42
+ DOMRenderContextSymbol,
43
+ name,
44
+ getDefaultValue,
45
+ isEqual,
46
+ );
47
+ }
48
+
49
+ /**
50
+ * Render context state that is true if the export was initiated from the root of the document.
51
+ * @experimental
52
+ */
53
+ export const RenderContextRoot = createRenderState('root', Boolean);
54
+
55
+ /**
56
+ * Render context state that is true if this is an export operation ($generateHtmlFromNodes).
57
+ * @experimental
58
+ */
59
+ export const RenderContextExport = createRenderState('isExport', Boolean);
60
+
61
+ function getDefaultRenderContext(
62
+ editor: LexicalEditor,
63
+ ): undefined | ContextRecord<typeof DOMRenderContextSymbol> {
64
+ const dep = getPeerDependencyFromEditor<typeof DOMRenderExtension>(
65
+ editor,
66
+ DOMRenderExtensionName,
67
+ );
68
+ return dep ? dep.output.defaults : undefined;
69
+ }
70
+
71
+ function getRenderContext(
72
+ editor: LexicalEditor,
73
+ ): undefined | ContextRecord<typeof DOMRenderContextSymbol> {
74
+ return (
75
+ getContextRecord(DOMRenderContextSymbol, editor) ||
76
+ getDefaultRenderContext(editor)
77
+ );
78
+ }
79
+
80
+ /**
81
+ * Get a render context value during a DOM render or export operation.
82
+ * @experimental
83
+ */
84
+ export function $getRenderContextValue<V>(
85
+ cfg: RenderStateConfig<V>,
86
+ editor: LexicalEditor = $getEditor(),
87
+ ): V {
88
+ return getContextValue(getRenderContext(editor), cfg);
89
+ }
90
+
91
+ function getRuntime(editor: LexicalEditor) {
92
+ const dep = getPeerDependencyFromEditor<typeof DOMRenderExtension>(
93
+ editor,
94
+ DOMRenderExtensionName,
95
+ );
96
+ return dep ? dep.output.runtime : undefined;
97
+ }
98
+
99
+ /**
100
+ * Imperatively set a value in the persistent editor render context.
101
+ *
102
+ * Unlike {@link $withRenderContext} (which scopes values to a callback), this
103
+ * persists on the editor. If the change flips any override's
104
+ * `disabledForEditor` result, the resident render config is recompiled and the
105
+ * affected nodes are re-rendered. No-op if {@link DOMRenderExtension} is not
106
+ * installed.
107
+ *
108
+ * @experimental
109
+ */
110
+ export function $setRenderContextValue<V>(
111
+ cfg: RenderStateConfig<V>,
112
+ value: V,
113
+ editor: LexicalEditor = $getEditor(),
114
+ ): void {
115
+ const runtime = getRuntime(editor);
116
+ if (runtime) {
117
+ runtime.setContextValue(cfg, value);
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Imperatively update a value in the persistent editor render context with an
123
+ * updater function. See {@link $setRenderContextValue}.
124
+ *
125
+ * @experimental
126
+ */
127
+ export function $updateRenderContextValue<V>(
128
+ cfg: RenderStateConfig<V>,
129
+ updater: (prev: V) => V,
130
+ editor: LexicalEditor = $getEditor(),
131
+ ): void {
132
+ const runtime = getRuntime(editor);
133
+ if (runtime) {
134
+ runtime.setContextValue(
135
+ cfg,
136
+ updater(getContextValue(runtime.editorContext, cfg)),
137
+ );
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Resolve the {@link EditorDOMRenderConfig} to use for the current
143
+ * export/generate session, applying any `disabledForSession` overrides against
144
+ * the active session context. Falls back to the editor's resident config when
145
+ * {@link DOMRenderExtension} is not installed.
146
+ *
147
+ * @experimental
148
+ */
149
+ export function $getSessionDOMRenderConfig(
150
+ editor: LexicalEditor = $getEditor(),
151
+ ): EditorDOMRenderConfig {
152
+ const runtime = getRuntime(editor);
153
+ return runtime
154
+ ? runtime.getSessionConfig()
155
+ : $getEditorDOMRenderConfig(editor);
156
+ }
157
+
158
+ /**
159
+ * Execute a callback within a render context with the given config pairs.
160
+ * @experimental
161
+ */
162
+ export const $withRenderContext: (
163
+ cfg: readonly AnyRenderStateConfigPairOrUpdater[],
164
+ editor?: LexicalEditor,
165
+ ) => <T>(f: () => T) => T = $withContext(
166
+ DOMRenderContextSymbol,
167
+ getDefaultRenderContext,
168
+ );
@@ -0,0 +1,416 @@
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 {getKnownTypesAndNodes} from '@lexical/extension';
9
+ import invariant from '@lexical/internal/invariant';
10
+ import {
11
+ $isLexicalNode,
12
+ DEFAULT_EDITOR_DOM_CONFIG,
13
+ type EditorDOMRenderConfig,
14
+ getStaticNodeConfig,
15
+ InitialEditorConfig,
16
+ Klass,
17
+ LexicalEditor,
18
+ type LexicalNode,
19
+ } from 'lexical';
20
+
21
+ import {ALWAYS_TRUE} from './constants';
22
+ import {AnyDOMRenderMatch, DOMRenderConfig, DOMRenderMatch} from './types';
23
+
24
+ interface TypeRecord {
25
+ readonly klass: Klass<LexicalNode>;
26
+ readonly types: {[NodeAndSubclasses in string]?: boolean};
27
+ }
28
+
29
+ type TypeTree = {
30
+ [NodeType in string]?: TypeRecord;
31
+ };
32
+
33
+ export function buildTypeTree(
34
+ editorConfig: Pick<InitialEditorConfig, 'nodes'>,
35
+ ): TypeTree {
36
+ const t: TypeTree = {};
37
+ const {nodes} = getKnownTypesAndNodes(editorConfig);
38
+ for (const klass of nodes) {
39
+ const type = klass.getType();
40
+ t[type] = {klass, types: {}};
41
+ }
42
+ for (const baseRec of Object.values(t)) {
43
+ if (baseRec) {
44
+ const baseType = baseRec.klass.getType();
45
+ for (
46
+ let {klass} = baseRec;
47
+ $isLexicalNode(klass.prototype);
48
+ klass = Object.getPrototypeOf(klass)
49
+ ) {
50
+ const {ownNodeType} = getStaticNodeConfig(klass);
51
+ const superRec = ownNodeType && t[ownNodeType];
52
+ if (superRec) {
53
+ superRec.types[baseType] = true;
54
+ }
55
+ }
56
+ }
57
+ }
58
+ return t;
59
+ }
60
+
61
+ type PredicateOrTypes =
62
+ | ((node: LexicalNode) => boolean)
63
+ | {[NodeType in string]?: true};
64
+ type TypeRender<T> = {[NodeType in string]?: T[]};
65
+ type AnyRender<T> =
66
+ | readonly [(node: LexicalNode) => boolean, T]
67
+ | readonly ['types', TypeRender<T>];
68
+
69
+ type PreEditorDOMRenderConfig = {
70
+ [K in keyof EditorDOMRenderConfig]: AnyRender<AnyDOMRenderMatch[K]>[];
71
+ };
72
+
73
+ function buildNodePredicate<T extends LexicalNode>(klass: Klass<T>) {
74
+ return (node: LexicalNode): node is T => node instanceof klass;
75
+ }
76
+
77
+ function getPredicate(
78
+ typeTree: TypeTree,
79
+ {nodes}: DOMRenderMatch<LexicalNode>,
80
+ ): {[NodeType in string]?: true} | ((node: LexicalNode) => boolean) {
81
+ if (nodes === '*') {
82
+ return ALWAYS_TRUE;
83
+ }
84
+ let types: undefined | {[NodeType in string]?: true} = {};
85
+ const predicates: ((node: LexicalNode) => boolean)[] = [];
86
+ for (const klassOrPredicate of nodes) {
87
+ if ('getType' in klassOrPredicate) {
88
+ const type = klassOrPredicate.getType();
89
+ if (types) {
90
+ const tree = typeTree[type];
91
+ invariant(
92
+ tree !== undefined,
93
+ 'Node class %s with type %s not registered in editor',
94
+ klassOrPredicate.name,
95
+ type,
96
+ );
97
+ types = Object.assign(types, tree.types);
98
+ }
99
+ predicates.push(buildNodePredicate(klassOrPredicate));
100
+ } else {
101
+ types = undefined;
102
+ predicates.push(klassOrPredicate);
103
+ }
104
+ }
105
+ if (types) {
106
+ return types;
107
+ } else if (predicates.length === 1) {
108
+ return predicates[0];
109
+ }
110
+ return (node: LexicalNode): boolean => {
111
+ for (const predicate of predicates) {
112
+ if (predicate(node)) {
113
+ return true;
114
+ }
115
+ }
116
+ return false;
117
+ };
118
+ }
119
+
120
+ function makePrerender(): PreEditorDOMRenderConfig {
121
+ return {
122
+ $createDOM: [],
123
+ $decorateDOM: [],
124
+ $exportDOM: [],
125
+ $extractWithChild: [],
126
+ $getDOMSlot: [],
127
+ $shouldExclude: [],
128
+ $shouldInclude: [],
129
+ $updateDOM: [],
130
+ };
131
+ }
132
+
133
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
134
+ type AccFn<T, N extends LexicalNode, Args extends any[]> = (
135
+ node: N,
136
+ ...rest: [...Args, editor: LexicalEditor]
137
+ ) => T;
138
+
139
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
140
+ type GetOverrideFn<T, N extends LexicalNode, Args extends any[]> = (
141
+ n: N,
142
+ ) => undefined | OverrideFn<T, N, Args>;
143
+
144
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
145
+ type OverrideFn<T, N extends LexicalNode, Args extends any[]> = (
146
+ node: N,
147
+ ...rest: [...Args, $next: () => T, editor: LexicalEditor]
148
+ ) => T;
149
+
150
+ function ignoreNext2<T, N extends LexicalNode>(
151
+ acc: AccFn<T, N, []>,
152
+ ): OverrideFn<T, N, []> {
153
+ return (node: N, _$next: () => T, editor: LexicalEditor) => acc(node, editor);
154
+ }
155
+ function ignoreNext3<T, N extends LexicalNode, A>(
156
+ acc: AccFn<T, N, [A]>,
157
+ ): OverrideFn<T, N, [A]> {
158
+ return (node: N, a: A, _$next: () => T, editor: LexicalEditor) =>
159
+ acc(node, a, editor);
160
+ }
161
+ function ignoreNext4<T, N extends LexicalNode, A, B>(
162
+ acc: AccFn<T, N, [A, B]>,
163
+ ): OverrideFn<T, N, [A, B]> {
164
+ return (node: N, a: A, b: B, _$next: () => T, editor: LexicalEditor) =>
165
+ acc(node, a, b, editor);
166
+ }
167
+ function ignoreNext5<T, N extends LexicalNode, A, B, C>(
168
+ acc: AccFn<T, N, [A, B, C]>,
169
+ ): OverrideFn<T, N, [A, B, C]> {
170
+ return (node: N, a: A, b: B, c: C, _$next: () => T, editor: LexicalEditor) =>
171
+ acc(node, a, b, c, editor);
172
+ }
173
+
174
+ function merge2<T, N extends LexicalNode>(
175
+ $acc: AccFn<T, N, []>,
176
+ $getOverride: GetOverrideFn<T, N, []>,
177
+ ): typeof $acc {
178
+ return (node, editor) => {
179
+ const $next = () => $acc(node, editor);
180
+ const $override = $getOverride(node);
181
+ return $override ? $override(node, $next, editor) : $next();
182
+ };
183
+ }
184
+
185
+ function merge3<T, N extends LexicalNode, A>(
186
+ acc: AccFn<T, N, [A]>,
187
+ $getOverride: GetOverrideFn<T, N, [A]>,
188
+ ): typeof acc {
189
+ return (node, a, editor) => {
190
+ const $next = () => acc(node, a, editor);
191
+ const $override = $getOverride(node);
192
+ return $override ? $override(node, a, $next, editor) : $next();
193
+ };
194
+ }
195
+
196
+ const merge3GetDOMSlot = merge3 as (
197
+ acc: EditorDOMRenderConfig['$getDOMSlot'],
198
+ $getOverride: (n: LexicalNode) => DOMRenderMatch<LexicalNode>['$getDOMSlot'],
199
+ ) => EditorDOMRenderConfig['$getDOMSlot'];
200
+
201
+ const ignoreNext3GetDOMSlot = ignoreNext3 as (
202
+ fn: EditorDOMRenderConfig['$getDOMSlot'],
203
+ ) => DOMRenderMatch<LexicalNode>['$getDOMSlot'];
204
+
205
+ function merge4<T, N extends LexicalNode, A, B>(
206
+ $acc: AccFn<T, N, [A, B]>,
207
+ $getOverride: GetOverrideFn<T, N, [A, B]>,
208
+ ): typeof $acc {
209
+ return (node, a, b, editor) => {
210
+ const $next = () => $acc(node, a, b, editor);
211
+ const $override = $getOverride(node);
212
+ return $override ? $override(node, a, b, $next, editor) : $next();
213
+ };
214
+ }
215
+
216
+ function merge5<T, N extends LexicalNode, A, B, C>(
217
+ acc: AccFn<T, N, [A, B, C]>,
218
+ $getOverride: GetOverrideFn<T, N, [A, B, C]>,
219
+ ): typeof acc {
220
+ return (node, a, b, c, editor) => {
221
+ const $next = () => acc(node, a, b, c, editor);
222
+ const $override = $getOverride(node);
223
+ return $override ? $override(node, a, b, c, $next, editor) : $next();
224
+ };
225
+ }
226
+
227
+ function sequence4<N extends LexicalNode, A, B>(
228
+ $acc: AccFn<void, N, [A, B]>,
229
+ $getOverride: (n: N) => undefined | AccFn<void, N, [A, B]>,
230
+ ): typeof $acc {
231
+ return (node, a, b, editor) => {
232
+ $acc(node, a, b, editor);
233
+ const $override = $getOverride(node);
234
+ if ($override) {
235
+ $override(node, a, b, editor);
236
+ }
237
+ };
238
+ }
239
+
240
+ function compilePrerenderKey<K extends keyof PreEditorDOMRenderConfig>(
241
+ prerender: PreEditorDOMRenderConfig,
242
+ k: K,
243
+ defaults: EditorDOMRenderConfig,
244
+ mergeFunction: (
245
+ $acc: EditorDOMRenderConfig[K],
246
+ $getOverride: (node: LexicalNode) => AnyDOMRenderMatch[K],
247
+ ) => typeof $acc,
248
+ ignoreNextFunction: (fn: EditorDOMRenderConfig[K]) => AnyDOMRenderMatch[K],
249
+ ): void {
250
+ let acc = defaults[k];
251
+ for (const pair of prerender[k]) {
252
+ if (typeof pair[0] === 'function') {
253
+ const [$predicate, $override] = pair;
254
+ acc = mergeFunction(
255
+ acc,
256
+ node => ($predicate(node) && $override) || undefined,
257
+ );
258
+ } else {
259
+ const typeOverrides = pair[1];
260
+ const compiled: Record<string, undefined | EditorDOMRenderConfig[K]> = {};
261
+ for (const type in typeOverrides) {
262
+ const arr = typeOverrides[type];
263
+ if (arr) {
264
+ compiled[type] = arr.reduce(
265
+ ($acc, $override) => mergeFunction($acc, () => $override),
266
+ acc,
267
+ );
268
+ }
269
+ }
270
+ acc = mergeFunction(acc, node => {
271
+ const f = compiled[node.getType()];
272
+ return f && ignoreNextFunction(f);
273
+ });
274
+ }
275
+ }
276
+ defaults[k] = acc;
277
+ }
278
+
279
+ function addOverride<K extends keyof PreEditorDOMRenderConfig>(
280
+ prerender: PreEditorDOMRenderConfig,
281
+ k: K,
282
+ predicateOrTypes: PredicateOrTypes,
283
+ override: AnyDOMRenderMatch[K],
284
+ ): void {
285
+ if (!override) {
286
+ return;
287
+ }
288
+ const arr = prerender[k];
289
+ if (typeof predicateOrTypes === 'function') {
290
+ arr.push([predicateOrTypes, override]);
291
+ } else {
292
+ const last = arr[arr.length - 1];
293
+ let types: TypeRender<AnyDOMRenderMatch[K]>;
294
+ if (last && last[0] === 'types') {
295
+ types = last[1];
296
+ } else {
297
+ types = {};
298
+ arr.push(['types', types]);
299
+ }
300
+ for (const type in predicateOrTypes) {
301
+ const typeArr = types[type] || [];
302
+ types[type] = typeArr;
303
+ typeArr.push(override);
304
+ }
305
+ }
306
+ }
307
+
308
+ type NormalizedDOMRenderMatch<T> = Omit<
309
+ DOMRenderMatch<LexicalNode>,
310
+ 'nodes'
311
+ > & {
312
+ nodes: T;
313
+ };
314
+
315
+ function isWildcard(
316
+ override: DOMRenderMatch<LexicalNode>,
317
+ ): override is NormalizedDOMRenderMatch<'*'> {
318
+ return override.nodes === '*';
319
+ }
320
+
321
+ function sortedOverrides(
322
+ overrides: DOMRenderMatch<LexicalNode>[],
323
+ ): DOMRenderMatch<LexicalNode>[] {
324
+ const byWildcard: NormalizedDOMRenderMatch<'*'>[] = [];
325
+ const byPredicate: NormalizedDOMRenderMatch<
326
+ [(node: LexicalNode) => node is LexicalNode]
327
+ >[] = [];
328
+ const byNode: NormalizedDOMRenderMatch<[Klass<LexicalNode>]>[] = [];
329
+ for (const override of overrides) {
330
+ if (isWildcard(override)) {
331
+ byWildcard.push(override);
332
+ } else if (Array.isArray(override.nodes)) {
333
+ for (const klassOrPredicate of override.nodes) {
334
+ if ($isLexicalNode(klassOrPredicate.prototype)) {
335
+ byNode.push(
336
+ override.nodes.length === 1
337
+ ? (override as NormalizedDOMRenderMatch<[Klass<LexicalNode>]>)
338
+ : {...override, nodes: [klassOrPredicate]},
339
+ );
340
+ } else {
341
+ byPredicate.push(
342
+ override.nodes.length === 1
343
+ ? (override as NormalizedDOMRenderMatch<
344
+ [(node: LexicalNode) => node is LexicalNode]
345
+ >)
346
+ : {...override, nodes: [klassOrPredicate]},
347
+ );
348
+ }
349
+ }
350
+ }
351
+ }
352
+ const depths = new Map<Klass<LexicalNode>, number>();
353
+ const depthOf = (klass: Klass<LexicalNode>): number => {
354
+ let depth = depths.get(klass);
355
+ if (depth === undefined) {
356
+ depth = 0;
357
+ for (
358
+ let k: Klass<LexicalNode> = klass;
359
+ $isLexicalNode(k.prototype);
360
+ k = Object.getPrototypeOf(k)
361
+ ) {
362
+ depth++;
363
+ }
364
+ depths.set(klass, depth);
365
+ }
366
+ return depth;
367
+ };
368
+ byNode.sort((a, b) => depthOf(a.nodes[0]) - depthOf(b.nodes[0]));
369
+ return [...byNode, ...byPredicate, ...byWildcard];
370
+ }
371
+
372
+ export function precompileDOMRenderConfigOverrides(
373
+ editorConfig: Pick<InitialEditorConfig, 'nodes'>,
374
+ overrides: DOMRenderConfig['overrides'],
375
+ ): PreEditorDOMRenderConfig {
376
+ const typeTree = buildTypeTree(editorConfig);
377
+ const prerender = makePrerender();
378
+ for (const override of sortedOverrides(overrides)) {
379
+ const predicateOrTypes = getPredicate(typeTree, override);
380
+ for (const k_ in prerender) {
381
+ const k = k_ as keyof typeof prerender;
382
+ addOverride(prerender, k, predicateOrTypes, override[k]);
383
+ }
384
+ }
385
+ return prerender;
386
+ }
387
+
388
+ function identity<T>(v: T) {
389
+ return v;
390
+ }
391
+
392
+ export function compileDOMRenderConfigOverrides(
393
+ editorConfig: Pick<InitialEditorConfig, 'nodes' | 'dom'>,
394
+ {overrides}: Pick<DOMRenderConfig, 'overrides'>,
395
+ ): EditorDOMRenderConfig {
396
+ const prerender = precompileDOMRenderConfigOverrides(editorConfig, overrides);
397
+ const dom = {
398
+ ...DEFAULT_EDITOR_DOM_CONFIG,
399
+ ...editorConfig.dom,
400
+ };
401
+ compilePrerenderKey(prerender, '$createDOM', dom, merge2, ignoreNext2);
402
+ compilePrerenderKey(prerender, '$exportDOM', dom, merge2, ignoreNext2);
403
+ compilePrerenderKey(prerender, '$extractWithChild', dom, merge5, ignoreNext5);
404
+ compilePrerenderKey(
405
+ prerender,
406
+ '$getDOMSlot',
407
+ dom,
408
+ merge3GetDOMSlot,
409
+ ignoreNext3GetDOMSlot,
410
+ );
411
+ compilePrerenderKey(prerender, '$shouldExclude', dom, merge3, ignoreNext3);
412
+ compilePrerenderKey(prerender, '$shouldInclude', dom, merge3, ignoreNext3);
413
+ compilePrerenderKey(prerender, '$updateDOM', dom, merge4, ignoreNext4);
414
+ compilePrerenderKey(prerender, '$decorateDOM', dom, sequence4, identity);
415
+ return dom;
416
+ }
@@ -0,0 +1,18 @@
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
+ export const DOMRenderExtensionName = '@lexical/html/DOM';
9
+ export const DOMRenderContextSymbol = Symbol.for(
10
+ '@lexical/html/DOMExportContext',
11
+ );
12
+
13
+ export const DOMImportExtensionName = '@lexical/html/DOMImport';
14
+ export const DOMImportContextSymbol = Symbol.for(
15
+ '@lexical/html/DOMImportContext',
16
+ );
17
+
18
+ export const ALWAYS_TRUE = () => true as const;
@@ -0,0 +1,46 @@
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
+ AnyDOMRenderMatch,
10
+ DOMOverrideOptions,
11
+ DOMRenderMatch,
12
+ DOMRenderMatchConfig,
13
+ NodeMatch,
14
+ } from './types';
15
+ import type {LexicalNode} from 'lexical';
16
+
17
+ /**
18
+ * A convenience function for type inference when constructing DOM overrides for
19
+ * use with {@link DOMRenderExtension}.
20
+ *
21
+ * The optional `options` argument controls *whether* the override is installed
22
+ * based only on render context — `disabledForEditor` gates residency in the
23
+ * editor's render pipeline (reconciliation), `disabledForSession` gates
24
+ * participation in a single export/generate session. See {@link DOMOverrideOptions}.
25
+ *
26
+ * @experimental
27
+ * @__NO_SIDE_EFFECTS__
28
+ */
29
+
30
+ export function domOverride(
31
+ nodes: '*',
32
+ config: DOMRenderMatchConfig<LexicalNode>,
33
+ options?: DOMOverrideOptions,
34
+ ): DOMRenderMatch<LexicalNode>;
35
+ export function domOverride<T extends LexicalNode>(
36
+ nodes: readonly NodeMatch<T>[],
37
+ config: DOMRenderMatchConfig<T>,
38
+ options?: DOMOverrideOptions,
39
+ ): DOMRenderMatch<T>;
40
+ export function domOverride(
41
+ nodes: AnyDOMRenderMatch['nodes'],
42
+ config: Omit<AnyDOMRenderMatch, 'nodes' | keyof DOMOverrideOptions>,
43
+ options?: DOMOverrideOptions,
44
+ ): AnyDOMRenderMatch {
45
+ return {...config, ...options, nodes};
46
+ }
@@ -0,0 +1,26 @@
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 {configExtension, defineExtension} from 'lexical';
9
+
10
+ import {CoreImportRules} from './coreImportRules';
11
+ import {DOMImportExtension} from './DOMImportExtension';
12
+
13
+ /**
14
+ * Bundles {@link CoreImportRules} into a {@link DOMImportExtension}-aware
15
+ * extension. Depend on this from your editor (directly or via richer
16
+ * extensions like `RichTextImportExtension`) to get the equivalent of the
17
+ * legacy core `importDOM` behavior for `<p>`, `<span>`, `<b>`,
18
+ * `<strong>`, `<em>`, `<i>`, `<code>`, `<mark>`, `<s>`, `<sub>`, `<sup>`,
19
+ * `<u>`, `<br>`, and `#text`.
20
+ *
21
+ * @experimental
22
+ */
23
+ export const CoreImportExtension = defineExtension({
24
+ dependencies: [configExtension(DOMImportExtension, {rules: CoreImportRules})],
25
+ name: '@lexical/html/CoreImport',
26
+ });