mirror of
https://github.com/facebook/lexical.git
synced 2025-05-17 15:18:47 +08:00
[lexical] Bug Fix: Ignore input event from inside decorators (#7354)
This commit is contained in:
@ -20,9 +20,7 @@ test.describe('Events', () => {
|
||||
test.beforeEach(({isCollab, page}) => initialize({isCollab, page}));
|
||||
|
||||
test('Autocapitalization (MacOS specific)', async ({page, isPlainText}) => {
|
||||
if (LEGACY_EVENTS) {
|
||||
return;
|
||||
}
|
||||
test.skip(LEGACY_EVENTS);
|
||||
await focusEditor(page);
|
||||
await page.keyboard.type('i');
|
||||
await evaluate(page, () => {
|
||||
@ -103,9 +101,7 @@ test.describe('Events', () => {
|
||||
page,
|
||||
isPlainText,
|
||||
}) => {
|
||||
if (LEGACY_EVENTS) {
|
||||
return;
|
||||
}
|
||||
test.skip(LEGACY_EVENTS);
|
||||
await focusEditor(page);
|
||||
await page.keyboard.type(':)');
|
||||
await assertHTML(
|
||||
|
@ -0,0 +1,240 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
import {moveLeft} from '../keyboardShortcuts/index.mjs';
|
||||
import {
|
||||
assertHTML,
|
||||
click,
|
||||
focusEditor,
|
||||
html,
|
||||
initialize,
|
||||
keyDownCtrlOrMeta,
|
||||
keyUpCtrlOrMeta,
|
||||
LEGACY_EVENTS,
|
||||
selectFromInsertDropdown,
|
||||
test,
|
||||
withExclusiveClipboardAccess,
|
||||
} from '../utils/index.mjs';
|
||||
|
||||
test.describe('HTML CopyAndPaste', () => {
|
||||
test.beforeEach(({isCollab, page}) => initialize({isCollab, page}));
|
||||
|
||||
test('Copy + paste multi line html with extra newlines', async ({
|
||||
page,
|
||||
isPlainText,
|
||||
isCollab,
|
||||
}) => {
|
||||
test.skip(isPlainText || isCollab || LEGACY_EVENTS);
|
||||
|
||||
await focusEditor(page);
|
||||
await selectFromInsertDropdown(page, '.poll');
|
||||
await click(page, '.Modal__overlay[role=dialog] .Input__input');
|
||||
await page.keyboard.type('Question');
|
||||
await click(page, '.Modal__overlay[role=dialog] .DialogActions button');
|
||||
await click(page, '.PollNode__optionInput');
|
||||
await assertHTML(
|
||||
page,
|
||||
html`
|
||||
<p class="PlaygroundEditorTheme__paragraph">
|
||||
<span
|
||||
contenteditable="false"
|
||||
style="display: inline-block"
|
||||
data-lexical-decorator="true">
|
||||
<div class="PollNode__container">
|
||||
<div class="PollNode__inner">
|
||||
<h2 class="PollNode__heading">Question</h2>
|
||||
<div class="PollNode__optionContainer">
|
||||
<div class="PollNode__optionCheckboxWrapper">
|
||||
<input class="PollNode__optionCheckbox" type="checkbox" />
|
||||
</div>
|
||||
<div class="PollNode__optionInputWrapper">
|
||||
<div
|
||||
class="PollNode__optionInputVotes"
|
||||
style="width: 0%"></div>
|
||||
<span class="PollNode__optionInputVotesCount"></span>
|
||||
<input
|
||||
class="PollNode__optionInput"
|
||||
placeholder="Option 1"
|
||||
type="text"
|
||||
value="" />
|
||||
</div>
|
||||
<button
|
||||
class="PollNode__optionDelete PollNode__optionDeleteDisabled"
|
||||
disabled=""
|
||||
aria-label="Remove"></button>
|
||||
</div>
|
||||
<div class="PollNode__optionContainer">
|
||||
<div class="PollNode__optionCheckboxWrapper">
|
||||
<input class="PollNode__optionCheckbox" type="checkbox" />
|
||||
</div>
|
||||
<div class="PollNode__optionInputWrapper">
|
||||
<div
|
||||
class="PollNode__optionInputVotes"
|
||||
style="width: 0%"></div>
|
||||
<span class="PollNode__optionInputVotesCount"></span>
|
||||
<input
|
||||
class="PollNode__optionInput"
|
||||
placeholder="Option 2"
|
||||
type="text"
|
||||
value="" />
|
||||
</div>
|
||||
<button
|
||||
class="PollNode__optionDelete PollNode__optionDeleteDisabled"
|
||||
disabled=""
|
||||
aria-label="Remove"></button>
|
||||
</div>
|
||||
<div class="PollNode__footer">
|
||||
<button class="Button__root Button__small">Add Option</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<br />
|
||||
</p>
|
||||
`,
|
||||
);
|
||||
await page.keyboard.type('hello');
|
||||
await assertHTML(
|
||||
page,
|
||||
html`
|
||||
<p class="PlaygroundEditorTheme__paragraph">
|
||||
<span
|
||||
contenteditable="false"
|
||||
style="display: inline-block"
|
||||
data-lexical-decorator="true">
|
||||
<div class="PollNode__container">
|
||||
<div class="PollNode__inner">
|
||||
<h2 class="PollNode__heading">Question</h2>
|
||||
<div class="PollNode__optionContainer">
|
||||
<div class="PollNode__optionCheckboxWrapper">
|
||||
<input class="PollNode__optionCheckbox" type="checkbox" />
|
||||
</div>
|
||||
<div class="PollNode__optionInputWrapper">
|
||||
<div
|
||||
class="PollNode__optionInputVotes"
|
||||
style="width: 0%"></div>
|
||||
<span class="PollNode__optionInputVotesCount"></span>
|
||||
<input
|
||||
class="PollNode__optionInput"
|
||||
placeholder="Option 1"
|
||||
type="text"
|
||||
value="hello" />
|
||||
</div>
|
||||
<button
|
||||
class="PollNode__optionDelete PollNode__optionDeleteDisabled"
|
||||
disabled=""
|
||||
aria-label="Remove"></button>
|
||||
</div>
|
||||
<div class="PollNode__optionContainer">
|
||||
<div class="PollNode__optionCheckboxWrapper">
|
||||
<input class="PollNode__optionCheckbox" type="checkbox" />
|
||||
</div>
|
||||
<div class="PollNode__optionInputWrapper">
|
||||
<div
|
||||
class="PollNode__optionInputVotes"
|
||||
style="width: 0%"></div>
|
||||
<span class="PollNode__optionInputVotesCount"></span>
|
||||
<input
|
||||
class="PollNode__optionInput"
|
||||
placeholder="Option 2"
|
||||
type="text"
|
||||
value="" />
|
||||
</div>
|
||||
<button
|
||||
class="PollNode__optionDelete PollNode__optionDeleteDisabled"
|
||||
disabled=""
|
||||
aria-label="Remove"></button>
|
||||
</div>
|
||||
<div class="PollNode__footer">
|
||||
<button class="Button__root Button__small">Add Option</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<br />
|
||||
</p>
|
||||
`,
|
||||
);
|
||||
|
||||
await page.keyboard.down('Shift');
|
||||
await moveLeft(page, 4);
|
||||
await page.keyboard.up('Shift');
|
||||
await keyDownCtrlOrMeta(page);
|
||||
await withExclusiveClipboardAccess(async () => {
|
||||
// copy 'ello' once
|
||||
await page.keyboard.press('c');
|
||||
await keyUpCtrlOrMeta(page);
|
||||
await keyDownCtrlOrMeta(page);
|
||||
// paste it twice into the decorator's input
|
||||
await page.keyboard.press('v');
|
||||
await page.keyboard.press('v');
|
||||
});
|
||||
await keyUpCtrlOrMeta(page);
|
||||
await assertHTML(
|
||||
page,
|
||||
html`
|
||||
<p class="PlaygroundEditorTheme__paragraph">
|
||||
<span
|
||||
contenteditable="false"
|
||||
style="display: inline-block"
|
||||
data-lexical-decorator="true">
|
||||
<div class="PollNode__container">
|
||||
<div class="PollNode__inner">
|
||||
<h2 class="PollNode__heading">Question</h2>
|
||||
<div class="PollNode__optionContainer">
|
||||
<div class="PollNode__optionCheckboxWrapper">
|
||||
<input class="PollNode__optionCheckbox" type="checkbox" />
|
||||
</div>
|
||||
<div class="PollNode__optionInputWrapper">
|
||||
<div
|
||||
class="PollNode__optionInputVotes"
|
||||
style="width: 0%"></div>
|
||||
<span class="PollNode__optionInputVotesCount"></span>
|
||||
<input
|
||||
class="PollNode__optionInput"
|
||||
placeholder="Option 1"
|
||||
type="text"
|
||||
value="helloello" />
|
||||
</div>
|
||||
<button
|
||||
class="PollNode__optionDelete PollNode__optionDeleteDisabled"
|
||||
disabled=""
|
||||
aria-label="Remove"></button>
|
||||
</div>
|
||||
<div class="PollNode__optionContainer">
|
||||
<div class="PollNode__optionCheckboxWrapper">
|
||||
<input class="PollNode__optionCheckbox" type="checkbox" />
|
||||
</div>
|
||||
<div class="PollNode__optionInputWrapper">
|
||||
<div
|
||||
class="PollNode__optionInputVotes"
|
||||
style="width: 0%"></div>
|
||||
<span class="PollNode__optionInputVotesCount"></span>
|
||||
<input
|
||||
class="PollNode__optionInput"
|
||||
placeholder="Option 2"
|
||||
type="text"
|
||||
value="" />
|
||||
</div>
|
||||
<button
|
||||
class="PollNode__optionDelete PollNode__optionDeleteDisabled"
|
||||
disabled=""
|
||||
aria-label="Remove"></button>
|
||||
</div>
|
||||
<div class="PollNode__footer">
|
||||
<button class="Button__root Button__small">Add Option</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<br />
|
||||
</p>
|
||||
`,
|
||||
);
|
||||
});
|
||||
});
|
@ -896,6 +896,13 @@ function onInput(event: InputEvent, editor: LexicalEditor): void {
|
||||
updateEditorSync(
|
||||
editor,
|
||||
() => {
|
||||
if (
|
||||
isHTMLElement(event.target) &&
|
||||
$isSelectionCapturedInDecorator(event.target)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selection = $getSelection();
|
||||
const data = event.data;
|
||||
const targetRange = getTargetRange(event);
|
||||
|
Reference in New Issue
Block a user