Use lexical-remark for Lexical<->Markdown conversions
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
6a172f525f
commit
3c5025c7f3
|
@ -6,7 +6,6 @@ Copyright (c) Meta Platforms, Inc. and affiliates.
|
|||
This source code is licensed under the MIT license found in the
|
||||
LICENSE file in the /app/soapbox/features/compose/editor directory.
|
||||
*/
|
||||
import { $convertFromMarkdownString, $convertToMarkdownString } from '@lexical/markdown';
|
||||
import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin';
|
||||
import { AutoLinkPlugin, createLinkMatcherWithRegExp } from '@lexical/react/LexicalAutoLinkPlugin';
|
||||
import { LexicalComposer, InitialConfigType } from '@lexical/react/LexicalComposer';
|
||||
|
@ -20,6 +19,7 @@ import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
|
|||
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
|
||||
import clsx from 'clsx';
|
||||
import { $createParagraphNode, $createTextNode, $getRoot } from 'lexical';
|
||||
import { $createRemarkExport, $createRemarkImport } from 'lexical-remark';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
|
@ -39,7 +39,6 @@ import FloatingLinkEditorPlugin from './plugins/floating-link-editor-plugin';
|
|||
import FloatingTextFormatToolbarPlugin from './plugins/floating-text-format-toolbar-plugin';
|
||||
import MentionPlugin from './plugins/mention-plugin';
|
||||
import StatePlugin from './plugins/state-plugin';
|
||||
import { TO_WYSIWYG_TRANSFORMERS } from './transformers';
|
||||
|
||||
interface IComposeEditor {
|
||||
className?: string
|
||||
|
@ -107,7 +106,7 @@ const ComposeEditor = React.forwardRef<string, IComposeEditor>(({
|
|||
|
||||
return function() {
|
||||
if (compose.content_type === 'text/markdown') {
|
||||
$convertFromMarkdownString(compose.text, TO_WYSIWYG_TRANSFORMERS);
|
||||
$createRemarkImport({})(compose.text);
|
||||
} else {
|
||||
const paragraph = $createParagraphNode();
|
||||
const textNode = $createTextNode(compose.text);
|
||||
|
@ -175,9 +174,7 @@ const ComposeEditor = React.forwardRef<string, IComposeEditor>(({
|
|||
/>
|
||||
{autoFocus && <AutoFocusPlugin />}
|
||||
<OnChangePlugin onChange={(_, editor) => {
|
||||
editor.update(() => {
|
||||
if (editorStateRef) (editorStateRef as any).current = $convertToMarkdownString(TO_WYSIWYG_TRANSFORMERS);
|
||||
});
|
||||
if (editorStateRef) (editorStateRef as any).current = editor.getEditorState().read($createRemarkExport());
|
||||
}}
|
||||
/>
|
||||
<HistoryPlugin />
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
// Adapted from: https://github.com/facebook/lexical/issues/2715#issuecomment-1209090485
|
||||
|
||||
import {
|
||||
BOLD_ITALIC_UNDERSCORE,
|
||||
BOLD_ITALIC_STAR,
|
||||
BOLD_STAR,
|
||||
BOLD_UNDERSCORE,
|
||||
STRIKETHROUGH,
|
||||
INLINE_CODE,
|
||||
HEADING,
|
||||
QUOTE,
|
||||
ORDERED_LIST,
|
||||
UNORDERED_LIST,
|
||||
LINK,
|
||||
TextMatchTransformer,
|
||||
} from '@lexical/markdown';
|
||||
|
||||
const replaceEscapedChars = (text: string): string => {
|
||||
// convert "\*" to "*", "\_" to "_", "\~" to "~", ...
|
||||
return text
|
||||
.replaceAll('\\*', '*')
|
||||
.replaceAll('\\_', '_')
|
||||
.replaceAll('\\-', '-')
|
||||
.replaceAll('\\#', '#')
|
||||
.replaceAll('\\>', '>')
|
||||
.replaceAll('\\+', '+')
|
||||
.replaceAll('\\~', '~');
|
||||
};
|
||||
|
||||
const replaceUnescapedChars = (text: string, regexes: RegExp[]): string => {
|
||||
// convert "*" to "", "_" to "", "~" to "" (all chars, which are not escaped - means with "\" in front)
|
||||
for (const regex of regexes) {
|
||||
text = text.replaceAll(regex, '');
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
const UNESCAPE_ITALIC_UNDERSCORE_IMPORT_REGEX =
|
||||
/([\_])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\_])(?!\w|\3)/;
|
||||
const UNESCAPE_ITALIC_UNDERSCORE_REGEX =
|
||||
/([\_])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\_])(?!\w|\3)/;
|
||||
|
||||
export const UNESCAPE_ITALIC_UNDERSCORE: TextMatchTransformer = {
|
||||
dependencies: [],
|
||||
export: () => null,
|
||||
importRegExp: UNESCAPE_ITALIC_UNDERSCORE_IMPORT_REGEX,
|
||||
regExp: UNESCAPE_ITALIC_UNDERSCORE_REGEX,
|
||||
replace: (textNode, _) => {
|
||||
const notEscapedUnderscoreRegex = /(?<![\\]{1})[\_]{1}/g;
|
||||
const textContent = replaceUnescapedChars(textNode.getTextContent(), [
|
||||
notEscapedUnderscoreRegex,
|
||||
]);
|
||||
textNode.setTextContent(replaceEscapedChars(textContent));
|
||||
textNode.setFormat('italic');
|
||||
},
|
||||
trigger: '_',
|
||||
type: 'text-match',
|
||||
};
|
||||
|
||||
const UNESCAPE_ITALIC_STAR_IMPORT_REGEX =
|
||||
/([\*])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\*])(?!\w|\3)/;
|
||||
const UNESCAPE_ITALIC_STAR_REGEX =
|
||||
/([\*])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\*])(?!\w|\3)/;
|
||||
|
||||
export const UNESCAPE_ITALIC_STAR: TextMatchTransformer = {
|
||||
dependencies: [],
|
||||
export: () => null,
|
||||
importRegExp: UNESCAPE_ITALIC_STAR_IMPORT_REGEX,
|
||||
regExp: UNESCAPE_ITALIC_STAR_REGEX,
|
||||
replace: (textNode, _) => {
|
||||
const notEscapedStarRegex = /(?<![\\]{1})[\*]{1}/g;
|
||||
const textContent = replaceUnescapedChars(textNode.getTextContent(), [
|
||||
notEscapedStarRegex,
|
||||
]);
|
||||
textNode.setTextContent(replaceEscapedChars(textContent));
|
||||
textNode.setFormat('italic');
|
||||
},
|
||||
trigger: '*',
|
||||
type: 'text-match',
|
||||
};
|
||||
|
||||
const UNESCAPE_BACKSLASH_IMPORT_REGEX = /(\\(?:\\\\)?).*?\1*[\~\*\_\{\}\[\]\(\)\#\+\-\.\!]/;
|
||||
const UNESCAPE_BACKSLASH_REGEX = /(\\(?:\\\\)?).*?\1*[\~\*\_\{\}\[\]\(\)\#\+\-\.\!]$/;
|
||||
|
||||
export const UNESCAPE_BACKSLASH: TextMatchTransformer = {
|
||||
dependencies: [],
|
||||
export: () => null,
|
||||
importRegExp: UNESCAPE_BACKSLASH_IMPORT_REGEX,
|
||||
regExp: UNESCAPE_BACKSLASH_REGEX,
|
||||
replace: (textNode, _) => {
|
||||
if (textNode) {
|
||||
textNode.setTextContent(replaceEscapedChars(textNode.getTextContent()));
|
||||
}
|
||||
},
|
||||
trigger: '\\',
|
||||
type: 'text-match',
|
||||
};
|
||||
|
||||
export const TO_WYSIWYG_TRANSFORMERS = [
|
||||
UNESCAPE_BACKSLASH,
|
||||
BOLD_ITALIC_UNDERSCORE,
|
||||
BOLD_ITALIC_STAR,
|
||||
BOLD_STAR,
|
||||
BOLD_UNDERSCORE,
|
||||
STRIKETHROUGH,
|
||||
UNESCAPE_ITALIC_UNDERSCORE,
|
||||
UNESCAPE_ITALIC_STAR,
|
||||
INLINE_CODE,
|
||||
HEADING,
|
||||
QUOTE,
|
||||
ORDERED_LIST,
|
||||
UNORDERED_LIST,
|
||||
LINK,
|
||||
];
|
|
@ -58,7 +58,6 @@
|
|||
"@lexical/hashtag": "^0.11.2",
|
||||
"@lexical/link": "^0.11.2",
|
||||
"@lexical/list": "^0.11.2",
|
||||
"@lexical/markdown": "^0.11.2",
|
||||
"@lexical/react": "^0.11.2",
|
||||
"@lexical/rich-text": "^0.11.2",
|
||||
"@lexical/selection": "^0.11.2",
|
||||
|
@ -138,6 +137,7 @@
|
|||
"intl-pluralrules": "^1.3.1",
|
||||
"leaflet": "^1.8.0",
|
||||
"lexical": "^0.11.2",
|
||||
"lexical-remark": "^0.3.8",
|
||||
"libphonenumber-js": "^1.10.8",
|
||||
"line-awesome": "^1.3.0",
|
||||
"localforage": "^1.10.0",
|
||||
|
|
|
@ -160,6 +160,7 @@ const configuration: Configuration = {
|
|||
// https://github.com/facebook/react/issues/20235#issuecomment-1061708958
|
||||
'react/jsx-runtime': 'react/jsx-runtime.js',
|
||||
'react/jsx-dev-runtime': 'react/jsx-dev-runtime.js',
|
||||
'process/browser': require.resolve('process/browser'),
|
||||
},
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue