Skip to content

Commit

Permalink
Various fixes in $wrapNodes (facebook#3234)
Browse files Browse the repository at this point in the history
  • Loading branch information
GermanJablo authored Dec 12, 2022
1 parent 5c8782f commit 0180f98
Show file tree
Hide file tree
Showing 14 changed files with 144 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import LexicalErrorBoundary from '@lexical/react/src/LexicalErrorBoundary';
import {HistoryPlugin} from '@lexical/react/src/LexicalHistoryPlugin';
import {RichTextPlugin} from '@lexical/react/src/LexicalRichTextPlugin';
import {$createQuoteNode} from '@lexical/rich-text/src';
import {$wrapNodes} from '@lexical/selection/src';
import {$setBlocksType_experimental} from '@lexical/selection/src';
import {
$createRangeSelection,
CAN_REDO_COMMAND,
Expand Down Expand Up @@ -145,7 +145,7 @@ describe('LexicalHistory tests', () => {
selection.focus.set(firstTextNode.getKey(), 3, 'text');

$setSelection(selection);
$wrapNodes(selection, () => $createQuoteNode());
$setBlocksType_experimental(selection, () => $createQuoteNode());
});
});

Expand Down
13 changes: 11 additions & 2 deletions packages/lexical-list/src/LexicalListItemNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,10 @@ export class ListItemNode extends ElementNode {
return this;
}

