@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,394 @@
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 { DOMImportContextSymbol } from '../constants';
9
+ import type { AnyContextConfigPairOrUpdater, ContextConfig, ContextRecord } from '../types';
10
+ import type { CompiledOverlayRules } from './defineOverlayRules';
11
+ import type { LexicalNode } from 'lexical';
12
+ /**
13
+ * Phantom-typed branding so consumers cannot construct or mutate a
14
+ * {@link CompiledSelector} directly; the only way to obtain one is via the
15
+ * {@link sel} builder or {@link parseSelector}. The actual runtime shape is
16
+ * an internal implementation detail (see `./sel`).
17
+ *
18
+ * @experimental
19
+ */
20
+ export declare const NodeBrand: unique symbol;
21
+ /** @experimental */
22
+ export declare const CaptureBrand: unique symbol;
23
+ /**
24
+ * An opaque, compiled selector used as the `match` field of a
25
+ * {@link DOMImportRule}. The two phantom type parameters carry the matched
26
+ * Node subtype (`N`) and a record of named regex captures (`C`) so the
27
+ * importer body gets correctly-typed `ctx` and `node` arguments without
28
+ * casts.
29
+ *
30
+ * @experimental
31
+ */
32
+ export interface CompiledSelector<N extends Node = Node, C extends Record<string, RegExpMatchArray> = Record<string, RegExpMatchArray>> {
33
+ readonly [NodeBrand]?: N;
34
+ readonly [CaptureBrand]?: C;
35
+ }
36
+ /**
37
+ * The Node subtype matched by a selector (e.g. `HTMLAnchorElement` for
38
+ * `sel.tag('a')`, `Text` for `sel.text()`).
39
+ *
40
+ * @experimental
41
+ */
42
+ export type NodeOfSelector<S> = S extends CompiledSelector<infer N, Record<string, RegExpMatchArray>> ? N : Node;
43
+ /**
44
+ * The named-capture map for a selector.
45
+ *
46
+ * @experimental
47
+ */
48
+ export type CapturesOfSelector<S> = S extends CompiledSelector<Node, infer C> ? C : Record<string, never>;
49
+ /**
50
+ * Options bag for {@link ElementSelectorBuilder.attr} when the value is a
51
+ * regex. Future options will be added here without breaking existing
52
+ * call-sites.
53
+ *
54
+ * @experimental
55
+ */
56
+ export interface AttrMatchOptions<K extends string = string> {
57
+ /**
58
+ * If provided, the {@link RegExpMatchArray} from the successful match is
59
+ * stored on `ctx.captures[capture]` for the importer to consume — saving
60
+ * a second regex execution.
61
+ */
62
+ readonly capture?: K;
63
+ }
64
+ /**
65
+ * Options bag for {@link ElementSelectorBuilder.styleAny} when the value is a
66
+ * regex. See {@link AttrMatchOptions} for capture semantics.
67
+ *
68
+ * @experimental
69
+ */
70
+ export interface StyleMatchOptions<K extends string = string> {
71
+ readonly capture?: K;
72
+ }
73
+ /**
74
+ * Fluent builder for an element selector. The two type parameters carry the
75
+ * matched element type and the named-capture map; each call refines them.
76
+ *
77
+ * The builder itself implements {@link CompiledSelector} so it can be used
78
+ * directly as the `match` field of a rule — no `.build()` call needed.
79
+ *
80
+ * @experimental
81
+ */
82
+ export interface ElementSelectorBuilder<E extends HTMLElement, C extends Record<string, RegExpMatchArray> = Record<string, never>> extends CompiledSelector<E, C> {
83
+ /** Require every listed class to be present on the element. */
84
+ classAll(...classes: readonly string[]): ElementSelectorBuilder<E, C>;
85
+ /** Require at least one of the listed classes to be present. */
86
+ classAny(...classes: readonly string[]): ElementSelectorBuilder<E, C>;
87
+ /** Require the attribute to be present (any value). */
88
+ attr(name: string, value: true): ElementSelectorBuilder<E, C>;
89
+ /** Require the attribute to equal the given string. */
90
+ attr(name: string, value: string): ElementSelectorBuilder<E, C>;
91
+ /**
92
+ * Require the attribute to match the given regex. With
93
+ * `{capture: 'name'}` the match result is exposed on
94
+ * `ctx.captures.name`.
95
+ */
96
+ attr<const O extends AttrMatchOptions>(name: string, value: RegExp, options?: O): ElementSelectorBuilder<E, O extends {
97
+ capture: infer K;
98
+ } ? C & Record<K & string, RegExpMatchArray> : C>;
99
+ /** Require the inline-style declaration to equal `value`. */
100
+ styleAny(prop: string, value: string): ElementSelectorBuilder<E, C>;
101
+ /** Require the inline-style declaration to match `value`. */
102
+ styleAny<const O extends StyleMatchOptions>(prop: string, value: RegExp, options?: O): ElementSelectorBuilder<E, O extends {
103
+ capture: infer K;
104
+ } ? C & Record<K & string, RegExpMatchArray> : C>;
105
+ }
106
+ /**
107
+ * Argument to {@link DOMImportContext.branch} / `$importChildren({context})`
108
+ * — see {@link ContextConfigPair} / {@link ContextConfigUpdater}.
109
+ *
110
+ * @experimental
111
+ */
112
+ export type ImportContextPairOrUpdater = AnyContextConfigPairOrUpdater<typeof DOMImportContextSymbol>;
113
+ /**
114
+ * A typed context-state key for the import pipeline. Create with
115
+ * {@link createImportState}.
116
+ *
117
+ * @experimental
118
+ */
119
+ export type ImportStateConfig<V> = ContextConfig<typeof DOMImportContextSymbol, V>;
120
+ /**
121
+ * A mutable, document-order-shared store for the import pipeline. Lets a
122
+ * rule visited early in the document write information that rules visited
123
+ * later can read — e.g. parse `<style>` or `<meta>` and influence
124
+ * subsequent matching.
125
+ *
126
+ * Implemented as the root-layer {@link ContextRecord} of the import walk:
127
+ * `ctx.session.set(cfg, v)` mutates the slot on that root record, and
128
+ * every unshadowed `ctx.get(cfg)` read in any branch picks it up. A
129
+ * `$importChildren({context: [...]})` branch that explicitly writes the
130
+ * same slot shadows the session value for the duration of that branch.
131
+ *
132
+ * @experimental
133
+ */
134
+ export interface ImportSession {
135
+ /** Read the current value, returning the config's default if unset. */
136
+ get<V>(cfg: ImportStateConfig<V>): V;
137
+ /** Write `value` into the slot. */
138
+ set<V>(cfg: ImportStateConfig<V>, value: V): void;
139
+ /** Read-modify-write. */
140
+ update<V>(cfg: ImportStateConfig<V>, updater: (prev: V) => V): void;
141
+ /** Returns `true` if the slot has been written since session creation. */
142
+ has<V>(cfg: ImportStateConfig<V>): boolean;
143
+ }
144
+ /**
145
+ * Context exposed to a rule's `$import` function. Mirrors the existing render
146
+ * context (see {@link RenderContext}) but is import-scoped.
147
+ *
148
+ * @experimental
149
+ */
150
+ export interface DOMImportContext<C extends Record<string, RegExpMatchArray> = Record<string, never>> {
151
+ /** Captures from this rule's selector. Fresh per rule invocation. */
152
+ readonly captures: Readonly<C>;
153
+ /**
154
+ * Mutable, document-order-shared store. Use to make information from
155
+ * earlier-visited nodes available to later-visited ones (e.g. a
156
+ * `<style>` or `<meta>` at the top of the document influencing how
157
+ * later elements are interpreted). One {@link ImportSession} instance
158
+ * is created per top-level `$generateNodesFromDOM` call and is shared
159
+ * across all recursive `$importChildren` / `$importOne` invocations.
160
+ */
161
+ readonly session: ImportSession;
162
+ /** Read a typed context value. */
163
+ get<V>(cfg: ImportStateConfig<V>): V;
164
+ /**
165
+ * Recursively import every child of `parent` and return the produced
166
+ * lexical nodes, optionally enforcing a {@link ChildSchema} and/or
167
+ * branching the import context for the duration of the call (via
168
+ * `opts.context`).
169
+ */
170
+ $importChildren(parent: ParentNode, opts?: ImportChildrenOpts): LexicalNode[];
171
+ /**
172
+ * Recursively import a single DOM node.
173
+ */
174
+ $importOne(node: Node, opts?: ImportNodeOpts): LexicalNode[];
175
+ }
176
+ /**
177
+ * Options accepted by {@link DOMImportContext.$importChildren}. The combination
178
+ * of `schema`, `$onChild`, and `$after` is sufficient to express every
179
+ * child-handling pattern in the legacy `forChild` / `after` / wrap-continuous
180
+ * machinery.
181
+ *
182
+ * @experimental
183
+ */
184
+ export interface ImportChildrenOpts {
185
+ /**
186
+ * How to validate and (re)package produced children. Defaults to whichever
187
+ * schema the parent's importer passed; the top-level entry uses
188
+ * {@link BlockSchema}.
189
+ */
190
+ readonly schema?: ChildSchema;
191
+ /**
192
+ * Called for each produced lexical child immediately after its rule
193
+ * returned, with the chance to substitute or drop it. Equivalent to the
194
+ * old `forChild` hook but scoped to one `$importChildren` call.
195
+ */
196
+ readonly $onChild?: (child: LexicalNode) => LexicalNode | null | undefined;
197
+ /**
198
+ * Called once with the full child array after all DOM children have been
199
+ * recursively imported but before {@link ChildSchema.$packageRun} is
200
+ * applied. Equivalent to the old `after` hook.
201
+ */
202
+ readonly $after?: (children: LexicalNode[]) => LexicalNode[];
203
+ /** Context overrides scoped to the children traversal. */
204
+ readonly context?: readonly ImportContextPairOrUpdater[];
205
+ /**
206
+ * Additional {@link DOMImportRule}s active only for this children
207
+ * traversal (and any nested `$importChildren` calls that don't push
208
+ * their own overlay). The overlay is checked BEFORE the main
209
+ * dispatcher, so its rules take precedence; calling `$next()` from an
210
+ * overlay rule falls through to the next overlay-or-main rule.
211
+ *
212
+ * Use this to scope cost-bearing rules to where they apply. For
213
+ * example, a GitHub code-table rule installs an overlay that
214
+ * unwraps `<tr>` / `<td>` inside the table, without paying that
215
+ * predicate cost on every other `<tr>` / `<td>` paste.
216
+ *
217
+ * The value must be produced by
218
+ * {@link defineOverlayRules}; this forces the dispatcher to be
219
+ * compiled once at module scope and reused across
220
+ * `$importChildren` calls, instead of being recompiled per invocation.
221
+ */
222
+ readonly rules?: CompiledOverlayRules;
223
+ }
224
+ /** @experimental */
225
+ export interface ImportNodeOpts {
226
+ readonly context?: readonly ImportContextPairOrUpdater[];
227
+ }
228
+ /**
229
+ * A {@link ChildSchema} encodes which lexical nodes a parent accepts as
230
+ * children and how to package or reject the rest. The legacy
231
+ * `wrapContinuousInlines` / `ArtificialNode__DO_NOT_USE` logic is the
232
+ * `BlockSchema` and `NestedBlockSchema` cases of this primitive.
233
+ *
234
+ * A schema only controls how the *children* are assembled before being
235
+ * appended to the parent the calling rule already chose. It cannot
236
+ * change the parent itself. Cases where the parent's shape needs to
237
+ * change in response to its children — e.g. an inline `<a>` that
238
+ * encloses a block `<h1>`, which must be lifted so the heading takes
239
+ * the link's place and the link is redistributed onto the heading's
240
+ * inline contents — belong in the rule body, not the schema. See the
241
+ * "Lifting blocks out of an inline parent" section of the docs.
242
+ *
243
+ * @experimental
244
+ */
245
+ export interface ChildSchema {
246
+ /** Optional name for debug output. */
247
+ readonly name?: string;
248
+ /**
249
+ * Returns `true` if `child` is a valid child of `parent` in this position.
250
+ */
251
+ $accepts(child: LexicalNode, parent: LexicalNode | null): boolean;
252
+ /**
253
+ * Package a maximal run of non-accepted siblings into zero or more
254
+ * accepted nodes. The returned nodes replace the rejected run at the
255
+ * same position in the child list and are not re-checked against
256
+ * `$accepts` — the caller is trusted to return valid children. If
257
+ * omitted, or if it returns an empty array, {@link ChildSchema.onReject}
258
+ * is consulted instead.
259
+ */
260
+ $packageRun?(rejected: LexicalNode[], parent: LexicalNode | null, domParent: Node | null): LexicalNode[];
261
+ /**
262
+ * Fallback strategy for a run of non-accepted children when
263
+ * `$packageRun` is missing or returns an empty array:
264
+ *
265
+ * - `'drop'` (default) — silently discards the run. Use when the
266
+ * schema is strict and rejected content is meaningless in this
267
+ * position (e.g. text between table rows).
268
+ * - `'hoist'` — emits the rejected nodes unchanged at the same
269
+ * position in the assembled child list. The caller's parent then
270
+ * receives them as-is, which is only useful if the calling rule
271
+ * intends to surface mixed content to *its* parent (a less common
272
+ * pattern; usually `$packageRun` should re-shape the run first).
273
+ *
274
+ * `'hoist'` does NOT lift the run all the way up out of the calling
275
+ * rule's parent — that requires the rule itself to detect the
276
+ * situation and emit a different parent structure (see the
277
+ * "Lifting blocks out of an inline parent" section).
278
+ */
279
+ readonly onReject?: 'hoist' | 'drop';
280
+ /**
281
+ * Final pass over the assembled child list (after `$packageRun`). Returns
282
+ * the children to actually attach. Use to enforce structural invariants
283
+ * (e.g. drop empty runs, pad short table rows).
284
+ */
285
+ $finalize?(children: LexicalNode[], parent: LexicalNode | null): LexicalNode[];
286
+ }
287
+ /**
288
+ * The middleware signature of an import rule. Call `$next()` to delegate to
289
+ * the next-matching rule for this node (returning its result, which may then
290
+ * be inspected or wrapped); return `[]` to drop the node.
291
+ *
292
+ * @experimental
293
+ */
294
+ export type DOMImportFn<E extends Node, C extends Record<string, RegExpMatchArray> = Record<string, never>> = (ctx: DOMImportContext<C>, node: E, $next: () => readonly LexicalNode[]) => readonly LexicalNode[];
295
+ /**
296
+ * An importer for a DOM node, dispatched by `match` and implemented by
297
+ * `$import`.
298
+ *
299
+ * @experimental
300
+ */
301
+ export interface DOMImportRule<S extends CompiledSelector = CompiledSelector> {
302
+ /**
303
+ * Optional identifier surfaced in dev-mode logs, error messages, and
304
+ * introspection devtools. Convention: `'@scope/package/rule-id'` for
305
+ * library rules.
306
+ */
307
+ readonly name?: string;
308
+ /** A {@link CompiledSelector} produced by the {@link sel} builder. */
309
+ readonly match: S;
310
+ /** Middleware that converts the matched DOM node into lexical nodes. */
311
+ readonly $import: DOMImportFn<NodeOfSelector<S>, CapturesOfSelector<S>>;
312
+ }
313
+ /** @experimental */
314
+ export type AnyDOMImportRule = DOMImportRule<any>;
315
+ /**
316
+ * Context exposed to a {@link DOMPreprocessFn}. Lets the preprocessor:
317
+ *
318
+ * - Write to the per-import {@link ImportSession} (the same
319
+ * `ctx.session` rules see during the walk). Writes mutate the
320
+ * root-layer context record, so they are visible to every scoped
321
+ * `ctx.get(cfg)` read that hasn't been shadowed by a branch.
322
+ *
323
+ * @experimental
324
+ */
325
+ export interface DOMPreprocessContext {
326
+ /**
327
+ * Document-order-shared store, same instance as `ctx.session` in
328
+ * rules. Use to pass info from the DOM preprocess phase (e.g.
329
+ * inspected `<meta>` tags, collected `<style>` text) to the
330
+ * importer rules.
331
+ */
332
+ readonly session: ImportSession;
333
+ }
334
+ /**
335
+ * A middleware step in the DOM-preprocess chain. Runs before walking
336
+ * begins and may:
337
+ *
338
+ * - Mutate the input DOM in place (e.g. inline stylesheets, strip
339
+ * unsafe elements, normalize attributes).
340
+ * - Write to {@link DOMPreprocessContext.session} for rules to read
341
+ * (and for unshadowed scoped reads to pick up).
342
+ * - Call `$next()` to defer to the next-lower preprocessor in the
343
+ * stack; omit the call to short-circuit and skip the rest.
344
+ *
345
+ * The preprocess phase runs inside the same editor read / update
346
+ * context as the walk that follows, so a preprocess function may call
347
+ * `$`-prefixed Lexical APIs (e.g. `$getState`, `$getRoot`) as needed.
348
+ * The `$next` parameter is named with a `$` prefix to make that
349
+ * editor-context expectation visible to readers and lints.
350
+ *
351
+ * Append-style merge applies: an extension's preprocessors are appended
352
+ * to the existing stack, so later-registered preprocessors run first
353
+ * and may delegate to earlier (lower-priority) ones via `$next()`. Same
354
+ * convention as {@link ExportMimeTypeFunction} on the export side.
355
+ *
356
+ * @experimental
357
+ */
358
+ export type DOMPreprocessFn = (dom: Document | ParentNode, ctx: DOMPreprocessContext, $next: () => void) => void;
359
+ /**
360
+ * Per-call options to the extension's `$generateNodesFromDOM`.
361
+ *
362
+ * @experimental
363
+ */
364
+ export interface GenerateNodesFromDOMOptions {
365
+ /**
366
+ * Context pairs/updaters applied for the duration of this import only —
367
+ * use to communicate per-call info such as the {@link ImportSource}.
368
+ */
369
+ readonly context?: readonly ImportContextPairOrUpdater[];
370
+ /**
371
+ * Additional preprocessors to run on this call only, on top of the
372
+ * extension's configured {@link DOMImportConfig.preprocess}. Per-call
373
+ * preprocessors run AFTER the configured ones.
374
+ */
375
+ readonly preprocess?: readonly DOMPreprocessFn[];
376
+ }
377
+ /**
378
+ * Output of {@link DOMImportExtension}.
379
+ *
380
+ * @experimental
381
+ */
382
+ export interface DOMImportExtensionOutput {
383
+ /**
384
+ * Convert a {@link Document} or {@link ParentNode} into lexical nodes,
385
+ * using the dispatcher compiled from this extension's configured
386
+ * {@link DOMImportRule}s.
387
+ *
388
+ * Must be called within an `editor.update()` or `editor.read()` because
389
+ * the importers may invoke `$create...` helpers.
390
+ */
391
+ $generateNodesFromDOM(dom: Document | ParentNode, options?: GenerateNodesFromDOMOptions): LexicalNode[];
392
+ /** @internal */
393
+ readonly defaults: undefined | ContextRecord<typeof DOMImportContextSymbol>;
394
+ }
@@ -0,0 +1,44 @@
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 { BaseSelection, LexicalEditor, LexicalNode } from 'lexical';
9
+ export { contextUpdater, contextValue } from './ContextRecord';
10
+ export { domOverride } from './domOverride';
11
+ export { DOMRenderExtension } from './DOMRenderExtension';
12
+ export type { AnyDOMImportRule, AttrMatchOptions, CapturesOfSelector, ChildSchema, CompiledOverlayRules, CompiledSelector, DOMImportContext, DOMImportExtensionOutput, DOMImportFn, DOMImportRule, DOMImportRuleEntry, DOMPreprocessContext, DOMPreprocessFn, ElementSelectorBuilder, GenerateNodesFromDOMOptions, ImportChildrenOpts, ImportContextPairOrUpdater, ImportNodeOpts, ImportSession, ImportStateConfig, NodeOfSelector, StyleMatchOptions, } from './import';
13
+ export { $distributeInlineWrapper, $generateNodesFromDOMViaExtension, $getImportContextValue, $inlineStylesFromStyleSheets, $isBlockLevel, $withImportContext, BlockSchema, CoreImportExtension, CoreImportRules, createImportState, defaultIsInline, defaultPreservesWhitespace, defineImportRule, defineOverlayRules, type DOMImportConfig, DOMImportExtension, HorizontalRuleImportExtension, HorizontalRuleImportRules, ImportOverlays, ImportSource, ImportSourceDataTransfer, type ImportSourceKind, ImportTextFormat, ImportTextStyle, ImportWhitespaceConfig, InlineSchema, isElementOfTag, type IsInlineForWhitespace, type IsPreserveWhitespaceDom, NestedBlockSchema, parseSelector, RootSchema, sel, type WhitespaceImportConfig, } from './import';
14
+ export { $getRenderContextValue, $getSessionDOMRenderConfig, $setRenderContextValue, $updateRenderContextValue, $withRenderContext, createRenderState, RenderContextExport, RenderContextRoot, } from './RenderContext';
15
+ export type { AnyDOMRenderMatch, AnyRenderStateConfig, AnyRenderStateConfigPairOrUpdater, ContextPairOrUpdater, DOMOverrideOptions, DOMRenderConfig, DOMRenderExtensionOutput, DOMRenderMatch, DOMRenderMatchConfig, NodeMatch, RenderContextReader, } from './types';
16
+ /**
17
+ * How you parse your html string to get a document is left up to you. In the browser you can use the native
18
+ * DOMParser API to generate a document (see clipboard.ts), but to use in a headless environment you can use JSDom
19
+ * or an equivalent library and pass in the document here.
20
+ */
21
+ export declare function $generateNodesFromDOM(editor: LexicalEditor, dom: Document | ParentNode): Array<LexicalNode>;
22
+ /**
23
+ * Generate DOM nodes from the editor state into the given container element,
24
+ * using the editor's {@link EditorDOMRenderConfig}.
25
+ * @experimental
26
+ */
27
+ export declare function $generateDOMFromNodes<T extends HTMLElement | DocumentFragment>(container: T, selection?: null | BaseSelection, editor?: LexicalEditor): T;
28
+ /**
29
+ * Generate DOM nodes from a root node into the given container element,
30
+ * including the root node itself. Uses the editor's {@link EditorDOMRenderConfig}.
31
+ * @experimental
32
+ */
33
+ export declare function $generateDOMFromRoot<T extends HTMLElement | DocumentFragment>(container: T, root?: LexicalNode): T;
34
+ /**
35
+ * Generate an HTML string from the editor's current state (or `selection`
36
+ * if provided).
37
+ *
38
+ * Must be called inside an active editor scope — i.e. `editor.update(...)`,
39
+ * `editor.read(...)`, or `editor.getEditorState().read(callback, {editor})`.
40
+ * The legacy `editor.getEditorState().read(callback)` call (without the
41
+ * `{editor}` option) does not set an active editor and is not supported;
42
+ * `editor.read(...)` is the drop-in replacement.
43
+ */
44
+ export declare function $generateHtmlFromNodes(editor: LexicalEditor, selection?: BaseSelection | null): string;
@@ -5,14 +5,14 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
7
  */
