@mx-space/cli 0.7.7 → 0.8.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 (55) hide show
  1. package/dist/{Lexical.dev-rcxzwpir.mjs → Lexical.dev-By5dOKBN.mjs} +1486 -356
  2. package/dist/{Lexical.node-BUsI9gWr.mjs → Lexical.node-fXM8Jp7p.mjs} +39 -17
  3. package/dist/{Lexical.prod-C8HtkSD6.mjs → Lexical.prod-BlCvXPGa.mjs} +2279 -1768
  4. package/dist/LexicalClipboard.dev--HxGoSkO.mjs +915 -0
  5. package/dist/{LexicalClipboard.node-CO-MCKx5.mjs → LexicalClipboard.node-C3mRbrmW.mjs} +10 -3
  6. package/dist/LexicalClipboard.prod-DNJzFMcT.mjs +371 -0
  7. package/dist/LexicalCodeCore.dev-DjSrd4A4.mjs +1109 -0
  8. package/dist/LexicalCodeCore.prod-DTDShkR3.mjs +642 -0
  9. package/dist/{LexicalDragon.dev-gBP8WSRS.mjs → LexicalDragon.dev-DwprRH0z.mjs} +3 -3
  10. package/dist/{LexicalDragon.node-OG6G55nl.mjs → LexicalDragon.node-BVhw4C7s.mjs} +2 -2
  11. package/dist/{LexicalDragon.prod-DP-_Q8cv.mjs → LexicalDragon.prod-nh4J-8vn.mjs} +3 -3
  12. package/dist/{LexicalExtension.dev-DVbjljrm.mjs → LexicalExtension.dev-BPNyvGqe.mjs} +335 -6
  13. package/dist/{LexicalExtension.node-CF3EAPN7.mjs → LexicalExtension.node-BVlcrgOx.mjs} +15 -8
  14. package/dist/{LexicalExtension.prod-DklHHErZ.mjs → LexicalExtension.prod-DFKbiNt-.mjs} +375 -265
  15. package/dist/{LexicalHeadless.dev-DdWLM7Nl.mjs → LexicalHeadless.dev-B-cj7Pr5.mjs} +2 -2
  16. package/dist/{LexicalHeadless.prod-CoiiTDzR.mjs → LexicalHeadless.prod-Byp1vNzT.mjs} +2 -2
  17. package/dist/LexicalHtml.dev-prBAwszN.mjs +2424 -0
  18. package/dist/LexicalHtml.node-BvNF96jZ.mjs +56 -0
  19. package/dist/LexicalHtml.prod-Sz3CW1ht.mjs +1207 -0
  20. package/dist/{LexicalLink.dev-BS1Bf-yD.mjs → LexicalLink.dev-NySTYhVR.mjs} +42 -8
  21. package/dist/{LexicalLink.prod-B_crkoHP.mjs → LexicalLink.prod-BuCM8gts.mjs} +209 -191
  22. package/dist/{LexicalList.dev-OMqmcnQ-.mjs → LexicalList.dev-DIMOvSFD.mjs} +252 -80
  23. package/dist/{LexicalList.prod-CpL1s8vS.mjs → LexicalList.prod-MVqfA6Vo.mjs} +364 -278
  24. package/dist/{LexicalMarkdown.dev-BHSdx_Gr.mjs → LexicalMarkdown.dev-C7aylvCG.mjs} +729 -552
  25. package/dist/LexicalMarkdown.prod-CfQSM406.mjs +868 -0
  26. package/dist/{LexicalRichText.dev-Bz9A_WbM.mjs → LexicalRichText.dev-DfICq6lU.mjs} +272 -77
  27. package/dist/{LexicalRichText.node-DDpwfE-P.mjs → LexicalRichText.node-Bg9jND3Q.mjs} +21 -8
  28. package/dist/LexicalRichText.prod-GsFzCK-o.mjs +550 -0
  29. package/dist/{LexicalSelection.dev-CQ380fnD.mjs → LexicalSelection.dev-DGjj12wW.mjs} +50 -38
  30. package/dist/{LexicalSelection.node-DesBMjIE.mjs → LexicalSelection.node-BU5L4193.mjs} +4 -4
  31. package/dist/{LexicalSelection.prod-D2jivCDB.mjs → LexicalSelection.prod-D-PwRbyK.mjs} +158 -140
  32. package/dist/{LexicalTable.dev-Ca7mQ7Jk.mjs → LexicalTable.dev-ChP7cugd.mjs} +215 -53
  33. package/dist/{LexicalTable.prod-DyPAcC7y.mjs → LexicalTable.prod-Bpr9YRXp.mjs} +668 -573
  34. package/dist/{LexicalUtils.dev-HxM8F0g6.mjs → LexicalUtils.dev-BiFU3789.mjs} +10 -47
  35. package/dist/{LexicalUtils.node-lCWjRjoG.mjs → LexicalUtils.node-j3Llm7Y3.mjs} +2 -2
  36. package/dist/{LexicalUtils.prod-Bti5w4ki.mjs → LexicalUtils.prod-DCvrA78p.mjs} +103 -105
  37. package/dist/bin/mxs.d.mts +1 -1
  38. package/dist/bin/mxs.mjs +1 -1
  39. package/dist/esm-By7trG9K.mjs +2 -0
  40. package/dist/{esm-CK9m5JKX.mjs → esm-Dg-WhPCe.mjs} +989 -989
  41. package/dist/index.d.mts +22 -2
  42. package/dist/index.mjs +1 -1
  43. package/dist/{mxs-vbxEu09D.mjs → mxs-DT0oYk6U.mjs} +10387 -8278
  44. package/package.json +18 -17
  45. package/dist/LexicalClipboard.dev-BpqRwTLP.mjs +0 -494
  46. package/dist/LexicalClipboard.prod-B_xdeiAC.mjs +0 -291
  47. package/dist/LexicalCodeCore.dev-7_cexm39.mjs +0 -537
  48. package/dist/LexicalCodeCore.prod-Bd6WFHcO.mjs +0 -381
  49. package/dist/LexicalHtml.dev-C3ZSWBFZ.mjs +0 -684
  50. package/dist/LexicalHtml.node-D0TD152E.mjs +0 -24
  51. package/dist/LexicalHtml.prod-CX47X0zl.mjs +0 -430
  52. package/dist/LexicalMarkdown.prod-C-S7Ii6-.mjs +0 -754
  53. package/dist/LexicalRichText.prod-C8qXACDL.mjs +0 -427
  54. package/dist/esm-DRbkkY3r.mjs +0 -2
  55. /package/dist/{mxs-CM8-6uAr.d.mts → mxs-iqJBopvE.d.mts} +0 -0
