diff --git a/packages/lexical-markdown/flow/LexicalMarkdown.js.flow b/packages/lexical-markdown/flow/LexicalMarkdown.js.flow index 973fab93726..63627c9b4f7 100644 --- a/packages/lexical-markdown/flow/LexicalMarkdown.js.flow +++ b/packages/lexical-markdown/flow/LexicalMarkdown.js.flow @@ -127,6 +127,7 @@ declare export var CHECK_LIST: ElementTransformer; declare export var ORDERED_LIST: ElementTransformer; declare export var LINK: TextMatchTransformer; +declare export var INDENT: TextMatchTransformer; declare export var TRANSFORMERS: Array; declare export var ELEMENT_TRANSFORMERS: Array; diff --git a/packages/lexical-markdown/src/MarkdownTransformers.ts b/packages/lexical-markdown/src/MarkdownTransformers.ts index 6a7f93dcef2..991a785fc30 100644 --- a/packages/lexical-markdown/src/MarkdownTransformers.ts +++ b/packages/lexical-markdown/src/MarkdownTransformers.ts @@ -36,6 +36,8 @@ import { $createLineBreakNode, $createTextNode, $getState, + $isParagraphNode, + $isTextNode, $setState, createState, ElementNode, @@ -216,6 +218,7 @@ const TAG_START_REGEX = /^<[a-z_][\w-]*(?:\s[^<>]*)?\/?>/i; const TAG_END_REGEX = /^<\/[a-z_][\w-]*\s*>/i; const ENDS_WITH = (regex: RegExp) => new RegExp(`(?:${regex.source})$`, regex.flags); +const INDENT_REGEX = /^\t+/; export const listMarkerState = createState('mdListMarker', { parse: (v) => (typeof v === 'string' && /^[-*+]$/.test(v) ? v : '-'), @@ -707,6 +710,37 @@ export const LINK: TextMatchTransformer = { type: 'text-match', }; +export const INDENT: TextMatchTransformer = { + dependencies: [], + export: (node, exportChildren, exportFormat) => { + const parentNode = node.getParent(); + const textContent = node.getTextContent(); + if ( + !$isParagraphNode(parentNode) || + !$isTextNode(node) || + !node.is(parentNode.getFirstChild()) + ) { + return null; + } + const indent = parentNode.getIndent(); + const textWithFormat = exportFormat(node, textContent); + return textWithFormat ? '\t'.repeat(indent) + textWithFormat : null; + }, + importRegExp: INDENT_REGEX, + regExp: INDENT_REGEX, + replace: (textNode, match) => { + const [indents] = match; + const parentNode = textNode.getParent(); + if (!parentNode || !$isParagraphNode(parentNode)) { + return; + } + parentNode.setIndent(indents.length); + textNode.setTextContent(textNode.getTextContent().replace(/^\t+/, '')); + return textNode; + }, + type: 'text-match', +}; + export const ELEMENT_TRANSFORMERS: Array = [ HEADING, QUOTE, diff --git a/packages/lexical-markdown/src/__tests__/unit/LexicalMarkdown.test.ts b/packages/lexical-markdown/src/__tests__/unit/LexicalMarkdown.test.ts index 8585f3364d0..a6c2377d22d 100644 --- a/packages/lexical-markdown/src/__tests__/unit/LexicalMarkdown.test.ts +++ b/packages/lexical-markdown/src/__tests__/unit/LexicalMarkdown.test.ts @@ -32,6 +32,7 @@ import {describe, expect, it} from 'vitest'; import { $convertFromMarkdownString, $convertToMarkdownString, + INDENT, LINK, registerMarkdownShortcuts, TextMatchTransformer, @@ -716,6 +717,26 @@ describe('Markdown', () => { md: '**text [link](https://lexical.dev)**', mdAfterExport: '**text **[**link**](https://lexical.dev)', }, + { + customTransformers: [INDENT], + html: '

Hello Word

', + md: '\tHello Word', + }, + { + customTransformers: [INDENT], + html: '

Hello Word

', + md: '\t\tHello Word', + }, + { + customTransformers: [INDENT], + html: '

Hello\t Word

', + md: 'Hello\t Word', + }, + { + customTransformers: [INDENT], + html: '

Hello Word

', + md: '\t*Hello* Word', + }, { html: '

texttext

', md: '*text**text***', diff --git a/packages/lexical-markdown/src/index.ts b/packages/lexical-markdown/src/index.ts index 3b9270d0e22..f0e16aa0c31 100644 --- a/packages/lexical-markdown/src/index.ts +++ b/packages/lexical-markdown/src/index.ts @@ -28,6 +28,7 @@ import { ELEMENT_TRANSFORMERS, HEADING, HIGHLIGHT, + INDENT, INLINE_CODE, ITALIC_STAR, ITALIC_UNDERSCORE, @@ -94,6 +95,7 @@ export { type ElementTransformer, HEADING, HIGHLIGHT, + INDENT, INLINE_CODE, ITALIC_STAR, ITALIC_UNDERSCORE, diff --git a/packages/lexical-playground/src/plugins/MarkdownTransformers/index.ts b/packages/lexical-playground/src/plugins/MarkdownTransformers/index.ts index 7498485217a..9f17da36919 100644 --- a/packages/lexical-playground/src/plugins/MarkdownTransformers/index.ts +++ b/packages/lexical-playground/src/plugins/MarkdownTransformers/index.ts @@ -12,6 +12,7 @@ import { CHECK_LIST, ELEMENT_TRANSFORMERS, ElementTransformer, + INDENT, MULTILINE_ELEMENT_TRANSFORMERS, TEXT_FORMAT_TRANSFORMERS, TEXT_MATCH_TRANSFORMERS, @@ -315,6 +316,7 @@ export const PLAYGROUND_TRANSFORMERS: Array = [ EQUATION, TWEET, CHECK_LIST, + INDENT, ...ELEMENT_TRANSFORMERS, ...MULTILINE_ELEMENT_TRANSFORMERS, ...TEXT_FORMAT_TRANSFORMERS,