8
- import type { DOMRenderContextSymbol } from './constants';
9
- import type { BaseSelection, DOMExportOutput, ElementDOMSlot, Klass, LexicalEditor, LexicalNode, StateConfig } from 'lexical';
8
+ import type { DOMImportContextSymbol, DOMRenderContextSymbol } from './constants';
9
+ import type { BaseSelection, DOMExportOutput, DOMSlotForNode, EditorDOMRenderConfig, Klass, LexicalEditor, LexicalNode, StateConfig } from 'lexical';
10
10
  /**
11
11
  * @experimental
12
12
  *
13
- * Any ContextSymbol for {@link ContextConfig} (currently only {@link DOMRenderContextSymbol})
13
+ * Any ContextSymbol for {@link ContextConfig} (DOM render or DOM import).
14
14
  */
15
- export type AnyContextSymbol = typeof DOMRenderContextSymbol;
15
+ export type AnyContextSymbol = typeof DOMRenderContextSymbol | typeof DOMImportContextSymbol;
16
16
  /**
17
17
  * @experimental
18
18
  *
@@ -68,6 +68,73 @@ export type AnyContextConfigPairOrUpdater<Ctx extends AnyContextSymbol> = Contex
68
68
  export interface DOMRenderExtensionOutput {
69
69
  /** @internal */
