@lexical/html 0.45.0 → 0.45.1-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LexicalHtml.dev.js +308 -211
- package/dist/LexicalHtml.dev.mjs +309 -213
- package/dist/LexicalHtml.mjs +1 -0
- package/dist/LexicalHtml.node.mjs +1 -0
- package/dist/LexicalHtml.prod.js +1 -1
- package/dist/LexicalHtml.prod.mjs +1 -1
- package/dist/import/HorizontalRuleImportExtension.d.ts +6 -5
- package/dist/import/coreImportRules.d.ts +1 -1
- package/dist/import/index.d.ts +1 -1
- package/dist/import/schemas.d.ts +15 -0
- package/dist/index.d.ts +1 -1
- package/package.json +6 -6
- package/src/import/HorizontalRuleImportExtension.ts +6 -7
- package/src/import/coreImportRules.ts +61 -1
- package/src/import/index.ts +1 -0
- package/src/import/schemas.ts +44 -0
- package/src/index.ts +6 -0
package/dist/LexicalHtml.dev.mjs
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { $sliceSelectedTextNodeContent } from '@lexical/selection';
|
|
10
|
-
import { $getEditor, createState, isDOMDocumentNode, isHTMLElement, $getEditorDOMRenderConfig, DEFAULT_EDITOR_DOM_CONFIG, $isLexicalNode, getStaticNodeConfig, $fullReconcile, defineExtension, shallowMergeConfig, RootNode, isDOMTextNode, isBlockDomNode, isInlineDomNode, IS_HIGHLIGHT, IS_CODE, $generateNodesFromRawText, $createTextNode,
|
|
10
|
+
import { $getEditor, createState, isDOMDocumentNode, isHTMLElement, $getEditorDOMRenderConfig, DEFAULT_EDITOR_DOM_CONFIG, $isLexicalNode, getStaticNodeConfig, $fullReconcile, defineExtension, shallowMergeConfig, RootNode, isDOMTextNode, isBlockDomNode, isInlineDomNode, $isElementNode, $isBlockElementNode, $isDecoratorNode, $isLineBreakNode, $createParagraphNode, IS_HIGHLIGHT, IS_CODE, $generateNodesFromRawText, $createTextNode, isOnlyChildInBlockNode, isLastChildInBlockNode, $createLineBreakNode, $setFormatFromDOM, setNodeIndentFromDOM, $setDirectionFromDOM, $isTextNode, IS_BOLD, IS_ITALIC, IS_UNDERLINE, IS_STRIKETHROUGH, IS_SUBSCRIPT, IS_SUPERSCRIPT, configExtension, $getRoot, $assumeActiveEditor, isDocumentFragment, $isRootOrShadowRoot, ArtificialNode__DO_NOT_USE } from 'lexical';
|
|
11
11
|
import { objectKlassEquals } from '@lexical/utils';
|
|
12
12
|
import { getPeerDependencyFromEditor, getKnownTypesAndNodes, $getExtensionOutput, HorizontalRuleExtension, $createHorizontalRuleNode } from '@lexical/extension';
|
|
13
13
|
|
|
@@ -1669,6 +1669,249 @@ function $getImportContextValue(cfg, editor = $getEditor()) {
|
|
|
1669
1669
|
*/
|
|
1670
1670
|
const $withImportContext = $withContext(DOMImportContextSymbol, getDefaultImportContext);
|
|
1671
1671
|
|
|
1672
|
+
/**
|
|
1673
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
1674
|
+
*
|
|
1675
|
+
* This source code is licensed under the MIT license found in the
|
|
1676
|
+
* LICENSE file in the root directory of this source tree.
|
|
1677
|
+
*
|
|
1678
|
+
*/
|
|
1679
|
+
|
|
1680
|
+
|
|
1681
|
+
/**
|
|
1682
|
+
* True if the node fills a block slot at the root or inside another
|
|
1683
|
+
* block — covers both ElementNode-style blocks (paragraph, heading,
|
|
1684
|
+
* quote) and block-level DecoratorNodes (HorizontalRuleNode,
|
|
1685
|
+
* ImageNode-as-block, etc.). Used by {@link BlockSchema},
|
|
1686
|
+
* {@link RootSchema}, and {@link NestedBlockSchema}.
|
|
1687
|
+
*
|
|
1688
|
+
* @experimental
|
|
1689
|
+
*/
|
|
1690
|
+
function $isBlockLevel(node) {
|
|
1691
|
+
return $isBlockElementNode(node) || $isDecoratorNode(node) && !node.isInline();
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
/**
|
|
1695
|
+
* Distribute an inline wrapper (`LinkNode`, `MarkNode`, …) across a
|
|
1696
|
+
* heterogeneous run of children produced by `$importChildren`, lifting
|
|
1697
|
+
* any block children to the top level while keeping the wrapper around
|
|
1698
|
+
* the leaf inline content.
|
|
1699
|
+
*
|
|
1700
|
+
* Use from a rule whose DOM source is an inline element that the
|
|
1701
|
+
* browser permitted to enclose block elements — the canonical case is
|
|
1702
|
+
* `<a href="…"><h1>title</h1><div>body</div></a>`, which a link rule
|
|
1703
|
+
* wants to surface as two block siblings (heading + paragraph), each
|
|
1704
|
+
* with its own link wrapping the original inline content. Schemas
|
|
1705
|
+
* can't express this because they reason about a parent's children
|
|
1706
|
+
* only — they cannot lift the parent out of itself.
|
|
1707
|
+
*
|
|
1708
|
+
* For each top-level child:
|
|
1709
|
+
* - **Inline children** are collected into runs; each run is wrapped
|
|
1710
|
+
* in a single fresh wrapper (from `$makeWrapper()`).
|
|
1711
|
+
* - **Block children** are descended into: their own children are
|
|
1712
|
+
* recursively distributed with `$makeWrapper`, then re-attached so
|
|
1713
|
+
* the block keeps its position at the top level.
|
|
1714
|
+
*
|
|
1715
|
+
* The returned list will contain a mix of blocks and wrapped inline
|
|
1716
|
+
* runs. The enclosing schema (typically {@link BlockSchema}) will
|
|
1717
|
+
* then package those inline wrappers into paragraphs as usual.
|
|
1718
|
+
*
|
|
1719
|
+
* @experimental
|
|
1720
|
+
*/
|
|
1721
|
+
function $distributeInlineWrapper(children, $makeWrapper) {
|
|
1722
|
+
const out = [];
|
|
1723
|
+
let inlineRun = [];
|
|
1724
|
+
const flushInline = () => {
|
|
1725
|
+
if (inlineRun.length === 0) {
|
|
1726
|
+
return;
|
|
1727
|
+
}
|
|
1728
|
+
out.push($makeWrapper().splice(0, 0, inlineRun));
|
|
1729
|
+
inlineRun = [];
|
|
1730
|
+
};
|
|
1731
|
+
for (const child of children) {
|
|
1732
|
+
if ($isBlockLevel(child)) {
|
|
1733
|
+
flushInline();
|
|
1734
|
+
// Recursively distribute the wrapper into the block's own
|
|
1735
|
+
// children. A block DecoratorNode (no children) is left alone.
|
|
1736
|
+
if ($isElementNode(child)) {
|
|
1737
|
+
const wrapped = $distributeInlineWrapper(child.getChildren(), $makeWrapper);
|
|
1738
|
+
child.splice(0, child.getChildrenSize(), wrapped);
|
|
1739
|
+
}
|
|
1740
|
+
out.push(child);
|
|
1741
|
+
} else {
|
|
1742
|
+
inlineRun.push(child);
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
flushInline();
|
|
1746
|
+
return out;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
/**
|
|
1750
|
+
* Apply a {@link ChildSchema} to a flat list of children produced by
|
|
1751
|
+
* `$importChildren`. Walks the list once, partitions into accepted vs.
|
|
1752
|
+
* rejected runs, packages or drops rejected runs, then runs `$finalize`.
|
|
1753
|
+
*
|
|
1754
|
+
* @internal
|
|
1755
|
+
*/
|
|
1756
|
+
function $applySchema(schema, children, parent, domParent) {
|
|
1757
|
+
const out = [];
|
|
1758
|
+
let run = null;
|
|
1759
|
+
const flushRun = () => {
|
|
1760
|
+
if (run === null) {
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1763
|
+
const rejected = run;
|
|
1764
|
+
run = null;
|
|
1765
|
+
if (schema.$packageRun) {
|
|
1766
|
+
const packaged = schema.$packageRun(rejected, parent, domParent);
|
|
1767
|
+
if (packaged.length > 0) {
|
|
1768
|
+
for (const n of packaged) {
|
|
1769
|
+
out.push(n);
|
|
1770
|
+
}
|
|
1771
|
+
return;
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
// No $packageRun (or it returned []) — apply onReject. 'drop' (default)
|
|
1775
|
+
// discards the run. 'hoist' lets it through unchanged at this level.
|
|
1776
|
+
if (schema.onReject === 'hoist') {
|
|
1777
|
+
for (const n of rejected) {
|
|
1778
|
+
out.push(n);
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
};
|
|
1782
|
+
for (const child of children) {
|
|
1783
|
+
if (schema.$accepts(child, parent)) {
|
|
1784
|
+
flushRun();
|
|
1785
|
+
out.push(child);
|
|
1786
|
+
} else {
|
|
1787
|
+
if (run === null) {
|
|
1788
|
+
run = [];
|
|
1789
|
+
}
|
|
1790
|
+
run.push(child);
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
flushRun();
|
|
1794
|
+
return schema.$finalize ? schema.$finalize(out, parent) : out;
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
/**
|
|
1798
|
+
* Apply a parent DOM element's `text-align` (when set to one of the
|
|
1799
|
+
* supported {@link ElementFormatType} values) to each block-level child
|
|
1800
|
+
* Lexical node that does not yet have its own format.
|
|
1801
|
+
*
|
|
1802
|
+
* Mirrors the part of the legacy `wrapContinuousInlines` that wrote
|
|
1803
|
+
* `node.setFormat(textAlign)` onto pre-existing block children when the
|
|
1804
|
+
* DOM parent carried `style.textAlign`. Pair with
|
|
1805
|
+
* {@link $paragraphPackageRun} (which carries the same propagation onto
|
|
1806
|
+
* paragraphs synthesized around inline runs) to fully replicate the
|
|
1807
|
+
* legacy behavior on a run of mixed children.
|
|
1808
|
+
*
|
|
1809
|
+
* @experimental
|
|
1810
|
+
*/
|
|
1811
|
+
function $propagateTextAlignToBlockChildren(children, domParent) {
|
|
1812
|
+
if (!isHTMLElement(domParent)) {
|
|
1813
|
+
return children;
|
|
1814
|
+
}
|
|
1815
|
+
const textAlign = domParent.style.textAlign;
|
|
1816
|
+
if (!isAlignmentValue(textAlign)) {
|
|
1817
|
+
return children;
|
|
1818
|
+
}
|
|
1819
|
+
for (const child of children) {
|
|
1820
|
+
if ($isBlockElementNode(child) && child.getFormatType() === '') {
|
|
1821
|
+
child.setFormat(textAlign);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
return children;
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
/**
|
|
1828
|
+
* Wrap a run of inline lexical nodes in a fresh paragraph, propagating the
|
|
1829
|
+
* `text-align` of `domParent` as the paragraph's format type (matching the
|
|
1830
|
+
* legacy `wrapContinuousInlines` behavior).
|
|
1831
|
+
*/
|
|
1832
|
+
function $paragraphPackageRun(run, _parent, domParent) {
|
|
1833
|
+
// Mirror the legacy `$wrapInlineNodes` (driven by
|
|
1834
|
+
// `selection.insertNodes`) shortcut where a lone `<br>` at this
|
|
1835
|
+
// level (a `LineBreakNode` is the only thing in the rejected run)
|
|
1836
|
+
// becomes an *empty* paragraph rather than a paragraph wrapping a
|
|
1837
|
+
// visible line break — that's the form clipboard pastes ending in a
|
|
1838
|
+
// trailing `<br>` (Google Docs, Gmail, …) rely on for the editor's
|
|
1839
|
+
// "extra trailing empty line" expectation.
|
|
1840
|
+
if (run.length === 1 && $isLineBreakNode(run[0])) {
|
|
1841
|
+
run = [];
|
|
1842
|
+
}
|
|
1843
|
+
const paragraph = $createParagraphNode();
|
|
1844
|
+
if (isHTMLElement(domParent)) {
|
|
1845
|
+
const textAlign = domParent.style.textAlign;
|
|
1846
|
+
if (isAlignmentValue(textAlign)) {
|
|
1847
|
+
paragraph.setFormat(textAlign);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
return [paragraph.splice(0, 0, run)];
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
/**
|
|
1854
|
+
* Default schema for block-level positions (root of the document, the body
|
|
1855
|
+
* of a block element node). Accepts block lexical nodes; packages runs of
|
|
1856
|
+
* inline children into fresh paragraph nodes.
|
|
1857
|
+
*
|
|
1858
|
+
* @experimental
|
|
1859
|
+
*/
|
|
1860
|
+
const BlockSchema = {
|
|
1861
|
+
$accepts: $isBlockLevel,
|
|
1862
|
+
$packageRun: $paragraphPackageRun,
|
|
1863
|
+
name: 'BlockSchema'
|
|
1864
|
+
};
|
|
1865
|
+
|
|
1866
|
+
/**
|
|
1867
|
+
* Schema for inline-only positions (the body of an inline lexical node such
|
|
1868
|
+
* as a link). Accepts non-block lexical nodes; runs of block children are
|
|
1869
|
+
* dropped (`onReject: 'drop'` is the default).
|
|
1870
|
+
*
|
|
1871
|
+
* @experimental
|
|
1872
|
+
*/
|
|
1873
|
+
const InlineSchema = {
|
|
1874
|
+
$accepts: child => !$isBlockLevel(child),
|
|
1875
|
+
name: 'InlineSchema'
|
|
1876
|
+
};
|
|
1877
|
+
|
|
1878
|
+
/**
|
|
1879
|
+
* Schema for nested block positions — the equivalent of the legacy
|
|
1880
|
+
* `ArtificialNode__DO_NOT_USE` flow used when a block DOM element appears
|
|
1881
|
+
* inside another block lexical ancestor. Accepts block nodes; runs of inline
|
|
1882
|
+
* children are emitted with a line break between consecutive runs (instead
|
|
1883
|
+
* of being wrapped in a paragraph, which would introduce an extra level of
|
|
1884
|
+
* nesting).
|
|
1885
|
+
*
|
|
1886
|
+
* @experimental
|
|
1887
|
+
*/
|
|
1888
|
+
const NestedBlockSchema = {
|
|
1889
|
+
$accepts: $isBlockLevel,
|
|
1890
|
+
/**
|
|
1891
|
+
* Pass an inline run through unchanged. Because the schema iterator only
|
|
1892
|
+
* groups *maximal* rejected runs (each separated from the next by an
|
|
1893
|
+
* accepted block child), the legacy "linebreak between adjacent inline
|
|
1894
|
+
* groups" case never arises — adjacent inline siblings are already
|
|
1895
|
+
* coalesced into one run.
|
|
1896
|
+
*/
|
|
1897
|
+
$packageRun: run => run,
|
|
1898
|
+
name: 'NestedBlockSchema'
|
|
1899
|
+
};
|
|
1900
|
+
|
|
1901
|
+
/**
|
|
1902
|
+
* Schema for the topmost level of `$generateNodesFromDOM`. Identical to
|
|
1903
|
+
* {@link BlockSchema}; aliased for clarity at the entry point and so it can
|
|
1904
|
+
* be overridden separately in the future (e.g. to synthesize a `ListNode`
|
|
1905
|
+
* around runs of orphan `ListItemNode`s).
|
|
1906
|
+
*
|
|
1907
|
+
* @experimental
|
|
1908
|
+
*/
|
|
1909
|
+
const RootSchema = {
|
|
1910
|
+
$accepts: $isBlockLevel,
|
|
1911
|
+
$packageRun: $paragraphPackageRun,
|
|
1912
|
+
name: 'RootSchema'
|
|
1913
|
+
};
|
|
1914
|
+
|
|
1672
1915
|
/**
|
|
1673
1916
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
1674
1917
|
*
|
|
@@ -2022,7 +2265,13 @@ const IgnoreScriptStyleRule = defineImportRule({
|
|
|
2022
2265
|
name: '@lexical/html/script-style-ignore'
|
|
2023
2266
|
});
|
|
2024
2267
|
const LineBreakRule = defineImportRule({
|
|
2025
|
-
|
|
2268
|
+
// Mirror the legacy LineBreakNode.importDOM filter: stray `<br>` that
|
|
2269
|
+
// are the sole or trailing child of a block parent (e.g. Apple's
|
|
2270
|
+
// `<br class="Apple-interchange-newline">` clipboard sentinel, or the
|
|
2271
|
+
// trailing `<br>` browsers insert after the last text in a `<div>`)
|
|
2272
|
+
// would otherwise survive as a LineBreakNode and tack an extra blank
|
|
2273
|
+
// line onto the imported content.
|
|
2274
|
+
$import: (_ctx, el) => isOnlyChildInBlockNode(el) || isLastChildInBlockNode(el) ? [] : [$createLineBreakNode()],
|
|
2026
2275
|
match: sel$1.tag('br'),
|
|
2027
2276
|
name: '@lexical/html/br'
|
|
2028
2277
|
});
|
|
@@ -2052,6 +2301,51 @@ const ParagraphRule = defineImportRule({
|
|
|
2052
2301
|
name: '@lexical/html/p'
|
|
2053
2302
|
});
|
|
2054
2303
|
|
|
2304
|
+
/**
|
|
2305
|
+
* Transparent block-container rule for any unconverted block-level DOM
|
|
2306
|
+
* element — `<div>`, but also `<section>`, `<article>`, `<header>`,
|
|
2307
|
+
* `<figure>`, … (everything {@link isBlockDomNode} recognizes via the
|
|
2308
|
+
* legacy `BLOCK_TAG_RE`). Without it these would fall through to the
|
|
2309
|
+
* dispatcher's `$hoistChildrenOf` / `DefaultHoistRule` fallback, which
|
|
2310
|
+
* transparently lifts children up to the enclosing context. That works
|
|
2311
|
+
* structurally, but (a) two sibling `<section>`s collapse into a single
|
|
2312
|
+
* paragraph instead of two, and (b) any `text-align` set on the element
|
|
2313
|
+
* is lost because the synthesized paragraph (built by the enclosing
|
|
2314
|
+
* schema) sees the *grandparent* as `domParent`.
|
|
2315
|
+
*
|
|
2316
|
+
* The rule is registered as a `sel.any()` wildcard and defers (via
|
|
2317
|
+
* `$next()`) for non-block elements so inline tags still reach the inline
|
|
2318
|
+
* rules. Higher-priority tag rules (`<p>`, `<li>`, `<td>`, headings, …)
|
|
2319
|
+
* are dispatched first and never reach here.
|
|
2320
|
+
*
|
|
2321
|
+
* The element's children run through {@link BlockSchema} so each inline
|
|
2322
|
+
* run becomes its own `ParagraphNode` (with the element's `text-align`
|
|
2323
|
+
* picked up via {@link $paragraphPackageRun}'s `domParent`), and any
|
|
2324
|
+
* pre-existing block children get the same alignment applied via
|
|
2325
|
+
* {@link $propagateTextAlignToBlockChildren}. The resulting block-level
|
|
2326
|
+
* nodes are what the enclosing context sees — at the root a sibling
|
|
2327
|
+
* paragraph is the natural shape; inside a block lexical container the
|
|
2328
|
+
* container rule (e.g. {@link ListItemRule}) collapses paragraph
|
|
2329
|
+
* children back into inline-with-line-break form. That way both `<p>`
|
|
2330
|
+
* and transparent blocks (`<div>`, `<section>`, …) project to the same
|
|
2331
|
+
* `ParagraphNode` intermediate, and there is no need for a marker node
|
|
2332
|
+
* to distinguish them.
|
|
2333
|
+
*/
|
|
2334
|
+
const TransparentBlockRule = defineImportRule({
|
|
2335
|
+
$import: (ctx, el, $next) => {
|
|
2336
|
+
if (!isBlockDomNode(el)) {
|
|
2337
|
+
// Inline element with no dedicated rule — let the inline rules (or
|
|
2338
|
+
// the default hoist) handle it.
|
|
2339
|
+
return $next();
|
|
2340
|
+
}
|
|
2341
|
+
return $propagateTextAlignToBlockChildren(ctx.$importChildren(el, {
|
|
2342
|
+
schema: BlockSchema
|
|
2343
|
+
}), el);
|
|
2344
|
+
},
|
|
2345
|
+
match: sel$1.any(),
|
|
2346
|
+
name: '@lexical/html/transparent-block'
|
|
2347
|
+
});
|
|
2348
|
+
|
|
2055
2349
|
/**
|
|
2056
2350
|
* Rules covering the {@link ParagraphNode}, {@link TextNode},
|
|
2057
2351
|
* {@link LineBreakNode}, and {@link TabNode} cases that the legacy
|
|
@@ -2061,7 +2355,7 @@ const ParagraphRule = defineImportRule({
|
|
|
2061
2355
|
*
|
|
2062
2356
|
* @experimental
|
|
2063
2357
|
*/
|
|
2064
|
-
const CoreImportRules = [IgnoreScriptStyleRule, ParagraphRule, TextRule, LineBreakRule, InlineFormatRule];
|
|
2358
|
+
const CoreImportRules = [IgnoreScriptStyleRule, ParagraphRule, TransparentBlockRule, TextRule, LineBreakRule, InlineFormatRule];
|
|
2065
2359
|
|
|
2066
2360
|
/**
|
|
2067
2361
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -2280,209 +2574,6 @@ function defineOverlayRules(entries) {
|
|
|
2280
2574
|
};
|
|
2281
2575
|
}
|
|
2282
2576
|
|
|
2283
|
-
/**
|
|
2284
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2285
|
-
*
|
|
2286
|
-
* This source code is licensed under the MIT license found in the
|
|
2287
|
-
* LICENSE file in the root directory of this source tree.
|
|
2288
|
-
*
|
|
2289
|
-
*/
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
/**
|
|
2293
|
-
* True if the node fills a block slot at the root or inside another
|
|
2294
|
-
* block — covers both ElementNode-style blocks (paragraph, heading,
|
|
2295
|
-
* quote) and block-level DecoratorNodes (HorizontalRuleNode,
|
|
2296
|
-
* ImageNode-as-block, etc.). Used by {@link BlockSchema},
|
|
2297
|
-
* {@link RootSchema}, and {@link NestedBlockSchema}.
|
|
2298
|
-
*
|
|
2299
|
-
* @experimental
|
|
2300
|
-
*/
|
|
2301
|
-
function $isBlockLevel(node) {
|
|
2302
|
-
return $isBlockElementNode(node) || $isDecoratorNode(node) && !node.isInline();
|
|
2303
|
-
}
|
|
2304
|
-
|
|
2305
|
-
/**
|
|
2306
|
-
* Distribute an inline wrapper (`LinkNode`, `MarkNode`, …) across a
|
|
2307
|
-
* heterogeneous run of children produced by `$importChildren`, lifting
|
|
2308
|
-
* any block children to the top level while keeping the wrapper around
|
|
2309
|
-
* the leaf inline content.
|
|
2310
|
-
*
|
|
2311
|
-
* Use from a rule whose DOM source is an inline element that the
|
|
2312
|
-
* browser permitted to enclose block elements — the canonical case is
|
|
2313
|
-
* `<a href="…"><h1>title</h1><div>body</div></a>`, which a link rule
|
|
2314
|
-
* wants to surface as two block siblings (heading + paragraph), each
|
|
2315
|
-
* with its own link wrapping the original inline content. Schemas
|
|
2316
|
-
* can't express this because they reason about a parent's children
|
|
2317
|
-
* only — they cannot lift the parent out of itself.
|
|
2318
|
-
*
|
|
2319
|
-
* For each top-level child:
|
|
2320
|
-
* - **Inline children** are collected into runs; each run is wrapped
|
|
2321
|
-
* in a single fresh wrapper (from `$makeWrapper()`).
|
|
2322
|
-
* - **Block children** are descended into: their own children are
|
|
2323
|
-
* recursively distributed with `$makeWrapper`, then re-attached so
|
|
2324
|
-
* the block keeps its position at the top level.
|
|
2325
|
-
*
|
|
2326
|
-
* The returned list will contain a mix of blocks and wrapped inline
|
|
2327
|
-
* runs. The enclosing schema (typically {@link BlockSchema}) will
|
|
2328
|
-
* then package those inline wrappers into paragraphs as usual.
|
|
2329
|
-
*
|
|
2330
|
-
* @experimental
|
|
2331
|
-
*/
|
|
2332
|
-
function $distributeInlineWrapper(children, $makeWrapper) {
|
|
2333
|
-
const out = [];
|
|
2334
|
-
let inlineRun = [];
|
|
2335
|
-
const flushInline = () => {
|
|
2336
|
-
if (inlineRun.length === 0) {
|
|
2337
|
-
return;
|
|
2338
|
-
}
|
|
2339
|
-
out.push($makeWrapper().splice(0, 0, inlineRun));
|
|
2340
|
-
inlineRun = [];
|
|
2341
|
-
};
|
|
2342
|
-
for (const child of children) {
|
|
2343
|
-
if ($isBlockLevel(child)) {
|
|
2344
|
-
flushInline();
|
|
2345
|
-
// Recursively distribute the wrapper into the block's own
|
|
2346
|
-
// children. A block DecoratorNode (no children) is left alone.
|
|
2347
|
-
if ($isElementNode(child)) {
|
|
2348
|
-
const wrapped = $distributeInlineWrapper(child.getChildren(), $makeWrapper);
|
|
2349
|
-
child.splice(0, child.getChildrenSize(), wrapped);
|
|
2350
|
-
}
|
|
2351
|
-
out.push(child);
|
|
2352
|
-
} else {
|
|
2353
|
-
inlineRun.push(child);
|
|
2354
|
-
}
|
|
2355
|
-
}
|
|
2356
|
-
flushInline();
|
|
2357
|
-
return out;
|
|
2358
|
-
}
|
|
2359
|
-
|
|
2360
|
-
/**
|
|
2361
|
-
* Apply a {@link ChildSchema} to a flat list of children produced by
|
|
2362
|
-
* `$importChildren`. Walks the list once, partitions into accepted vs.
|
|
2363
|
-
* rejected runs, packages or drops rejected runs, then runs `$finalize`.
|
|
2364
|
-
*
|
|
2365
|
-
* @internal
|
|
2366
|
-
*/
|
|
2367
|
-
function $applySchema(schema, children, parent, domParent) {
|
|
2368
|
-
const out = [];
|
|
2369
|
-
let run = null;
|
|
2370
|
-
const flushRun = () => {
|
|
2371
|
-
if (run === null) {
|
|
2372
|
-
return;
|
|
2373
|
-
}
|
|
2374
|
-
const rejected = run;
|
|
2375
|
-
run = null;
|
|
2376
|
-
if (schema.$packageRun) {
|
|
2377
|
-
const packaged = schema.$packageRun(rejected, parent, domParent);
|
|
2378
|
-
if (packaged.length > 0) {
|
|
2379
|
-
for (const n of packaged) {
|
|
2380
|
-
out.push(n);
|
|
2381
|
-
}
|
|
2382
|
-
return;
|
|
2383
|
-
}
|
|
2384
|
-
}
|
|
2385
|
-
// No $packageRun (or it returned []) — apply onReject. 'drop' (default)
|
|
2386
|
-
// discards the run. 'hoist' lets it through unchanged at this level.
|
|
2387
|
-
if (schema.onReject === 'hoist') {
|
|
2388
|
-
for (const n of rejected) {
|
|
2389
|
-
out.push(n);
|
|
2390
|
-
}
|
|
2391
|
-
}
|
|
2392
|
-
};
|
|
2393
|
-
for (const child of children) {
|
|
2394
|
-
if (schema.$accepts(child, parent)) {
|
|
2395
|
-
flushRun();
|
|
2396
|
-
out.push(child);
|
|
2397
|
-
} else {
|
|
2398
|
-
if (run === null) {
|
|
2399
|
-
run = [];
|
|
2400
|
-
}
|
|
2401
|
-
run.push(child);
|
|
2402
|
-
}
|
|
2403
|
-
}
|
|
2404
|
-
flushRun();
|
|
2405
|
-
return schema.$finalize ? schema.$finalize(out, parent) : out;
|
|
2406
|
-
}
|
|
2407
|
-
|
|
2408
|
-
/**
|
|
2409
|
-
* Wrap a run of inline lexical nodes in a fresh paragraph, propagating the
|
|
2410
|
-
* `text-align` of `domParent` as the paragraph's format type (matching the
|
|
2411
|
-
* legacy `wrapContinuousInlines` behavior).
|
|
2412
|
-
*/
|
|
2413
|
-
function $paragraphPackageRun(run, _parent, domParent) {
|
|
2414
|
-
const paragraph = $createParagraphNode();
|
|
2415
|
-
if (isHTMLElement(domParent)) {
|
|
2416
|
-
const textAlign = domParent.style.textAlign;
|
|
2417
|
-
if (isAlignmentValue(textAlign)) {
|
|
2418
|
-
paragraph.setFormat(textAlign);
|
|
2419
|
-
}
|
|
2420
|
-
}
|
|
2421
|
-
return [paragraph.splice(0, 0, run)];
|
|
2422
|
-
}
|
|
2423
|
-
|
|
2424
|
-
/**
|
|
2425
|
-
* Default schema for block-level positions (root of the document, the body
|
|
2426
|
-
* of a block element node). Accepts block lexical nodes; packages runs of
|
|
2427
|
-
* inline children into fresh paragraph nodes.
|
|
2428
|
-
*
|
|
2429
|
-
* @experimental
|
|
2430
|
-
*/
|
|
2431
|
-
const BlockSchema = {
|
|
2432
|
-
$accepts: $isBlockLevel,
|
|
2433
|
-
$packageRun: $paragraphPackageRun,
|
|
2434
|
-
name: 'BlockSchema'
|
|
2435
|
-
};
|
|
2436
|
-
|
|
2437
|
-
/**
|
|
2438
|
-
* Schema for inline-only positions (the body of an inline lexical node such
|
|
2439
|
-
* as a link). Accepts non-block lexical nodes; runs of block children are
|
|
2440
|
-
* dropped (`onReject: 'drop'` is the default).
|
|
2441
|
-
*
|
|
2442
|
-
* @experimental
|
|
2443
|
-
*/
|
|
2444
|
-
const InlineSchema = {
|
|
2445
|
-
$accepts: child => !$isBlockLevel(child),
|
|
2446
|
-
name: 'InlineSchema'
|
|
2447
|
-
};
|
|
2448
|
-
|
|
2449
|
-
/**
|
|
2450
|
-
* Schema for nested block positions — the equivalent of the legacy
|
|
2451
|
-
* `ArtificialNode__DO_NOT_USE` flow used when a block DOM element appears
|
|
2452
|
-
* inside another block lexical ancestor. Accepts block nodes; runs of inline
|
|
2453
|
-
* children are emitted with a line break between consecutive runs (instead
|
|
2454
|
-
* of being wrapped in a paragraph, which would introduce an extra level of
|
|
2455
|
-
* nesting).
|
|
2456
|
-
*
|
|
2457
|
-
* @experimental
|
|
2458
|
-
*/
|
|
2459
|
-
const NestedBlockSchema = {
|
|
2460
|
-
$accepts: $isBlockLevel,
|
|
2461
|
-
/**
|
|
2462
|
-
* Pass an inline run through unchanged. Because the schema iterator only
|
|
2463
|
-
* groups *maximal* rejected runs (each separated from the next by an
|
|
2464
|
-
* accepted block child), the legacy "linebreak between adjacent inline
|
|
2465
|
-
* groups" case never arises — adjacent inline siblings are already
|
|
2466
|
-
* coalesced into one run.
|
|
2467
|
-
*/
|
|
2468
|
-
$packageRun: run => run,
|
|
2469
|
-
name: 'NestedBlockSchema'
|
|
2470
|
-
};
|
|
2471
|
-
|
|
2472
|
-
/**
|
|
2473
|
-
* Schema for the topmost level of `$generateNodesFromDOM`. Identical to
|
|
2474
|
-
* {@link BlockSchema}; aliased for clarity at the entry point and so it can
|
|
2475
|
-
* be overridden separately in the future (e.g. to synthesize a `ListNode`
|
|
2476
|
-
* around runs of orphan `ListItemNode`s).
|
|
2477
|
-
*
|
|
2478
|
-
* @experimental
|
|
2479
|
-
*/
|
|
2480
|
-
const RootSchema = {
|
|
2481
|
-
$accepts: $isBlockLevel,
|
|
2482
|
-
$packageRun: $paragraphPackageRun,
|
|
2483
|
-
name: 'RootSchema'
|
|
2484
|
-
};
|
|
2485
|
-
|
|
2486
2577
|
/**
|
|
2487
2578
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2488
2579
|
*
|
|
@@ -2831,20 +2922,21 @@ const HorizontalRuleRule = defineImportRule({
|
|
|
2831
2922
|
const HorizontalRuleImportRules = [HorizontalRuleRule];
|
|
2832
2923
|
|
|
2833
2924
|
/**
|
|
2834
|
-
* Bundles {@link HorizontalRuleImportRules}
|
|
2835
|
-
* {@link
|
|
2836
|
-
*
|
|
2837
|
-
*
|
|
2925
|
+
* Bundles {@link HorizontalRuleImportRules} together with the runtime
|
|
2926
|
+
* {@link HorizontalRuleExtension}. The application is expected to
|
|
2927
|
+
* already have `CoreImportExtension` (or some equivalent) in its
|
|
2928
|
+
* dependency graph — the core/text/paragraph/inline-format rules are a
|
|
2929
|
+
* shared baseline, not something this leaf importer should re-declare.
|
|
2838
2930
|
*
|
|
2839
2931
|
* Lives in `@lexical/html` (not `@lexical/extension`) because
|
|
2840
2932
|
* {@link DOMImportExtension} itself is in `@lexical/html`, and
|
|
2841
2933
|
* `@lexical/extension` is upstream of `@lexical/html` in the dependency
|
|
2842
|
-
* graph
|
|
2934
|
+
* graph.
|
|
2843
2935
|
*
|
|
2844
2936
|
* @experimental
|
|
2845
2937
|
*/
|
|
2846
2938
|
const HorizontalRuleImportExtension = defineExtension({
|
|
2847
|
-
dependencies: [
|
|
2939
|
+
dependencies: [HorizontalRuleExtension, configExtension(DOMImportExtension, {
|
|
2848
2940
|
rules: HorizontalRuleImportRules
|
|
2849
2941
|
})],
|
|
2850
2942
|
name: '@lexical/html/HorizontalRuleImport'
|
|
@@ -2952,6 +3044,10 @@ function $generateHtmlFromNodes(editor, selection = null) {
|
|
|
2952
3044
|
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.`);
|
|
2953
3045
|
}
|
|
2954
3046
|
}
|
|
3047
|
+
// BC: $setTextContent now requires an active-editor scope (added in #8519).
|
|
3048
|
+
// If the caller is in a legacy `editorState.read(cb)` scope (no active editor),
|
|
3049
|
+
// establish one via internal API.
|
|
3050
|
+
$assumeActiveEditor(editor);
|
|
2955
3051
|
return $generateDOMFromNodes(document.createElement('div'), selection, editor).innerHTML;
|
|
2956
3052
|
}
|
|
2957
3053
|
function $appendNodesToHTML(editor, currentNode, parentElementAppend, selection = null, domConfig = $getEditorDOMRenderConfig(editor)) {
|
|
@@ -3143,4 +3239,4 @@ function isDomNodeBetweenTwoInlineNodes(node) {
|
|
|
3143
3239
|
return isInlineDomNode(node.nextSibling) && isInlineDomNode(node.previousSibling);
|
|
3144
3240
|
}
|
|
3145
3241
|
|
|
3146
|
-
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 };
|
|
3242
|
+
export { $distributeInlineWrapper, $generateDOMFromNodes, $generateDOMFromRoot, $generateHtmlFromNodes, $generateNodesFromDOM, $generateNodesFromDOMViaExtension, $getImportContextValue, $getRenderContextValue, $getSessionDOMRenderConfig, $inlineStylesFromStyleSheets, $isBlockLevel, $propagateTextAlignToBlockChildren, $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 };
|
package/dist/LexicalHtml.mjs
CHANGED
|
@@ -20,6 +20,7 @@ export const $getRenderContextValue = mod.$getRenderContextValue;
|
|
|
20
20
|
export const $getSessionDOMRenderConfig = mod.$getSessionDOMRenderConfig;
|
|
21
21
|
export const $inlineStylesFromStyleSheets = mod.$inlineStylesFromStyleSheets;
|
|
22
22
|
export const $isBlockLevel = mod.$isBlockLevel;
|
|
23
|
+
export const $propagateTextAlignToBlockChildren = mod.$propagateTextAlignToBlockChildren;
|
|
23
24
|
export const $setRenderContextValue = mod.$setRenderContextValue;
|
|
24
25
|
export const $updateRenderContextValue = mod.$updateRenderContextValue;
|
|
25
26
|
export const $withImportContext = mod.$withImportContext;
|
|
@@ -18,6 +18,7 @@ export const $getRenderContextValue = mod.$getRenderContextValue;
|
|
|
18
18
|
export const $getSessionDOMRenderConfig = mod.$getSessionDOMRenderConfig;
|
|
19
19
|
export const $inlineStylesFromStyleSheets = mod.$inlineStylesFromStyleSheets;
|
|
20
20
|
export const $isBlockLevel = mod.$isBlockLevel;
|
|
21
|
+
export const $propagateTextAlignToBlockChildren = mod.$propagateTextAlignToBlockChildren;
|
|
21
22
|
export const $setRenderContextValue = mod.$setRenderContextValue;
|
|
22
23
|
export const $updateRenderContextValue = mod.$updateRenderContextValue;
|
|
23
24
|
export const $withImportContext = mod.$withImportContext;
|