wip lexical

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak
2023-01-01 23:01:21 +01:00
parent 0b6f12ecae
commit fa2afbd629
10 changed files with 443 additions and 331 deletions

View File

@ -29,7 +29,6 @@ import ComposeEditor from '../editor';
import { countableText } from '../util/counter';
import EmojiPickerDropdown from './emoji-picker/emoji-picker-dropdown';
import MarkdownButton from './markdown-button';
import PollButton from './poll-button';
import PollForm from './polls/poll-form';
import PrivacyDropdown from './privacy-dropdown';
@ -42,7 +41,6 @@ import UploadForm from './upload-form';
import VisualCharacterCounter from './visual-character-counter';
import Warning from './warning';
import type { EditorState } from 'lexical';
import type { Emoji } from 'soapbox/components/autosuggest-emoji';
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
@ -139,8 +137,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
};
const handleSubmit = (e?: React.FormEvent<Element>) => {
// editorStateRef.current
console.log(editorStateRef.current);
dispatch(changeCompose(id, editorStateRef.current!));
// if (text !== autosuggestTextareaRef.current?.textarea?.value) {
// // Something changed the text inside the textarea (e.g. browser extensions like Grammarly)
@ -237,7 +233,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
{features.privacyScopes && <PrivacyDropdown composeId={id} />}
{features.scheduledStatuses && <ScheduleButton composeId={id} />}
{features.spoilers && <SpoilerButton composeId={id} />}
{features.richText && <MarkdownButton composeId={id} />}
</HStack>
), [features, id]);
@ -248,24 +243,17 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
const shouldAutoFocus = autoFocus && !showSearch && !isMobile(window.innerWidth);
let publishText: string | JSX.Element = '';
let publishIcon: string | undefined = undefined;
let textareaPlaceholder: MessageDescriptor;
if (isEditing) {
publishText = intl.formatMessage(messages.saveChanges);
} else if (privacy === 'direct') {
publishText = (
<>
<Icon src={require('@tabler/icons/mail.svg')} />
{intl.formatMessage(messages.message)}
</>
);
publishIcon = require('@tabler/icons/mail.svg');
publishText = intl.formatMessage(messages.message);
} else if (privacy === 'private') {
publishText = (
<>
<Icon src={require('@tabler/icons/lock.svg')} />
{intl.formatMessage(messages.publish)}
</>
);
publishIcon = require('@tabler/icons/lock.svg');
publishText = intl.formatMessage(messages.publish);
} else {
publishText = privacy !== 'unlisted' ? intl.formatMessage(messages.publishLoud, { publish: intl.formatMessage(messages.publish) }) : intl.formatMessage(messages.publish);
}
@ -309,7 +297,29 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
{!shouldCondense && !event && <ReplyMentions composeId={id} />}
<ComposeEditor ref={editorStateRef} />
<div>
<ComposeEditor
ref={editorStateRef}
condensed={condensed}
onFocus={handleComposeFocus}
/>
{
!condensed &&
<Stack space={4} className='compose-form__modifiers'>
<UploadForm composeId={id} />
<PollForm composeId={id} />
<ScheduleFormContainer composeId={id} />
<SpoilerInput
composeId={id}
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
onSuggestionsClearRequested={onSuggestionsClearRequested}
onSuggestionSelected={onSpoilerSuggestionSelected}
ref={spoilerTextRef}
/>
</Stack>
}
</div>
<AutosuggestTextarea
ref={(isModalOpen && shouldCondense) ? undefined : autosuggestTextareaRef}
@ -327,24 +337,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
autoFocus={shouldAutoFocus}
condensed={condensed}
id='compose-textarea'
>
{
!condensed &&
<Stack space={4} className='compose-form__modifiers'>
<UploadForm composeId={id} />
<PollForm composeId={id} />
<ScheduleFormContainer composeId={id} />
<SpoilerInput
composeId={id}
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
onSuggestionsClearRequested={onSuggestionsClearRequested}
onSuggestionSelected={onSpoilerSuggestionSelected}
ref={spoilerTextRef}
/>
</Stack>
}
</AutosuggestTextarea>
/>
<QuotedStatusContainer composeId={id} />
@ -363,7 +356,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
</HStack>
)}
<Button type='submit' theme='primary' text={publishText} disabled={disabledButton} />
<Button type='submit' theme='primary' icon={publishIcon} text={publishText} disabled={disabledButton} />
</HStack>
{/* <HStack alignItems='center' space={4}>
</HStack> */}