70
70
  defaults: undefined | ContextRecord<typeof DOMRenderContextSymbol>;
71
+ /** @internal */
72
+ runtime: DOMRenderRuntime;
73
+ }
74
+ /**
75
+ * @experimental
76
+ *
77
+ * A read-only view of a render context layer, passed to the
78
+ * {@link DOMOverrideOptions} predicates so they can decide whether an
79
+ * override should be installed based only on context values.
80
+ */
81
+ export interface RenderContextReader {
82
+ get<V>(cfg: RenderStateConfig<V>): V;
83
+ }
84
+ /**
85
+ * @experimental
86
+ * @internal
87
+ *
88
+ * Per-editor runtime state for {@link DOMRenderExtension} that backs the
89
+ * imperative editor context ({@link createRenderState} writes via
90
+ * `$setRenderContextValue`) and the conditional install of overrides.
91
+ */
92
+ export interface DOMRenderRuntime {
93
+ /**
94
+ * The mutable, persistent editor-level context record. Reads of a
95
+ * {@link RenderStateConfig} during reconciliation (and as the base layer
96
+ * during a session) fall through to this record. It is also the layer
97
+ * that {@link DOMOverrideOptions.disabledForEditor} predicates read from.
98
+ */
99
+ readonly editorContext: ContextRecord<typeof DOMRenderContextSymbol>;
100
+ /**
101
+ * Imperatively set a value in the editor context. If the change flips any
102
+ * override's `disabledForEditor` result, the resident render config is
103
+ * recompiled and the affected nodes are re-rendered (recreating DOM for
104
+ * structural overrides).
105
+ */
106
+ setContextValue<V>(cfg: RenderStateConfig<V>, value: V): void;
107
+ /**
108
+ * Resolve the {@link EditorDOMRenderConfig} for the current export/generate
109
+ * session, applying any {@link DOMOverrideOptions.disabledForSession}
110
+ * predicates against the active session context. Returns the resident
111
+ * config when no session gating applies.
112
+ */
113
+ getSessionConfig(): EditorDOMRenderConfig;
114
+ }
115
+ /**
116
+ * @experimental
117
+ *
118
+ * Options for {@link domOverride} controlling *whether* an override is
119
+ * installed, based only on render context. Both predicates default to
120
+ * "not disabled".
121
+ */
122
+ export interface DOMOverrideOptions {
123
+ /**
124
+ * Gate residency in the editor's render config (used by reconciliation and
125
+ * as the base for export/generate). Evaluated against the persistent editor
126
+ * context at compile time, and re-evaluated when that context changes via
127
+ * `$setRenderContextValue`; a change recompiles the config and re-renders
128
+ * affected nodes. Return `true` to remove the override. Default: not disabled.
129
+ */
130
+ disabledForEditor?: (ctx: RenderContextReader) => boolean;
131
+ /**
132
+ * Gate participation in a single export/generate session. Evaluated once at
133
+ * the start of each session against that session's context. Has no effect on
134
+ * live reconciliation (which is not a session). Return `true` to remove the
135
+ * override for that session. Default: not disabled.
136
+ */
137
+ disabledForSession?: (ctx: RenderContextReader) => boolean;
71
138
  }