@@ -0,0 +1,2424 @@
1
+ import { d as getPeerDependencyFromEditor, i as HorizontalRuleExtension, n as $getExtensionOutput, t as $createHorizontalRuleNode, u as getKnownTypesAndNodes } from "./LexicalExtension.node-BVlcrgOx.mjs";
2
+ import { $ as $isElementNode, At as ArtificialNode__DO_NOT_USE, Cn as IS_STRIKETHROUGH, En as IS_UNDERLINE, F as $getEditor, Fr as shallowMergeConfig, Gn as RootNode, Gt as DEFAULT_EDITOR_DOM_CONFIG, H as $getRoot, I as $getEditorDOMRenderConfig, Pr as setNodeIndentFromDOM, Sr as isHTMLElement, St as $setFormatFromDOM, Tn as IS_SUPERSCRIPT, Y as $isBlockElementNode, Z as $isDecoratorNode, _ as $createTextNode, _n as IS_CODE, _r as isDOMDocumentNode, b as $fullReconcile, br as isDocumentFragment, cr as defineExtension, f as $createParagraphNode, fr as getStaticNodeConfig, ft as $isTextNode, hn as IS_BOLD, hr as isBlockDomNode, lt as $isRootOrShadowRoot, or as createState, rr as configExtension, rt as $isLexicalNode, u as $createLineBreakNode, wn as IS_SUBSCRIPT, wr as isInlineDomNode, x as $generateNodesFromRawText, xn as IS_ITALIC, xt as $setDirectionFromDOM, yn as IS_HIGHLIGHT, yr as isDOMTextNode } from "./Lexical.node-fXM8Jp7p.mjs";
3
+ import { i as $sliceSelectedTextNodeContent } from "./LexicalSelection.node-BU5L4193.mjs";
4
+ import { g as objectKlassEquals } from "./LexicalUtils.node-j3Llm7Y3.mjs";
5
+ //#region ../../node_modules/.pnpm/@lexical+html@0.45.0/node_modules/@lexical/html/dist/LexicalHtml.dev.mjs
6
+ /**
7
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
8
+ *
9
+ * This source code is licensed under the MIT license found in the
10
+ * LICENSE file in the root directory of this source tree.
11
+ *
12
+ */
13
+ /**
14
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
15
+ *
16
+ * This source code is licensed under the MIT license found in the
17
+ * LICENSE file in the root directory of this source tree.
18
+ *
19
+ */
20
+ function formatDevErrorMessage(message) {
21
+ throw new Error(message);
22
+ }
23
+ /**
24
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
25
+ *
26
+ * This source code is licensed under the MIT license found in the
27
+ * LICENSE file in the root directory of this source tree.
28
+ *
29
+ */
30
+ let activeContext;
31
+ /**
32
+ * @experimental
33
+ *
34
+ * The LexicalEditor with context
35
+ */
36
+ /**
37
+ * @experimental
38
+ *
39
+ * @param contextRecord The ContextRecord
40
+ * @param cfg The configuration
41
+ * @returns The value or defaultValue of cfg
42
+ */
43
+ function getContextValue(contextRecord, cfg) {
44
+ const { key } = cfg;
45
+ return contextRecord && key in contextRecord ? contextRecord[key] : cfg.defaultValue;
46
+ }
47
+ function getEditorContext(editor) {
48
+ return activeContext && activeContext.editor === editor ? activeContext : void 0;
49
+ }
50
+ /**
51
+ * @experimental
52
+ *
53
+ * @param sym The symbol for this ContextRecord (e.g. DOMRenderContextSymbol)
54
+ * @param editor The editor
55
+ * @returns The current context or undefined
56
+ */
57
+ function getContextRecord(sym, editor) {
58
+ const editorContext = getEditorContext(editor);
59
+ return editorContext && editorContext[sym];
60
+ }
61
+ function toPair(contextRecord, pairOrUpdater) {
62
+ if ("cfg" in pairOrUpdater) {
63
+ const { cfg, updater } = pairOrUpdater;
64
+ return [cfg, updater(getContextValue(contextRecord, cfg))];
65
+ }
66
+ return pairOrUpdater;
67
+ }
68
+ /**
69
+ * Construct a new context from a parent context and pairs
70
+ *
71
+ * @param pairs The pairs and updaters to build the context from
72
+ * @param parent The parent context
73
+ * @returns The new context
74
+ */
75
+ function contextFromPairs(pairs, parent) {
76
+ let rval = parent;
77
+ for (const pairOrUpdater of pairs) {
78
+ const [k, v] = toPair(rval, pairOrUpdater);
79
+ const key = k.key;
80
+ if (rval === parent && getContextValue(rval, k) === v) continue;
81
+ const ctx = rval === parent || rval === void 0 ? createChildContext(parent) : rval;
82
+ ctx[key] = v;
83
+ rval = ctx;
84
+ }
85
+ return rval;
86
+ }
87
+ function createChildContext(parent) {
88
+ return Object.create(parent || null);
89
+ }
90
+ /**
91
+ * Create a context config pair that sets a value in the render context.
92
+ * @experimental
93
+ */
94
+ function contextValue(cfg, value) {
95
+ return [cfg, value];
96
+ }
97
+ /**
98
+ * Create a context config updater that transforms a value in the render context.
99
+ * @experimental
100
+ */
101
+ function contextUpdater(cfg, updater) {
102
+ return {
103
+ cfg,
104
+ updater
105
+ };
106
+ }
107
+ /**
108
+ * @internal
109
+ * @experimental
110
+ * @__NO_SIDE_EFFECTS__
111
+ */
112
+ function $withFullContext(sym, contextRecord, f, editor = $getEditor()) {
113
+ const prevDOMContext = activeContext;
114
+ const parentEditorContext = getEditorContext(editor);
115
+ try {
116
+ activeContext = {
117
+ ...parentEditorContext,
118
+ editor,
119
+ [sym]: contextRecord
120
+ };
121
+ return f();
122
+ } finally {
123
+ activeContext = prevDOMContext;
124
+ }
125
+ }
126
+ /**
127
+ * @internal
128
+ * @experimental
129
+ * @__NO_SIDE_EFFECTS__
130
+ */
131
+ function $withContext(sym, $defaults = () => void 0) {
132
+ return (cfg, editor = $getEditor()) => {
133
+ return (f) => {
134
+ const parentEditorContext = getEditorContext(editor);
135
+ const parentContextRecord = parentEditorContext && parentEditorContext[sym];
136
+ const contextRecord = contextFromPairs(cfg, parentContextRecord || $defaults(editor));
137
+ if (!contextRecord || contextRecord === parentContextRecord) return f();
138
+ return $withFullContext(sym, contextRecord, f, editor);
139
+ };
140
+ };
141
+ }
142
+ /**
143
+ * @experimental
144
+ * @internal
145
+ * @__NO_SIDE_EFFECTS__
146
+ */
147
+ function createContextState(tag, name, getDefaultValue, isEqual) {
148
+ return Object.assign(createState(Symbol(name), {
149
+ isEqual,
150
+ parse: getDefaultValue
151
+ }), { [tag]: true });
152
+ }
153
+ /**
154
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
155
+ *
156
+ * This source code is licensed under the MIT license found in the
157
+ * LICENSE file in the root directory of this source tree.
158
+ *
159
+ */
160
+ /**
161
+ * Inlines CSS rules from `<style>` tags onto matching elements as inline
162
+ * styles.
163
+ *
164
+ * Used by apps like Excel that generate HTML where styles live in
165
+ * class-based `<style>` rules (e.g. `.xl65 { background: #FFFF00; color:
166
+ * blue; }`) rather than inline styles. Since Lexical's import converters
167
+ * read inline styles, we resolve stylesheet rules into inline styles
168
+ * before conversion.
169
+ *
170
+ * Mutates the DOM in-place. Original inline styles always take
171
+ * precedence over stylesheet rules (matching CSS specificity behavior).
172
+ *
173
+ * No-op for {@link ParentNode}s that are not {@link Document}s — only a
174
+ * full document carries `styleSheets` we can iterate.
175
+ *
176
+ * @experimental
177
+ */
178
+ const $inlineStylesFromStyleSheets = (dom, _ctx, $next) => {
179
+ $inlineStylesFromStyleSheetsDOM(dom);
180
+ $next();
181
+ };
182
+ function $inlineStylesFromStyleSheetsDOM(dom) {
183
+ if (!isDOMDocumentNode(dom)) return;
184
+ const doc = dom;
185
+ if (doc.querySelector("style") === null) return;
186
+ const originalInlineStyles = /* @__PURE__ */ new Map();
187
+ function getOriginalInlineProps(el) {
188
+ let props = originalInlineStyles.get(el);
189
+ if (props === void 0) {
190
+ props = /* @__PURE__ */ new Set();
191
+ for (let i = 0; i < el.style.length; i++) props.add(el.style[i]);
192
+ originalInlineStyles.set(el, props);
193
+ }
194
+ return props;
195
+ }
196
+ try {
197
+ for (const sheet of Array.from(doc.styleSheets)) {
198
+ let rules;
199
+ try {
200
+ rules = sheet.cssRules;
201
+ } catch (_unused) {
202
+ continue;
203
+ }
204
+ for (const rule of Array.from(rules)) {
205
+ if (!objectKlassEquals(rule, CSSStyleRule)) continue;
206
+ let elements;
207
+ try {
208
+ elements = doc.querySelectorAll(rule.selectorText);
209
+ } catch (_unused2) {
210
+ continue;
211
+ }
212
+ for (const el of Array.from(elements)) {
213
+ if (!isHTMLElement(el)) continue;
214
+ const originalProps = getOriginalInlineProps(el);
215
+ for (let i = 0; i < rule.style.length; i++) {
216
+ const prop = rule.style[i];
217
+ if (!originalProps.has(prop)) el.style.setProperty(prop, rule.style.getPropertyValue(prop), rule.style.getPropertyPriority(prop));
218
+ }
219
+ }
220
+ }
221
+ }
222
+ } catch (_unused3) {}
223
+ }
224
+ /**
225
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
226
+ *
227
+ * This source code is licensed under the MIT license found in the
228
+ * LICENSE file in the root directory of this source tree.
229
+ *
230
+ */
231
+ const DOMRenderExtensionName = "@lexical/html/DOM";
232
+ const DOMRenderContextSymbol = Symbol.for("@lexical/html/DOMExportContext");
233
+ const DOMImportExtensionName = "@lexical/html/DOMImport";
234
+ const DOMImportContextSymbol = Symbol.for("@lexical/html/DOMImportContext");
235
+ const ALWAYS_TRUE = () => true;
236
+ /**
237
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
238
+ *
239
+ * This source code is licensed under the MIT license found in the
240
+ * LICENSE file in the root directory of this source tree.
241
+ *
242
+ */
243
+ /**
244
+ * Create a context state to be used during render.
245
+ *
246
+ * Note that to support the ValueOrUpdater pattern you can not use a
247
+ * function for V (but you may wrap it in an array or object).
248
+ *
249
+ * @experimental
250
+ * @__NO_SIDE_EFFECTS__
251
+ */
252
+ function createRenderState(name, getDefaultValue, isEqual) {
253
+ return createContextState(DOMRenderContextSymbol, name, getDefaultValue, isEqual);
254
+ }
255
+ /**
256
+ * Render context state that is true if the export was initiated from the root of the document.
257
+ * @experimental
258
+ */
259
+ const RenderContextRoot = createRenderState("root", Boolean);
260
+ /**
261
+ * Render context state that is true if this is an export operation ($generateHtmlFromNodes).
262
+ * @experimental
263
+ */
264
+ const RenderContextExport = createRenderState("isExport", Boolean);
265
+ function getDefaultRenderContext(editor) {
266
+ const dep = getPeerDependencyFromEditor(editor, DOMRenderExtensionName);
267
+ return dep ? dep.output.defaults : void 0;
268
+ }
269
+ function getRenderContext(editor) {
270
+ return getContextRecord(DOMRenderContextSymbol, editor) || getDefaultRenderContext(editor);
271
+ }
272
+ /**
273
+ * Get a render context value during a DOM render or export operation.
274
+ * @experimental
275
+ */
276
+ function $getRenderContextValue(cfg, editor = $getEditor()) {
277
+ return getContextValue(getRenderContext(editor), cfg);
278
+ }
279
+ function getRuntime(editor) {
280
+ const dep = getPeerDependencyFromEditor(editor, DOMRenderExtensionName);
281
+ return dep ? dep.output.runtime : void 0;
282
+ }
283
+ /**
284
+ * Imperatively set a value in the persistent editor render context.
285
+ *
286
+ * Unlike {@link $withRenderContext} (which scopes values to a callback), this
287
+ * persists on the editor. If the change flips any override's
288
+ * `disabledForEditor` result, the resident render config is recompiled and the
289
+ * affected nodes are re-rendered. No-op if {@link DOMRenderExtension} is not
290
+ * installed.
291
+ *
292
+ * @experimental
293
+ */
294
+ function $setRenderContextValue(cfg, value, editor = $getEditor()) {
295
+ const runtime = getRuntime(editor);
296
+ if (runtime) runtime.setContextValue(cfg, value);
297
+ }
298
+ /**
299
+ * Imperatively update a value in the persistent editor render context with an
300
+ * updater function. See {@link $setRenderContextValue}.
301
+ *
302
+ * @experimental
303
+ */
304
+ function $updateRenderContextValue(cfg, updater, editor = $getEditor()) {
305
+ const runtime = getRuntime(editor);
306
+ if (runtime) runtime.setContextValue(cfg, updater(getContextValue(runtime.editorContext, cfg)));
307
+ }
308
+ /**
309
+ * Resolve the {@link EditorDOMRenderConfig} to use for the current
310
+ * export/generate session, applying any `disabledForSession` overrides against
311
+ * the active session context. Falls back to the editor's resident config when
312
+ * {@link DOMRenderExtension} is not installed.
313
+ *
314
+ * @experimental
315
+ */
316
+ function $getSessionDOMRenderConfig(editor = $getEditor()) {
317
+ const runtime = getRuntime(editor);
318
+ return runtime ? runtime.getSessionConfig() : $getEditorDOMRenderConfig(editor);
319
+ }
320
+ /**
321
+ * Execute a callback within a render context with the given config pairs.
322
+ * @experimental
323
+ */
324
+ const $withRenderContext = $withContext(DOMRenderContextSymbol, getDefaultRenderContext);
325
+ /**
326
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
327
+ *
328
+ * This source code is licensed under the MIT license found in the
329
+ * LICENSE file in the root directory of this source tree.
330
+ *
331
+ */
332
+ /**
333
+ * A convenience function for type inference when constructing DOM overrides for
334
+ * use with {@link DOMRenderExtension}.
335
+ *
336
+ * The optional `options` argument controls *whether* the override is installed
337
+ * based only on render context — `disabledForEditor` gates residency in the
338
+ * editor's render pipeline (reconciliation), `disabledForSession` gates
339
+ * participation in a single export/generate session. See {@link DOMOverrideOptions}.
340
+ *
341
+ * @experimental
342
+ * @__NO_SIDE_EFFECTS__
343
+ */
344
+ function domOverride(nodes, config, options) {
345
+ return {
346
+ ...config,
347
+ ...options,
348
+ nodes
349
+ };
350
+ }
351
+ function buildTypeTree(editorConfig) {
352
+ const t = {};
353
+ const { nodes } = getKnownTypesAndNodes(editorConfig);
354
+ for (const klass of nodes) {
355
+ const type = klass.getType();
356
+ t[type] = {
357
+ klass,
358
+ types: {}
359
+ };
360
+ }
361
+ for (const baseRec of Object.values(t)) if (baseRec) {
362
+ const baseType = baseRec.klass.getType();
363
+ for (let { klass } = baseRec; $isLexicalNode(klass.prototype); klass = Object.getPrototypeOf(klass)) {
364
+ const { ownNodeType } = getStaticNodeConfig(klass);
365
+ const superRec = ownNodeType && t[ownNodeType];
366
+ if (superRec) superRec.types[baseType] = true;
367
+ }
368
+ }
369
+ return t;
370
+ }
371
+ function buildNodePredicate(klass) {
372
+ return (node) => node instanceof klass;
373
+ }
374
+ function getPredicate(typeTree, { nodes }) {
375
+ if (nodes === "*") return ALWAYS_TRUE;
376
+ let types = {};
377
+ const predicates = [];
378
+ for (const klassOrPredicate of nodes) if ("getType" in klassOrPredicate) {
379
+ const type = klassOrPredicate.getType();
380
+ if (types) {
381
+ const tree = typeTree[type];
382
+ if (!(tree !== void 0)) formatDevErrorMessage(`Node class ${klassOrPredicate.name} with type ${type} not registered in editor`);
383
+ types = Object.assign(types, tree.types);
384
+ }
385
+ predicates.push(buildNodePredicate(klassOrPredicate));
386
+ } else {
387
+ types = void 0;
388
+ predicates.push(klassOrPredicate);
389
+ }
390
+ if (types) return types;
391
+ else if (predicates.length === 1) return predicates[0];
392
+ return (node) => {
393
+ for (const predicate of predicates) if (predicate(node)) return true;
394
+ return false;
395
+ };
396
+ }
397
+ function makePrerender() {
398
+ return {
399
+ $createDOM: [],
400
+ $decorateDOM: [],
401
+ $exportDOM: [],
402
+ $extractWithChild: [],
403
+ $getDOMSlot: [],
404
+ $shouldExclude: [],
405
+ $shouldInclude: [],
406
+ $updateDOM: []
407
+ };
408
+ }
409
+ function ignoreNext2(acc) {
410
+ return (node, _$next, editor) => acc(node, editor);
411
+ }
412
+ function ignoreNext3(acc) {
413
+ return (node, a, _$next, editor) => acc(node, a, editor);
414
+ }
415
+ function ignoreNext4(acc) {
416
+ return (node, a, b, _$next, editor) => acc(node, a, b, editor);
417
+ }
418
+ function ignoreNext5(acc) {
419
+ return (node, a, b, c, _$next, editor) => acc(node, a, b, c, editor);
420
+ }
421
+ function merge2($acc, $getOverride) {
422
+ return (node, editor) => {
423
+ const $next = () => $acc(node, editor);
424
+ const $override = $getOverride(node);
425
+ return $override ? $override(node, $next, editor) : $next();
426
+ };
427
+ }
428
+ function merge3(acc, $getOverride) {
429
+ return (node, a, editor) => {
430
+ const $next = () => acc(node, a, editor);
431
+ const $override = $getOverride(node);
432
+ return $override ? $override(node, a, $next, editor) : $next();
433
+ };
434
+ }
435
+ const merge3GetDOMSlot = merge3;
436
+ const ignoreNext3GetDOMSlot = ignoreNext3;
437
+ function merge4($acc, $getOverride) {
438
+ return (node, a, b, editor) => {
439
+ const $next = () => $acc(node, a, b, editor);
440
+ const $override = $getOverride(node);
441
+ return $override ? $override(node, a, b, $next, editor) : $next();
442
+ };
443
+ }
444
+ function merge5(acc, $getOverride) {
445
+ return (node, a, b, c, editor) => {
446
+ const $next = () => acc(node, a, b, c, editor);
447
+ const $override = $getOverride(node);
448
+ return $override ? $override(node, a, b, c, $next, editor) : $next();
449
+ };
450
+ }
451
+ function sequence4($acc, $getOverride) {
452
+ return (node, a, b, editor) => {
453
+ $acc(node, a, b, editor);
454
+ const $override = $getOverride(node);
455
+ if ($override) $override(node, a, b, editor);
456
+ };
457
+ }
458
+ function compilePrerenderKey(prerender, k, defaults, mergeFunction, ignoreNextFunction) {
459
+ let acc = defaults[k];
460
+ for (const pair of prerender[k]) if (typeof pair[0] === "function") {
461
+ const [$predicate, $override] = pair;
462
+ acc = mergeFunction(acc, (node) => $predicate(node) && $override || void 0);
463
+ } else {
464
+ const typeOverrides = pair[1];
465
+ const compiled = {};
466
+ for (const type in typeOverrides) {
467
+ const arr = typeOverrides[type];
468
+ if (arr) compiled[type] = arr.reduce(($acc, $override) => mergeFunction($acc, () => $override), acc);
469
+ }
470
+ acc = mergeFunction(acc, (node) => {
471
+ const f = compiled[node.getType()];
472
+ return f && ignoreNextFunction(f);
473
+ });
474
+ }
475
+ defaults[k] = acc;
476
+ }
477
+ function addOverride(prerender, k, predicateOrTypes, override) {
478
+ if (!override) return;
479
+ const arr = prerender[k];
480
+ if (typeof predicateOrTypes === "function") arr.push([predicateOrTypes, override]);
481
+ else {
482
+ const last = arr[arr.length - 1];
483
+ let types;
484
+ if (last && last[0] === "types") types = last[1];
485
+ else {
486
+ types = {};
487
+ arr.push(["types", types]);
488
+ }
489
+ for (const type in predicateOrTypes) {
490
+ const typeArr = types[type] || [];
491
+ types[type] = typeArr;
492
+ typeArr.push(override);
493
+ }
494
+ }
495
+ }
496
+ function isWildcard(override) {
497
+ return override.nodes === "*";
498
+ }
499
+ function sortedOverrides(overrides) {
500
+ const byWildcard = [];
501
+ const byPredicate = [];
502
+ const byNode = [];
503
+ for (const override of overrides) if (isWildcard(override)) byWildcard.push(override);
504
+ else if (Array.isArray(override.nodes)) for (const klassOrPredicate of override.nodes) if ($isLexicalNode(klassOrPredicate.prototype)) byNode.push(override.nodes.length === 1 ? override : {
505
+ ...override,
506
+ nodes: [klassOrPredicate]
507
+ });
508
+ else byPredicate.push(override.nodes.length === 1 ? override : {
509
+ ...override,
510
+ nodes: [klassOrPredicate]
511
+ });
512
+ const depths = /* @__PURE__ */ new Map();
513
+ const depthOf = (klass) => {
514
+ let depth = depths.get(klass);
515
+ if (depth === void 0) {
516
+ depth = 0;
517
+ for (let k = klass; $isLexicalNode(k.prototype); k = Object.getPrototypeOf(k)) depth++;
518
+ depths.set(klass, depth);
519
+ }
520
+ return depth;
521
+ };
522
+ byNode.sort((a, b) => depthOf(a.nodes[0]) - depthOf(b.nodes[0]));
523
+ return [
524
+ ...byNode,
525
+ ...byPredicate,
526
+ ...byWildcard
527
+ ];
528
+ }
529
+ function precompileDOMRenderConfigOverrides(editorConfig, overrides) {
530
+ const typeTree = buildTypeTree(editorConfig);
531
+ const prerender = makePrerender();
532
+ for (const override of sortedOverrides(overrides)) {
533
+ const predicateOrTypes = getPredicate(typeTree, override);
534
+ for (const k_ in prerender) {
535
+ const k = k_;
536
+ addOverride(prerender, k, predicateOrTypes, override[k]);
537
+ }
538
+ }
539
+ return prerender;
540
+ }
541
+ function identity(v) {
542
+ return v;
543
+ }
544
+ function compileDOMRenderConfigOverrides(editorConfig, { overrides }) {
545
+ const prerender = precompileDOMRenderConfigOverrides(editorConfig, overrides);
546
+ const dom = {
547
+ ...DEFAULT_EDITOR_DOM_CONFIG,
548
+ ...editorConfig.dom
549
+ };
550
+ compilePrerenderKey(prerender, "$createDOM", dom, merge2, ignoreNext2);
551
+ compilePrerenderKey(prerender, "$exportDOM", dom, merge2, ignoreNext2);
552
+ compilePrerenderKey(prerender, "$extractWithChild", dom, merge5, ignoreNext5);
553
+ compilePrerenderKey(prerender, "$getDOMSlot", dom, merge3GetDOMSlot, ignoreNext3GetDOMSlot);
554
+ compilePrerenderKey(prerender, "$shouldExclude", dom, merge3, ignoreNext3);
555
+ compilePrerenderKey(prerender, "$shouldInclude", dom, merge3, ignoreNext3);
556
+ compilePrerenderKey(prerender, "$updateDOM", dom, merge4, ignoreNext4);
557
+ compilePrerenderKey(prerender, "$decorateDOM", dom, sequence4, identity);
558
+ return dom;
559
+ }
560
+ /**
561
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
562
+ *
563
+ * This source code is licensed under the MIT license found in the
564
+ * LICENSE file in the root directory of this source tree.
565
+ *
566
+ */
567
+ function makeReader(record) {
568
+ return { get(cfg) {
569
+ return getContextValue(record, cfg);
570
+ } };
571
+ }
572
+ /**
573
+ * The mutable, writable editor-level context record. Reads of a render state
574
+ * during reconciliation (and as the base layer of a session) fall through to
575
+ * this record, and it is the layer the `disabledForEditor` predicates read.
576
+ *
577
+ * @internal
578
+ */
579
+ function createEditorContextRecord(contextDefaults) {
580
+ const parent = Object.create(null);
581
+ return contextFromPairs(contextDefaults, parent) || parent;
582
+ }
583
+ /**
584
+ * Filter the configured overrides down to those that are resident in the
585
+ * editor's render config, removing any whose `disabledForEditor` predicate
586
+ * returns `true` for the given editor context.
587
+ *
588
+ * @internal
589
+ */
590
+ function filterEditorInstalled(overrides, record) {
591
+ const reader = makeReader(record);
592
+ return overrides.filter((o) => !(o.disabledForEditor && o.disabledForEditor(reader)));
593
+ }
594
+ function sameOverrides(a, b) {
595
+ if (a.length !== b.length) return false;
596
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
597
+ return true;
598
+ }
599
+ function symmetricDiff(prev, next) {
600
+ const prevSet = new Set(prev);
601
+ const nextSet = new Set(next);
602
+ const changed = [];
603
+ for (const o of prev) if (!nextSet.has(o)) changed.push(o);
604
+ for (const o of next) if (!prevSet.has(o)) changed.push(o);
605
+ return changed;
606
+ }
607
+ /**
608
+ * Build a predicate matching the nodes an override targets — `'*'` matches
609
+ * everything, a node class matches by `instanceof`, and a guard is used as-is.
610
+ */
611
+ function nodeMatcher(o) {
612
+ if (o.nodes === "*") return () => true;
613
+ const matchers = o.nodes.map((match) => {
614
+ const klass = match;
615
+ return $isLexicalNode(klass.prototype) ? (node) => node instanceof klass : match;
616
+ });
617
+ return (node) => matchers.some((f) => f(node));
618
+ }
619
+ /**
620
+ * Build a predicate matching the nodes whose DOM must be recreated for the
621
+ * given override change, or `null` when no live re-render is needed.
622
+ *
623
+ * `$createDOM`/`$getDOMSlot` produce the element and slot, and `$decorateDOM`
624
+ * may add DOM that only a fresh `$createDOM` can revert — so toggling any of
625
+ * them recreates the affected nodes. `$updateDOM` is diff-driven and applies on
626
+ * the next node update, and export-only hooks ($exportDOM/$shouldInclude/…)
627
+ * don't touch the live DOM, so neither needs a re-render. Recreating every
628
+ * affected node is the simple, always-correct choice; toggles are rare, so the
629
+ * cost is acceptable and can be optimized later if needed.
630
+ */
631
+ function recreatePredicate(changed) {
632
+ const matchers = [];
633
+ for (const o of changed) if (o.$createDOM || o.$getDOMSlot || o.$decorateDOM) matchers.push(nodeMatcher(o));
634
+ return matchers.length === 0 ? null : (node) => matchers.some((f) => f(node));
635
+ }
636
+ /**
637
+ * Per-editor runtime backing {@link DOMRenderExtension}'s conditional
638
+ * overrides and imperative editor context. See {@link DOMRenderRuntime}.
639
+ *
640
+ * @internal
641
+ */
642
+ var DOMRenderRuntimeImpl = class {
643
+ editor;
644
+ /**
645
+ * The `nodes` and base `dom` captured at `init` (before `dom` was
646
+ * overwritten with the compiled config) — the clean base for every recompile.
647
+ */
648
+ initialEditorConfig;
649
+ overrides;
650
+ editorContext;
651
+ hasSessionGates;
652
+ installed;
653
+ /** Memoized session configs keyed by the set of session-disabled overrides. */
654
+ sessionCache = /* @__PURE__ */ new Map();
655
+ constructor(editor, initialEditorConfig, overrides, editorContext) {
656
+ this.editor = editor;
657
+ this.initialEditorConfig = initialEditorConfig;
658
+ this.overrides = overrides;
659
+ this.editorContext = editorContext;
660
+ this.installed = filterEditorInstalled(overrides, editorContext);
661
+ this.hasSessionGates = overrides.some((o) => o.disabledForSession);
662
+ }
663
+ setContextValue(cfg, value) {
664
+ const prev = this.installed;
665
+ this.editorContext[cfg.key] = value;
666
+ const next = filterEditorInstalled(this.overrides, this.editorContext);
667
+ if (sameOverrides(prev, next)) return;
668
+ const changed = symmetricDiff(prev, next);
669
+ this.installed = next;
670
+ this.sessionCache.clear();
671
+ const dom = compileDOMRenderConfigOverrides(this.initialEditorConfig, { overrides: next });
672
+ this.editor._config.dom = dom;
673
+ const recreate = recreatePredicate(changed);
674
+ if (!recreate) return;
675
+ const base = dom.$updateDOM;
676
+ dom.$updateDOM = (nextNode, prevNode, el, editor) => recreate(nextNode) ? true : base(nextNode, prevNode, el, editor);
677
+ this.editor.update($fullReconcile, { discrete: true });
678
+ dom.$updateDOM = base;
679
+ }
680
+ getSessionConfig() {
681
+ const resident = this.editor._config.dom || DEFAULT_EDITOR_DOM_CONFIG;
682
+ if (!this.hasSessionGates) return resident;
683
+ const reader = makeReader(getContextRecord(DOMRenderContextSymbol, this.editor) || this.editorContext);
684
+ const disabledKeys = [];
685
+ const sessionSet = [];
686
+ this.installed.forEach((o, i) => {
687
+ if (o.disabledForSession && o.disabledForSession(reader)) disabledKeys.push(String(i));
688
+ else sessionSet.push(o);
689
+ });
690
+ if (disabledKeys.length === 0) return resident;
691
+ const key = disabledKeys.join(",");
692
+ let cfg = this.sessionCache.get(key);
693
+ if (!cfg) {
694
+ cfg = compileDOMRenderConfigOverrides(this.initialEditorConfig, { overrides: sessionSet });
695
+ this.sessionCache.set(key, cfg);
696
+ }
697
+ return cfg;
698
+ }
699
+ };
700
+ /**
701
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
702
+ *
703
+ * This source code is licensed under the MIT license found in the
704
+ * LICENSE file in the root directory of this source tree.
705
+ *
706
+ */
707
+ /** @internal The result returned from {@link DOMRenderExtension}'s `init`. */
708
+ /**
709
+ * @experimental
710
+ *
711
+ * An extension that allows overriding the render and export behavior for an
712
+ * editor. This is highly experimental and subject to change from one version
713
+ * to the next.
714
+ **/
715
+ const DOMRenderExtension = defineExtension({
716
+ build(editor, config, state) {
717
+ const { initialEditorConfig } = state.getInitResult();
718
+ const editorContext = createEditorContextRecord(config.contextDefaults);
719
+ return {
720
+ defaults: editorContext,
721
+ runtime: new DOMRenderRuntimeImpl(editor, initialEditorConfig, config.overrides, editorContext)
722
+ };
723
+ },
724
+ config: {
725
+ contextDefaults: [],
726
+ overrides: []
727
+ },
728
+ html: { export: new Map([[RootNode, () => {
729
+ const element = document.createElement("div");
730
+ element.role = "textbox";
731
+ return { element };
732
+ }]]) },
733
+ init(editorConfig, config) {
734
+ const initialEditorConfig = {
735
+ dom: editorConfig.dom,
736
+ nodes: editorConfig.nodes
737
+ };
738
+ const editorContext = createEditorContextRecord(config.contextDefaults);
739
+ editorConfig.dom = compileDOMRenderConfigOverrides(editorConfig, { overrides: filterEditorInstalled(config.overrides, editorContext) });
740
+ return { initialEditorConfig };
741
+ },
742
+ mergeConfig(config, partial) {
743
+ const merged = shallowMergeConfig(config, partial);
744
+ for (const k of ["overrides", "contextDefaults"]) if (partial[k]) merged[k] = [...config[k], ...partial[k]];
745
+ return merged;
746
+ },
747
+ name: DOMRenderExtensionName
748
+ });
749
+ /**
750
+ * @internal
751
+ *
752
+ * A predicate that may write into the per-invocation `captures` map. Returns
753
+ * `true` if the rule matches; `false` otherwise.
754
+ */
755
+ /** @internal */
756
+ /** @internal The runtime shape of a {@link CompiledSelector}. */
757
+ const IMPL = Symbol.for("@lexical/html/SelectorImpl");
758
+ /** @internal */
759
+ function getSelectorImpl(sel) {
760
+ const impl = sel[IMPL];
761
+ if (!(impl !== void 0)) formatDevErrorMessage(`match must be a CompiledSelector produced by sel.* or sel.css(); received a raw object.`);
762
+ return impl;
763
+ }
764
+ function combinePredicates(preds) {
765
+ if (preds.length === 0) return isHTMLElement;
766
+ if (preds.length === 1) return preds[0];
767
+ return (node, captures) => {
768
+ for (const p of preds) if (!p(node, captures)) return false;
769
+ return true;
770
+ };
771
+ }
772
+ /**
773
+ * @internal
774
+ *
775
+ * Build a selector value from a tag set and a predicate list. Used by the
776
+ * combinator API and the CSS parser.
777
+ */
778
+ function buildSelector(tags, predicates) {
779
+ const impl = {
780
+ kind: "element",
781
+ predicate: combinePredicates(predicates),
782
+ tags
783
+ };
784
+ const refine = (additional) => buildSelector(tags, [...predicates, additional]);
785
+ return {
786
+ [IMPL]: impl,
787
+ attr: (name, value, options) => refine(buildAttrPredicate(name, value, options)),
788
+ classAll: (...classes) => refine(buildClassAllPredicate(classes)),
789
+ classAny: (...classes) => refine(buildClassAnyPredicate(classes)),
790
+ styleAny: (prop, value, options) => refine(buildStylePredicate(prop, value, options))
791
+ };
792
+ }
793
+ function normalizeClassList(classes) {
794
+ const out = [];
795
+ for (const c of classes) if (c) out.push(c);
796
+ return out;
797
+ }
798
+ /** @internal */
799
+ function buildClassAllPredicate(classes) {
800
+ const ns = normalizeClassList(classes);
801
+ if (ns.length === 0) return () => true;
802
+ return (node) => {
803
+ if (!isHTMLElement(node)) return false;
804
+ const cl = node.classList;
805
+ for (const c of ns) if (!cl.contains(c)) return false;
806
+ return true;
807
+ };
808
+ }
809
+ /** @internal */
810
+ function buildClassAnyPredicate(classes) {
811
+ const ns = normalizeClassList(classes);
812
+ if (ns.length === 0) return () => false;
813
+ return (node) => {
814
+ if (!isHTMLElement(node)) return false;
815
+ const cl = node.classList;
816
+ for (const c of ns) if (cl.contains(c)) return true;
817
+ return false;
818
+ };
819
+ }
820
+ /** @internal */
821
+ function buildAttrPredicate(name, value, options) {
822
+ if (value === true) return (node) => isHTMLElement(node) && node.hasAttribute(name);
823
+ if (typeof value === "string") return (node) => isHTMLElement(node) && node.getAttribute(name) === value;
824
+ if (value instanceof RegExp) {
825
+ const capture = options && options.capture;
826
+ const re = value;
827
+ return (node, captures) => {
828
+ if (!isHTMLElement(node)) return false;
829
+ const v = node.getAttribute(name);
830
+ if (v == null) return false;
831
+ const m = v.match(re);
832
+ if (m === null) return false;
833
+ if (capture !== void 0) captures[capture] = m;
834
+ return true;
835
+ };
836
+ }
837
+ formatDevErrorMessage(`sel.attr(${JSON.stringify(name)}, ...) requires true, a string, or a RegExp`);
838
+ }
839
+ function buildStylePredicate(prop, value, options) {
840
+ if (typeof value === "string") return (node) => isHTMLElement(node) && node.style.getPropertyValue(prop) === value;
841
+ if (value instanceof RegExp) {
842
+ const capture = options && options.capture;
843
+ const re = value;
844
+ return (node, captures) => {
845
+ if (!isHTMLElement(node)) return false;
846
+ const v = node.style.getPropertyValue(prop);
847
+ if (!v) return false;
848
+ const m = v.match(re);
849
+ if (m === null) return false;
850
+ if (capture !== void 0) captures[capture] = m;
851
+ return true;
852
+ };
853
+ }
854
+ formatDevErrorMessage(`sel.styleAny(${JSON.stringify(prop)}, ...) requires a string or a RegExp`);
855
+ }
856
+ const TEXT_SELECTOR_IMPL = {
857
+ kind: "text",
858
+ predicate: isDOMTextNode,
859
+ tags: /* @__PURE__ */ new Set()
860
+ };
861
+ const TEXT_SELECTOR = { [IMPL]: TEXT_SELECTOR_IMPL };
862
+ const COMMENT_SELECTOR_IMPL = {
863
+ kind: "comment",
864
+ predicate: (node) => node.nodeType === 8,
865
+ tags: /* @__PURE__ */ new Set()
866
+ };
867
+ const COMMENT_SELECTOR = { [IMPL]: COMMENT_SELECTOR_IMPL };
868
+ /**
869
+ * Combinator API for building {@link CompiledSelector}s. The public
870
+ * `sel` is augmented from this in `./index.ts` (where the CSS parser is
871
+ * available without a circular import); consumers outside `@lexical/html`
872
+ * should always import the public `sel` from the package root.
873
+ *
874
+ * @internal
875
+ */
876
+ const selBase = {
877
+ /** Match any {@link HTMLElement}. */
878
+ any() {
879
+ return buildSelector(/* @__PURE__ */ new Set(), []);
880
+ },
881
+ /** Match DOM {@link Comment} nodes. */
882
+ comment() {
883
+ return COMMENT_SELECTOR;
884
+ },
885
+ /**
886
+ * Match by tag name(s). With one literal tag the element type is narrowed
887
+ * (e.g. `'a' → HTMLAnchorElement`); with multiple, it is the union of
888
+ * their `HTMLElementTagNameMap` entries.
889
+ */
890
+ tag(...tags) {
891
+ if (!(tags.length > 0)) formatDevErrorMessage(`sel.tag() requires at least one tag name`);
892
+ const upper = /* @__PURE__ */ new Set();
893
+ for (const t of tags) upper.add(t.toUpperCase());
894
+ return buildSelector(upper, []);
895
+ },
896
+ /** Match DOM {@link Text} nodes. */
897
+ text() {
898
+ return TEXT_SELECTOR;
899
+ }
900
+ };
901
+ /**
902
+ * Cross-frame-safe replacement for `node instanceof HTMLXxxElement`. Returns
903
+ * true when `node` is an HTMLElement whose `nodeName` equals `tag` (compared
904
+ * case-insensitively).
905
+ *
906
+ * @experimental
907
+ */
908
+ function isElementOfTag(node, tag) {
909
+ return isHTMLElement(node) && node.nodeName === tag.toUpperCase();
910
+ }
911
+ const IDENT_CHAR = /[A-Za-z0-9_-]/;
912
+ var Cursor = class {
913
+ constructor(source, pos) {
914
+ this.source = source;
915
+ this.pos = pos;
916
+ }
917
+ peek(offset = 0) {
918
+ return this.source[this.pos + offset] || "";
919
+ }
920
+ consume() {
921
+ return this.source[this.pos++] || "";
922
+ }
923
+ eof() {
924
+ return this.pos >= this.source.length;
925
+ }
926
+ skipWhitespace() {
927
+ while (!this.eof() && /\s/.test(this.peek())) this.pos++;
928
+ }
929
+ readIdent() {
930
+ const start = this.pos;
931
+ while (!this.eof() && IDENT_CHAR.test(this.peek())) this.pos++;
932
+ return this.source.slice(start, this.pos);
933
+ }
934
+ readQuoted() {
935
+ const quote = this.consume();
936
+ this.assert(quote === "\"" || quote === "'", "expected quote");
937
+ const start = this.pos;
938
+ while (!this.eof() && this.peek() !== quote) if (this.peek() === "\\") this.pos += 2;
939
+ else this.pos++;
940
+ this.assert(!this.eof(), "unterminated string");
941
+ const value = this.source.slice(start, this.pos);
942
+ this.pos++;
943
+ return value.replace(/\\(.)/g, "$1");
944
+ }
945
+ /**
946
+ * `invariant(cond, fmt, …)`-flavored assertion that also surfaces the
947
+ * cursor's position context. Use for parse-time errors so a malformed
948
+ * CSS selector gets a useful, position-annotated message.
949
+ */
950
+ assert(cond, msg) {
951
+ if (!cond) formatDevErrorMessage(`invalid CSS selector at col ${String(this.pos + 1)}: ${msg} in ${this.source}`);
952
+ }
953
+ };
954
+ function parseSimpleSelector(c) {
955
+ const tags = /* @__PURE__ */ new Set();
956
+ const predicates = [];
957
+ const classes = [];
958
+ c.skipWhitespace();
959
+ if (c.peek() === "*") c.consume();
960
+ else if (IDENT_CHAR.test(c.peek())) {
961
+ const tag = c.readIdent();
962
+ if (tag) tags.add(tag.toUpperCase());
963
+ }
964
+ while (!c.eof()) {
965
+ const ch = c.peek();
966
+ if (ch === ".") {
967
+ c.consume();
968
+ const cls = c.readIdent();
969
+ c.assert(cls !== "", "expected class name after \".\"");
970
+ classes.push(cls);
971
+ } else if (ch === "#") {
972
+ c.consume();
973
+ const id = c.readIdent();
974
+ c.assert(id !== "", "expected id after \"#\"");
975
+ predicates.push(buildAttrPredicate("id", id));
976
+ } else if (ch === "[") {
977
+ c.consume();
978
+ c.skipWhitespace();
979
+ const name = c.readIdent();
980
+ c.assert(name !== "", "expected attribute name after \"[\"");
981
+ c.skipWhitespace();
982
+ let value = true;
983
+ if (c.peek() === "=") {
984
+ c.consume();
985
+ c.skipWhitespace();
986
+ const next = c.peek();
987
+ if (next === "\"" || next === "'") value = c.readQuoted();
988
+ else {
989
+ value = c.readIdent();
990
+ c.assert(value !== "", "expected attribute value");
991
+ }
992
+ c.skipWhitespace();
993
+ }
994
+ c.assert(c.peek() === "]", "expected \"]\"");
995
+ c.consume();
996
+ predicates.push(buildAttrPredicate(name, value));
997
+ } else break;
998
+ }
999
+ if (classes.length > 0) predicates.push(buildClassAllPredicate(classes));
1000
+ return {
1001
+ predicates,
1002
+ tags
1003
+ };
1004
+ }
1005
+ /**
1006
+ * Parse a reduced CSS-selector subset and return a {@link CompiledSelector}.
1007
+ * Supported:
1008
+ * - Tag (`p`), wildcard (`*`).
1009
+ * - Tag list (`h1, h2, h3`).
1010
+ * - Class (`.foo`, `.foo.bar`).
1011
+ * - ID (`#foo`).
1012
+ * - Attribute presence (`[name]`).
1013
+ * - Attribute equality (`[name="value"]`, `[name=value]`).
1014
+ *
1015
+ * Anything outside the subset (regex attribute, inline-style match,
1016
+ * combinators, pseudo-classes) is intentionally rejected — chain combinator
1017
+ * methods off the returned builder instead.
1018
+ *
1019
+ * @experimental
1020
+ */
1021
+ function parseSelector(source) {
1022
+ const c = new Cursor(source, 0);
1023
+ const groups = [];
1024
+ while (true) {
1025
+ const group = parseSimpleSelector(c);
1026
+ groups.push(group);
1027
+ c.skipWhitespace();
1028
+ if (c.eof()) break;
1029
+ c.assert(c.peek() === ",", "expected \",\" (selector lists are the only supported combinator)");
1030
+ c.consume();
1031
+ c.skipWhitespace();
1032
+ }
1033
+ if (groups.length === 1) return buildSelector(groups[0].tags, groups[0].predicates);
1034
+ const tags = /* @__PURE__ */ new Set();
1035
+ for (const g of groups) for (const t of g.tags) tags.add(t);
1036
+ const orPredicate = (node, captures) => {
1037
+ for (const g of groups) {
1038
+ const upper = node.nodeName;
1039
+ if (g.tags.size > 0 && !g.tags.has(upper)) continue;
1040
+ let ok = true;
1041
+ for (const p of g.predicates) if (!p(node, captures)) {
1042
+ ok = false;
1043
+ break;
1044
+ }
1045
+ if (ok) return true;
1046
+ }
1047
+ return false;
1048
+ };
1049
+ return buildSelector(tags, [orPredicate]);
1050
+ }
1051
+ /**
1052
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
1053
+ *
1054
+ * This source code is licensed under the MIT license found in the
1055
+ * LICENSE file in the root directory of this source tree.
1056
+ *
1057
+ */
1058
+ /**
1059
+ * Identity helper that infers a rule's matched node type and capture map
1060
+ * from its `match` selector and threads them into the `$import` signature.
1061
+ * Usage:
1062
+ *
1063
+ * ```ts
1064
+ * defineImportRule({
1065
+ * name: '@lexical/list/li',
1066
+ * match: sel.tag('li'),
1067
+ * $import: (ctx, el, $next) => {
1068
+ * // el: HTMLLIElement
1069
+ * return [$createListItemNode()];
1070
+ * },
1071
+ * });
1072
+ * ```
1073
+ *
1074
+ * @experimental
1075
+ * @__NO_SIDE_EFFECTS__
1076
+ */
1077
+ function defineImportRule(rule) {
1078
+ return rule;
1079
+ }
1080
+ /**
1081
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
1082
+ *
1083
+ * This source code is licensed under the MIT license found in the
1084
+ * LICENSE file in the root directory of this source tree.
1085
+ *
1086
+ */
1087
+ /**
1088
+ * Create an import context state. The phantom symbol prevents accidental
1089
+ * use of a render-context state in an import context (and vice versa).
1090
+ *
1091
+ * Note: to support the value-or-updater pattern, `V` cannot be a function
1092
+ * type; wrap it in an array or object if needed.
1093
+ *
1094
+ * `getDefaultValue` is called **once at state creation** and the result is
1095
+ * shared between every session that reads the state without first writing
1096
+ * a value. Defaults must therefore be immutable (primitives, frozen
1097
+ * objects, or read-only arrays / records). If your state needs mutable
1098
+ * per-session storage, lazily initialize it inside your rule (e.g.
1099
+ * `if (!ctx.session.has(cfg)) ctx.session.set(cfg, new …())`).
1100
+ *
1101
+ * @experimental
1102
+ * @__NO_SIDE_EFFECTS__
1103
+ */
1104
+ function createImportState(name, getDefaultValue, isEqual) {
1105
+ return createContextState(DOMImportContextSymbol, name, getDefaultValue, isEqual);
1106
+ }
1107
+ /**
1108
+ * The kind of operation that produced this import. Lets rules adapt
1109
+ * their behavior (e.g. preserve more whitespace on `'paste'`).
1110
+ * Defaults to `'unknown'`. Apps that need a different vocabulary can
1111
+ * define their own {@link ImportStateConfig} with whatever value type
1112
+ * they want.
1113
+ *
1114
+ * @experimental
1115
+ */
1116
+ /**
1117
+ * Built-in import-context state identifying how this import was initiated.
1118
+ * Callers of `$generateNodesFromDOM` should set it via the `context` option.
1119
+ *
1120
+ * @experimental
1121
+ */
1122
+ const ImportSource = createImportState("importSource", () => "unknown");
1123
+ /**
1124
+ * Built-in import-context state holding the {@link DataTransfer} the
1125
+ * import was sourced from, if any. `null` outside paste/drop flows.
1126
+ *
1127
+ * The clipboard import pipeline passes the original `DataTransfer`
1128
+ * through to its per-MIME-type handler stack (see
1129
+ * {@link ImportMimeTypeFunction}); handlers that route HTML through
1130
+ * the {@link DOMImportExtension} pipeline should forward it into the
1131
+ * walk via `context: [contextValue(ImportSourceDataTransfer,
1132
+ * dataTransfer)]` so rules and preprocessors can call
1133
+ * `ctx.get(ImportSourceDataTransfer)` to inspect companion MIME types
1134
+ * (e.g. an `'application/rtf'` alternative or an attached
1135
+ * `'application/x-officedrawing'` payload), the file list, or any
1136
+ * custom drag-and-drop slot.
1137
+ *
1138
+ * Use sparingly: the safer pattern is to decide *which* MIME-type
1139
+ * payload to walk in the clipboard handler stack and hand a finalized
1140
+ * DOM to the rules; only fall back to peeking at `ImportSourceDataTransfer`
1141
+ * when the source-detection signal genuinely lives in a companion
1142
+ * slot.
1143
+ *
1144
+ * @experimental
1145
+ */
1146
+ const ImportSourceDataTransfer = createImportState("importSourceDataTransfer", () => null);
1147
+ /**
1148
+ * Built-in import-context state holding the bit-packed
1149
+ * {@link TextFormatType} formats that should apply to {@link TextNode}s
1150
+ * produced during the current subtree. Used by inline-format wrappers
1151
+ * (`<b>`, `<i>`, `<u>`, …) to propagate formatting through the context
1152
+ * record instead of via the legacy `forChild` chain.
1153
+ *
1154
+ * @experimental
1155
+ */
1156
+ const ImportTextFormat = createImportState("textFormat", () => 0);
1157
+ /**
1158
+ * Built-in import-context state holding a parsed CSS-style record
1159
+ * (the {@link getStyleObjectFromCSS} shape) that should apply to
1160
+ * {@link TextNode}s produced during the current subtree. Mirrors the
1161
+ * format-bit propagation in {@link ImportTextFormat} for properties
1162
+ * that don't fit into the format bit mask — `color`, `font-family`,
1163
+ * `font-size`, etc.
1164
+ *
1165
+ * Ancestor rules that contribute a style branch the context with a
1166
+ * merged record; the core `#text` rule materializes the non-empty
1167
+ * record to a CSS string and calls `setStyle` on the new TextNode.
1168
+ * Once TextNode adopts a parsed style record, the materialization
1169
+ * step will go away.
1170
+ *
1171
+ * @experimental
1172
+ */
1173
+ const ImportTextStyle = createImportState("textStyle", () => ({}));
1174
+ /**
1175
+ * Determines whether a given DOM element should be treated as preserving
1176
+ * whitespace (i.e. text content under it is not collapsed and is split on
1177
+ * `\n` / `\t` into `LineBreakNode` / `TabNode`). The default matches the
1178
+ * legacy behavior: the element itself is `<pre>` or its inline
1179
+ * `white-space` style begins with `'pre'`.
1180
+ *
1181
+ * @experimental
1182
+ */
1183
+ /**
1184
+ * Determines whether a given DOM node sits on the same visual line as its
1185
+ * adjacent text siblings, governing whether leading/trailing whitespace in
1186
+ * a `#text` is collapsed against neighbors. The default consults
1187
+ * {@link isInlineDomNode} from `lexical` (style.display or a fixed inline
1188
+ * tag-name set) and additionally treats elements with an explicit
1189
+ * non-inline `display` style as block.
1190
+ *
1191
+ * @experimental
1192
+ */
1193
+ /**
1194
+ * Configuration for the core text whitespace-collapse logic. Override via
1195
+ * {@link ImportWhitespaceConfig} either as a `contextDefaults` entry on
1196
+ * the {@link DOMImportExtension} or per-call on `$generateNodesFromDOM`'s
1197
+ * `context` option.
1198
+ *
1199
+ * @experimental
1200
+ */
1201
+ /**
1202
+ * Default {@link WhitespaceImportConfig.preservesWhitespace}: matches
1203
+ * `<pre>` and any element with `white-space: pre*`.
1204
+ *
1205
+ * @experimental
1206
+ */
1207
+ function defaultPreservesWhitespace(node) {
1208
+ if (!isHTMLElement(node)) return false;
1209
+ if (node.nodeName === "PRE") return true;
1210
+ const ws = node.style.whiteSpace;
1211
+ return typeof ws === "string" && ws.startsWith("pre");
1212
+ }
1213
+ /**
1214
+ * Default {@link WhitespaceImportConfig.isInline}: treats an element as
1215
+ * inline iff its inline `display` style is `inline*` OR (no explicit
1216
+ * non-inline display) its nodeName is a known inline tag (`isInlineDomNode`).
1217
+ * Text nodes are always inline; comments and other non-elements are not.
1218
+ *
1219
+ * @experimental
1220
+ */
1221
+ function defaultIsInline(node) {
1222
+ if (isDOMTextNode(node)) return true;
1223
+ if (!isHTMLElement(node)) return false;
1224
+ const display = node.style.display;
1225
+ if (display) return display.startsWith("inline");
1226
+ if (isBlockDomNode(node)) return false;
1227
+ return isInlineDomNode(node);
1228
+ }
1229
+ /**
1230
+ * Built-in import-context state controlling text-node whitespace handling
1231
+ * (collapse vs. preserve, what counts as an inline sibling). Override per
1232
+ * editor via {@link DOMImportConfig.contextDefaults} or per call via
1233
+ * {@link GenerateNodesFromDOMOptions.context}.
1234
+ *
1235
+ * @experimental
1236
+ */
1237
+ const ImportWhitespaceConfig = createImportState("whitespaceConfig", () => ({
1238
+ isInline: defaultIsInline,
1239
+ preservesWhitespace: defaultPreservesWhitespace
1240
+ }));
1241
+ /**
1242
+ * Built-in session slot for runtime overlay rules that should be in
1243
+ * effect for the entire walk. A preprocessor writes here when it wants
1244
+ * to conditionally install handling for a particular paste source
1245
+ * (e.g. "if the Microsoft Word generator meta tag is present, push the
1246
+ * Word-paste overlay"). Each entry contributes an overlay dispatcher
1247
+ * to the runtime's overlay stack; later array entries are higher
1248
+ * priority. Use `ctx.session.update(ImportOverlays, prev => […])` to
1249
+ * append.
1250
+ *
1251
+ * This is the walk-wide counterpart to
1252
+ * `$importChildren({rules: …})` (which scopes an overlay to one
1253
+ * subtree): write to {@link ImportOverlays} when the overlay should
1254
+ * apply for the whole document; use `$importChildren`'s `rules` when
1255
+ * the overlay should only apply for a deeper region.
1256
+ *
1257
+ * @experimental
1258
+ */
1259
+ const ImportOverlays = createImportState("importOverlays", () => []);
1260
+ /**
1261
+ * The session IS the root-layer {@link ContextRecord} of the walk. Reads
1262
+ * fall through the prototype chain to the editor's `contextDefaults`,
1263
+ * writes mutate the record's own properties, and any branch pushed by
1264
+ * `$importChildren({context})` sits above this layer and can shadow
1265
+ * (but does not overwrite) slots.
1266
+ *
1267
+ * @internal
1268
+ */
1269
+ var ImportSessionImpl = class {
1270
+ constructor(record) {
1271
+ this.record = record;
1272
+ }
1273
+ get(cfg) {
1274
+ return getContextValue(this.record, cfg);
1275
+ }
1276
+ set(cfg, value) {
1277
+ this.record[cfg.key] = value;
1278
+ }
1279
+ update(cfg, updater) {
1280
+ this.record[cfg.key] = updater(getContextValue(this.record, cfg));
1281
+ }
1282
+ has(cfg) {
1283
+ return Object.prototype.hasOwnProperty.call(this.record, cfg.key);
1284
+ }
1285
+ };
1286
+ function getDefaultImportContext(editor) {
1287
+ const dep = getPeerDependencyFromEditor(editor, DOMImportExtensionName);
1288
+ return dep ? dep.output.defaults : void 0;
1289
+ }
1290
+ function getImportContext(editor) {
1291
+ return getContextRecord(DOMImportContextSymbol, editor) || getDefaultImportContext(editor);
1292
+ }
1293
+ /**
1294
+ * Read an import context value during an import operation.
1295
+ * @experimental
1296
+ */
1297
+ function $getImportContextValue(cfg, editor = $getEditor()) {
1298
+ return getContextValue(getImportContext(editor), cfg);
1299
+ }
1300
+ /**
1301
+ * Run `f` with the given context pairs applied on top of the editor's
1302
+ * current import context.
1303
+ *
1304
+ * @experimental
1305
+ */
1306
+ const $withImportContext = $withContext(DOMImportContextSymbol, getDefaultImportContext);
1307
+ /**
1308
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
1309
+ *
1310
+ * This source code is licensed under the MIT license found in the
1311
+ * LICENSE file in the root directory of this source tree.
1312
+ *
1313
+ */
1314
+ const sel$1 = selBase;
1315
+ const ALIGNMENT_VALUES = new Set([
1316
+ "center",
1317
+ "end",
1318
+ "justify",
1319
+ "left",
1320
+ "right",
1321
+ "start"
1322
+ ]);
1323
+ /**
1324
+ * True if `value` is a non-empty {@link ElementFormatType} (matches one of
1325
+ * the supported `text-align` / legacy `align`-attribute values).
1326
+ *
1327
+ * @internal
1328
+ */
1329
+ function isAlignmentValue(value) {
1330
+ return ALIGNMENT_VALUES.has(value);
1331
+ }
1332
+ /**
1333
+ * A pair of bitmasks describing which {@link TextFormatType} bits to set
1334
+ * and which to clear when descending into an element. The clear pass
1335
+ * matters for cases the legacy OR-merge mishandled, e.g. `<b
1336
+ * style="font-weight: normal">` clearing an inherited bold, or `<sub>` /
1337
+ * `<sup>` clearing each other.
1338
+ */
1339
+ /**
1340
+ * The small subset of inline-style properties that affect text formatting
1341
+ * during import. Modeled as a plain object so tag-implicit defaults and
1342
+ * the element's own inline `style` can be merged with `{...defaults,
1343
+ * ...override-if-set}` semantics rather than relying on CSSStyleDeclaration.
1344
+ */
1345
+ /**
1346
+ * Default style implied by each inline format tag. `<b>`/`<strong>` set
1347
+ * font-weight, `<sub>` sets vertical-align, etc. Any of these can be
1348
+ * overridden by the element's own inline `style` (so `<b
1349
+ * style="font-weight: normal">` ends up with `fontWeight: 'normal'` in
1350
+ * the effective style).
1351
+ */
1352
+ const TAG_DEFAULT_STYLE = {
1353
+ B: { fontWeight: "bold" },
1354
+ EM: { fontStyle: "italic" },
1355
+ I: { fontStyle: "italic" },
1356
+ S: { textDecoration: "line-through" },
1357
+ STRONG: { fontWeight: "bold" },
1358
+ SUB: { verticalAlign: "sub" },
1359
+ SUP: { verticalAlign: "super" },
1360
+ U: { textDecoration: "underline" }
1361
+ };
1362
+ /**
1363
+ * Tags whose effect on TextFormat has no CSS analog (so the style-merge
1364
+ * path can't reach them). Applied as a pure "set" override.
1365
+ */
1366
+ const TAG_ONLY_SET = {
1367
+ CODE: IS_CODE,
1368
+ MARK: IS_HIGHLIGHT
1369
+ };
1370
+ function readElementFormatStyle(el) {
1371
+ return {
1372
+ fontStyle: el.style.fontStyle,
1373
+ fontWeight: el.style.fontWeight,
1374
+ textDecoration: el.style.textDecoration,
1375
+ verticalAlign: el.style.verticalAlign
1376
+ };
1377
+ }
1378
+ function mergeStyles(defaults, override) {
1379
+ return {
1380
+ fontStyle: override.fontStyle || defaults.fontStyle,
1381
+ fontWeight: override.fontWeight || defaults.fontWeight,
1382
+ textDecoration: override.textDecoration || defaults.textDecoration,
1383
+ verticalAlign: override.verticalAlign || defaults.verticalAlign
1384
+ };
1385
+ }
1386
+ /**
1387
+ * The CSS property names {@link styleFormatOverride} reads — these are
1388
+ * "owned" by {@link ImportTextFormat} (the bit mask). When the
1389
+ * {@link ImportTextStyle} record is materialized onto a TextNode's
1390
+ * inline style by {@link styleObjectToCSS}, these are skipped so the
1391
+ * bit-mask side is the single source of truth and the same property
1392
+ * doesn't end up in both places (where the inline-style version would
1393
+ * shadow the format's themed CSS).
1394
+ */
1395
+ const FORMAT_BIT_STYLE_PROPS = new Set([
1396
+ "font-weight",
1397
+ "font-style",
1398
+ "text-decoration",
1399
+ "vertical-align"
1400
+ ]);
1401
+ /**
1402
+ * Translate a {@link FormatStyle} into a {@link FormatOverride}. Explicit
1403
+ * "non-decorating" values (`font-weight: normal`, `text-decoration: none`,
1404
+ * `vertical-align: baseline`) produce `clear` bits, so an inner element
1405
+ * can remove a format inherited from its ancestors.
1406
+ */
1407
+ function styleFormatOverride(style) {
1408
+ let set = 0;
1409
+ let clear = 0;
1410
+ const { fontWeight, fontStyle, textDecoration, verticalAlign } = style;
1411
+ if (fontWeight === "700" || fontWeight === "bold") set |= IS_BOLD;
1412
+ else if (fontWeight === "normal" || fontWeight === "400") clear |= IS_BOLD;
1413
+ if (fontStyle === "italic") set |= IS_ITALIC;
1414
+ else if (fontStyle === "normal") clear |= IS_ITALIC;
1415
+ if (textDecoration) {
1416
+ const parts = textDecoration.split(" ");
1417
+ if (parts.includes("underline")) set |= IS_UNDERLINE;
1418
+ if (parts.includes("line-through")) set |= IS_STRIKETHROUGH;
1419
+ if (parts.includes("none")) clear |= IS_UNDERLINE | IS_STRIKETHROUGH;
1420
+ }
1421
+ if (verticalAlign === "sub") {
1422
+ set |= IS_SUBSCRIPT;
1423
+ clear |= IS_SUPERSCRIPT;
1424
+ } else if (verticalAlign === "super") {
1425
+ set |= IS_SUPERSCRIPT;
1426
+ clear |= IS_SUBSCRIPT;
1427
+ } else if (verticalAlign === "baseline") clear |= IS_SUBSCRIPT | IS_SUPERSCRIPT;
1428
+ return {
1429
+ clear,
1430
+ set
1431
+ };
1432
+ }
1433
+ function applyFormatOverride(format, ov) {
1434
+ return format & ~ov.clear | ov.set;
1435
+ }
1436
+ /**
1437
+ * Unified rule for inline-format-bearing tags and `<span>`. The element's
1438
+ * effective style is its tag's {@link TAG_DEFAULT_STYLE} merged with its
1439
+ * inline `style` (element's own style wins for any property it sets), and
1440
+ * the resulting style is translated into a {@link FormatOverride}. Tags
1441
+ * with no CSS analog (`<code>`, `<mark>`) contribute their bit as a pure
1442
+ * `set` override.
1443
+ *
1444
+ * This shape lets:
1445
+ * - `<b style="font-weight: normal">` clear an inherited IS_BOLD.
1446
+ * - `<sub><sup>x</sup></sub>` resolve to IS_SUPERSCRIPT only (sub/sup
1447
+ * mutex via the vertical-align clear logic).
1448
+ * - `<span style="text-decoration: none">` strip inherited underline /
1449
+ * line-through.
1450
+ */
1451
+ const InlineFormatRule = defineImportRule({
1452
+ $import: (ctx, el) => {
1453
+ const inherited = ctx.get(ImportTextFormat);
1454
+ const tagDefault = TAG_DEFAULT_STYLE[el.nodeName];
1455
+ const elStyle = readElementFormatStyle(el);
1456
+ let merged = applyFormatOverride(inherited, styleFormatOverride(tagDefault ? mergeStyles(tagDefault, elStyle) : elStyle));
1457
+ const tagOnly = TAG_ONLY_SET[el.nodeName];
1458
+ if (tagOnly) merged |= tagOnly;
1459
+ if (merged === inherited) return ctx.$importChildren(el);
1460
+ return ctx.$importChildren(el, { context: [contextValue(ImportTextFormat, merged)] });
1461
+ },
1462
+ match: sel$1.tag("b", "strong", "em", "i", "code", "mark", "s", "sub", "sup", "u", "span"),
1463
+ name: "@lexical/html/inline-format"
1464
+ });
1465
+ /**
1466
+ * Walk up the DOM ancestor chain to determine whether `node` is inside an
1467
+ * element whose whitespace should be preserved, per the supplied
1468
+ * {@link WhitespaceImportConfig.preservesWhitespace} predicate. Pure
1469
+ * ancestor walk, no caching.
1470
+ */
1471
+ function isInsidePreserveWhitespace(node, wsConfig) {
1472
+ let current = node.parentNode;
1473
+ while (current !== null) {
1474
+ if (wsConfig.preservesWhitespace(current)) return true;
1475
+ current = current.parentNode;
1476
+ }
1477
+ return false;
1478
+ }
1479
+ function findAdjacentTextOnLine(text, forward, wsConfig) {
1480
+ let node = text;
1481
+ while (true) {
1482
+ let sibling = null;
1483
+ while ((sibling = forward ? node.nextSibling : node.previousSibling) === null) {
1484
+ const parent = node.parentNode;
1485
+ if (parent === null) return null;
1486
+ node = parent;
1487
+ }
1488
+ node = sibling;
1489
+ if (!wsConfig.isInline(node)) return null;
1490
+ let descendant = node;
1491
+ while ((descendant = forward ? node.firstChild : node.lastChild) !== null) node = descendant;
1492
+ if (isDOMTextNode(node)) return node;
1493
+ if (node.nodeName === "BR") return null;
1494
+ }
1495
+ }
1496
+ function collapseWhitespace(textNode, wsConfig) {
1497
+ let textContent = (textNode.textContent || "").replace(/\r/g, "").replace(/[ \t\n]+/g, " ");
1498
+ if (textContent.length === 0) return "";
1499
+ if (textContent[0] === " ") {
1500
+ let neighbor = textNode;
1501
+ let isStartOfLine = true;
1502
+ while (neighbor !== null && (neighbor = findAdjacentTextOnLine(neighbor, false, wsConfig)) !== null) {
1503
+ const neighborContent = neighbor.textContent || "";
1504
+ if (neighborContent.length > 0) {
1505
+ if (/[ \t\n]$/.test(neighborContent)) textContent = textContent.slice(1);
1506
+ isStartOfLine = false;
1507
+ break;
1508
+ }
1509
+ }
1510
+ if (isStartOfLine) textContent = textContent.slice(1);
1511
+ }
1512
+ if (textContent.length > 0 && textContent[textContent.length - 1] === " ") {
1513
+ let neighbor = textNode;
1514
+ let isEndOfLine = true;
1515
+ while (neighbor !== null && (neighbor = findAdjacentTextOnLine(neighbor, true, wsConfig)) !== null) if ((neighbor.textContent || "").replace(/^( |\t|\r?\n)+/, "").length > 0) {
1516
+ isEndOfLine = false;
1517
+ break;
1518
+ }
1519
+ if (isEndOfLine) textContent = textContent.slice(0, -1);
1520
+ }
1521
+ return textContent;
1522
+ }
1523
+ function $applyFormat(node, format) {
1524
+ return format !== 0 && $isTextNode(node) ? node.setFormat(format) : node;
1525
+ }
1526
+ /**
1527
+ * Inverse of {@link getStyleObjectFromCSS}: serialize a parsed style
1528
+ * record back into a CSS declaration string suitable for
1529
+ * `TextNode.setStyle`. Returns the empty string for an empty record.
1530
+ */
1531
+ function styleObjectToCSS(style) {
1532
+ let css = "";
1533
+ for (const prop in style) {
1534
+ if (FORMAT_BIT_STYLE_PROPS.has(prop)) continue;
1535
+ css += `${prop}: ${style[prop]}; `;
1536
+ }
1537
+ return css.trimEnd();
1538
+ }
1539
+ function $applyTextStyle(node, style) {
1540
+ if ($isTextNode(node)) {
1541
+ const css = styleObjectToCSS(style);
1542
+ if (css !== "") node.setStyle(css);
1543
+ }
1544
+ return node;
1545
+ }
1546
+ /**
1547
+ * `#text` rule. Inside a `<pre>` ancestor, preserve whitespace and split
1548
+ * on `\n` and `\t` into `LineBreakNode`/`TabNode` siblings. Otherwise
1549
+ * collapse whitespace using the same neighbor-aware rules as the legacy
1550
+ * `$convertTextDOMNode`.
1551
+ */
1552
+ const TextRule = defineImportRule({
1553
+ $import: (ctx, el) => {
1554
+ const format = ctx.get(ImportTextFormat);
1555
+ const style = ctx.get(ImportTextStyle);
1556
+ const wsConfig = ctx.get(ImportWhitespaceConfig);
1557
+ if (isInsidePreserveWhitespace(el, wsConfig)) {
1558
+ const out = $generateNodesFromRawText(el.textContent || "");
1559
+ for (const node of out) {
1560
+ $applyFormat(node, format);
1561
+ $applyTextStyle(node, style);
1562
+ }
1563
+ return out;
1564
+ }
1565
+ const collapsed = collapseWhitespace(el, wsConfig);
1566
+ if (collapsed === "") return [];
1567
+ const text = $createTextNode(collapsed);
1568
+ $applyFormat(text, format);
1569
+ $applyTextStyle(text, style);
1570
+ return [text];
1571
+ },
1572
+ match: sel$1.text(),
1573
+ name: "@lexical/html/#text"
1574
+ });
1575
+ /**
1576
+ * Drop `<style>` and `<script>` and skip descending into them — matches
1577
+ * the legacy `IGNORE_TAGS` set, but as a regular rule so apps can register
1578
+ * a higher-priority `<style>` rule to capture stylesheet text into the
1579
+ * import session for later use.
1580
+ */
1581
+ const IgnoreScriptStyleRule = defineImportRule({
1582
+ $import: () => [],
1583
+ match: sel$1.tag("script", "style"),
1584
+ name: "@lexical/html/script-style-ignore"
1585
+ });
1586
+ const LineBreakRule = defineImportRule({
1587
+ $import: () => [$createLineBreakNode()],
1588
+ match: sel$1.tag("br"),
1589
+ name: "@lexical/html/br"
1590
+ });
1591
+ /**
1592
+ * Rules covering the {@link ParagraphNode}, {@link TextNode},
1593
+ * {@link LineBreakNode}, and {@link TabNode} cases that the legacy
1594
+ * `importDOM` machinery in `@lexical/lexical` handled. Intended to be
1595
+ * registered as a dependency of every editor that uses
1596
+ * {@link DOMImportExtension}.
1597
+ *
1598
+ * @experimental
1599
+ */
1600
+ const CoreImportRules = [
1601
+ IgnoreScriptStyleRule,
1602
+ defineImportRule({
1603
+ $import: (ctx, el) => {
1604
+ const p = $createParagraphNode();
1605
+ $setFormatFromDOM(p, el);
1606
+ setNodeIndentFromDOM(el, p);
1607
+ if (p.getFormatType() === "") {
1608
+ const align = el.getAttribute("align");
1609
+ if (align && isAlignmentValue(align)) p.setFormat(align);
1610
+ }
1611
+ $setDirectionFromDOM(p, el);
1612
+ return [p.splice(0, 0, ctx.$importChildren(el))];
1613
+ },
1614
+ match: sel$1.tag("p"),
1615
+ name: "@lexical/html/p"
1616
+ }),
1617
+ TextRule,
1618
+ LineBreakRule,
1619
+ InlineFormatRule
1620
+ ];
1621
+ /**
1622
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
1623
+ *
1624
+ * This source code is licensed under the MIT license found in the
1625
+ * LICENSE file in the root directory of this source tree.
1626
+ *
1627
+ */
1628
+ /** @internal */
1629
+ /** @internal */
1630
+ function mergeSortedAsc(a, b) {
1631
+ const out = [];
1632
+ let i = 0;
1633
+ let j = 0;
1634
+ while (i < a.length && j < b.length) if (a[i] <= b[j]) out.push(a[i++]);
1635
+ else out.push(b[j++]);
1636
+ while (i < a.length) out.push(a[i++]);
1637
+ while (j < b.length) out.push(b[j++]);
1638
+ return out;
1639
+ }
1640
+ /**
1641
+ * Compile an ordered list of {@link DOMImportRule}s into the dispatch tables
1642
+ * used by the import runtime. The rule at index 0 is the highest-priority
1643
+ * (`mergeConfig` prepends partial.rules so later-merged extensions land
1644
+ * first).
1645
+ *
1646
+ * @internal
1647
+ */
1648
+ function compileImportRules(rules) {
1649
+ const compiled = [];
1650
+ const byTag = /* @__PURE__ */ new Map();
1651
+ const wildcardIndices = [];
1652
+ const textIndices = [];
1653
+ const commentIndices = [];
1654
+ const seenNames = /* @__PURE__ */ new Set();
1655
+ rules.forEach((rule, i) => {
1656
+ const sel = getSelectorImpl(rule.match);
1657
+ const name = rule.name || defaultRuleName(sel, i);
1658
+ if (typeof rule.name === "string" && seenNames.has(rule.name)) console.warn(`[lexical] duplicate DOMImportRule name "${rule.name}" — keep names unique to aid debugging.`);
1659
+ if (rule.name) seenNames.add(rule.name);
1660
+ compiled.push({
1661
+ $import: rule.$import,
1662
+ name,
1663
+ predicate: sel.predicate
1664
+ });
1665
+ if (sel.kind === "text") textIndices.push(i);
1666
+ else if (sel.kind === "comment") commentIndices.push(i);
1667
+ else if (sel.tags.size === 0) wildcardIndices.push(i);
1668
+ else for (const tag of sel.tags) {
1669
+ let list = byTag.get(tag);
1670
+ if (!list) {
1671
+ list = [];
1672
+ byTag.set(tag, list);
1673
+ }
1674
+ list.push(i);
1675
+ }
1676
+ });
1677
+ const finalByTag = /* @__PURE__ */ new Map();
1678
+ if (wildcardIndices.length === 0) for (const [tag, list] of byTag) finalByTag.set(tag, list);
1679
+ else for (const [tag, list] of byTag) finalByTag.set(tag, mergeSortedAsc(list, wildcardIndices));
1680
+ return {
1681
+ byTag: finalByTag,
1682
+ commentIndices,
1683
+ rules: compiled,
1684
+ textIndices,
1685
+ wildcardIndices
1686
+ };
1687
+ }
1688
+ function defaultRuleName(sel, index) {
1689
+ if (sel.kind === "text") return `#text@${index}`;
1690
+ if (sel.kind === "comment") return `#comment@${index}`;
1691
+ if (sel.tags.size === 0) return `*@${index}`;
1692
+ return `${Array.from(sel.tags).join(",").toLowerCase()}@${index}`;
1693
+ }
1694
+ /**
1695
+ * Look up the (already interleaved) rule indices relevant to `node`. Element
1696
+ * nodes hit `byTag` (with wildcards merged in) or fall back to the wildcard
1697
+ * bucket if no tag-specific rules exist; text and comment nodes use their
1698
+ * own buckets.
1699
+ *
1700
+ * @internal
1701
+ */
1702
+ function getDispatchIndices(dispatch, node) {
1703
+ if (isDOMTextNode(node)) return dispatch.textIndices;
1704
+ if (node.nodeType === 8) return dispatch.commentIndices;
1705
+ if (isHTMLElement(node)) return dispatch.byTag.get(node.nodeName) || dispatch.wildcardIndices;
1706
+ return EMPTY_INDICES;
1707
+ }
1708
+ const EMPTY_INDICES = Object.freeze([]);
1709
+ /**
1710
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
1711
+ *
1712
+ * This source code is licensed under the MIT license found in the
1713
+ * LICENSE file in the root directory of this source tree.
1714
+ *
1715
+ */
1716
+ /**
1717
+ * Opaque handle for a pre-compiled set of overlay rules. Produce one with
1718
+ * {@link defineOverlayRules} and pass it to
1719
+ * {@link DOMImportContext.$importChildren} via
1720
+ * {@link ImportChildrenOpts.rules}.
1721
+ *
1722
+ * To merge two or more overlays into a single one, pass them (alongside
1723
+ * raw {@link DOMImportRule}s if desired) to a fresh
1724
+ * {@link defineOverlayRules} — earlier arguments are higher priority.
1725
+ *
1726
+ * The internal shape is intentionally not part of the public API: it's a
1727
+ * compiled dispatch table tagged with `__type` so callers cannot pass a
1728
+ * raw rule array where a compiled overlay is expected.
1729
+ *
1730
+ * @experimental
1731
+ */
1732
+ /**
1733
+ * An entry accepted everywhere rules are configured (overlay
1734
+ * definitions, {@link DOMImportConfig.rules}). Either a single
1735
+ * {@link DOMImportRule} or a {@link CompiledOverlayRules} produced by
1736
+ * a previous {@link defineOverlayRules} call — passing the latter
1737
+ * inlines the overlay's rules at this position in priority order.
1738
+ *
1739
+ * @experimental
1740
+ */
1741
+ /** @internal */
1742
+ function flattenRuleEntries(entries) {
1743
+ const out = [];
1744
+ for (const entry of entries) if (isCompiledOverlayRules(entry)) for (const r of entry.rules) out.push(r);
1745
+ else out.push(entry);
1746
+ return out;
1747
+ }
1748
+ function isCompiledOverlayRules(entry) {
1749
+ return typeof entry === "object" && entry !== null && "__type" in entry && entry.__type === "CompiledOverlayRules";
1750
+ }
1751
+ /**
1752
+ * Pre-compile a set of {@link DOMImportRuleEntry}s into a
1753
+ * {@link CompiledOverlayRules} handle that can be installed via
1754
+ * `ctx.$importChildren(el, {rules: …})`.
1755
+ *
1756
+ * Entries can be raw {@link DOMImportRule}s or other
1757
+ * {@link CompiledOverlayRules} (the latter are inlined at their
1758
+ * position in priority order, so the same call composes any number of
1759
+ * overlays). Earlier entries are higher priority.
1760
+ *
1761
+ * Overlay rules installed as a raw array would be re-compiled on every
1762
+ * `$importChildren` call. For overlays that are reused (e.g. a GitHub
1763
+ * code-table rule that wraps every matching table), call this once at
1764
+ * module scope so the dispatch table is built up front.
1765
+ *
1766
+ * @experimental
1767
+ */
1768
+ function defineOverlayRules(entries) {
1769
+ const rules = flattenRuleEntries(entries);
1770
+ return {
1771
+ __type: "CompiledOverlayRules",
1772
+ dispatch: compileImportRules(rules),
1773
+ rules
1774
+ };
1775
+ }
1776
+ /**
1777
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
1778
+ *
1779
+ * This source code is licensed under the MIT license found in the
1780
+ * LICENSE file in the root directory of this source tree.
1781
+ *
1782
+ */
1783
+ /**
1784
+ * True if the node fills a block slot at the root or inside another
1785
+ * block — covers both ElementNode-style blocks (paragraph, heading,
1786
+ * quote) and block-level DecoratorNodes (HorizontalRuleNode,
1787
+ * ImageNode-as-block, etc.). Used by {@link BlockSchema},
1788
+ * {@link RootSchema}, and {@link NestedBlockSchema}.
1789
+ *
1790
+ * @experimental
1791
+ */
1792
+ function $isBlockLevel(node) {
1793
+ return $isBlockElementNode(node) || $isDecoratorNode(node) && !node.isInline();
1794
+ }
1795
+ /**
1796
+ * Distribute an inline wrapper (`LinkNode`, `MarkNode`, …) across a
1797
+ * heterogeneous run of children produced by `$importChildren`, lifting
1798
+ * any block children to the top level while keeping the wrapper around
1799
+ * the leaf inline content.
1800
+ *
1801
+ * Use from a rule whose DOM source is an inline element that the
1802
+ * browser permitted to enclose block elements — the canonical case is
1803
+ * `<a href="…"><h1>title</h1><div>body</div></a>`, which a link rule
1804
+ * wants to surface as two block siblings (heading + paragraph), each
1805
+ * with its own link wrapping the original inline content. Schemas
1806
+ * can't express this because they reason about a parent's children
1807
+ * only — they cannot lift the parent out of itself.
1808
+ *
1809
+ * For each top-level child:
1810
+ * - **Inline children** are collected into runs; each run is wrapped
1811
+ * in a single fresh wrapper (from `$makeWrapper()`).
1812
+ * - **Block children** are descended into: their own children are
1813
+ * recursively distributed with `$makeWrapper`, then re-attached so
1814
+ * the block keeps its position at the top level.
1815
+ *
1816
+ * The returned list will contain a mix of blocks and wrapped inline
1817
+ * runs. The enclosing schema (typically {@link BlockSchema}) will
1818
+ * then package those inline wrappers into paragraphs as usual.
1819
+ *
1820
+ * @experimental
1821
+ */
1822
+ function $distributeInlineWrapper(children, $makeWrapper) {
1823
+ const out = [];
1824
+ let inlineRun = [];
1825
+ const flushInline = () => {
1826
+ if (inlineRun.length === 0) return;
1827
+ out.push($makeWrapper().splice(0, 0, inlineRun));
1828
+ inlineRun = [];
1829
+ };
1830
+ for (const child of children) if ($isBlockLevel(child)) {
1831
+ flushInline();
1832
+ if ($isElementNode(child)) {
1833
+ const wrapped = $distributeInlineWrapper(child.getChildren(), $makeWrapper);
1834
+ child.splice(0, child.getChildrenSize(), wrapped);
1835
+ }
1836
+ out.push(child);
1837
+ } else inlineRun.push(child);
1838
+ flushInline();
1839
+ return out;
1840
+ }
1841
+ /**
1842
+ * Apply a {@link ChildSchema} to a flat list of children produced by
1843
+ * `$importChildren`. Walks the list once, partitions into accepted vs.
1844
+ * rejected runs, packages or drops rejected runs, then runs `$finalize`.
1845
+ *
1846
+ * @internal
1847
+ */
1848
+ function $applySchema(schema, children, parent, domParent) {
1849
+ const out = [];
1850
+ let run = null;
1851
+ const flushRun = () => {
1852
+ if (run === null) return;
1853
+ const rejected = run;
1854
+ run = null;
1855
+ if (schema.$packageRun) {
1856
+ const packaged = schema.$packageRun(rejected, parent, domParent);
1857
+ if (packaged.length > 0) {
1858
+ for (const n of packaged) out.push(n);
1859
+ return;
1860
+ }
1861
+ }
1862
+ if (schema.onReject === "hoist") for (const n of rejected) out.push(n);
1863
+ };
1864
+ for (const child of children) if (schema.$accepts(child, parent)) {
1865
+ flushRun();
1866
+ out.push(child);
1867
+ } else {
1868
+ if (run === null) run = [];
1869
+ run.push(child);
1870
+ }
1871
+ flushRun();
1872
+ return schema.$finalize ? schema.$finalize(out, parent) : out;
1873
+ }
1874
+ /**
1875
+ * Wrap a run of inline lexical nodes in a fresh paragraph, propagating the
1876
+ * `text-align` of `domParent` as the paragraph's format type (matching the
1877
+ * legacy `wrapContinuousInlines` behavior).
1878
+ */
1879
+ function $paragraphPackageRun(run, _parent, domParent) {
1880
+ const paragraph = $createParagraphNode();
1881
+ if (isHTMLElement(domParent)) {
1882
+ const textAlign = domParent.style.textAlign;
1883
+ if (isAlignmentValue(textAlign)) paragraph.setFormat(textAlign);
1884
+ }
1885
+ return [paragraph.splice(0, 0, run)];
1886
+ }
1887
+ /**
1888
+ * Default schema for block-level positions (root of the document, the body
1889
+ * of a block element node). Accepts block lexical nodes; packages runs of
1890
+ * inline children into fresh paragraph nodes.
1891
+ *
1892
+ * @experimental
1893
+ */
1894
+ const BlockSchema = {
1895
+ $accepts: $isBlockLevel,
1896
+ $packageRun: $paragraphPackageRun,
1897
+ name: "BlockSchema"
1898
+ };
1899
+ /**
1900
+ * Schema for inline-only positions (the body of an inline lexical node such
1901
+ * as a link). Accepts non-block lexical nodes; runs of block children are
1902
+ * dropped (`onReject: 'drop'` is the default).
1903
+ *
1904
+ * @experimental
1905
+ */
1906
+ const InlineSchema = {
1907
+ $accepts: (child) => !$isBlockLevel(child),
1908
+ name: "InlineSchema"
1909
+ };
1910
+ /**
1911
+ * Schema for nested block positions — the equivalent of the legacy
1912
+ * `ArtificialNode__DO_NOT_USE` flow used when a block DOM element appears
1913
+ * inside another block lexical ancestor. Accepts block nodes; runs of inline
1914
+ * children are emitted with a line break between consecutive runs (instead
1915
+ * of being wrapped in a paragraph, which would introduce an extra level of
1916
+ * nesting).
1917
+ *
1918
+ * @experimental
1919
+ */
1920
+ const NestedBlockSchema = {
1921
+ $accepts: $isBlockLevel,
1922
+ /**
1923
+ * Pass an inline run through unchanged. Because the schema iterator only
1924
+ * groups *maximal* rejected runs (each separated from the next by an
1925
+ * accepted block child), the legacy "linebreak between adjacent inline
1926
+ * groups" case never arises — adjacent inline siblings are already
1927
+ * coalesced into one run.
1928
+ */
1929
+ $packageRun: (run) => run,
1930
+ name: "NestedBlockSchema"
1931
+ };
1932
+ /**
1933
+ * Schema for the topmost level of `$generateNodesFromDOM`. Identical to
1934
+ * {@link BlockSchema}; aliased for clarity at the entry point and so it can
1935
+ * be overridden separately in the future (e.g. to synthesize a `ListNode`
1936
+ * around runs of orphan `ListItemNode`s).
1937
+ *
1938
+ * @experimental
1939
+ */
1940
+ const RootSchema = {
1941
+ $accepts: $isBlockLevel,
1942
+ $packageRun: $paragraphPackageRun,
1943
+ name: "RootSchema"
1944
+ };
1945
+ /**
1946
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
1947
+ *
1948
+ * This source code is licensed under the MIT license found in the
1949
+ * LICENSE file in the root directory of this source tree.
1950
+ *
1951
+ */
1952
+ const NO_CAPTURES = Object.freeze({});
1953
+ function makeContext(runtime, captures) {
1954
+ return {
1955
+ $importChildren: (parent, opts) => $importChildrenInternal(runtime, parent, opts),
1956
+ $importOne: (node, opts) => $importOneInternal(runtime, node, opts),
1957
+ captures,
1958
+ get(cfg) {
1959
+ return $getImportContextValue(cfg, runtime.editor);
1960
+ },
1961
+ session: runtime.session
1962
+ };
1963
+ }
1964
+ function $importChildrenInternal(runtime, parent, opts) {
1965
+ const overlay = opts && opts.rules ? opts.rules.dispatch : void 0;
1966
+ if (overlay) runtime.overlays.push(overlay);
1967
+ try {
1968
+ const run = () => $importChildrenRun(runtime, parent, opts);
1969
+ return opts && opts.context ? $withImportContext(opts.context, runtime.editor)(run) : run();
1970
+ } finally {
1971
+ if (overlay) runtime.overlays.pop();
1972
+ }
1973
+ }
1974
+ function $importChildrenRun(runtime, parent, opts) {
1975
+ const onChild = opts && opts.$onChild;
1976
+ const collected = [];
1977
+ for (const child of Array.from(parent.childNodes)) {
1978
+ const produced = $importOneInternal(runtime, child, void 0);
1979
+ for (const lex of produced) {
1980
+ const result = onChild ? onChild(lex) : lex;
1981
+ if (result != null) collected.push(result);
1982
+ }
1983
+ }
1984
+ const afterApplied = opts && opts.$after ? opts.$after(collected) : collected;
1985
+ const schema = opts && opts.schema;
1986
+ if (!schema) return afterApplied;
1987
+ return $applySchema(schema, afterApplied, null, parent);
1988
+ }
1989
+ function $importOneInternal(runtime, node, opts) {
1990
+ const run = () => $dispatch(runtime, node);
1991
+ return opts && opts.context ? $withImportContext(opts.context, runtime.editor)(run) : run();
1992
+ }
1993
+ /**
1994
+ * Build the candidate (dispatch, indices) list for `node`. Overlays are
1995
+ * tried first in top-of-stack order; the main dispatcher comes last. The
1996
+ * `$next()` chain walks through all of them in sequence — an overlay rule
1997
+ * can defer to a lower overlay rule, or all the way through to a main
1998
+ * rule, just by calling `$next()`.
1999
+ */
2000
+ function getCandidates(runtime, node) {
2001
+ const candidates = [];
2002
+ for (let i = runtime.overlays.length - 1; i >= 0; i--) {
2003
+ const d = runtime.overlays[i];
2004
+ const idx = getDispatchIndices(d, node);
2005
+ if (idx.length > 0) candidates.push({
2006
+ dispatch: d,
2007
+ indices: idx
2008
+ });
2009
+ }
2010
+ const mainIdx = getDispatchIndices(runtime.dispatch, node);
2011
+ if (mainIdx.length > 0) candidates.push({
2012
+ dispatch: runtime.dispatch,
2013
+ indices: mainIdx
2014
+ });
2015
+ return candidates;
2016
+ }
2017
+ function $dispatch(runtime, node) {
2018
+ const candidates = getCandidates(runtime, node);
2019
+ if (candidates.length === 0) return $hoistChildrenOf(runtime, node);
2020
+ let groupCursor = 0;
2021
+ let ruleCursor = 0;
2022
+ const $next = () => {
2023
+ while (groupCursor < candidates.length) {
2024
+ const { dispatch, indices } = candidates[groupCursor];
2025
+ while (ruleCursor < indices.length) {
2026
+ const idx = indices[ruleCursor++];
2027
+ const rule = dispatch.rules[idx];
2028
+ const captures = {};
2029
+ if (rule.predicate(node, captures)) {
2030
+ const ctx = makeContext(runtime, Object.keys(captures).length === 0 ? NO_CAPTURES : captures);
2031
+ try {
2032
+ return rule.$import(ctx, node, $next);
2033
+ } catch (e) {
2034
+ console.error(`[lexical] DOM import rule "${rule.name}" threw on node`, node, e);
2035
+ throw e;
2036
+ }
2037
+ }
2038
+ }
2039
+ groupCursor++;
2040
+ ruleCursor = 0;
2041
+ }
2042
+ return $hoistChildrenOf(runtime, node);
2043
+ };
2044
+ return $next();
2045
+ }
2046
+ /**
2047
+ * Fallback when no rule matched and `$next()` was called past the end of the
2048
+ * chain: hoist the element's children to take its place, recursively. Pure
2049
+ * elements with no rule become invisible, matching the legacy
2050
+ * `$createNodesFromDOM` hoisting behavior.
2051
+ */
2052
+ function $hoistChildrenOf(runtime, node) {
2053
+ if (node.childNodes.length === 0) return [];
2054
+ const collected = [];
2055
+ for (const child of Array.from(node.childNodes)) {
2056
+ const produced = $importOneInternal(runtime, child, void 0);
2057
+ for (const lex of produced) collected.push(lex);
2058
+ }
2059
+ return collected;
2060
+ }
2061
+ /**
2062
+ * Top-level walker for a compiled dispatcher. Iterates the DOM children of
2063
+ * `dom` (using the document body if a {@link Document} is passed) and
2064
+ * applies `RootSchema` to the produced lexical nodes so runs of inlines are
2065
+ * wrapped in paragraphs — same shape as the legacy `$generateNodesFromDOM`.
2066
+ *
2067
+ * @internal
2068
+ */
2069
+ function $runImport(dispatch, editor, dom, session) {
2070
+ return $importChildrenRun({
2071
+ dispatch,
2072
+ editor,
2073
+ overlays: session.get(ImportOverlays).map((o) => o.dispatch),
2074
+ session
2075
+ }, isDOMDocumentNode(dom) ? dom.body : dom, { schema: RootSchema });
2076
+ }
2077
+ /**
2078
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
2079
+ *
2080
+ * This source code is licensed under the MIT license found in the
2081
+ * LICENSE file in the root directory of this source tree.
2082
+ *
2083
+ */
2084
+ /**
2085
+ * Configuration for {@link DOMImportExtension}.
2086
+ *
2087
+ * @experimental
2088
+ */
2089
+ /**
2090
+ * Drive a stack of {@link DOMPreprocessFn}s top-to-bottom: the highest-
2091
+ * index fn runs first and may call `$next()` to defer to the next-lower
2092
+ * one. Matches the export-side `callExportMimeTypeFunctionStack` shape.
2093
+ */
2094
+ function $runPreprocessStack(stack, dom, ctx) {
2095
+ let i = stack.length - 1;
2096
+ const $next = () => {
2097
+ while (i >= 0) {
2098
+ const cur = stack[i--];
2099
+ cur(dom, ctx, $next);
2100
+ return;
2101
+ }
2102
+ };
2103
+ $next();
2104
+ }
2105
+ /**
2106
+ * Lowest-priority catch-all rule used as the default `config.rules` entry
2107
+ * for {@link DOMImportExtension}: descends into the element's children
2108
+ * and returns whatever they produced. With no other matching rule, an
2109
+ * element vanishes and its contents are inserted in its place — the
2110
+ * legacy `$createNodesFromDOM` hoisting behavior, but now expressed as a
2111
+ * regular rule that apps can override (e.g. with a `sel.any()` rule that
2112
+ * captures and discards unknown elements).
2113
+ *
2114
+ * @experimental
2115
+ */
2116
+ const DefaultHoistRule = defineImportRule({
2117
+ $import: (ctx, el) => ctx.$importChildren(el),
2118
+ match: selBase.any(),
2119
+ name: "@lexical/html/default-hoist"
2120
+ });
2121
+ /**
2122
+ * @experimental
2123
+ *
2124
+ * Extension-based replacement for the legacy `importDOM` / `DOMConversion`
2125
+ * machinery. Rules are contributed via configuration (see
2126
+ * {@link DOMImportConfig.rules}), compiled into a tag-bucketed dispatcher at
2127
+ * editor build time, and consumed via the extension's
2128
+ * {@link DOMImportExtensionOutput.$generateNodesFromDOM} output.
2129
+ *
2130
+ * The legacy `$generateNodesFromDOM` continues to work in parallel; the
2131
+ * intent is to migrate node packages over to this extension incrementally.
2132
+ */
2133
+ const DOMImportExtension = defineExtension({
2134
+ build(editor, config) {
2135
+ const dispatch = compileImportRules(flattenRuleEntries(config.rules));
2136
+ const defaults = contextFromPairs(config.contextDefaults, void 0);
2137
+ const configPreprocess = config.preprocess;
2138
+ return {
2139
+ $generateNodesFromDOM: (dom, options) => {
2140
+ const fromOpts = options && options.context ? contextFromPairs(options.context, defaults) : defaults;
2141
+ const sessionRecord = fromOpts !== void 0 && fromOpts !== defaults ? fromOpts : Object.create(defaults || null);
2142
+ const session = new ImportSessionImpl(sessionRecord);
2143
+ const preprocessCtx = { session };
2144
+ $runPreprocessStack(options && options.preprocess ? [...configPreprocess, ...options.preprocess] : configPreprocess, dom, preprocessCtx);
2145
+ return $withFullContext(DOMImportContextSymbol, sessionRecord, () => $runImport(dispatch, editor, dom, session), editor);
2146
+ },
2147
+ defaults
2148
+ };
2149
+ },
2150
+ config: {
2151
+ contextDefaults: [],
2152
+ preprocess: [$inlineStylesFromStyleSheets],
2153
+ rules: [DefaultHoistRule]
2154
+ },
2155
+ mergeConfig(config, partial) {
2156
+ return shallowMergeConfig(config, {
2157
+ ...partial,
2158
+ ...partial.contextDefaults && { contextDefaults: [...config.contextDefaults, ...partial.contextDefaults] },
2159
+ ...partial.preprocess && { preprocess: [...config.preprocess, ...partial.preprocess] },
2160
+ ...partial.rules && { rules: [...partial.rules, ...config.rules] }
2161
+ });
2162
+ },
2163
+ name: DOMImportExtensionName
2164
+ });
2165
+ /**
2166
+ * Look up the editor's {@link DOMImportExtension} and run its
2167
+ * `$generateNodesFromDOM`. Designed as a drop-in replacement for the
2168
+ * legacy `$generateNodesFromDOM(editor, dom)` signature so it can be
2169
+ * supplied to `ClipboardImportExtension.$generateNodesFromDOM` (or any
2170
+ * other consumer that wants to route through the extension pipeline).
2171
+ *
2172
+ * Throws if the editor was not built with {@link DOMImportExtension} as a
2173
+ * dependency.
2174
+ *
2175
+ * @experimental
2176
+ */
2177
+ function $generateNodesFromDOMViaExtension(dom, options) {
2178
+ return $getExtensionOutput(DOMImportExtension).$generateNodesFromDOM(dom, options);
2179
+ }
2180
+ /**
2181
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
2182
+ *
2183
+ * This source code is licensed under the MIT license found in the
2184
+ * LICENSE file in the root directory of this source tree.
2185
+ *
2186
+ */
2187
+ /**
2188
+ * Bundles {@link CoreImportRules} into a {@link DOMImportExtension}-aware
2189
+ * extension. Depend on this from your editor (directly or via richer
2190
+ * extensions like `RichTextImportExtension`) to get the equivalent of the
2191
+ * legacy core `importDOM` behavior for `<p>`, `<span>`, `<b>`,
2192
+ * `<strong>`, `<em>`, `<i>`, `<code>`, `<mark>`, `<s>`, `<sub>`, `<sup>`,
2193
+ * `<u>`, `<br>`, and `#text`.
2194
+ *
2195
+ * @experimental
2196
+ */
2197
+ const CoreImportExtension = defineExtension({
2198
+ dependencies: [configExtension(DOMImportExtension, { rules: CoreImportRules })],
2199
+ name: "@lexical/html/CoreImport"
2200
+ });
2201
+ /**
2202
+ * Import rules for {@link HorizontalRuleNode}.
2203
+ *
2204
+ * @experimental
2205
+ */
2206
+ const HorizontalRuleImportRules = [defineImportRule({
2207
+ $import: () => [$createHorizontalRuleNode()],
2208
+ match: selBase.tag("hr"),
2209
+ name: "@lexical/html/hr"
2210
+ })];
2211
+ /**
2212
+ * Bundles {@link HorizontalRuleImportRules} (plus
2213
+ * {@link CoreImportExtension}) into a single dependency. The legacy
2214
+ * {@link HorizontalRuleExtension.importDOM} continues to work in parallel;
2215
+ * depend on this extension to opt into the new pipeline.
2216
+ *
2217
+ * Lives in `@lexical/html` (not `@lexical/extension`) because
2218
+ * {@link DOMImportExtension} itself is in `@lexical/html`, and
2219
+ * `@lexical/extension` is upstream of `@lexical/html` in the dependency
2220
+ * graph — same arrangement as {@link CoreImportExtension}.
2221
+ *
2222
+ * @experimental
2223
+ */
2224
+ const HorizontalRuleImportExtension = defineExtension({
2225
+ dependencies: [
2226
+ CoreImportExtension,
2227
+ HorizontalRuleExtension,
2228
+ configExtension(DOMImportExtension, { rules: HorizontalRuleImportRules })
2229
+ ],
2230
+ name: "@lexical/html/HorizontalRuleImport"
2231
+ });
2232
+ /**
2233
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
2234
+ *
2235
+ * This source code is licensed under the MIT license found in the
2236
+ * LICENSE file in the root directory of this source tree.
2237
+ *
2238
+ */
2239
+ /**
2240
+ * Combinator-and-parser-based builder for {@link CompiledSelector}s. The
2241
+ * runtime shape returned by these factory methods is opaque; consumers
2242
+ * should never inspect or construct selector objects directly.
2243
+ *
2244
+ * @experimental
2245
+ */
2246
+ const sel = {
2247
+ any: selBase.any,
2248
+ comment: selBase.comment,
2249
+ /**
2250
+ * Parse a reduced CSS-selector subset and return a builder you can chain
2251
+ * combinator methods off of.
2252
+ */
2253
+ css: parseSelector,
2254
+ tag: selBase.tag,
2255
+ text: selBase.text
2256
+ };
2257
+ const IGNORE_TAGS = new Set(["STYLE", "SCRIPT"]);
2258
+ /**
2259
+ * How you parse your html string to get a document is left up to you. In the browser you can use the native
2260
+ * DOMParser API to generate a document (see clipboard.ts), but to use in a headless environment you can use JSDom
2261
+ * or an equivalent library and pass in the document here.
2262
+ */
2263
+ function $generateNodesFromDOM(editor, dom) {
2264
+ $inlineStylesFromStyleSheetsDOM(dom);
2265
+ const elements = isDOMDocumentNode(dom) ? dom.body.childNodes : dom.childNodes;
2266
+ const lexicalNodes = [];
2267
+ const allArtificialNodes = [];
2268
+ for (const element of elements) if (!IGNORE_TAGS.has(element.nodeName)) {
2269
+ const lexicalNode = $createNodesFromDOM(element, editor, allArtificialNodes, false);
2270
+ if (lexicalNode !== null) for (const node of lexicalNode) lexicalNodes.push(node);
2271
+ }
2272
+ $unwrapArtificialNodes(allArtificialNodes);
2273
+ return lexicalNodes;
2274
+ }
2275
+ /**
2276
+ * Generate DOM nodes from the editor state into the given container element,
2277
+ * using the editor's {@link EditorDOMRenderConfig}.
2278
+ * @experimental
2279
+ */
2280
+ function $generateDOMFromNodes(container, selection = null, editor = $getEditor()) {
2281
+ return $withRenderContext([contextValue(RenderContextExport, true)], editor)(() => {
2282
+ const root = $getRoot();
2283
+ const domConfig = $getSessionDOMRenderConfig(editor);
2284
+ const parentElementAppend = container.append.bind(container);
2285
+ for (const topLevelNode of root.getChildren()) $appendNodesToHTML(editor, topLevelNode, parentElementAppend, selection, domConfig);
2286
+ return container;
2287
+ });
2288
+ }
2289
+ /**
2290
+ * Generate DOM nodes from a root node into the given container element,
2291
+ * including the root node itself. Uses the editor's {@link EditorDOMRenderConfig}.
2292
+ * @experimental
2293
+ */
2294
+ function $generateDOMFromRoot(container, root = $getRoot()) {
2295
+ const editor = $getEditor();
2296
+ return $withRenderContext([contextValue(RenderContextExport, true), contextValue(RenderContextRoot, true)], editor)(() => {
2297
+ const selection = null;
2298
+ const domConfig = $getSessionDOMRenderConfig(editor);
2299
+ $appendNodesToHTML(editor, root, container.append.bind(container), selection, domConfig);
2300
+ return container;
2301
+ });
2302
+ }
2303
+ /**
2304
+ * Generate an HTML string from the editor's current state (or `selection`
2305
+ * if provided).
2306
+ *
2307
+ * Must be called inside an active editor scope — i.e. `editor.update(...)`,
2308
+ * `editor.read(...)`, or `editor.getEditorState().read(callback, {editor})`.
2309
+ * The legacy `editor.getEditorState().read(callback)` call (without the
2310
+ * `{editor}` option) does not set an active editor and is not supported;
2311
+ * `editor.read(...)` is the drop-in replacement.
2312
+ */
2313
+ function $generateHtmlFromNodes(editor, selection = null) {
2314
+ if (typeof document === "undefined" || typeof window === "undefined" && typeof global.window === "undefined") formatDevErrorMessage(`To use $generateHtmlFromNodes in headless mode please initialize a headless browser implementation such as JSDom or use withDOM from @lexical/headless/dom before calling this function.`);
2315
+ return $generateDOMFromNodes(document.createElement("div"), selection, editor).innerHTML;
2316
+ }
2317
+ function $appendNodesToHTML(editor, currentNode, parentElementAppend, selection = null, domConfig = $getEditorDOMRenderConfig(editor)) {
2318
+ let shouldInclude = domConfig.$shouldInclude(currentNode, selection, editor);
2319
+ const shouldExclude = domConfig.$shouldExclude(currentNode, selection, editor);
2320
+ let target = currentNode;
2321
+ if (selection !== null && $isTextNode(currentNode)) target = $sliceSelectedTextNodeContent(selection, currentNode, "clone");
2322
+ const { element, after, append, $getChildNodes } = domConfig.$exportDOM(target, editor);
2323
+ if (!element) return false;
2324
+ const fragment = document.createDocumentFragment();
2325
+ const children = $getChildNodes ? $getChildNodes() : $isElementNode(target) ? target.getChildren() : [];
2326
+ const fragmentAppend = fragment.append.bind(fragment);
2327
+ for (const childNode of children) {
2328
+ const shouldIncludeChild = $appendNodesToHTML(editor, childNode, fragmentAppend, selection, domConfig);
2329
+ if (!shouldInclude && shouldIncludeChild && domConfig.$extractWithChild(currentNode, childNode, selection, "html", editor)) shouldInclude = true;
2330
+ }
2331
+ if (shouldInclude && !shouldExclude) {
2332
+ if (isHTMLElement(element) || isDocumentFragment(element)) if (append) append(fragment);
2333
+ else element.append(fragment);
2334
+ parentElementAppend(element);
2335
+ if (after) {
2336
+ const newElement = after.call(target, element);
2337
+ if (newElement) if (isDocumentFragment(element)) element.replaceChildren(newElement);
2338
+ else element.replaceWith(newElement);
2339
+ }
2340
+ } else parentElementAppend(fragment);
2341
+ return shouldInclude;
2342
+ }
2343
+ function getConversionFunction(domNode, editor) {
2344
+ const { nodeName } = domNode;
2345
+ const cachedConversions = editor._htmlConversions.get(nodeName.toLowerCase());
2346
+ let currentConversion = null;
2347
+ if (cachedConversions !== void 0) for (const cachedConversion of cachedConversions) {
2348
+ const domConversion = cachedConversion(domNode);
2349
+ if (domConversion !== null && (currentConversion === null || (currentConversion.priority || 0) <= (domConversion.priority || 0))) currentConversion = domConversion;
2350
+ }
2351
+ return currentConversion !== null ? currentConversion.conversion : null;
2352
+ }
2353
+ function $createNodesFromDOM(node, editor, allArtificialNodes, hasBlockAncestorLexicalNode, forChildMap = /* @__PURE__ */ new Map(), parentLexicalNode) {
2354
+ const lexicalNodes = [];
2355
+ if (IGNORE_TAGS.has(node.nodeName)) return lexicalNodes;
2356
+ let currentLexicalNode = null;
2357
+ const transformFunction = getConversionFunction(node, editor);
2358
+ const transformOutput = transformFunction ? transformFunction(node) : null;
2359
+ let postTransform = null;
2360
+ if (transformOutput !== null) {
2361
+ postTransform = transformOutput.after;
2362
+ const transformNodes = transformOutput.node;
2363
+ currentLexicalNode = Array.isArray(transformNodes) ? transformNodes[transformNodes.length - 1] : transformNodes;
2364
+ if (currentLexicalNode !== null) {
2365
+ for (const [, forChildFunction] of forChildMap) {
2366
+ currentLexicalNode = forChildFunction(currentLexicalNode, parentLexicalNode);
2367
+ if (!currentLexicalNode) break;
2368
+ }
2369
+ if (currentLexicalNode) lexicalNodes.push(...Array.isArray(transformNodes) ? transformNodes : [currentLexicalNode]);
2370
+ }
2371
+ if (transformOutput.forChild != null) forChildMap.set(node.nodeName, transformOutput.forChild);
2372
+ }
2373
+ const children = node.childNodes;
2374
+ let childLexicalNodes = [];
2375
+ const hasBlockAncestorLexicalNodeForChildren = currentLexicalNode != null && $isRootOrShadowRoot(currentLexicalNode) ? false : currentLexicalNode != null && $isBlockElementNode(currentLexicalNode) || hasBlockAncestorLexicalNode;
2376
+ for (let i = 0; i < children.length; i++) childLexicalNodes.push(...$createNodesFromDOM(children[i], editor, allArtificialNodes, hasBlockAncestorLexicalNodeForChildren, new Map(forChildMap), currentLexicalNode));
2377
+ if (postTransform != null) childLexicalNodes = postTransform(childLexicalNodes);
2378
+ if (isBlockDomNode(node)) if (!hasBlockAncestorLexicalNodeForChildren) childLexicalNodes = wrapContinuousInlines(node, childLexicalNodes, $createParagraphNode);
2379
+ else childLexicalNodes = wrapContinuousInlines(node, childLexicalNodes, () => {
2380
+ const artificialNode = new ArtificialNode__DO_NOT_USE();
2381
+ allArtificialNodes.push(artificialNode);
2382
+ return artificialNode;
2383
+ });
2384
+ if (currentLexicalNode == null) {
2385
+ if (childLexicalNodes.length > 0) for (const childNode of childLexicalNodes) lexicalNodes.push(childNode);
2386
+ else if (isBlockDomNode(node) && isDomNodeBetweenTwoInlineNodes(node)) lexicalNodes.push($createLineBreakNode());
2387
+ } else if ($isElementNode(currentLexicalNode)) currentLexicalNode.append(...childLexicalNodes);
2388
+ return lexicalNodes;
2389
+ }
2390
+ function wrapContinuousInlines(domNode, nodes, createWrapperFn) {
2391
+ const textAlign = domNode.style.textAlign;
2392
+ const out = [];
2393
+ let continuousInlines = [];
2394
+ for (let i = 0; i < nodes.length; i++) {
2395
+ const node = nodes[i];
2396
+ if ($isBlockElementNode(node)) {
2397
+ if (textAlign && !node.getFormat()) node.setFormat(textAlign);
2398
+ out.push(node);
2399
+ } else {
2400
+ continuousInlines.push(node);
2401
+ if (i === nodes.length - 1 || i < nodes.length - 1 && $isBlockElementNode(nodes[i + 1])) {
2402
+ const wrapper = createWrapperFn();
2403
+ wrapper.setFormat(textAlign);
2404
+ wrapper.append(...continuousInlines);
2405
+ out.push(wrapper);
2406
+ continuousInlines = [];
2407
+ }
2408
+ }
2409
+ }
2410
+ return out;
2411
+ }
2412
+ function $unwrapArtificialNodes(allArtificialNodes) {
2413
+ for (const node of allArtificialNodes) if (node.getParent() && node.getNextSibling() instanceof ArtificialNode__DO_NOT_USE) node.insertAfter($createLineBreakNode());
2414
+ for (const node of allArtificialNodes) {
2415
+ const parent = node.getParent();
2416
+ if (parent) parent.splice(node.getIndexWithinParent(), 1, node.getChildren());
2417
+ }
2418
+ }
2419
+ function isDomNodeBetweenTwoInlineNodes(node) {
2420
+ if (node.nextSibling == null || node.previousSibling == null) return false;
2421
+ return isInlineDomNode(node.nextSibling) && isInlineDomNode(node.previousSibling);
2422
+ }
2423
+ //#endregion
2424
+ export { $distributeInlineWrapper, $generateDOMFromNodes, $generateDOMFromRoot, $generateHtmlFromNodes, $generateNodesFromDOM, $generateNodesFromDOMViaExtension, $getImportContextValue, $getRenderContextValue, $getSessionDOMRenderConfig, $inlineStylesFromStyleSheets, $isBlockLevel, $setRenderContextValue, $updateRenderContextValue, $withImportContext, $withRenderContext, BlockSchema, CoreImportExtension, CoreImportRules, DOMImportExtension, DOMRenderExtension, HorizontalRuleImportExtension, HorizontalRuleImportRules, ImportOverlays, ImportSource, ImportSourceDataTransfer, ImportTextFormat, ImportTextStyle, ImportWhitespaceConfig, InlineSchema, NestedBlockSchema, RenderContextExport, RenderContextRoot, RootSchema, contextUpdater, contextValue, createImportState, createRenderState, defaultIsInline, defaultPreservesWhitespace, defineImportRule, defineOverlayRules, domOverride, isElementOfTag, parseSelector, sel };