Skip to content

Commit

Permalink
Merge branch 'main' into fix-paragraph-styling-on-list-exit
Browse files Browse the repository at this point in the history
  • Loading branch information
aleksandr-lapushkin authored Dec 9, 2024
2 parents 6c43d9b + 05fa244 commit 31c64c6
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 107 deletions.
30 changes: 27 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 14 additions & 12 deletions packages/lexical-playground/__tests__/utils/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ async function assertHTMLOnPageOrFrame(
frameName,
actualHtmlModificationsCallback = (actualHtml) => actualHtml,
) {
const expected = prettifyHTML(expectedHtml.replace(/\n/gm, ''), {
const expected = await prettifyHTML(expectedHtml.replace(/\n/gm, ''), {
ignoreClasses,
ignoreInlineStyles,
});
Expand All @@ -236,7 +236,7 @@ async function assertHTMLOnPageOrFrame(
.first()
.innerHTML(),
);
let actual = prettifyHTML(actualHtml.replace(/\n/gm, ''), {
let actual = await prettifyHTML(actualHtml.replace(/\n/gm, ''), {
ignoreClasses,
ignoreInlineStyles,
});
Expand Down Expand Up @@ -780,7 +780,10 @@ export async function dragImage(
);
}

export function prettifyHTML(string, {ignoreClasses, ignoreInlineStyles} = {}) {
export async function prettifyHTML(
string,
{ignoreClasses, ignoreInlineStyles} = {},
) {
let output = string;

if (ignoreClasses) {
Expand All @@ -793,15 +796,14 @@ export function prettifyHTML(string, {ignoreClasses, ignoreInlineStyles} = {}) {

output = output.replace(/\s__playwright_target__="[^"]+"/, '');

return prettier
.format(output, {
attributeGroups: ['$DEFAULT', '^data-'],
attributeSort: 'ASC',
bracketSameLine: true,
htmlWhitespaceSensitivity: 'ignore',
parser: 'html',
})
.trim();
return await prettier.format(output, {
attributeGroups: ['$DEFAULT', '^data-'],
attributeSort: 'asc',
bracketSameLine: true,
htmlWhitespaceSensitivity: 'ignore',
parser: 'html',
plugins: ['prettier-plugin-organize-attributes'],
});
}

// This function does not suppose to do anything, it's only used as a trigger
Expand Down
2 changes: 1 addition & 1 deletion packages/lexical-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"katex": "^0.16.10",
"lexical": "0.21.0",
"lodash-es": "^4.17.21",
"prettier": "^2.3.2",
"prettier": "^3.4.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^3.1.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import './index.css';
import {$isCodeNode} from '@lexical/code';
import {$getNearestNodeFromDOMNode, LexicalEditor} from 'lexical';
import {Options} from 'prettier';
import * as React from 'react';
import {useState} from 'react';

interface Props {
Expand All @@ -20,17 +19,27 @@ interface Props {
}

const PRETTIER_PARSER_MODULES = {
css: () => import('prettier/parser-postcss'),
html: () => import('prettier/parser-html'),
js: () => import('prettier/parser-babel'),
markdown: () => import('prettier/parser-markdown'),
css: [() => import('prettier/parser-postcss')],
html: [() => import('prettier/parser-html')],
js: [
() => import('prettier/parser-babel'),
() => import('prettier/plugins/estree'),
],
markdown: [() => import('prettier/parser-markdown')],
typescript: [
() => import('prettier/parser-typescript'),
() => import('prettier/plugins/estree'),
],
} as const;

type LanguagesType = keyof typeof PRETTIER_PARSER_MODULES;

async function loadPrettierParserByLang(lang: string) {
const dynamicImport = PRETTIER_PARSER_MODULES[lang as LanguagesType];
return await dynamicImport();
const dynamicImports = PRETTIER_PARSER_MODULES[lang as LanguagesType];
const modules = await Promise.all(
dynamicImports.map((dynamicImport) => dynamicImport()),
);
return modules;
}

async function loadPrettierFormat() {
Expand All @@ -39,18 +48,11 @@ async function loadPrettierFormat() {
}

const PRETTIER_OPTIONS_BY_LANG: Record<string, Options> = {
css: {
parser: 'css',
},
html: {
parser: 'html',
},
js: {
parser: 'babel',
},
markdown: {
parser: 'markdown',
},
css: {parser: 'css'},
html: {parser: 'html'},
js: {parser: 'babel'},
markdown: {parser: 'markdown'},
typescript: {parser: 'typescript'},
};

const LANG_CAN_BE_PRETTIER = Object.keys(PRETTIER_OPTIONS_BY_LANG);
Expand All @@ -76,36 +78,37 @@ export function PrettierButton({lang, editor, getCodeDOMNode}: Props) {

async function handleClick(): Promise<void> {
const codeDOMNode = getCodeDOMNode();
if (!codeDOMNode) {
return;
}

let content = '';
editor.update(() => {
const codeNode = $getNearestNodeFromDOMNode(codeDOMNode);
if ($isCodeNode(codeNode)) {
content = codeNode.getTextContent();
}
});
if (content === '') {
return;
}

try {
const format = await loadPrettierFormat();
const options = getPrettierOptions(lang);
options.plugins = [await loadPrettierParserByLang(lang)];

if (!codeDOMNode) {
return;
}
const prettierParsers = await loadPrettierParserByLang(lang);
options.plugins = prettierParsers.map(
(parser) => parser.default || parser,
);
const formattedCode = await format(content, options);

editor.update(() => {
const codeNode = $getNearestNodeFromDOMNode(codeDOMNode);

if ($isCodeNode(codeNode)) {
const content = codeNode.getTextContent();

let parsed = '';

try {
parsed = format(content, options);
} catch (error: unknown) {
setError(error);
}

if (parsed !== '') {
const selection = codeNode.select(0);
selection.insertText(parsed);
setSyntaxError('');
setTipsVisible(false);
}
const selection = codeNode.select(0);
selection.insertText(formattedCode);
setSyntaxError('');
setTipsVisible(false);
}
});
} catch (error: unknown) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,25 @@ export function LayoutPlugin(): null {
return false;
};

const $fillLayoutItemIfEmpty = (node: LayoutItemNode) => {
if (node.isEmpty()) {
node.append($createParagraphNode());
}
};

const $removeIsolatedLayoutItem = (node: LayoutItemNode): boolean => {
const parent = node.getParent<ElementNode>();
if (!$isLayoutContainerNode(parent)) {
const children = node.getChildren<LexicalNode>();
for (const child of children) {
node.insertBefore(child);
}
node.remove();
return true;
}
return false;
};

return mergeRegister(
// When layout is the last child pressing down/right arrow will insert paragraph
// below it to allow adding more content. It's similar what $insertBlockNode
Expand Down Expand Up @@ -186,17 +205,17 @@ export function LayoutPlugin(): null {
},
COMMAND_PRIORITY_EDITOR,
),
// Structure enforcing transformers for each node type. In case nesting structure is not
// "Container > Item" it'll unwrap nodes and convert it back
// to regular content.

editor.registerNodeTransform(LayoutItemNode, (node) => {
const parent = node.getParent<ElementNode>();
if (!$isLayoutContainerNode(parent)) {
const children = node.getChildren<LexicalNode>();
for (const child of children) {
node.insertBefore(child);
}
node.remove();
// Structure enforcing transformers for each node type. In case nesting structure is not
// "Container > Item" it'll unwrap nodes and convert it back
// to regular content.
const isRemoved = $removeIsolatedLayoutItem(node);

if (!isRemoved) {
// Layout item should always have a child. this function will listen
// for any empty layout item and fill it with a paragraph node
$fillLayoutItemIfEmpty(node);
}
}),
editor.registerNodeTransform(LayoutContainerNode, (node) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/lexical-selection/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
$isParentElementRTL,
$moveCaretSelection,
$moveCharacter,
$selectAll,
$setBlocksType,
$shouldOverrideDefaultCharacterSelection,
$wrapNodes,
Expand All @@ -32,7 +31,9 @@ import {

export {
/** @deprecated moved to the lexical package */ $cloneWithProperties,
/** @deprecated moved to the lexical package */ $selectAll,
} from 'lexical';

export {
$addNodeStyle,
$isAtNodeEnd,
Expand All @@ -48,7 +49,6 @@ export {
$isParentElementRTL,
$moveCaretSelection,
$moveCharacter,
$selectAll,
$setBlocksType,
$shouldOverrideDefaultCharacterSelection,
$wrapNodes,
Expand Down
35 changes: 0 additions & 35 deletions packages/lexical-selection/src/range-selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,41 +452,6 @@ export function $moveCharacter(
);
}

/**
* Expands the current Selection to cover all of the content in the editor.
* @param selection - The current selection.
*/
export function $selectAll(selection: RangeSelection): void {
const anchor = selection.anchor;
const focus = selection.focus;
const anchorNode = anchor.getNode();
const topParent = anchorNode.getTopLevelElementOrThrow();
const root = topParent.getParentOrThrow();
let firstNode = root.getFirstDescendant();
let lastNode = root.getLastDescendant();
let firstType: 'element' | 'text' = 'element';
let lastType: 'element' | 'text' = 'element';
let lastOffset = 0;

if ($isTextNode(firstNode)) {
firstType = 'text';
} else if (!$isElementNode(firstNode) && firstNode !== null) {
firstNode = firstNode.getParentOrThrow();
}

if ($isTextNode(lastNode)) {
lastType = 'text';
lastOffset = lastNode.getTextContentSize();
} else if (!$isElementNode(lastNode) && lastNode !== null) {
lastNode = lastNode.getParentOrThrow();
}

if (firstNode && lastNode) {
anchor.set(firstNode.getKey(), 0, firstType);
focus.set(lastNode.getKey(), lastOffset, lastType);
}
}

/**
* Returns the current value of a CSS property for Nodes, if set. If not set, it returns the defaultValue.
* @param node - The node whose style value to get.
Expand Down
Loading

0 comments on commit 31c64c6

Please sign in to comment.