72
139
  /**
73
140
  * @experimental
@@ -157,16 +224,19 @@ export interface DOMRenderMatch<T extends LexicalNode> {
157
224
  * after the children. The root of the node returned by createDOM must
158
225
  * still be exactly one HTMLElement.
159
226
  *
160
- * Generally you will call `$next()` to get an ElementDOMSlot and then use
161
- * its methods to create a new one.
227
+ * Generally you will call `$next()` to get a slot and then use its methods
228
+ * to create a new one. The slot type is narrowed via {@link DOMSlotForNode}:
229
+ * for `ElementNode` it resolves to {@link ElementDOMSlot} with
230
+ * children-management semantics; for non-Element nodes the base
231
+ * {@link DOMSlot} pointing at the keyed DOM.
162
232
  *
163
233
  * @param node The LexicalNode
164
234
  * @param dom The rendered HTMLElement
165
235
  * @param $next Call the next implementation
166
236
  * @param editor The editor
167
- * @returns The `ElementDOMSlot` for this node
237
+ * @returns The slot for this node
168
238
  */
169
- $getDOMSlot?: <N extends LexicalNode>(node: N, dom: HTMLElement, $next: () => ElementDOMSlot<HTMLElement>, editor: LexicalEditor) => ElementDOMSlot<HTMLElement>;
239
+ $getDOMSlot?: (node: T, dom: HTMLElement, $next: () => DOMSlotForNode<T>, editor: LexicalEditor) => DOMSlotForNode<T>;
170
240
  /**
171
241
  * Called during the reconciliation process to determine which nodes
172
242
  * to insert into the DOM for this Lexical Node. This is also the default
@@ -290,4 +360,22 @@ export interface DOMRenderMatch<T extends LexicalNode> {
290
360
  * @returns true if this
291
361
  */