replace<N extends LexicalNode>(replaceWithNode: N): N {
replace<N extends LexicalNode>(
replaceWithNode: N,
includeChildren?: boolean,
): N {
if ($isListItemNode(replaceWithNode)) {
return super.replace(replaceWithNode);
}
Expand Down Expand Up @@ -178,6 +181,11 @@ export class ListItemNode extends ElementNode {
list.insertAfter(replaceWithNode);
replaceWithNode.insertAfter(newList);
}
if (includeChildren) {
this.getChildren().forEach((child: LexicalNode) => {
replaceWithNode.append(child);
});
}
this.remove();

if (childrenLength === 1) {
Expand Down Expand Up @@ -281,7 +289,8 @@ export class ListItemNode extends ElementNode {
listNode.remove();
listNodeParent.select();
} else {
listNode.replace(paragraph);
listNode.insertBefore(paragraph);
listNode.remove();
// If we have selection on the list item, we'll need to move it
// to the paragraph
const anchor = selection.anchor;
Expand Down
40 changes: 28 additions & 12 deletions packages/lexical-playground/__tests__/e2e/Composition.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -513,20 +513,36 @@ test.describe('Composition', () => {
await page.keyboard.imeSetComposition('もじあ', 3, 3);
await page.keyboard.insertText('もじあ');

await assertHTML(
page,
html`
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">Luke すし もじあSkywalker</span>
</p>
`,
);
if (browserName === 'webkit')
await assertHTML(
page,
html`
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">
Luke &nbsp;すし もじあSkywalker
</span>
</p>
`,
);

if (browserName === 'chromium')
await assertHTML(
page,
html`
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">Luke ​すし もじあSkywalker</span>
</p>
`,
);

await assertSelection(page, {
anchorOffset: 11,
anchorOffset: 12,
anchorPath: [0, 0, 0],
focusOffset: 11,
focusOffset: 12,
focusPath: [0, 0, 0],
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
useBasicTypeaheadTriggerMatch,
} from '@lexical/react/LexicalTypeaheadMenuPlugin';
import {$createHeadingNode, $createQuoteNode} from '@lexical/rich-text';
import {$wrapNodes} from '@lexical/selection';
import {$setBlocksType_experimental} from '@lexical/selection';
import {INSERT_TABLE_COMMAND} from '@lexical/table';
import {
$createParagraphNode,
Expand Down Expand Up @@ -173,7 +173,9 @@ export default function ComponentPickerMenuPlugin(): JSX.Element {
editor.update(() => {
const selection = $getSelection();
if ($isRangeSelection(selection)) {
$wrapNodes(selection, () => $createParagraphNode());
$setBlocksType_experimental(selection, () =>
$createParagraphNode(),
);
}
}),
}),
Expand All @@ -186,7 +188,7 @@ export default function ComponentPickerMenuPlugin(): JSX.Element {
editor.update(() => {
const selection = $getSelection();
if ($isRangeSelection(selection)) {
$wrapNodes(selection, () =>
$setBlocksType_experimental(selection, () =>
// @ts-ignore Correct types, but since they're dynamic TS doesn't like it.
$createHeadingNode(`h${n}`),
);
Expand Down Expand Up @@ -227,7 +229,7 @@ export default function ComponentPickerMenuPlugin(): JSX.Element {
editor.update(() => {
const selection = $getSelection();
if ($isRangeSelection(selection)) {
$wrapNodes(selection, () => $createQuoteNode());
$setBlocksType_experimental(selection, () => $createQuoteNode());
}
}),
}),
Expand All @@ -240,7 +242,7 @@ export default function ComponentPickerMenuPlugin(): JSX.Element {

if ($isRangeSelection(selection)) {
if (selection.isCollapsed()) {
$wrapNodes(selection, () => $createCodeNode());
$setBlocksType_experimental(selection, () => $createCodeNode());
} else {
// Will this ever happen?
const textContent = selection.getTextContent();
Expand Down
24 changes: 12 additions & 12 deletions packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import {
$isParentElementRTL,
$patchStyleText,
$selectAll,
$wrapNodes,
$setBlocksType_experimental,
} from '@lexical/selection';
import {
$findMatchingParent,
Expand Down Expand Up @@ -160,13 +160,11 @@ function BlockFormatDropDown({
if (blockType !== 'paragraph') {
editor.update(() => {
const selection = $getSelection();

if (
$isRangeSelection(selection) ||
DEPRECATED_$isGridSelection(selection)
) {
$wrapNodes(selection, () => $createParagraphNode());
}
)
$setBlocksType_experimental(selection, () => $createParagraphNode());
});
}
};
Expand All @@ -175,12 +173,13 @@ function BlockFormatDropDown({
if (blockType !== headingSize) {
editor.update(() => {
const selection = $getSelection();

if (
$isRangeSelection(selection) ||
DEPRECATED_$isGridSelection(selection)
) {
$wrapNodes(selection, () => $createHeadingNode(headingSize));
$setBlocksType_experimental(selection, () =>
$createHeadingNode(headingSize),
);
}
});
}
Expand Down Expand Up @@ -214,12 +213,11 @@ function BlockFormatDropDown({
if (blockType !== 'quote') {
editor.update(() => {
const selection = $getSelection();

if (
$isRangeSelection(selection) ||
DEPRECATED_$isGridSelection(selection)
) {
$wrapNodes(selection, () => $createQuoteNode());
$setBlocksType_experimental(selection, () => $createQuoteNode());
}
});
}
Expand All @@ -228,19 +226,21 @@ function BlockFormatDropDown({
const formatCode = () => {
if (blockType !== 'code') {
editor.update(() => {
const selection = $getSelection();
let selection = $getSelection();

if (
$isRangeSelection(selection) ||
DEPRECATED_$isGridSelection(selection)
) {
if (selection.isCollapsed()) {
$wrapNodes(selection, () => $createCodeNode());
$setBlocksType_experimental(selection, () => $createCodeNode());
} else {
const textContent = selection.getTextContent();
const codeNode = $createCodeNode();
selection.insertNodes([codeNode]);
selection.insertRawText(textContent);
selection = $getSelection();
if ($isRangeSelection(selection))
selection.insertRawText(textContent);
}
}
});
Expand Down
7 changes: 3 additions & 4 deletions packages/lexical-selection/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,14 @@ Expands the current Selection to cover all of the content in the editor.
export function $selectAll(selection: RangeSelection): void;
```

#### `$wrapNodes`
#### `$setBlocksType_experimental`

Attempts to wrap all nodes in the Selection in ElementNodes returned from createElement. If wrappingElement is provided, all of the wrapped leaves are appended to the wrappingElement. It attempts to append the resulting sub-tree to the nearest safe insertion target.
Converts all nodes in the selection that are of one block type to another specified by parameter

```ts
export function $wrapNodes(
export function $setBlocksType_experimental(
selection: RangeSelection,
createElement: () => ElementNode,
wrappingElement?: ElementNode,
): void;
```

Expand Down
5 changes: 2 additions & 3 deletions packages/lexical-selection/flow/LexicalSelection.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ declare export function $moveCharacter(
isBackward: boolean,
): void;
declare export function $selectAll(selection: RangeSelection): void;
declare export function $wrapNodes(
selection: RangeSelection | GridSelection,
declare export function $setBlocksType_experimental(
selection: RangeSelection,
createElement: () => ElementNode,
wrappingElement?: ElementNode,
): void;
declare export function $isAtNodeEnd(point: Point): boolean;
declare export function $shouldOverrideDefaultCharacterSelection(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {$createHeadingNode} from '@lexical/rich-text';
import {
$addNodeStyle,
$getSelectionStyleValueForProperty,
$wrapNodes,
$setBlocksType_experimental,
} from '@lexical/selection';
import {$createTableNodeWithDimensions} from '@lexical/table';
import {
Expand Down Expand Up @@ -2279,7 +2279,7 @@ describe('LexicalSelection tests', () => {
});
});

describe('$wrapNodes', () => {
describe('$setBlocksType_experimental', () => {
test('Collapsed selection in text', async () => {
const testEditor = createTestEditor();
const element = document.createElement('div');
Expand Down Expand Up @@ -2308,7 +2308,7 @@ describe('LexicalSelection tests', () => {
type: 'text',
});

$wrapNodes(selection, () => {
$setBlocksType_experimental(selection, () => {
return $createHeadingNode('h1');
});

Expand Down Expand Up @@ -2343,7 +2343,7 @@ describe('LexicalSelection tests', () => {
type: 'element',
});

$wrapNodes(selection, () => {
$setBlocksType_experimental(selection, () => {
return $createHeadingNode('h1');
});

Expand Down Expand Up @@ -2382,7 +2382,7 @@ describe('LexicalSelection tests', () => {
type: 'text',
});

$wrapNodes(selection, () => {
$setBlocksType_experimental(selection, () => {
return $createHeadingNode('h1');
});

Expand Down Expand Up @@ -2417,14 +2417,16 @@ describe('LexicalSelection tests', () => {
type: 'element',
});

$wrapNodes(selection, () => {
$setBlocksType_experimental(selection, () => {
return $createHeadingNode('h1');
});

const rootChildren = root.getChildren();
expect(rootChildren[0].__type).toBe('heading');
expect(rootChildren[1].__type).toBe('heading');
expect(rootChildren.length).toBe(2);
const sel = $getSelection();
expect(sel.getNodes().length).toBe(2);
});
});

Expand Down Expand Up @@ -2456,7 +2458,7 @@ describe('LexicalSelection tests', () => {
type: 'text',
});

$wrapNodes(selection, () => {
$setBlocksType_experimental(selection, () => {
return $createHeadingNode('h1');
});

Expand All @@ -2478,6 +2480,7 @@ describe('LexicalSelection tests', () => {
const row = table.getFirstChild();
const column = row.getFirstChild();
const paragraph = column.getFirstChild();
if (paragraph.getFirstChild()) paragraph.getFirstChild().remove();
root.append(table);

const selection = $createRangeSelection();
Expand All @@ -2495,7 +2498,7 @@ describe('LexicalSelection tests', () => {

const columnChildrenPrev = column.getChildren();
expect(columnChildrenPrev[0].__type).toBe('paragraph');
$wrapNodes(selection, () => {
$setBlocksType_experimental(selection, () => {
return $createHeadingNode('h1');
});

Expand Down Expand Up @@ -2537,7 +2540,7 @@ describe('LexicalSelection tests', () => {

const columnChildrenPrev = column.getChildren();
expect(columnChildrenPrev[0].__type).toBe('paragraph');
$wrapNodes(selection, () => {
$setBlocksType_experimental(selection, () => {
return $createHeadingNode('h1');
});

Expand Down Expand Up @@ -2600,7 +2603,7 @@ describe('LexicalSelection tests', () => {
// @ts-ignore
const selection = $getSelection() as RangeSelection;

$wrapNodes(selection, () => {
$setBlocksType_experimental(selection, () => {
return $createHeadingNode('h1');
});

Expand Down Expand Up @@ -2644,7 +2647,7 @@ describe('LexicalSelection tests', () => {
type: 'text',
});

$wrapNodes(selection, () => {
$setBlocksType_experimental(selection, () => {
return $createHeadingNode('h1');
});

Expand Down
6 changes: 2 additions & 4 deletions packages/lexical-selection/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ import {
$moveCaretSelection,
$moveCharacter,
$selectAll,
$setBlocksType_experimental,
$shouldOverrideDefaultCharacterSelection,
$wrapNodes,
$wrapNodesImpl,
} from './range-selection';
import {
createDOMRange,
Expand All @@ -46,9 +45,8 @@ export {
$moveCaretSelection,
$moveCharacter,
$selectAll,
$setBlocksType_experimental,
$shouldOverrideDefaultCharacterSelection,
$wrapNodes,
$wrapNodesImpl,
};

export {createDOMRange, createRectsFromDOMRange, getStyleObjectFromCSS};
Loading

0 comments on commit 0180f98

Please sign in to comment.