Skip to content

Commit

Permalink
Merge branch 'main' into bugfix/collapsed_selection_on_link_insertion
Browse files Browse the repository at this point in the history
  • Loading branch information
bhavyakaria authored Sep 23, 2024
2 parents 4fb3b34 + 1469aa7 commit 8f937e8
Show file tree
Hide file tree
Showing 18 changed files with 636 additions and 376 deletions.
2 changes: 1 addition & 1 deletion packages/lexical-code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@types/prismjs": "^1.26.0"
},
"module": "LexicalCode.mjs",
"sideEffects": false,
"sideEffects": true,
"exports": {
".": {
"import": {
Expand Down
7 changes: 3 additions & 4 deletions packages/lexical-code/src/CodeHighlightNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import type {
TabNode,
} from 'lexical';

import './CodeHighlighterPrism';

import {
addClassNamesToElement,
removeClassNamesFromElement,
Expand All @@ -30,6 +28,7 @@ import {
TextNode,
} from 'lexical';

import {Prism} from './CodeHighlighterPrism';
import {$createCodeNode} from './CodeNode';

export const DEFAULT_CODE_LANGUAGE = 'javascript';
Expand Down Expand Up @@ -84,11 +83,11 @@ export function getLanguageFriendlyName(lang: string) {
export const getDefaultCodeLanguage = (): string => DEFAULT_CODE_LANGUAGE;

export const getCodeLanguages = (): Array<string> =>
Object.keys(window.Prism.languages)
Object.keys(Prism.languages)
.filter(
// Prism has several language helpers mixed into languages object
// so filtering them out here to get langs list
(language) => typeof window.Prism.languages[language] !== 'function',
(language) => typeof Prism.languages[language] !== 'function',
)
.sort();

Expand Down
8 changes: 3 additions & 5 deletions packages/lexical-code/src/CodeHighlighter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import type {
RangeSelection,
} from 'lexical';

import './CodeHighlighterPrism';

import {mergeRegister} from '@lexical/utils';
import {
$createLineBreakNode,
Expand All @@ -44,6 +42,7 @@ import {
} from 'lexical';
import invariant from 'shared/invariant';

import {Prism} from './CodeHighlighterPrism';
import {
$createCodeHighlightNode,
$isCodeHighlightNode,
Expand All @@ -69,10 +68,9 @@ export interface Tokenizer {
export const PrismTokenizer: Tokenizer = {
defaultLanguage: DEFAULT_CODE_LANGUAGE,
tokenize(code: string, language?: string): (string | Token)[] {
return window.Prism.tokenize(
return Prism.tokenize(
code,
window.Prism.languages[language || ''] ||
window.Prism.languages[this.defaultLanguage],
Prism.languages[language || ''] || Prism.languages[this.defaultLanguage],
);
},
};
Expand Down
11 changes: 1 addition & 10 deletions packages/lexical-code/src/CodeHighlighterPrism.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,5 @@ import 'prismjs/components/prism-swift';
import 'prismjs/components/prism-typescript';
import 'prismjs/components/prism-java';
import 'prismjs/components/prism-cpp';
import {CAN_USE_DOM} from 'shared/canUseDOM';

declare global {
interface Window {
Prism: typeof import('prismjs');
}
}

export const Prism: typeof import('prismjs') = CAN_USE_DOM
? window.Prism
: (global as unknown as {Prism: typeof import('prismjs')}).Prism;
export const Prism: typeof import('prismjs') = globalThis.Prism || window.Prism;
1 change: 1 addition & 0 deletions packages/lexical-markdown/flow/LexicalMarkdown.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ declare export function $convertFromMarkdownString(
transformers?: Array<Transformer>,
node?: ElementNode,
shouldPreserveNewLines?: boolean,
shouldMergeAdjacentLines?: boolean,
): void;

// TODO:
Expand Down
4 changes: 4 additions & 0 deletions packages/lexical-markdown/src/MarkdownExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ function exportChildren(

mainLoop: for (const child of children) {
for (const transformer of textMatchTransformers) {
if (!transformer.export) {
continue;
}

const result = transformer.export(
child,
(parentNode) =>
Expand Down
3 changes: 3 additions & 0 deletions packages/lexical-markdown/src/MarkdownImport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,9 @@ function importTextMatchTransformers(

mainLoop: while (textNode) {
for (const transformer of textMatchTransformers) {
if (!transformer.replace || !transformer.importRegExp) {
continue;
}
const match = textNode.getTextContent().match(transformer.importRegExp);

if (!match) {
Expand Down
11 changes: 7 additions & 4 deletions packages/lexical-markdown/src/MarkdownShortcuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ function runTextMatchTransformers(
}

for (const transformer of transformers) {
if (!transformer.replace || !transformer.regExp) {
continue;
}
const match = textContent.match(transformer.regExp);

if (match === null) {
Expand Down Expand Up @@ -389,11 +392,11 @@ export function registerMarkdownShortcuts(
transformers: Array<Transformer> = TRANSFORMERS,
): () => void {
const byType = transformersByType(transformers);
const textFormatTransformersIndex = indexBy(
const textFormatTransformersByTrigger = indexBy(
byType.textFormat,
({tag}) => tag[tag.length - 1],
);
const textMatchTransformersIndex = indexBy(
const textMatchTransformersByTrigger = indexBy(
byType.textMatch,
({trigger}) => trigger,
);
Expand Down Expand Up @@ -449,7 +452,7 @@ export function registerMarkdownShortcuts(
runTextMatchTransformers(
anchorNode,
anchorOffset,
textMatchTransformersIndex,
textMatchTransformersByTrigger,
)
) {
return;
Expand All @@ -458,7 +461,7 @@ export function registerMarkdownShortcuts(
$runTextFormatTransformers(
anchorNode,
anchorOffset,
textFormatTransformersIndex,
textFormatTransformersByTrigger,
);
};

Expand Down
32 changes: 26 additions & 6 deletions packages/lexical-markdown/src/MarkdownTransformers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,33 @@ export type TextFormatTransformer = Readonly<{

export type TextMatchTransformer = Readonly<{
dependencies: Array<Klass<LexicalNode>>;
export: (
/**
* Determines how a node should be exported to markdown
*/
export?: (
node: LexicalNode,
// eslint-disable-next-line no-shadow
exportChildren: (node: ElementNode) => string,
// eslint-disable-next-line no-shadow
exportFormat: (node: TextNode, textContent: string) => string,
) => string | null;
importRegExp: RegExp;
/**
* This regex determines what text is matched during markdown imports
*/
importRegExp?: RegExp;
/**
* This regex determines what text is matched for markdown shortcuts while typing in the editor
*/
regExp: RegExp;
replace: (node: TextNode, match: RegExpMatchArray) => void;
trigger: string;
/**
* Determines how the matched markdown text should be transformed into a node during the markdown import process
*/
replace?: (node: TextNode, match: RegExpMatchArray) => void;
/**
* Single character that allows the transformer to trigger when typed in the editor. This does not affect markdown imports outside of the markdown shortcut plugin.
* If the trigger is matched, the `regExp` will be used to match the text in the second step.
*/
trigger?: string;
type: 'text-match';
}>;

Expand Down Expand Up @@ -532,7 +548,10 @@ export const LINK: TextMatchTransformer = {
type: 'text-match',
};

export function normalizeMarkdown(input: string): string {
export function normalizeMarkdown(
input: string,
shouldMergeAdjacentLines = true,
): string {
const lines = input.split('\n');
let inCodeBlock = false;
const sanitizedLines: string[] = [];
Expand Down Expand Up @@ -573,7 +592,8 @@ export function normalizeMarkdown(input: string): string {
UNORDERED_LIST_REGEX.test(line) ||
CHECK_LIST_REGEX.test(line) ||
TABLE_ROW_REG_EXP.test(line) ||
TABLE_ROW_DIVIDER_REG_EXP.test(line)
TABLE_ROW_DIVIDER_REG_EXP.test(line) ||
!shouldMergeAdjacentLines
) {
sanitizedLines.push(line);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ describe('Markdown', () => {
skipExport?: true;
skipImport?: true;
shouldPreserveNewLines?: true;
shouldMergeAdjacentLines?: true | false;
customTransformers?: Transformer[];
}>;

Expand Down Expand Up @@ -202,6 +203,17 @@ describe('Markdown', () => {
html: '<p><i><em style="white-space: pre-wrap;">Hello </em></i><i><b><strong style="white-space: pre-wrap;">world</strong></b></i><i><em style="white-space: pre-wrap;">!</em></i></p>',
md: '*Hello **world**!*',
},
{
html: '<p><span style="white-space: pre-wrap;">helloworld</span></p>',
md: 'hello\nworld',
shouldMergeAdjacentLines: true,
skipExport: true,
},
{
html: '<p><span style="white-space: pre-wrap;">hello</span><br><span style="white-space: pre-wrap;">world</span></p>',
md: 'hello\nworld',
shouldMergeAdjacentLines: false,
},
{
html: '<p><span style="white-space: pre-wrap;">hello</span><br><span style="white-space: pre-wrap;">world</span></p>',
md: 'hello\nworld',
Expand Down Expand Up @@ -342,6 +354,7 @@ describe('Markdown', () => {
md,
skipImport,
shouldPreserveNewLines,
shouldMergeAdjacentLines,
customTransformers,
} of IMPORT_AND_EXPORT) {
if (skipImport) {
Expand Down Expand Up @@ -371,6 +384,7 @@ describe('Markdown', () => {
],
undefined,
shouldPreserveNewLines,
shouldMergeAdjacentLines,
),
{
discrete: true,
Expand Down
6 changes: 5 additions & 1 deletion packages/lexical-markdown/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,20 @@ const TRANSFORMERS: Array<Transformer> = [

/**
* Renders markdown from a string. The selection is moved to the start after the operation.
*
* @param {boolean} [shouldPreserveNewLines] By setting this to true, new lines will be preserved between conversions
* @param {boolean} [shouldMergeAdjacentLines] By setting this to true, adjacent non empty lines will be merged according to commonmark spec: https://spec.commonmark.org/0.24/#example-177. Not applicable if shouldPreserveNewLines = true.
*/
function $convertFromMarkdownString(
markdown: string,
transformers: Array<Transformer> = TRANSFORMERS,
node?: ElementNode,
shouldPreserveNewLines = false,
shouldMergeAdjacentLines = true,
): void {
const sanitizedMarkdown = shouldPreserveNewLines
? markdown
: normalizeMarkdown(markdown);
: normalizeMarkdown(markdown, shouldMergeAdjacentLines);
const importMarkdown = createMarkdownImport(
transformers,
shouldPreserveNewLines,
Expand Down
6 changes: 5 additions & 1 deletion packages/lexical-markdown/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,13 +405,17 @@ function codeBlockExport(node: LexicalNode) {

export function indexBy<T>(
list: Array<T>,
callback: (arg0: T) => string,
callback: (arg0: T) => string | undefined,
): Readonly<Record<string, Array<T>>> {
const index: Record<string, Array<T>> = {};

for (const item of list) {
const key = callback(item);

if (!key) {
continue;
}

if (index[key]) {
index[key].push(item);
} else {
Expand Down
42 changes: 42 additions & 0 deletions packages/lexical-playground/__tests__/e2e/Tables.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
copyToClipboard,
deleteTableColumns,
deleteTableRows,
expect,
focusEditor,
html,
initialize,
Expand Down Expand Up @@ -1360,6 +1361,47 @@ test.describe.parallel('Tables', () => {
);
});

test('Can delete all with range selection anchored in table', async ({
page,
isCollab,
isPlainText,
}) => {
test.skip(isPlainText || isCollab);
await initialize({isCollab, page});
await focusEditor(page);
await insertTable(page, 1, 1);
// Remove paragraph before
await moveUp(page);
await page.keyboard.press('Backspace');
await assertHTML(
page,
html`
<table class="PlaygroundEditorTheme__table">
<colgroup><col style="width: 92px" /></colgroup>
<tr>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</th>
</tr>
</table>
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
`,
);
// Select all but from the table
const modifier = process.platform === 'darwin' ? 'Meta' : 'Control';
await page.keyboard.press(`${modifier}+A`);
// The observer is active
await expect(page.locator('.table-cell-action-button')).toBeVisible();
await page.keyboard.press('Backspace');
await assertHTML(
page,
html`
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
`,
);
});

test(`Horizontal rule inside cell`, async ({page, isPlainText, isCollab}) => {
await initialize({isCollab, page});
test.skip(isPlainText);
Expand Down
12 changes: 7 additions & 5 deletions packages/lexical-playground/src/plugins/ActionsPlugin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,12 @@ export default function ActionsPlugin({
undefined, //node
shouldPreserveNewLinesInMarkdown,
);
root
.clear()
.append(
$createCodeNode('markdown').append($createTextNode(markdown)),
);
const codeNode = $createCodeNode('markdown');
codeNode.append($createTextNode(markdown));
root.clear().append(codeNode);
if (markdown.length === 0) {
codeNode.select();
}
}
});
}, [editor, shouldPreserveNewLinesInMarkdown]);
Expand Down Expand Up @@ -218,6 +219,7 @@ export default function ActionsPlugin({
aria-label="Import editor state from JSON">
<i className="import" />
</button>

<button
className="action-button export"
onClick={() =>
Expand Down
Loading

0 comments on commit 8f937e8

Please sign in to comment.