292
362
  $extractWithChild?: (node: T, childNode: LexicalNode, selection: null | BaseSelection, destination: 'clone' | 'html', $next: () => boolean, editor: LexicalEditor) => boolean;
363
+ /**
364
+ * Set via {@link domOverride}'s options argument, not directly. See
365
+ * {@link DOMOverrideOptions.disabledForEditor}.
366
+ */
367
+ disabledForEditor?: (ctx: RenderContextReader) => boolean;
368
+ /**
369
+ * Set via {@link domOverride}'s options argument, not directly. See
370
+ * {@link DOMOverrideOptions.disabledForSession}.
371
+ */
372
+ disabledForSession?: (ctx: RenderContextReader) => boolean;
293
373
  }
374
+ /**
375
+ * @experimental
376
+ *
377
+ * The hook fields of a {@link DOMRenderMatch} — i.e. without `nodes` or the
378
+ * {@link DOMOverrideOptions} predicates, which are passed separately to
379
+ * {@link domOverride}.
380
+ */
381
+ export type DOMRenderMatchConfig<T extends LexicalNode> = Omit<DOMRenderMatch<T>, 'nodes' | keyof DOMOverrideOptions>;
package/package.json CHANGED
@@ -8,37 +8,52 @@
8
8
  "html"
9
9
  ],