View File

@ -1,37 +0,0 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { changeComposeContentType } from 'soapbox/actions/compose';
import { useAppDispatch, useCompose } from 'soapbox/hooks';
import ComposeFormButton from './compose-form-button';
const messages = defineMessages({
marked: { id: 'compose_form.markdown.marked', defaultMessage: 'Post markdown enabled' },
unmarked: { id: 'compose_form.markdown.unmarked', defaultMessage: 'Post markdown disabled' },
});
interface IMarkdownButton {
composeId: string,
}
const MarkdownButton: React.FC<IMarkdownButton> = ({ composeId }) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const active = useCompose(composeId).content_type === 'text/markdown';
const onClick = () => dispatch(changeComposeContentType(composeId, active ? 'text/plain' : 'text/markdown'));
return (
<ComposeFormButton
icon={require('@tabler/icons/markdown.svg')}
title={intl.formatMessage(active ? messages.marked : messages.unmarked)}
active={active}
onClick={onClick}
/>
);
};
export default MarkdownButton;

View File

@ -2,29 +2,44 @@ import {
$convertToMarkdownString,
TRANSFORMERS,
} from '@lexical/markdown';
import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { LexicalComposer, InitialConfigType } from '@lexical/react/LexicalComposer';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
import classNames from 'clsx';
import React, { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { useFeatures } from 'soapbox/hooks';
import nodes from './nodes';
import FloatingLinkEditorPlugin from './plugins/floating-link-editor-plugin';
import FloatingTextFormatToolbarPlugin from './plugins/floating-text-format-toolbar-plugin';
// import type { EditorState } from 'lexical';
const initialConfig = {
const initialConfig: InitialConfigType = {
namespace: 'ComposeForm',
onError: console.error,
nodes,
theme: {
text: {
bold: 'font-bold',
code: 'font-mono',
italic: 'italic',
strikethrough: 'line-through',
underline: 'underline',
underlineStrikethrough: 'underline-line-through',
},
},
};
const ComposeEditor = React.forwardRef<string, any>((_, editorStateRef) => {
const ComposeEditor = React.forwardRef<string, any>(({ condensed, onFocus }, editorStateRef) => {
const features = useFeatures();
const [floatingAnchorElem, setFloatingAnchorElem] =
useState<HTMLDivElement | null>(null);
@ -36,11 +51,16 @@ const ComposeEditor = React.forwardRef<string, any>((_, editorStateRef) => {
return (
<LexicalComposer initialConfig={initialConfig}>
<div className='relative' data-markup>
<div className='lexical relative' data-markup>
<RichTextPlugin
contentEditable={
<div className='editor' ref={onRef}>
<ContentEditable className='outline-none py-2 min-h-[100px]' />
<div className='editor' ref={onRef} onFocus={onFocus}>
<ContentEditable
className={classNames('outline-none py-2 transition-[min-height] motion-reduce:transition-none', {
'min-h-[40px]': condensed,
'min-h-[100px]': !condensed,
})}
/>
</div>
}
placeholder={(
@ -57,13 +77,13 @@ const ComposeEditor = React.forwardRef<string, any>((_, editorStateRef) => {
}}
/>
<HistoryPlugin />
<LinkPlugin />
{floatingAnchorElem ? (
{features.richText && <LinkPlugin />}
{features.richText && floatingAnchorElem && (
<>
<FloatingTextFormatToolbarPlugin anchorElem={floatingAnchorElem} />
<FloatingLinkEditorPlugin anchorElem={floatingAnchorElem} />
</>
) : ''}
)}
</div>
</LexicalComposer>
);