@lexical/html 0.44.1-nightly.20260519.0 → 0.45.1-dev.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 +3289 -0
  4. package/dist/LexicalHtml.dev.mjs +3242 -0
  5. package/{LexicalHtml.js.flow → dist/LexicalHtml.js.flow} +16 -16
  6. package/dist/LexicalHtml.mjs +57 -0
  7. package/dist/LexicalHtml.node.mjs +55 -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 +28 -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 +106 -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 +52 -0
  42. package/src/import/ImportContext.ts +339 -0
  43. package/src/import/compileImportRules.ts +178 -0
  44. package/src/import/coreImportRules.ts +545 -0
  45. package/src/import/defineImportRule.ts +40 -0
  46. package/src/import/defineOverlayRules.ts +105 -0
  47. package/src/import/index.ts +97 -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 +280 -0
  52. package/src/import/sel.ts +314 -0
  53. package/src/import/types.ts +471 -0
  54. package/src/index.ts +561 -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
package/src/types.ts ADDED
@@ -0,0 +1,470 @@
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
+
9
+ import type {DOMImportContextSymbol, DOMRenderContextSymbol} from './constants';
10
+ import type {
11
+ BaseSelection,
12
+ DOMExportOutput,
13
+ DOMSlotForNode,
14
+ EditorDOMRenderConfig,
15
+ Klass,
16
+ LexicalEditor,
17
+ LexicalNode,
18
+ StateConfig,
19
+ } from 'lexical';
20
+
21
+ /**
22
+ * @experimental
23
+ *
24
+ * Any ContextSymbol for {@link ContextConfig} (DOM render or DOM import).
25
+ */
26
+ export type AnyContextSymbol =
27
+ | typeof DOMRenderContextSymbol
28
+ | typeof DOMImportContextSymbol;
29
+
30
+ /**
31
+ * @experimental
32
+ *
33
+ * Context with a phantom type for its purpose (such as {@link DOMRenderContextSymbol}).
34
+ *
35
+ * A ContextRecord is a data structure used in the export and import pipelines
36
+ * to allow for information to be passed throughout the chain without explicit
37
+ * argument passing, e.g. to specify whether the intended use case for HTML
38
+ * export is for serialization or for clipboard copy.
39
+ */
40
+ export type ContextRecord<_K extends symbol> = Record<string | symbol, unknown>;
41
+
42
+ /**
43
+ * @experimental
44
+ *
45
+ * A data structure much like StateConfig (they share implementation details)
46
+ * but for managing context during an export or import pipeline rather than
47
+ * individual node state.
48
+ */
49
+ export type ContextConfig<Sym extends symbol, V> = StateConfig<symbol, V> & {
50
+ readonly [K in Sym]?: true;
51
+ };
52
+
53
+ /**
54
+ * @experimental
55
+ *
56
+ * Update the context at `cfg` with updater, constructed with {@link contextUpdater}
57
+ */
58
+ export type ContextConfigUpdater<Ctx extends AnyContextSymbol, V> = {
59
+ readonly cfg: ContextConfig<Ctx, V>;
60
+ /**
61
+ * @param prev The current or default value
62
+ * @returns The new value
63
+ */
64
+ readonly updater: (prev: V) => V;
65
+ };
66
+
67
+ /**
68
+ * @experimental
69
+ *
70
+ * Set the the context at `cfg` to a specific value, constructed with {@link contextValue}
71
+ */
72
+ export type ContextConfigPair<Ctx extends AnyContextSymbol, V> = readonly [
73
+ ContextConfig<Ctx, V>,
74
+ V,
75
+ ];
76
+
77
+ /**
78
+ * @experimental
79
+ *
80
+ * Set or update a context value, constructed with {@link contextValue} or {@link contextUpdater}
81
+ */
82
+ export type ContextPairOrUpdater<Ctx extends AnyContextSymbol, V> =
83
+ | ContextConfigPair<Ctx, V>
84
+ | ContextConfigUpdater<Ctx, V>;
85
+
86
+ /** @experimental */
87
+ export type AnyContextConfigPairOrUpdater<Ctx extends AnyContextSymbol> =
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ ContextPairOrUpdater<Ctx, any>;
90
+
91
+ /** @experimental */
92
+ export interface DOMRenderExtensionOutput {
93
+ /** @internal */
94
+ defaults: undefined | ContextRecord<typeof DOMRenderContextSymbol>;
95
+ /** @internal */
96
+ runtime: DOMRenderRuntime;
97
+ }
98
+
99
+ /**
100
+ * @experimental
101
+ *
102
+ * A read-only view of a render context layer, passed to the
103
+ * {@link DOMOverrideOptions} predicates so they can decide whether an
104
+ * override should be installed based only on context values.
105
+ */
106
+ export interface RenderContextReader {
107
+ get<V>(cfg: RenderStateConfig<V>): V;
108
+ }
109
+
110
+ /**
111
+ * @experimental
112
+ * @internal
113
+ *
114
+ * Per-editor runtime state for {@link DOMRenderExtension} that backs the
115
+ * imperative editor context ({@link createRenderState} writes via
116
+ * `$setRenderContextValue`) and the conditional install of overrides.
117
+ */
118
+ export interface DOMRenderRuntime {
119
+ /**
120
+ * The mutable, persistent editor-level context record. Reads of a
121
+ * {@link RenderStateConfig} during reconciliation (and as the base layer
122
+ * during a session) fall through to this record. It is also the layer
123
+ * that {@link DOMOverrideOptions.disabledForEditor} predicates read from.
124
+ */
125
+ readonly editorContext: ContextRecord<typeof DOMRenderContextSymbol>;
126
+ /**
127
+ * Imperatively set a value in the editor context. If the change flips any
128
+ * override's `disabledForEditor` result, the resident render config is
129
+ * recompiled and the affected nodes are re-rendered (recreating DOM for
130
+ * structural overrides).
131
+ */
132
+ setContextValue<V>(cfg: RenderStateConfig<V>, value: V): void;
133
+ /**
134
+ * Resolve the {@link EditorDOMRenderConfig} for the current export/generate
135
+ * session, applying any {@link DOMOverrideOptions.disabledForSession}
136
+ * predicates against the active session context. Returns the resident
137
+ * config when no session gating applies.
138
+ */
139
+ getSessionConfig(): EditorDOMRenderConfig;
140
+ }
141
+
142
+ /**
143
+ * @experimental
144
+ *
145
+ * Options for {@link domOverride} controlling *whether* an override is
146
+ * installed, based only on render context. Both predicates default to
147
+ * "not disabled".
148
+ */
149
+ export interface DOMOverrideOptions {
150
+ /**
151
+ * Gate residency in the editor's render config (used by reconciliation and
152
+ * as the base for export/generate). Evaluated against the persistent editor
153
+ * context at compile time, and re-evaluated when that context changes via
154
+ * `$setRenderContextValue`; a change recompiles the config and re-renders
155
+ * affected nodes. Return `true` to remove the override. Default: not disabled.
156
+ */
157
+ disabledForEditor?: (ctx: RenderContextReader) => boolean;
158
+ /**
159
+ * Gate participation in a single export/generate session. Evaluated once at
160
+ * the start of each session against that session's context. Has no effect on
161
+ * live reconciliation (which is not a session). Return `true` to remove the
162
+ * override for that session. Default: not disabled.
163
+ */
164
+ disabledForSession?: (ctx: RenderContextReader) => boolean;
165
+ }
166
+
167
+ /**
168
+ * @experimental
169
+ *
170
+ * Context configuration for render context, created with {@link createRenderState}
171
+ */
172
+ export type RenderStateConfig<V> = ContextConfig<
173
+ typeof DOMRenderContextSymbol,
174
+ V
175
+ >;
176
+
177
+ /**
178
+ * @experimental
179
+ *
180
+ * Any setter or updater for {@link RenderStateConfig}
181
+ */
182
+ export type AnyRenderStateConfigPairOrUpdater = AnyContextConfigPairOrUpdater<
183
+ typeof DOMRenderContextSymbol
184
+ >;
185
+
186
+ /**
187
+ * @experimental
188
+ *
189
+ * Any {@link RenderStateConfig}
190
+ */
191
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
192
+ export type AnyRenderStateConfig = RenderStateConfig<any>;
193
+
194
+ /**
195
+ * @experimental
196
+ *
197
+ * Configuration for {@link DOMRenderExtension}
198
+ */
199
+ export interface DOMRenderConfig {
200
+ /**
201
+ * {@link DOMRenderMatch} overrides to customize node behavior,
202
+ * the final priority of these will be based on the following criteria:
203
+ *
204
+ * - Wildcards (`'*'`) have highest priority
205
+ * - Predicates (`$isParagraphNode`) have next priority
206
+ * - Subclasses have higher priority (e.g. `ParagraphNode` before `ElementNode`)
207
+ * - Extensions closer to the root have higher priority
208
+ * - Extensions depended on later have higher priority
209
+ * - Overrides defined later have higher priority
210
+ */
211
+ overrides: AnyDOMRenderMatch[];
212
+ /**
213
+ * Default context to provide in all exports, the configurations are created
214
+ * with {@link createRenderState} and should be created at the module-level.
215
+ *
216
+ * Only specify these if overriding the default value globally, since each
217
+ * configuration has a built-in default value that will be used if not
218
+ * already present in the context.
219
+ */
220
+ contextDefaults: AnyRenderStateConfigPairOrUpdater[];
221
+ }
222
+
223
+ /**
224
+ * @experimental
225
+ * Any {@link DOMRenderMatch}
226
+ */
227
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
228
+ export type AnyDOMRenderMatch = DOMRenderMatch<any>;
229
+
230
+ /**
231
+ * @experimental
232
+ *
233
+ * Match a node (and any subclass of that node) by its LexicalNode class,
234
+ * or with a guard (e.g. `ElementNode` or `$isElementNode`).
235
+ *
236
+ * Note that using the class compiles to significantly more efficient code
237
+ * than using a guard.
238
+ */
239
+ export type NodeMatch<T extends LexicalNode> =
240
+ | Klass<T>
241
+ | ((node: LexicalNode) => node is T);
242
+
243
+ /**
244
+ * @experimental
245
+ *
246
+ * Used to define overrides for the render and export
247
+ * behavior for nodes matching the `nodes` predicate.
248
+ *
249
+ * All of these overrides are in a middleware style where you may use the
250
+ * result of `$next()` to enhance the result of the default implementation
251
+ * (or a lower priority override) by calling it and manipulating the result,
252
+ * or you may choose not to call `$next()` to entirely replace the behavior.
253
+ *
254
+ * It is not permitted to update the lexical editor state during any of
255
+ * these calls, you should only be doing read-only operations.
256
+ */
257
+ export interface DOMRenderMatch<T extends LexicalNode> {
258
+ /**
259
+ * '*' for all nodes, or an array of `NodeClass | $isNodeGuard` to match
260
+ * nodes more specifically. Using classes is more efficient, but will
261
+ * also target subclasses.
262
+ */
263
+ readonly nodes: '*' | readonly NodeMatch<T>[];
264
+ /**
265
+ * Control where an ElementNode's children are inserted into the DOM,
266
+ * this is useful to add a wrapping node or accessory nodes before or
267
+ * after the children. The root of the node returned by createDOM must
268
+ * still be exactly one HTMLElement.
269
+ *
270
+ * Generally you will call `$next()` to get a slot and then use its methods
271
+ * to create a new one. The slot type is narrowed via {@link DOMSlotForNode}:
272
+ * for `ElementNode` it resolves to {@link ElementDOMSlot} with
273
+ * children-management semantics; for non-Element nodes the base
274
+ * {@link DOMSlot} pointing at the keyed DOM.
275
+ *
276
+ * @param node The LexicalNode
277
+ * @param dom The rendered HTMLElement
278
+ * @param $next Call the next implementation
279
+ * @param editor The editor
280
+ * @returns The slot for this node
281
+ */
282
+ $getDOMSlot?: (
283
+ node: T,
284
+ dom: HTMLElement,
285
+ $next: () => DOMSlotForNode<T>,
286
+ editor: LexicalEditor,
287
+ ) => DOMSlotForNode<T>;
288
+ /**
289
+ * Called during the reconciliation process to determine which nodes
290
+ * to insert into the DOM for this Lexical Node. This is also the default
291
+ * implementation of `$exportDOM` for most nodes.
292
+ *
293
+ * This method must return exactly one `HTMLElement`.
294
+ *
295
+ * Nested elements are not supported except with `DecoratorNode`
296
+ * (which have unmanaged contents) or `ElementNode` using an appropriate
297
+ * `$getDOMSlot` return value.
298
+ *
299
+ * @param node The LexicalNode
300
+ * @param $next Call the next implementation
301
+ * @param editor The editor
302
+ * @returns The HTMLElement for this node to be rendered in the editor
303
+ */
304
+ $createDOM?: (
305
+ node: T,
306
+ $next: () => HTMLElement,
307
+ editor: LexicalEditor,
308
+ ) => HTMLElement;
309
+ /**
310
+ * Called when a node changes and should update the DOM
311
+ * in whatever way is necessary to make it align with any changes that might
312
+ * have happened during the update.
313
+ *
314
+ * Returning `true` here will cause lexical to unmount and recreate the DOM
315
+ * node (by calling `$createDOM`). You would need to do this if the element
316
+ * tag changes, for instance.
317
+ *
318
+ * @param nextNode The current version of this node
319
+ * @param prevNode The previous version of this node
320
+ * @param dom The previously rendered HTMLElement for this node
321
+ * @param $next Call the next implementation
322
+ * @param editor The editor
323
+ * @returns `false` if no update needed or was performed in-place, `true` if `$createDOM` should be called to re-create the node
324
+ */
325
+ $updateDOM?: (
326
+ nextNode: T,
327
+ prevNode: T,
328
+ dom: HTMLElement,
329
+ $next: () => boolean,
330
+ editor: LexicalEditor,
331
+ ) => boolean;
332
+ /**
333
+ * Called after a node is created or updated and should make any in-place
334
+ * updates to the DOM in whatever way is necessary to make it align with
335
+ * any changes that might have happened during the `$createDOM` or
336
+ * `$updateDOM`. This also runs after any children have been reconciled.
337
+ *
338
+ * Use this when you have code that you would need to duplicate in both
339
+ * methods, or if there is a need to ensure that the children are also
340
+ * reconciled before performing this in-place update.
341
+ *
342
+ * Unlike other overrides, all applicable `$decorateDOM` functions are
343
+ * called unconditionally. There is no `$next` argument, because there
344
+ * are no known use cases for avoiding the next implementation and due
345
+ * to the void return value it would be error-prone and add boilerplate
346
+ * to require calling it.
347
+ *
348
+ * The ordering here is equivalent to an implicit `$next` call *first*.
349
+ *
350
+ * @param nextNode The current version of this node
351
+ * @param prevNode The previous version of this node if `$updateDOM` returned `false`, or `null` if `$createDOM` was just called
352
+ * @param dom The previously rendered `HTMLElement` for this node
353
+ * @param editor The editor
354
+ */
355
+ $decorateDOM?: (
356
+ nextNode: T,
357
+ prevNode: null | T,
358
+ dom: HTMLElement,
359
+ editor: LexicalEditor,
360
+ ) => void;
361
+
362
+ /**
363
+ * Controls how the this node is serialized to HTML. This is important for
364
+ * copy and paste between Lexical and non-Lexical editors, or Lexical
365
+ * editors with different namespaces, in which case the primary transfer
366
+ * format is HTML. It's also important if you're serializing to HTML for
367
+ * any other reason via {@link @lexical/html!$generateHtmlFromNodes}.
368
+ *
369
+ * @param node The LexicalNode
370
+ * @param $next Call the next implementation
371
+ * @param editor The editor
372
+ * @returns A {@link DOMExportOutput} structure that defines how the node should be exported to HTML
373
+ */
374
+ $exportDOM?: (
375
+ node: T,
376
+ $next: () => DOMExportOutput,
377
+ editor: LexicalEditor,
378
+ ) => DOMExportOutput;
379
+ /**
380
+ * Equivalent to `ElementNode.excludeFromCopy`, if it returns `true` this
381
+ * lexical node will not be exported to DOM (but if it's an `ElementNode`
382
+ * its children may still be inserted in its place).
383
+ *
384
+ * Has higher precedence than `$shouldInclude` and `$extractWithChild`.
385
+ *
386
+ * @param node The LexicalNode
387
+ * @param selection The current selection
388
+ * @param $next The next implementation
389
+ * @param editor The editor
390
+ * @returns true to exclude this node, false otherwise
391
+ */
392
+ $shouldExclude?: (
393
+ node: T,
394
+ selection: null | BaseSelection,
395
+ $next: () => boolean,
396
+ editor: LexicalEditor,
397
+ ) => boolean;
398
+ /**
399
+ * Return `true` if this node should be included in the export, typically based
400
+ * on the current selection (all nodes by default are included when there
401
+ * is no selection).
402
+ *
403
+ * The default implementation is equivalent to
404
+ * `selection ? node.isSelected(selection) : true`.
405
+ *
406
+ * This has lower precedence than `$extractWithChild` and `$shouldExclude`.
407
+ *
408
+ * @param node The current node
409
+ * @param selection The current selection
410
+ * @param $next The next implementation
411
+ * @param editor The editor
412
+ * @returns `true` if this node should be included in the export, `false` otherwise
413
+ */
414
+ $shouldInclude?: (
415
+ node: T,
416
+ selection: null | BaseSelection,
417
+ $next: () => boolean,
418
+ editor: LexicalEditor,
419
+ ) => boolean;
420
+ /**
421
+ * Return `true` if this node should be included in the export based on
422
+ * `childNode`, even if it would not otherwise be included based on its
423
+ * `$shouldInclude` result.
424
+ *
425
+ * Typically used to ensure that required wrapping nodes are always
426
+ * present with its children, e.g. a ListNode when some of its ListItemNode
427
+ * children are selected.
428
+ *
429
+ * This has higher precedence than `$extractWithChild` and lower precedence
430
+ * than `$shouldExclude`.
431
+ *
432
+ * @param node The lexical node
433
+ * @param childNode A child of this lexical node
434
+ * @param selection The current selection
435
+ * @param destination Currently always `'html'`
436
+ * @param $next The next implementation
437
+ * @param editor The editor
438
+ * @returns true if this
439
+ */
440
+ $extractWithChild?: (
441
+ node: T,
442
+ childNode: LexicalNode,
443
+ selection: null | BaseSelection,
444
+ destination: 'clone' | 'html',
445
+ $next: () => boolean,
446
+ editor: LexicalEditor,
447
+ ) => boolean;
448
+ /**
449
+ * Set via {@link domOverride}'s options argument, not directly. See
450
+ * {@link DOMOverrideOptions.disabledForEditor}.
451
+ */
452
+ disabledForEditor?: (ctx: RenderContextReader) => boolean;
453
+ /**
454
+ * Set via {@link domOverride}'s options argument, not directly. See
455
+ * {@link DOMOverrideOptions.disabledForSession}.
456
+ */
457
+ disabledForSession?: (ctx: RenderContextReader) => boolean;
458
+ }
459
+
460
+ /**
461
+ * @experimental
462
+ *
463
+ * The hook fields of a {@link DOMRenderMatch} — i.e. without `nodes` or the
464
+ * {@link DOMOverrideOptions} predicates, which are passed separately to
465
+ * {@link domOverride}.
466
+ */
467
+ export type DOMRenderMatchConfig<T extends LexicalNode> = Omit<
468
+ DOMRenderMatch<T>,
469
+ 'nodes' | keyof DOMOverrideOptions
470
+ >;