10
10
  "license": "MIT",
11
- "version": "0.44.1-nightly.20260519.0",
12
- "main": "LexicalHtml.js",
13
- "types": "index.d.ts",
11
+ "version": "0.45.0",
12
+ "main": "./dist/LexicalHtml.js",
13
+ "types": "./dist/index.d.ts",
14
14
  "repository": {
15
15
  "type": "git",
16
16
  "url": "git+https://github.com/facebook/lexical.git",
17
17
  "directory": "packages/lexical-html"
18
18
  },
19
19
  "dependencies": {
20
- "@lexical/extension": "0.44.1-nightly.20260519.0",
21
- "@lexical/selection": "0.44.1-nightly.20260519.0",
22
- "@lexical/utils": "0.44.1-nightly.20260519.0",
23
- "lexical": "0.44.1-nightly.20260519.0"
20
+ "@lexical/extension": "0.45.0",
21
+ "@lexical/internal": "0.45.0",
22
+ "@lexical/selection": "0.45.0",
23
+ "@lexical/utils": "0.45.0",
24
+ "lexical": "0.45.0"
24
25
  },
25
- "module": "LexicalHtml.mjs",
26
+ "module": "./dist/LexicalHtml.mjs",
26
27
  "sideEffects": false,
27
28
  "exports": {
28
29
  ".": {
30
+ "source": "./src/index.ts",
29
31
  "import": {
30
- "types": "./index.d.ts",
31
- "development": "./LexicalHtml.dev.mjs",
32
- "production": "./LexicalHtml.prod.mjs",
33
- "node": "./LexicalHtml.node.mjs",
34
- "default": "./LexicalHtml.mjs"
32
+ "types": "./dist/index.d.ts",
33
+ "development": "./dist/LexicalHtml.dev.mjs",
34
+ "production": "./dist/LexicalHtml.prod.mjs",
35
+ "node": "./dist/LexicalHtml.node.mjs",
36
+ "default": "./dist/LexicalHtml.mjs"
35
37
  },
36
38
  "require": {
37
- "types": "./index.d.ts",
38
- "development": "./LexicalHtml.dev.js",
39
- "production": "./LexicalHtml.prod.js",
40
- "default": "./LexicalHtml.js"
39
+ "types": "./dist/index.d.ts",
40
+ "development": "./dist/LexicalHtml.dev.js",
41
+ "production": "./dist/LexicalHtml.prod.js",
42
+ "default": "./dist/LexicalHtml.js"
41
43
  }
42
44
  }
43
- }
45
+ },
46
+ "files": [
47
+ "dist",
48
+ "src",
49
+ "!src/__tests__",
50
+ "!src/__bench__",
51
+ "!src/__mocks__",
52
+ "!src/**/*.test.ts",
53
+ "!src/**/*.test.tsx",
54
+ "!src/**/*.bench.ts",
55
+ "!src/**/*.bench.tsx",
56
+ "README.md",
57
+ "LICENSE"
58
+ ]
44
59
  }