lexical 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/Lexical.dev.js +213 -148
- package/dist/Lexical.dev.mjs +210 -149
- package/dist/Lexical.js.flow +9 -1
- package/dist/Lexical.mjs +4 -0
- package/dist/Lexical.node.mjs +4 -0
- package/dist/Lexical.prod.js +1 -1
- package/dist/Lexical.prod.mjs +1 -1
- package/dist/LexicalNode.d.ts +8 -0
- package/dist/LexicalUpdates.d.ts +2 -0
- package/dist/LexicalUtils.d.ts +41 -5
- package/dist/index.d.ts +3 -3
- package/dist/nodes/LexicalLineBreakNode.d.ts +18 -0
- package/package.json +2 -2
- package/src/LexicalEditor.ts +10 -9
- package/src/LexicalEvents.ts +4 -5
- package/src/LexicalMutations.ts +0 -6
- package/src/LexicalNode.ts +8 -0
- package/src/LexicalReconciler.ts +8 -0
- package/src/LexicalSelection.ts +10 -11
- package/src/LexicalUpdates.ts +12 -0
- package/src/LexicalUtils.ts +66 -15
- package/src/index.ts +5 -0
- package/src/nodes/LexicalLineBreakNode.ts +18 -2
- package/src/nodes/LexicalTextNode.ts +2 -16
package/dist/Lexical.dev.js
CHANGED
|
@@ -534,9 +534,9 @@ function indexPath(root, child) {
|
|
|
534
534
|
*
|
|
535
535
|
*/
|
|
536
536
|
|
|
537
|
-
// `"0.45.0+dev.cjs"` is statically replaced with the build-specific
|
|
537
|
+
// `"0.45.1-dev.0+dev.cjs"` is statically replaced with the build-specific
|
|
538
538
|
// version string in a Rollup build, and a consumer's bundler `define` can
|
|
539
|
-
// inject it the same way — so the exact `"0.45.0+dev.cjs"` member
|
|
539
|
+
// inject it the same way — so the exact `"0.45.1-dev.0+dev.cjs"` member
|
|
540
540
|
// expression must be preserved for that substitution to match. Reading it
|
|
541
541
|
// inside a try/catch lets the source be consumed directly (via the `source`
|
|
542
542
|
// export condition) in a browser bundle, where `process` is undefined and
|
|
@@ -545,11 +545,11 @@ function indexPath(root, child) {
|
|
|
545
545
|
// `pnpm run update-version`.
|
|
546
546
|
let envLexicalVersion;
|
|
547
547
|
try {
|
|
548
|
-
envLexicalVersion = "0.45.0+dev.cjs";
|
|
548
|
+
envLexicalVersion = "0.45.1-dev.0+dev.cjs";
|
|
549
549
|
} catch (_unused) {
|
|
550
550
|
// `process` is not defined in some browser bundles; use the fallback.
|
|
551
551
|
}
|
|
552
|
-
const LEXICAL_VERSION = envLexicalVersion ?? '0.45.0+source';
|
|
552
|
+
const LEXICAL_VERSION = envLexicalVersion ?? '0.45.1-dev.0+source';
|
|
553
553
|
|
|
554
554
|
/**
|
|
555
555
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -968,7 +968,7 @@ function shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode) {
|
|
|
968
968
|
}
|
|
969
969
|
return isDOMTextNode(targetDOM) && targetNode.isAttached();
|
|
970
970
|
}
|
|
971
|
-
function $getNearestManagedNodePairFromDOMNode(startingDOM, editor, editorState
|
|
971
|
+
function $getNearestManagedNodePairFromDOMNode(startingDOM, editor, editorState) {
|
|
972
972
|
for (let dom = startingDOM; dom && !isDOMUnmanaged(dom); dom = getParentElement(dom)) {
|
|
973
973
|
const key = getNodeKeyFromDOMNode(dom, editor);
|
|
974
974
|
if (key !== undefined) {
|
|
@@ -977,8 +977,6 @@ function $getNearestManagedNodePairFromDOMNode(startingDOM, editor, editorState,
|
|
|
977
977
|
// All decorator nodes are unmanaged
|
|
978
978
|
return $isDecoratorNode(node) || !isHTMLElement(dom) ? undefined : [dom, node];
|
|
979
979
|
}
|
|
980
|
-
} else if (dom === rootElement) {
|
|
981
|
-
return [rootElement, internalGetRoot(editorState)];
|
|
982
980
|
}
|
|
983
981
|
}
|
|
984
982
|
}
|
|
@@ -989,7 +987,6 @@ function flushMutations(editor, mutations, observer) {
|
|
|
989
987
|
updateEditorSync(editor, () => {
|
|
990
988
|
const selection = $getSelection() || getLastSelection(editor);
|
|
991
989
|
const badDOMTargets = new Map();
|
|
992
|
-
const rootElement = editor.getRootElement();
|
|
993
990
|
// We use the current editor state, as that reflects what is
|
|
994
991
|
// actually "on screen".
|
|
995
992
|
const currentEditorState = editor._editorState;
|
|
@@ -1000,7 +997,7 @@ function flushMutations(editor, mutations, observer) {
|
|
|
1000
997
|
const mutation = mutations[i];
|
|
1001
998
|
const type = mutation.type;
|
|
1002
999
|
const targetDOM = mutation.target;
|
|
1003
|
-
const pair = $getNearestManagedNodePairFromDOMNode(targetDOM, editor, currentEditorState
|
|
1000
|
+
const pair = $getNearestManagedNodePairFromDOMNode(targetDOM, editor, currentEditorState);
|
|
1004
1001
|
if (!pair) {
|
|
1005
1002
|
continue;
|
|
1006
1003
|
}
|
|
@@ -2302,6 +2299,15 @@ function $createNode(key, slot) {
|
|
|
2302
2299
|
dom.setAttribute('data-lexical-text', 'true');
|
|
2303
2300
|
} else if ($isDecoratorNode(node)) {
|
|
2304
2301
|
dom.setAttribute('data-lexical-decorator', 'true');
|
|
2302
|
+
// DecoratorNode DOM is selection-captured: window selection inside
|
|
2303
|
+
// a decorator subtree (e.g. an embedded input) is owned by the
|
|
2304
|
+
// decorator, not by Lexical's caret management. Marking it via
|
|
2305
|
+
// setDOMUnmanaged unifies the decorator case with extension-owned
|
|
2306
|
+
// unmanaged subtrees so callers only need isDOMCapturingSelection /
|
|
2307
|
+
// isDOMUnmanaged.
|
|
2308
|
+
setDOMUnmanaged(dom, {
|
|
2309
|
+
captureSelection: true
|
|
2310
|
+
});
|
|
2305
2311
|
}
|
|
2306
2312
|
if ($isElementNode(node)) {
|
|
2307
2313
|
const indent = node.__indent;
|
|
@@ -3806,7 +3812,7 @@ function onPointerDown(event, editor) {
|
|
|
3806
3812
|
updateEditorSync(editor, () => {
|
|
3807
3813
|
// Drag & drop should not recompute selection until mouse up; otherwise the initially
|
|
3808
3814
|
// selected content is lost.
|
|
3809
|
-
if (
|
|
3815
|
+
if (!isDOMCapturingSelection(target, editor)) {
|
|
3810
3816
|
isSelectionChangeFromMouseDown = true;
|
|
3811
3817
|
}
|
|
3812
3818
|
});
|
|
@@ -4211,10 +4217,10 @@ function onInput(event, editor) {
|
|
|
4211
4217
|
unprocessedBeforeInputData = null;
|
|
4212
4218
|
}
|
|
4213
4219
|
function $handleInput(event) {
|
|
4214
|
-
|
|
4220
|
+
const editor = getActiveEditor();
|
|
4221
|
+
if (isHTMLElement(event.target) && isDOMCapturingSelection(event.target, editor)) {
|
|
4215
4222
|
return true;
|
|
4216
4223
|
}
|
|
4217
|
-
const editor = getActiveEditor();
|
|
4218
4224
|
const selection = $getSelection();
|
|
4219
4225
|
const data = event.data;
|
|
4220
4226
|
const targetRange = getTargetRange(event);
|
|
@@ -6198,101 +6204,6 @@ function setDOMStyleFromCSS(domStyle, cssText, prevCSSText = '') {
|
|
|
6198
6204
|
}
|
|
6199
6205
|
}
|
|
6200
6206
|
|
|
6201
|
-
/**
|
|
6202
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
6203
|
-
*
|
|
6204
|
-
* This source code is licensed under the MIT license found in the
|
|
6205
|
-
* LICENSE file in the root directory of this source tree.
|
|
6206
|
-
*
|
|
6207
|
-
*/
|
|
6208
|
-
|
|
6209
|
-
/** @noInheritDoc */
|
|
6210
|
-
class LineBreakNode extends LexicalNode {
|
|
6211
|
-
/** @internal */
|
|
6212
|
-
|
|
6213
|
-
static getType() {
|
|
6214
|
-
return 'linebreak';
|
|
6215
|
-
}
|
|
6216
|
-
static clone(node) {
|
|
6217
|
-
return new LineBreakNode(node.__key);
|
|
6218
|
-
}
|
|
6219
|
-
constructor(key) {
|
|
6220
|
-
super(key);
|
|
6221
|
-
}
|
|
6222
|
-
getTextContent() {
|
|
6223
|
-
return '\n';
|
|
6224
|
-
}
|
|
6225
|
-
createDOM() {
|
|
6226
|
-
return document.createElement('br');
|
|
6227
|
-
}
|
|
6228
|
-
updateDOM() {
|
|
6229
|
-
return false;
|
|
6230
|
-
}
|
|
6231
|
-
isInline() {
|
|
6232
|
-
return true;
|
|
6233
|
-
}
|
|
6234
|
-
static importDOM() {
|
|
6235
|
-
return {
|
|
6236
|
-
br: node => {
|
|
6237
|
-
if (isOnlyChildInBlockNode(node) || isLastChildInBlockNode(node)) {
|
|
6238
|
-
return null;
|
|
6239
|
-
}
|
|
6240
|
-
return {
|
|
6241
|
-
conversion: $convertLineBreakElement,
|
|
6242
|
-
priority: 0
|
|
6243
|
-
};
|
|
6244
|
-
}
|
|
6245
|
-
};
|
|
6246
|
-
}
|
|
6247
|
-
static importJSON(serializedLineBreakNode) {
|
|
6248
|
-
return $createLineBreakNode().updateFromJSON(serializedLineBreakNode);
|
|
6249
|
-
}
|
|
6250
|
-
}
|
|
6251
|
-
function $convertLineBreakElement(node) {
|
|
6252
|
-
return {
|
|
6253
|
-
node: $createLineBreakNode()
|
|
6254
|
-
};
|
|
6255
|
-
}
|
|
6256
|
-
function $createLineBreakNode() {
|
|
6257
|
-
return $applyNodeReplacement(new LineBreakNode());
|
|
6258
|
-
}
|
|
6259
|
-
function $isLineBreakNode(node) {
|
|
6260
|
-
return node instanceof LineBreakNode;
|
|
6261
|
-
}
|
|
6262
|
-
function isOnlyChildInBlockNode(node) {
|
|
6263
|
-
const parentElement = node.parentElement;
|
|
6264
|
-
if (parentElement !== null && isBlockDomNode(parentElement)) {
|
|
6265
|
-
const firstChild = parentElement.firstChild;
|
|
6266
|
-
if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) {
|
|
6267
|
-
const lastChild = parentElement.lastChild;
|
|
6268
|
-
if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) {
|
|
6269
|
-
return true;
|
|
6270
|
-
}
|
|
6271
|
-
}
|
|
6272
|
-
}
|
|
6273
|
-
return false;
|
|
6274
|
-
}
|
|
6275
|
-
function isLastChildInBlockNode(node) {
|
|
6276
|
-
const parentElement = node.parentElement;
|
|
6277
|
-
if (parentElement !== null && isBlockDomNode(parentElement)) {
|
|
6278
|
-
// check if node is first child, because only child dont count
|
|
6279
|
-
const firstChild = parentElement.firstChild;
|
|
6280
|
-
if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) {
|
|
6281
|
-
return false;
|
|
6282
|
-
}
|
|
6283
|
-
|
|
6284
|
-
// check if its last child
|
|
6285
|
-
const lastChild = parentElement.lastChild;
|
|
6286
|
-
if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) {
|
|
6287
|
-
return true;
|
|
6288
|
-
}
|
|
6289
|
-
}
|
|
6290
|
-
return false;
|
|
6291
|
-
}
|
|
6292
|
-
function isWhitespaceDomTextNode(node) {
|
|
6293
|
-
return isDOMTextNode(node) && /^( |\t|\r?\n)+$/.test(node.textContent || '');
|
|
6294
|
-
}
|
|
6295
|
-
|
|
6296
6207
|
function getElementOuterTag(node, format) {
|
|
6297
6208
|
if (format & IS_CODE) {
|
|
6298
6209
|
return 'code';
|
|
@@ -7268,21 +7179,8 @@ function $convertTextDOMNode(domNode) {
|
|
|
7268
7179
|
let textContent = domNode_.textContent || '';
|
|
7269
7180
|
// No collapse and preserve segment break for pre, pre-wrap and pre-line
|
|
7270
7181
|
if (findParentPreDOMNode(domNode_) !== null) {
|
|
7271
|
-
const parts = textContent.split(/(\r?\n|\t)/);
|
|
7272
|
-
const nodes = [];
|
|
7273
|
-
const length = parts.length;
|
|
7274
|
-
for (let i = 0; i < length; i++) {
|
|
7275
|
-
const part = parts[i];
|
|
7276
|
-
if (part === '\n' || part === '\r\n') {
|
|
7277
|
-
nodes.push($createLineBreakNode());
|
|
7278
|
-
} else if (part === '\t') {
|
|
7279
|
-
nodes.push($createTabNode());
|
|
7280
|
-
} else if (part !== '') {
|
|
7281
|
-
nodes.push($createTextNode(part));
|
|
7282
|
-
}
|
|
7283
|
-
}
|
|
7284
7182
|
return {
|
|
7285
|
-
node:
|
|
7183
|
+
node: $generateNodesFromRawText(textContent)
|
|
7286
7184
|
};
|
|
7287
7185
|
}
|
|
7288
7186
|
textContent = textContent.replace(/\r/g, '').replace(/[ \t\n]+/g, ' ');
|
|
@@ -9221,7 +9119,7 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
|
9221
9119
|
moveSelectionToEnd = true;
|
|
9222
9120
|
resolvedOffset = childNodesLength - 1;
|
|
9223
9121
|
}
|
|
9224
|
-
if (getNodeKeyFromDOMNode(dom, editor) === undefined && dom
|
|
9122
|
+
if (getNodeKeyFromDOMNode(dom, editor) === undefined && !isDOMCapturingSelection(dom, editor)) {
|
|
9225
9123
|
// The DOM caret is sitting on a node that has no Lexical key
|
|
9226
9124
|
// (e.g. <col> inside an unmanaged <colgroup>, or any unmanaged
|
|
9227
9125
|
// scaffolding around a DOMSlot — wrap elements, contenteditable=false
|
|
@@ -9231,14 +9129,14 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
|
9231
9129
|
// selection dirty so the reconciler writes a valid DOM caret back
|
|
9232
9130
|
// at the resolved Lexical position.
|
|
9233
9131
|
//
|
|
9234
|
-
//
|
|
9235
|
-
//
|
|
9236
|
-
//
|
|
9237
|
-
//
|
|
9238
|
-
// -
|
|
9239
|
-
//
|
|
9240
|
-
//
|
|
9241
|
-
//
|
|
9132
|
+
// Exclusions split across the two guard clauses:
|
|
9133
|
+
// - The first clause (`key !== undefined`) covers any DOM node
|
|
9134
|
+
// with a `__lexicalKey_*` attribute — Lexical-managed elements
|
|
9135
|
+
// and the editor root (stashed in `resetEditor`).
|
|
9136
|
+
// - `isDOMCapturingSelection` covers DecoratorNode subtrees (which
|
|
9137
|
+
// own their own DOM) and subtrees marked via
|
|
9138
|
+
// `setDOMUnmanaged(dom, {captureSelection: true})` —
|
|
9139
|
+
// extension-owned widgets that keep a native caret.
|
|
9242
9140
|
//
|
|
9243
9141
|
// Void elements that ARE Lexical nodes (LineBreakNode <br>,
|
|
9244
9142
|
// empty decorator containers, etc.) have keys, so this check
|
|
@@ -10159,6 +10057,17 @@ function getActiveEditorState() {
|
|
|
10159
10057
|
}
|
|
10160
10058
|
return activeEditorState;
|
|
10161
10059
|
}
|
|
10060
|
+
|
|
10061
|
+
/** @internal */
|
|
10062
|
+
function $assumeActiveEditor(editor) {
|
|
10063
|
+
// Throw if called outside of an update
|
|
10064
|
+
if (getActiveEditorState() !== null && activeEditor === null) {
|
|
10065
|
+
activeEditor = editor;
|
|
10066
|
+
}
|
|
10067
|
+
if (!(activeEditor === editor)) {
|
|
10068
|
+
formatDevErrorMessage(`The given editor argument does not match $getEditor() in this context. Use editor.getEditorState().read(..., {editor}) if this cross-editor call is intentional.`);
|
|
10069
|
+
}
|
|
10070
|
+
}
|
|
10162
10071
|
function getActiveEditor() {
|
|
10163
10072
|
if (activeEditor === null) {
|
|
10164
10073
|
{
|
|
@@ -11774,6 +11683,119 @@ class ArtificialNode__DO_NOT_USE extends ElementNode {
|
|
|
11774
11683
|
}
|
|
11775
11684
|
}
|
|
11776
11685
|
|
|
11686
|
+
/**
|
|
11687
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
11688
|
+
*
|
|
11689
|
+
* This source code is licensed under the MIT license found in the
|
|
11690
|
+
* LICENSE file in the root directory of this source tree.
|
|
11691
|
+
*
|
|
11692
|
+
*/
|
|
11693
|
+
|
|
11694
|
+
/** @noInheritDoc */
|
|
11695
|
+
class LineBreakNode extends LexicalNode {
|
|
11696
|
+
/** @internal */
|
|
11697
|
+
|
|
11698
|
+
static getType() {
|
|
11699
|
+
return 'linebreak';
|
|
11700
|
+
}
|
|
11701
|
+
static clone(node) {
|
|
11702
|
+
return new LineBreakNode(node.__key);
|
|
11703
|
+
}
|
|
11704
|
+
constructor(key) {
|
|
11705
|
+
super(key);
|
|
11706
|
+
}
|
|
11707
|
+
getTextContent() {
|
|
11708
|
+
return '\n';
|
|
11709
|
+
}
|
|
11710
|
+
createDOM() {
|
|
11711
|
+
return document.createElement('br');
|
|
11712
|
+
}
|
|
11713
|
+
updateDOM() {
|
|
11714
|
+
return false;
|
|
11715
|
+
}
|
|
11716
|
+
isInline() {
|
|
11717
|
+
return true;
|
|
11718
|
+
}
|
|
11719
|
+
static importDOM() {
|
|
11720
|
+
return {
|
|
11721
|
+
br: node => {
|
|
11722
|
+
if (isOnlyChildInBlockNode(node) || isLastChildInBlockNode(node)) {
|
|
11723
|
+
return null;
|
|
11724
|
+
}
|
|
11725
|
+
return {
|
|
11726
|
+
conversion: $convertLineBreakElement,
|
|
11727
|
+
priority: 0
|
|
11728
|
+
};
|
|
11729
|
+
}
|
|
11730
|
+
};
|
|
11731
|
+
}
|
|
11732
|
+
static importJSON(serializedLineBreakNode) {
|
|
11733
|
+
return $createLineBreakNode().updateFromJSON(serializedLineBreakNode);
|
|
11734
|
+
}
|
|
11735
|
+
}
|
|
11736
|
+
function $convertLineBreakElement(node) {
|
|
11737
|
+
return {
|
|
11738
|
+
node: $createLineBreakNode()
|
|
11739
|
+
};
|
|
11740
|
+
}
|
|
11741
|
+
function $createLineBreakNode() {
|
|
11742
|
+
return $applyNodeReplacement(new LineBreakNode());
|
|
11743
|
+
}
|
|
11744
|
+
function $isLineBreakNode(node) {
|
|
11745
|
+
return node instanceof LineBreakNode;
|
|
11746
|
+
}
|
|
11747
|
+
|
|
11748
|
+
/**
|
|
11749
|
+
* True when `node` is the sole non-whitespace child of a block DOM
|
|
11750
|
+
* element. Used by the LineBreak importer to drop stray `<br>` elements
|
|
11751
|
+
* that the legacy `$generateNodesFromDOM` also skipped (matches the
|
|
11752
|
+
* behavior of `LineBreakNode.importDOM`).
|
|
11753
|
+
*
|
|
11754
|
+
* @experimental
|
|
11755
|
+
*/
|
|
11756
|
+
function isOnlyChildInBlockNode(node) {
|
|
11757
|
+
const parentElement = node.parentElement;
|
|
11758
|
+
if (parentElement !== null && isBlockDomNode(parentElement)) {
|
|
11759
|
+
const firstChild = parentElement.firstChild;
|
|
11760
|
+
if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) {
|
|
11761
|
+
const lastChild = parentElement.lastChild;
|
|
11762
|
+
if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) {
|
|
11763
|
+
return true;
|
|
11764
|
+
}
|
|
11765
|
+
}
|
|
11766
|
+
}
|
|
11767
|
+
return false;
|
|
11768
|
+
}
|
|
11769
|
+
|
|
11770
|
+
/**
|
|
11771
|
+
* True when `node` is the trailing non-whitespace child of a block DOM
|
|
11772
|
+
* element (excluding the only-child case). Used by the LineBreak
|
|
11773
|
+
* importer to drop trailing `<br>` elements like the Apple-interchange
|
|
11774
|
+
* clipboard artifact (matches `LineBreakNode.importDOM`).
|
|
11775
|
+
*
|
|
11776
|
+
* @experimental
|
|
11777
|
+
*/
|
|
11778
|
+
function isLastChildInBlockNode(node) {
|
|
11779
|
+
const parentElement = node.parentElement;
|
|
11780
|
+
if (parentElement !== null && isBlockDomNode(parentElement)) {
|
|
11781
|
+
// check if node is first child, because only child dont count
|
|
11782
|
+
const firstChild = parentElement.firstChild;
|
|
11783
|
+
if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) {
|
|
11784
|
+
return false;
|
|
11785
|
+
}
|
|
11786
|
+
|
|
11787
|
+
// check if its last child
|
|
11788
|
+
const lastChild = parentElement.lastChild;
|
|
11789
|
+
if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) {
|
|
11790
|
+
return true;
|
|
11791
|
+
}
|
|
11792
|
+
}
|
|
11793
|
+
return false;
|
|
11794
|
+
}
|
|
11795
|
+
function isWhitespaceDomTextNode(node) {
|
|
11796
|
+
return isDOMTextNode(node) && /^( |\t|\r?\n)+$/.test(node.textContent || '');
|
|
11797
|
+
}
|
|
11798
|
+
|
|
11777
11799
|
/**
|
|
11778
11800
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
11779
11801
|
*
|
|
@@ -12069,10 +12091,18 @@ function resetEditor(editor, prevRootElement, nextRootElement, pendingEditorStat
|
|
|
12069
12091
|
// Remove all the DOM nodes from the root element
|
|
12070
12092
|
if (prevRootElement !== null) {
|
|
12071
12093
|
prevRootElement.textContent = '';
|
|
12094
|
+
clearNodeKeyOnDOMNode(prevRootElement, editor);
|
|
12072
12095
|
}
|
|
12073
12096
|
if (nextRootElement !== null) {
|
|
12074
12097
|
nextRootElement.textContent = '';
|
|
12075
12098
|
keyNodeMap.set('root', nextRootElement);
|
|
12099
|
+
// Stash __lexicalKey_${editor._key} = 'root' on the root element so it
|
|
12100
|
+
// participates in the unified key lookup (selection resolution in
|
|
12101
|
+
// $internalResolveSelectionPoint, mutation handling in
|
|
12102
|
+
// $getNearestManagedNodePairFromDOMNode, $getNodeFromDOM, and
|
|
12103
|
+
// $getNearestNodeFromDOMNode) instead of requiring a dedicated
|
|
12104
|
+
// editor.getRootElement() carveout at each call site.
|
|
12105
|
+
setNodeKeyOnDOMNode(nextRootElement, editor, 'root');
|
|
12076
12106
|
}
|
|
12077
12107
|
}
|
|
12078
12108
|
function initializeConversionCache(nodes, additionalConversions) {
|
|
@@ -12214,9 +12244,6 @@ function createEditor(editorConfig) {
|
|
|
12214
12244
|
console.warn(`${name} must implement static "${method}" method`);
|
|
12215
12245
|
}
|
|
12216
12246
|
});
|
|
12217
|
-
if (!hasOwnStaticMethod(klass, 'importDOM') && hasOwnExportDOM(klass)) {
|
|
12218
|
-
console.warn(`${name} should implement "importDOM" if using a custom "exportDOM" method to ensure HTML serialization (important for copy & paste) works as expected`);
|
|
12219
|
-
}
|
|
12220
12247
|
if (!hasOwnStaticMethod(klass, 'importJSON')) {
|
|
12221
12248
|
console.warn(`${name} should implement "importJSON" method to ensure JSON and default HTML serialization works as expected`);
|
|
12222
12249
|
}
|
|
@@ -12984,9 +13011,6 @@ const scheduleMicroTask = typeof queueMicrotask === 'function' ? queueMicrotask
|
|
|
12984
13011
|
// No window prefix intended (#1400)
|
|
12985
13012
|
Promise.resolve().then(fn);
|
|
12986
13013
|
};
|
|
12987
|
-
function $isSelectionCapturedInDecorator(node) {
|
|
12988
|
-
return $isDecoratorNode($getNearestNodeFromDOMNode(node));
|
|
12989
|
-
}
|
|
12990
13014
|
function isSelectionCapturedInDecoratorInput(anchorDOM) {
|
|
12991
13015
|
const activeElement = document.activeElement;
|
|
12992
13016
|
if (!isHTMLElement(activeElement)) {
|
|
@@ -13312,6 +13336,10 @@ function setNodeKeyOnDOMNode(dom, editor, key) {
|
|
|
13312
13336
|
const prop = `__lexicalKey_${editor._key}`;
|
|
13313
13337
|
dom[prop] = key;
|
|
13314
13338
|
}
|
|
13339
|
+
function clearNodeKeyOnDOMNode(dom, editor) {
|
|
13340
|
+
const prop = `__lexicalKey_${editor._key}`;
|
|
13341
|
+
delete dom[prop];
|
|
13342
|
+
}
|
|
13315
13343
|
function getNodeKeyFromDOMNode(dom, editor) {
|
|
13316
13344
|
const prop = `__lexicalKey_${editor._key}`;
|
|
13317
13345
|
return dom[prop];
|
|
@@ -13398,10 +13426,6 @@ function $getNodeFromDOM(dom) {
|
|
|
13398
13426
|
const editor = getActiveEditor();
|
|
13399
13427
|
const nodeKey = getNodeKeyFromDOMTree(dom, editor);
|
|
13400
13428
|
if (nodeKey === null) {
|
|
13401
|
-
const rootElement = editor.getRootElement();
|
|
13402
|
-
if (dom === rootElement) {
|
|
13403
|
-
return $getNodeByKey('root');
|
|
13404
|
-
}
|
|
13405
13429
|
return null;
|
|
13406
13430
|
}
|
|
13407
13431
|
return $getNodeByKey(nodeKey);
|
|
@@ -14587,16 +14611,29 @@ function $setFormatFromDOM(node, domNode) {
|
|
|
14587
14611
|
return alignment && alignment in ELEMENT_TYPE_TO_FORMAT ? node.setFormat(alignment) : node;
|
|
14588
14612
|
}
|
|
14589
14613
|
|
|
14614
|
+
/**
|
|
14615
|
+
* Options accepted by {@link setDOMUnmanaged}.
|
|
14616
|
+
*
|
|
14617
|
+
* @experimental
|
|
14618
|
+
*/
|
|
14619
|
+
|
|
14590
14620
|
/**
|
|
14591
14621
|
* Mark this DOM element as unmanaged by lexical's mutation observer (like
|
|
14592
14622
|
* decorator nodes are). Extensions that inject non-lexical decoration
|
|
14593
14623
|
* elements into a node's DOM should mark them so the mutation observer
|
|
14594
14624
|
* doesn't evict them as "unknown DOM children" during cleanup.
|
|
14595
14625
|
*
|
|
14626
|
+
* Pass `{captureSelection: true}` to additionally treat the subtree's
|
|
14627
|
+
* window selection as decorator-like, so resolution does not force-sync
|
|
14628
|
+
* the caret out of unmanaged DOM (see {@link isDOMCapturingSelection}).
|
|
14629
|
+
*
|
|
14596
14630
|
* @experimental
|
|
14597
14631
|
*/
|
|
14598
|
-
function setDOMUnmanaged(elementDom) {
|
|
14632
|
+
function setDOMUnmanaged(elementDom, options) {
|
|
14599
14633
|
elementDom.__lexicalUnmanaged = true;
|
|
14634
|
+
if (options && options.captureSelection !== undefined) {
|
|
14635
|
+
elementDom.__lexicalCapturedSelection = options.captureSelection;
|
|
14636
|
+
}
|
|
14600
14637
|
}
|
|
14601
14638
|
|
|
14602
14639
|
/**
|
|
@@ -14608,6 +14645,37 @@ function isDOMUnmanaged(elementDom) {
|
|
|
14608
14645
|
return elementDom.__lexicalUnmanaged === true;
|
|
14609
14646
|
}
|
|
14610
14647
|
|
|
14648
|
+
/**
|
|
14649
|
+
* True if the DOM node sits inside a subtree marked with
|
|
14650
|
+
* `{captureSelection: true}` via {@link setDOMUnmanaged}. Walks ancestors
|
|
14651
|
+
* so any descendant of a marked subtree (e.g. an `<input>` inside a marked
|
|
14652
|
+
* `<div>`) reports as captured too.
|
|
14653
|
+
*
|
|
14654
|
+
* The walk aborts at the first DOM node that corresponds to a Lexical
|
|
14655
|
+
* node in `editor` — that boundary is the implicit owner of the subtree's
|
|
14656
|
+
* selection, so a captureSelection marker above it (in non-Lexical
|
|
14657
|
+
* scaffolding around the editor) does not leak in.
|
|
14658
|
+
*
|
|
14659
|
+
* DecoratorNode DOM is marked with `setDOMUnmanaged({captureSelection:
|
|
14660
|
+
* true})` by the reconciler, so decorator subtrees also report as
|
|
14661
|
+
* captured here.
|
|
14662
|
+
*
|
|
14663
|
+
* @experimental
|
|
14664
|
+
*/
|
|
14665
|
+
function isDOMCapturingSelection(elementDom, editor) {
|
|
14666
|
+
let dom = elementDom;
|
|
14667
|
+
while (dom != null) {
|
|
14668
|
+
if (dom.__lexicalCapturedSelection === true) {
|
|
14669
|
+
return true;
|
|
14670
|
+
}
|
|
14671
|
+
if (getNodeKeyFromDOMNode(dom, editor) !== undefined) {
|
|
14672
|
+
return false;
|
|
14673
|
+
}
|
|
14674
|
+
dom = getParentElement(dom);
|
|
14675
|
+
}
|
|
14676
|
+
return false;
|
|
14677
|
+
}
|
|
14678
|
+
|
|
14611
14679
|
/**
|
|
14612
14680
|
* @internal
|
|
14613
14681
|
*
|
|
@@ -14624,13 +14692,6 @@ function hasOwnStaticMethod(klass, k) {
|
|
|
14624
14692
|
return hasOwn(klass, k) && klass[k] !== LexicalNode[k];
|
|
14625
14693
|
}
|
|
14626
14694
|
|
|
14627
|
-
/**
|
|
14628
|
-
* @internal
|
|
14629
|
-
*/
|
|
14630
|
-
function hasOwnExportDOM(klass) {
|
|
14631
|
-
return hasOwn(klass.prototype, 'exportDOM');
|
|
14632
|
-
}
|
|
14633
|
-
|
|
14634
14695
|
/** @internal */
|
|
14635
14696
|
function isAbstractNodeClass(klass) {
|
|
14636
14697
|
if (!(klass === LexicalNode || klass.prototype instanceof LexicalNode)) {
|
|
@@ -16391,6 +16452,7 @@ function mergeRegister(...func) {
|
|
|
16391
16452
|
|
|
16392
16453
|
exports.$addUpdateTag = $addUpdateTag;
|
|
16393
16454
|
exports.$applyNodeReplacement = $applyNodeReplacement;
|
|
16455
|
+
exports.$assumeActiveEditor = $assumeActiveEditor;
|
|
16394
16456
|
exports.$caretFromPoint = $caretFromPoint;
|
|
16395
16457
|
exports.$caretRangeFromSelection = $caretRangeFromSelection;
|
|
16396
16458
|
exports.$cloneWithProperties = $cloneWithProperties;
|
|
@@ -16615,6 +16677,7 @@ exports.getTextDirection = getTextDirection;
|
|
|
16615
16677
|
exports.getTransformSetFromKlass = getTransformSetFromKlass;
|
|
16616
16678
|
exports.isBlockDomNode = isBlockDomNode;
|
|
16617
16679
|
exports.isCurrentlyReadOnlyMode = isCurrentlyReadOnlyMode;
|
|
16680
|
+
exports.isDOMCapturingSelection = isDOMCapturingSelection;
|
|
16618
16681
|
exports.isDOMDocumentNode = isDOMDocumentNode;
|
|
16619
16682
|
exports.isDOMNode = isDOMNode;
|
|
16620
16683
|
exports.isDOMTextNode = isDOMTextNode;
|
|
@@ -16626,8 +16689,10 @@ exports.isHTMLElement = isHTMLElement;
|
|
|
16626
16689
|
exports.isHTMLTableCellElement = isHTMLTableCellElement;
|
|
16627
16690
|
exports.isHTMLTableRowElement = isHTMLTableRowElement;
|
|
16628
16691
|
exports.isInlineDomNode = isInlineDomNode;
|
|
16692
|
+
exports.isLastChildInBlockNode = isLastChildInBlockNode;
|
|
16629
16693
|
exports.isLexicalEditor = isLexicalEditor;
|
|
16630
16694
|
exports.isModifierMatch = isModifierMatch;
|
|
16695
|
+
exports.isOnlyChildInBlockNode = isOnlyChildInBlockNode;
|
|
16631
16696
|
exports.isSelectionCapturedInDecoratorInput = isSelectionCapturedInDecoratorInput;
|
|
16632
16697
|
exports.isSelectionWithinEditor = isSelectionWithinEditor;
|
|
16633
16698
|
exports.makeStepwiseIterator = makeStepwiseIterator;
|