kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Lexical: load editor async
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>environments/review-lexical-ujdd17/deployments/3995
rodzic
d5d6f89707
commit
43a656a9c3
|
@ -17,6 +17,8 @@ import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest
|
||||||
import AutosuggestTextarea from 'soapbox/components/autosuggest-textarea';
|
import AutosuggestTextarea from 'soapbox/components/autosuggest-textarea';
|
||||||
import { Button, HStack, Stack } from 'soapbox/components/ui';
|
import { Button, HStack, Stack } from 'soapbox/components/ui';
|
||||||
import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container';
|
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 { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, usePrevious, useSettings } from 'soapbox/hooks';
|
||||||
import { isMobile } from 'soapbox/is-mobile';
|
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 ScheduleFormContainer from '../containers/schedule-form-container';
|
||||||
import UploadButtonContainer from '../containers/upload-button-container';
|
import UploadButtonContainer from '../containers/upload-button-container';
|
||||||
import WarningContainer from '../containers/warning-container';
|
import WarningContainer from '../containers/warning-container';
|
||||||
import ComposeEditor from '../editor';
|
|
||||||
import { countableText } from '../util/counter';
|
import { countableText } from '../util/counter';
|
||||||
|
|
||||||
import MarkdownButton from './markdown-button';
|
import MarkdownButton from './markdown-button';
|
||||||
|
@ -331,7 +332,9 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
|
|
||||||
{wysiwygEditor ? (
|
{wysiwygEditor ? (
|
||||||
<div>
|
<div>
|
||||||
<ComposeEditor
|
<Bundle fetchComponent={ComposeEditor}>
|
||||||
|
{(Component: any) => (
|
||||||
|
<Component
|
||||||
ref={editorStateRef}
|
ref={editorStateRef}
|
||||||
className='my-2'
|
className='my-2'
|
||||||
composeId={id}
|
composeId={id}
|
||||||
|
@ -343,6 +346,8 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
onFocus={handleComposeFocus}
|
onFocus={handleComposeFocus}
|
||||||
onPaste={onPaste}
|
onPaste={onPaste}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</Bundle>
|
||||||
{composeModifiers}
|
{composeModifiers}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -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 { 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 AccountContainer from 'soapbox/containers/account-container';
|
||||||
import { isCurrentOrFutureDate } from 'soapbox/features/compose/components/schedule-form';
|
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 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 { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
import UploadButton from './upload-button';
|
import UploadButton from './upload-button';
|
||||||
|
@ -236,7 +235,9 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
|
||||||
<FormGroup
|
<FormGroup
|
||||||
labelText={<FormattedMessage id='compose_event.fields.description_label' defaultMessage='Event description' />}
|
labelText={<FormattedMessage id='compose_event.fields.description_label' defaultMessage='Event description' />}
|
||||||
>
|
>
|
||||||
<ComposeEditor
|
<BundleContainer fetchComponent={ComposeEditor}>
|
||||||
|
{(Component: any) => (
|
||||||
|
<Component
|
||||||
ref={editorStateRef}
|
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'
|
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'
|
placeholderClassName='pt-2'
|
||||||
|
@ -244,6 +245,8 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
|
||||||
placeholder={intl.formatMessage(messages.eventDescriptionPlaceholder)}
|
placeholder={intl.formatMessage(messages.eventDescriptionPlaceholder)}
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</BundleContainer>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
labelText={<FormattedMessage id='compose_event.fields.location_label' defaultMessage='Event location' />}
|
labelText={<FormattedMessage id='compose_event.fields.location_label' defaultMessage='Event location' />}
|
||||||
|
|
|
@ -641,3 +641,7 @@ export function EditAnnouncementModal() {
|
||||||
export function FollowedTags() {
|
export function FollowedTags() {
|
||||||
return import(/* webpackChunkName: "features/followed-tags" */'../../followed-tags');
|
return import(/* webpackChunkName: "features/followed-tags" */'../../followed-tags');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ComposeEditor() {
|
||||||
|
return import(/* webpackChunkName: "lexical" */'../../compose/editor');
|
||||||
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue