From 43a656a9c38bfd3bf7d24bc098cb39a682863aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 3 Aug 2023 19:32:06 +0200 Subject: [PATCH] Lexical: load editor async MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../compose/components/compose-form.tsx | 31 +++++---- .../compose/editor/nodes/mention-node.ts | 69 +++++++++++++++++++ .../compose-event-modal.tsx | 23 ++++--- .../features/ui/util/async-components.ts | 4 ++ 4 files changed, 104 insertions(+), 23 deletions(-) create mode 100644 app/soapbox/features/compose/editor/nodes/mention-node.ts diff --git a/app/soapbox/features/compose/components/compose-form.tsx b/app/soapbox/features/compose/components/compose-form.tsx index dadcdcf66..284ae3a2c 100644 --- a/app/soapbox/features/compose/components/compose-form.tsx +++ b/app/soapbox/features/compose/components/compose-form.tsx @@ -17,6 +17,8 @@ import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest import AutosuggestTextarea from 'soapbox/components/autosuggest-textarea'; import { Button, HStack, Stack } from 'soapbox/components/ui'; import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container'; +import Bundle from 'soapbox/features/ui/components/bundle'; +import { ComposeEditor } from 'soapbox/features/ui/util/async-components'; import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, usePrevious, useSettings } from 'soapbox/hooks'; import { isMobile } from 'soapbox/is-mobile'; @@ -25,7 +27,6 @@ import ReplyIndicatorContainer from '../containers/reply-indicator-container'; import ScheduleFormContainer from '../containers/schedule-form-container'; import UploadButtonContainer from '../containers/upload-button-container'; import WarningContainer from '../containers/warning-container'; -import ComposeEditor from '../editor'; import { countableText } from '../util/counter'; import MarkdownButton from './markdown-button'; @@ -331,18 +332,22 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab {wysiwygEditor ? (
- + + {(Component: any) => ( + + )} + {composeModifiers}
) : ( diff --git a/app/soapbox/features/compose/editor/nodes/mention-node.ts b/app/soapbox/features/compose/editor/nodes/mention-node.ts new file mode 100644 index 000000000..a559eda40 --- /dev/null +++ b/app/soapbox/features/compose/editor/nodes/mention-node.ts @@ -0,0 +1,69 @@ +/** + * 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 /app/soapbox/features/compose/editor directory. + */ + +import { addClassNamesToElement } from '@lexical/utils'; +import { $applyNodeReplacement, TextNode } from 'lexical'; + +import type { + EditorConfig, + LexicalNode, + NodeKey, + SerializedTextNode, +} from 'lexical'; + +class MentionNode extends TextNode { + + static getType(): string { + return 'mention'; + } + + static clone(node: MentionNode): MentionNode { + return new MentionNode(node.__text, node.__key); + } + + constructor(text: string, key?: NodeKey) { + super(text, key); + } + + createDOM(config: EditorConfig): HTMLElement { + const element = super.createDOM(config); + addClassNamesToElement(element, config.theme.mention); + return element; + } + + static importJSON(serializedNode: SerializedTextNode): MentionNode { + const node = $createMentionNode(serializedNode.text); + node.setFormat(serializedNode.format); + node.setDetail(serializedNode.detail); + node.setMode(serializedNode.mode); + node.setStyle(serializedNode.style); + return node; + } + + exportJSON(): SerializedTextNode { + return { + ...super.exportJSON(), + type: 'mention', + }; + } + + canInsertTextBefore(): boolean { + return false; + } + + isTextEntity(): true { + return true; + } + +} + +const $createMentionNode = (text = ''): MentionNode => $applyNodeReplacement(new MentionNode(text)); + +const $isMentionNode = ( + node: LexicalNode | null | undefined, +): node is MentionNode => node instanceof MentionNode; + +export { MentionNode, $createMentionNode, $isMentionNode }; diff --git a/app/soapbox/features/ui/components/modals/compose-event-modal/compose-event-modal.tsx b/app/soapbox/features/ui/components/modals/compose-event-modal/compose-event-modal.tsx index 544f0e63c..f5453c52e 100644 --- a/app/soapbox/features/ui/components/modals/compose-event-modal/compose-event-modal.tsx +++ b/app/soapbox/features/ui/components/modals/compose-event-modal/compose-event-modal.tsx @@ -24,9 +24,8 @@ import { checkEventComposeContent } from 'soapbox/components/modal-root'; import { Button, Form, FormGroup, HStack, Icon, IconButton, Input, Modal, Spinner, Stack, Tabs, Text, Toggle } from 'soapbox/components/ui'; import AccountContainer from 'soapbox/containers/account-container'; import { isCurrentOrFutureDate } from 'soapbox/features/compose/components/schedule-form'; -import ComposeEditor from 'soapbox/features/compose/editor'; import BundleContainer from 'soapbox/features/ui/containers/bundle-container'; -import { DatePicker } from 'soapbox/features/ui/util/async-components'; +import { ComposeEditor, DatePicker } from 'soapbox/features/ui/util/async-components'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import UploadButton from './upload-button'; @@ -236,14 +235,18 @@ const ComposeEventModal: React.FC = ({ onClose }) => { } > - + + {(Component: any) => ( + + )} + } diff --git a/app/soapbox/features/ui/util/async-components.ts b/app/soapbox/features/ui/util/async-components.ts index 4891185fa..4efd47413 100644 --- a/app/soapbox/features/ui/util/async-components.ts +++ b/app/soapbox/features/ui/util/async-components.ts @@ -641,3 +641,7 @@ export function EditAnnouncementModal() { export function FollowedTags() { return import(/* webpackChunkName: "features/followed-tags" */'../../followed-tags'); } + +export function ComposeEditor() { + return import(/* webpackChunkName: "lexical" */'../../compose/editor'); +}