Skip to content

Commit

Permalink
$insertNodes: Selection-agnostic node insertion with Grid/Node select…
Browse files Browse the repository at this point in the history
…ion support (#2638)
  • Loading branch information
zurfyx authored and thegreatercurve committed Nov 25, 2022
1 parent 47adc7e commit 6b1c087
Show file tree
Hide file tree
Showing 20 changed files with 622 additions and 59 deletions.
6 changes: 1 addition & 5 deletions examples/decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,7 @@ function VideoPlugin(): ReactNode {
(payload) => {
// Adding custom command that will be handled by this plugin
editor.update(() => {
const selection = $getSelection();
if (selection !== null) {
const url: string = payload;
selection.insertNodes([$createVideoNode(url)]);
}
$insertNodes([$createVideoNode(url)]);
});

// Returning true indicates that command is handled and no further propagation is required
Expand Down
3 changes: 1 addition & 2 deletions packages/lexical-html/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,5 @@ const nodes = $generateNodesFromDOM(editor, dom);
const editor = createEditor({ ...config, nodes });

// Or insert them at a selection.
const selection = $getSelection();
selection.insertNodes(nodes);
$insertNodes(nodes);
```
124 changes: 124 additions & 0 deletions packages/lexical-playground/__tests__/e2e/Images.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
insertUrlImage,
IS_WINDOWS,
SAMPLE_IMAGE_URL,
SAMPLE_LANDSCAPE_IMAGE_URL,
selectorBoundingBox,
test,
waitForSelector,
Expand Down Expand Up @@ -606,4 +607,127 @@ test.describe('Images', () => {
expect(lexicalSelection.anchor).toBeTruthy();
expect(lexicalSelection.focus).toBeTruthy();
});

test('Node selection: can select multiple image nodes and replace them with a new image', async ({
page,
isPlainText,
}) => {
test.skip(isPlainText);

await focusEditor(page);

await page.keyboard.type('text1');
await page.keyboard.press('Enter');
await insertSampleImage(page);
await page.keyboard.press('Enter');
await page.keyboard.type('text2');
await page.keyboard.press('Enter');
await insertSampleImage(page, 'alt');
await page.keyboard.press('Enter');
await page.keyboard.type('text3');

await assertHTML(
page,
html`
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">text1</span>
</p>
<p class="PlaygroundEditorTheme__paragraph">
<span
class="editor-image"
contenteditable="false"
data-lexical-decorator="true">
<div draggable="false">
<img
alt="Yellow flower in tilt shift lens"
draggable="false"
src="${SAMPLE_IMAGE_URL}"
style="height: inherit; max-width: 500px; width: inherit" />
</div>
</span>
<br />
</p>
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">text2</span>
</p>
<p class="PlaygroundEditorTheme__paragraph">
<span
class="editor-image"
contenteditable="false"
data-lexical-decorator="true">
<div draggable="false">
<img
alt="Daylight fir trees forest glacier green high ice landscape"
draggable="false"
src="${SAMPLE_LANDSCAPE_IMAGE_URL}"
style="height: inherit; max-width: 500px; width: inherit" />
</div>
</span>
<br />
</p>
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">text3</span>
</p>
`,
);

await click(
page,
'.editor-image img[alt="Yellow flower in tilt shift lens"]',
);
await page.keyboard.down('Shift');
await click(
page,
'.editor-image img[alt="Daylight fir trees forest glacier green high ice landscape"]',
);
await page.keyboard.up('Shift');

await insertSampleImage(page);
await page.keyboard.type(' <- it works!');

await assertHTML(
page,
html`
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">text1</span>
</p>
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">text2</span>
</p>
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span
class="editor-image"
contenteditable="false"
data-lexical-decorator="true">
<div draggable="false">
<img
alt="Yellow flower in tilt shift lens"
draggable="false"
src="${SAMPLE_IMAGE_URL}"
style="height: inherit; max-width: 500px; width: inherit" />
</div>
</span>
<span data-lexical-text="true">&lt;- it works!</span>
</p>
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">text3</span>
</p>
`,
);
});
});
148 changes: 148 additions & 0 deletions packages/lexical-playground/__tests__/e2e/Tables.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import {
html,
initialize,
insertHorizontalRule,
insertSampleImage,
insertTable,
IS_COLLAB,
pasteFromClipboard,
SAMPLE_IMAGE_URL,
selectCellsFromTableCords,
selectFromAdditionalStylesDropdown,
test,
Expand Down Expand Up @@ -2019,4 +2021,150 @@ test.describe('Tables', () => {
{ignoreClasses: true},
);
});

test('Grid selection: can select multiple cells and insert an image', async ({
page,
isPlainText,
}) => {
test.skip(isPlainText);

await focusEditor(page);

await insertTable(page);

await click(page, '.PlaygroundEditorTheme__tableCell');
await page.keyboard.type('Hello');

await page.keyboard.down('Shift');
await page.keyboard.press('ArrowRight');
await page.keyboard.press('ArrowDown');
await page.keyboard.up('Shift');

await insertSampleImage(page);
await page.keyboard.type(' <- it works!');

await assertHTML(
page,
html`
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
<table class="PlaygroundEditorTheme__table">
<tr>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">Hello</span>
</p>
</th>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</th>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</th>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</th>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</th>
</tr>
<tr>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</th>
<td class="PlaygroundEditorTheme__tableCell">
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span
class="editor-image"
contenteditable="false"
data-lexical-decorator="true">
<div draggable="false">
<img
alt="Yellow flower in tilt shift lens"
draggable="false"
src="${SAMPLE_IMAGE_URL}"
style="height: inherit; max-width: 500px; width: inherit" />
</div>
</span>
<span data-lexical-text="true">&lt;- it works!</span>
</p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
</tr>
<tr>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</th>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
</tr>
<tr>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</th>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
</tr>
<tr>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</th>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
<td class="PlaygroundEditorTheme__tableCell">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</td>
</tr>
</table>
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
`,
);
});
});
12 changes: 11 additions & 1 deletion packages/lexical-playground/__tests__/utils/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export const SAMPLE_IMAGE_URL =
E2E_PORT === 3000
? '/src/images/yellow-flower.jpg'
: '/assets/yellow-flower.a2a7c7a2.jpg';
export const SAMPLE_LANDSCAPE_IMAGE_URL =
E2E_PORT === 3000
? '/src/images/landscape.jpg'
: '/assets/landscape.21352c66.jpg';

export async function initialize({
page,
Expand Down Expand Up @@ -481,9 +485,15 @@ export async function clearEditor(page) {
await page.keyboard.press('Backspace');
}

export async function insertSampleImage(page) {
export async function insertSampleImage(page, modifier) {
await selectFromInsertDropdown(page, '.image');
if (modifier === 'alt') {
await page.keyboard.down('Alt');
}
await click(page, 'button[data-test-id="image-modal-option-sample"]');
if (modifier === 'alt') {
await page.keyboard.up('Alt');
}
}

export async function insertUrlImage(page, url, altText) {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ export default function ComponentPickerMenuPlugin(): JSX.Element {
if (selection.isCollapsed()) {
$wrapLeafNodesInElements(selection, () => $createCodeNode());
} else {
// Will this ever happen?
const textContent = selection.getTextContent();
const codeNode = $createCodeNode();
selection.insertNodes([codeNode]);
Expand Down
17 changes: 9 additions & 8 deletions packages/lexical-playground/src/plugins/EquationsPlugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@
*
*/

import type {LexicalCommand} from 'lexical';

import 'katex/dist/katex.css';

import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import {$wrapNodeInElement} from '@lexical/utils';
import {
$getSelection,
$isRangeSelection,
$createParagraphNode,
$insertNodes,
$isRootOrShadowRoot,
COMMAND_PRIORITY_EDITOR,
createCommand,
LexicalCommand,
} from 'lexical';
import {useEffect} from 'react';

Expand Down Expand Up @@ -43,11 +44,11 @@ export default function EquationsPlugin(): JSX.Element | null {
INSERT_EQUATION_COMMAND,
(payload) => {
const {equation, inline} = payload;
const selection = $getSelection();
const equationNode = $createEquationNode(equation, inline);

if ($isRangeSelection(selection)) {
const equationNode = $createEquationNode(equation, inline);
selection.insertNodes([equationNode]);
$insertNodes([equationNode]);
if ($isRootOrShadowRoot(equationNode.getParentOrThrow())) {
$wrapNodeInElement(equationNode, $createParagraphNode).selectEnd();
}

return true;
Expand Down
Loading

0 comments on commit 6b1c087

Please sign in to comment.