pl-fe: use @lexical/markdown for wysiwyg markdown export

Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>
This commit is contained in:
Nicole Mikołajczyk
2025-03-27 16:37:16 +01:00
parent c66f98771e
commit a7504fc988
4 changed files with 80 additions and 17 deletions

View File

@ -49,6 +49,7 @@
"@lexical/hashtag": "^0.29.0",
"@lexical/link": "^0.29.0",
"@lexical/list": "^0.29.0",
"@lexical/markdown": "^0.29.0",
"@lexical/react": "^0.29.0",
"@lexical/rich-text": "^0.29.0",
"@lexical/selection": "^0.29.0",

View File

@ -1,6 +1,6 @@
import { AutoLinkNode, LinkNode } from '@lexical/link';
import { $convertToMarkdownString } from '@lexical/markdown';
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import { $createRemarkExport } from '@mkljczk/lexical-remark';
import { $nodesOfType, $getRoot, type EditorState, $getNodeByKey } from 'lexical';
import debounce from 'lodash/debounce';
import { useCallback, useEffect } from 'react';
@ -14,6 +14,8 @@ import { useSettings } from 'pl-fe/hooks/use-settings';
import { getStatusIdsFromLinksInContent } from 'pl-fe/utils/status';
import Purify from 'pl-fe/utils/url-purify';
import { TRANSFORMERS } from '../transformers';
import type { LanguageIdentificationModel } from 'fasttext.wasm.js/dist/models/language-identification/common.js';
let lidModel: LanguageIdentificationModel;
@ -136,21 +138,18 @@ const StatePlugin: React.FC<IStatePlugin> = ({ composeId, isWysiwyg }) => {
useEffect(() => {
return editor.registerUpdateListener(({ editorState }) => {
const plainText = editorState.read(() => $getRoot().getTextContent());
let text = plainText;
if (isWysiwyg) {
text = editorState.read($createRemarkExport({
handlers: {
hashtag: (node) => ({ type: 'text', value: node.getTextContent() }),
mention: (node) => ({ type: 'text', value: node.getTextContent() }),
},
}));
}
const isEmpty = text === '';
const data = isEmpty ? null : JSON.stringify(editorState.toJSON());
dispatch(setEditorState(composeId, data, text));
checkUrls(editorState);
getQuoteSuggestions(plainText);
detectLanguage(plainText);
editor.update(() => {
let text = plainText;
if (isWysiwyg) {
text = $convertToMarkdownString(TRANSFORMERS);
}
const isEmpty = text === '';
const data = isEmpty ? null : JSON.stringify(editorState.toJSON());
dispatch(setEditorState(composeId, data, text));
checkUrls(editorState);
getQuoteSuggestions(plainText);
detectLanguage(plainText);
});
});
}, [editor]);

View File

@ -0,0 +1,63 @@
/**
* This source code is derived from code from Meta Platforms, Inc.
* and affiliates, licensed under the MIT license located in the
* LICENSE file in the /src/features/compose/editor directory.
*/
import { TRANSFORMERS as DEFAULT_TRANSFORMERS, type ElementTransformer, type TextMatchTransformer } from '@lexical/markdown';
import { $createHorizontalRuleNode, $isHorizontalRuleNode, HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode';
import { LexicalNode } from 'lexical';
import { $createImageNode, $isImageNode, ImageNode } from '../nodes/image-node';
const IMAGE_TRANSFORMER: TextMatchTransformer = {
dependencies: [ImageNode],
export: (node) => {
if ($isImageNode(node)) {
const src = node.getSrc();
const alt = node.getAltText();
return `![${alt.replace(/([[\]])/g, '\\$1')}](${src})`;
}
return null;
},
importRegExp: /!(?:\[([^[]*)\])(?:\(([^(]+)\))/,
regExp: /!(?:\[([^[]*)\])(?:\(([^(]+)\))$/,
replace: (textNode, match) => {
const [, altText, src] = match;
const imageNode = $createImageNode({
altText,
src,
});
textNode.replace(imageNode);
},
type: 'text-match',
};
const HORIZONTAL_RULE_TRANSFORMER: ElementTransformer = {
dependencies: [HorizontalRuleNode],
export: (node: LexicalNode) => {
return $isHorizontalRuleNode(node) ? '***' : null;
},
regExp: /^(---|\*\*\*|___)\s?$/,
replace: (parentNode, _1, _2, isImport) => {
const line = $createHorizontalRuleNode();
// TODO: Get rid of isImport flag
if (isImport || parentNode.getNextSibling() !== null) {
parentNode.replace(line);
} else {
parentNode.insertBefore(line);
}
line.selectNext();
},
type: 'element',
};
const TRANSFORMERS = [
...DEFAULT_TRANSFORMERS,
HORIZONTAL_RULE_TRANSFORMER,
IMAGE_TRANSFORMER,
];
export { TRANSFORMERS };

View File

@ -1596,7 +1596,7 @@
"@lexical/utils" "0.29.0"
lexical "0.29.0"
"@lexical/markdown@0.29.0":
"@lexical/markdown@0.29.0", "@lexical/markdown@^0.29.0":
version "0.29.0"
resolved "https://registry.yarnpkg.com/@lexical/markdown/-/markdown-0.29.0.tgz#673ca4fb1cbedf2b17e905cf9a229ce0eb505b65"
integrity sha512-4Od8WoDoviv9DxJZVgrIORTIAzyoGOpztbGbIBXguGmwvy7NnHQDh9fZYIYRrdI1Awp1VVGdJ3ku/7KTgSOoRw==