Lexical: load editor async
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
d5d6f89707
commit
43a656a9c3
4 changed files with 104 additions and 23 deletions
|
@ -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 extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
|
||||
{wysiwygEditor ? (
|
||||
<div>
|
||||
<ComposeEditor
|
||||
ref={editorStateRef}
|
||||
className='my-2'
|
||||
composeId={id}
|
||||
condensed={condensed}
|
||||
eventDiscussion={!!event}
|
||||
autoFocus={shouldAutoFocus}
|
||||
hasPoll={hasPoll}
|
||||
handleSubmit={handleSubmit}
|
||||
onFocus={handleComposeFocus}
|
||||
onPaste={onPaste}
|
||||
/>
|
||||
<Bundle fetchComponent={ComposeEditor}>
|
||||
{(Component: any) => (
|
||||
<Component
|
||||
ref={editorStateRef}
|
||||
className='my-2'
|
||||
composeId={id}
|
||||
condensed={condensed}
|
||||
eventDiscussion={!!event}
|
||||
autoFocus={shouldAutoFocus}
|
||||
hasPoll={hasPoll}
|
||||
handleSubmit={handleSubmit}
|
||||
onFocus={handleComposeFocus}
|
||||
onPaste={onPaste}
|
||||
/>
|
||||
)}
|
||||
</Bundle>
|
||||
{composeModifiers}
|
||||
</div>
|
||||
) : (
|
||||
|
|
69
app/soapbox/features/compose/editor/nodes/mention-node.ts
Normal file
69
app/soapbox/features/compose/editor/nodes/mention-node.ts
Normal file
|
@ -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 };
|
|
@ -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<IComposeEventModal> = ({ onClose }) => {
|
|||
<FormGroup
|
||||
labelText={<FormattedMessage id='compose_event.fields.description_label' defaultMessage='Event description' />}
|
||||
>
|
||||
<ComposeEditor
|
||||
ref={editorStateRef}
|
||||
className='block w-full rounded-md border border-gray-400 bg-white px-3 py-2 text-base text-gray-900 ring-1 placeholder:text-gray-600 focus-within:border-primary-500 focus-within:ring-primary-500 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500 sm:text-sm'
|
||||
placeholderClassName='pt-2'
|
||||
composeId='compose-event-modal'
|
||||
placeholder={intl.formatMessage(messages.eventDescriptionPlaceholder)}
|
||||
handleSubmit={handleSubmit}
|
||||
/>
|
||||
<BundleContainer fetchComponent={ComposeEditor}>
|
||||
{(Component: any) => (
|
||||
<Component
|
||||
ref={editorStateRef}
|
||||
className='block w-full rounded-md border border-gray-400 bg-white px-3 py-2 text-base text-gray-900 ring-1 placeholder:text-gray-600 focus-within:border-primary-500 focus-within:ring-primary-500 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500 sm:text-sm'
|
||||
placeholderClassName='pt-2'
|
||||
composeId='compose-event-modal'
|
||||
placeholder={intl.formatMessage(messages.eventDescriptionPlaceholder)}
|
||||
handleSubmit={handleSubmit}
|
||||
/>
|
||||
)}
|
||||
</BundleContainer>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
labelText={<FormattedMessage id='compose_event.fields.location_label' defaultMessage='Event location' />}
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue