Files
CyyNote/cyynote-frontend/src/components/lexical/Editor.tsx
T
2026-04-29 14:58:02 +08:00

279 lines
11 KiB
TypeScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
import {CharacterLimitPlugin} from '@lexical/react/LexicalCharacterLimitPlugin';
import {CheckListPlugin} from '@lexical/react/LexicalCheckListPlugin';
import {ClearEditorPlugin} from '@lexical/react/LexicalClearEditorPlugin';
import LexicalClickableLinkPlugin from '@lexical/react/LexicalClickableLinkPlugin';
import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin';
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
import {HashtagPlugin} from '@lexical/react/LexicalHashtagPlugin';
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
import {HorizontalRulePlugin} from '@lexical/react/LexicalHorizontalRulePlugin';
import {ListPlugin} from '@lexical/react/LexicalListPlugin';
import {PlainTextPlugin} from '@lexical/react/LexicalPlainTextPlugin';
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
import {TabIndentationPlugin} from '@lexical/react/LexicalTabIndentationPlugin';
import {TablePlugin} from '@lexical/react/LexicalTablePlugin';
import useLexicalEditable from '@lexical/react/useLexicalEditable';
import {useEffect, useState,useLayoutEffect} from 'react';
import {CAN_USE_DOM} from './shared/src/canUseDOM';
import {createWebsocketProvider} from './collaboration';
import {useSettings} from './context/SettingsContext';
import {useSharedHistoryContext} from './context/SharedHistoryContext';
import ActionsPlugin from './plugins/ActionsPlugin';
import AutocompletePlugin from './plugins/AutocompletePlugin';
import AutoEmbedPlugin from './plugins/AutoEmbedPlugin';
import AutoLinkPlugin from './plugins/AutoLinkPlugin';
import CodeActionMenuPlugin from './plugins/CodeActionMenuPlugin';
import CodeHighlightPlugin from './plugins/CodeHighlightPlugin';
import CollapsiblePlugin from './plugins/CollapsiblePlugin';
import CommentPlugin from './plugins/CommentPlugin';
import ComponentPickerPlugin from './plugins/ComponentPickerPlugin';
import ContextMenuPlugin from './plugins/ContextMenuPlugin';
import DragDropPaste from './plugins/DragDropPastePlugin';
import DraggableBlockPlugin from './plugins/DraggableBlockPlugin';
import EmojiPickerPlugin from './plugins/EmojiPickerPlugin';
import EmojisPlugin from './plugins/EmojisPlugin';
import EquationsPlugin from './plugins/EquationsPlugin';
import ExcalidrawPlugin from './plugins/ExcalidrawPlugin';
import FigmaPlugin from './plugins/FigmaPlugin';
import FloatingLinkEditorPlugin from './plugins/FloatingLinkEditorPlugin';
import FloatingTextFormatToolbarPlugin from './plugins/FloatingTextFormatToolbarPlugin';
import ImagesPlugin from './plugins/ImagesPlugin';
import InlineImagePlugin from './plugins/InlineImagePlugin';
import KeywordsPlugin from './plugins/KeywordsPlugin';
import {LayoutPlugin} from './plugins/LayoutPlugin/LayoutPlugin';
import LinkPlugin from './plugins/LinkPlugin';
import ListMaxIndentLevelPlugin from './plugins/ListMaxIndentLevelPlugin';
import MarkdownShortcutPlugin from './plugins/MarkdownShortcutPlugin';
import {MaxLengthPlugin} from './plugins/MaxLengthPlugin';
import MentionsPlugin from './plugins/MentionsPlugin';
import PageBreakPlugin from './plugins/PageBreakPlugin';
import PollPlugin from './plugins/PollPlugin';
import SpeechToTextPlugin from './plugins/SpeechToTextPlugin';
import TabFocusPlugin from './plugins/TabFocusPlugin';
import TableCellActionMenuPlugin from './plugins/TableActionMenuPlugin';
import TableCellResizer from './plugins/TableCellResizer';
import TableOfContentsPlugin from './plugins/TableOfContentsPlugin';
import ToolbarPlugin from './plugins/ToolbarPlugin';
import TreeViewPlugin from './plugins/TreeViewPlugin';
import TwitterPlugin from './plugins/TwitterPlugin';
import YouTubePlugin from './plugins/YouTubePlugin';
import ContentEditable from './ui/ContentEditable';
import Placeholder from './ui/Placeholder';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import GlobalEventsPlugin from "./plugins/GlobalEventsPlugin";
const skipCollaborationInit =
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
window.parent != null && window.parent.frames.right === window;
function OnChangePlugin({ onChange }) {
const [editor] = useLexicalComposerContext();
useEffect(() => {
return editor.registerUpdateListener(({editorState}) => {
onChange(editorState);
});
}, [editor, onChange]);
}
export default function Editor(props: { noteId: bigint; noteTitle: string; editData: any; handleLawClick_item2: any; }): JSX.Element {
const [editor] = useLexicalComposerContext();
console.log(props.noteId)
const {historyState} = useSharedHistoryContext();
const {
settings: {
isCollab,
isAutocomplete,
isMaxLength,
isCharLimit,
isCharLimitUtf8,
isRichText,
showTreeView,
showTableOfContents,
shouldUseLexicalContextMenu,
tableCellMerge,
tableCellBackgroundColor,
},
} = useSettings();
const isEditable = useLexicalEditable();
const text = isCollab
? 'Enter some collaborative rich text...'
: isRichText
? 'Enter some rich text...'
: 'Enter some plain text...';
const placeholder = <Placeholder>{text}</Placeholder>;
const [floatingAnchorElem, setFloatingAnchorElem] =
useState<HTMLDivElement | null>(null);
const [isSmallWidthViewport, setIsSmallWidthViewport] =
useState<boolean>(false);
const [isLinkEditMode, setIsLinkEditMode] = useState<boolean>(false);
const [editorState, setEditorState] = useState();
const onRef = (_floatingAnchorElem: HTMLDivElement) => {
if (_floatingAnchorElem !== null) {
setFloatingAnchorElem(_floatingAnchorElem);
}
};
useEffect(() => {
const updateViewPortWidth = () => {
const isNextSmallWidthViewport =
CAN_USE_DOM && window.matchMedia('(max-width: 1025px)').matches;
if (isNextSmallWidthViewport !== isSmallWidthViewport) {
setIsSmallWidthViewport(isNextSmallWidthViewport);
}
};
updateViewPortWidth();
window.addEventListener('resize', updateViewPortWidth);
return () => {
window.removeEventListener('resize', updateViewPortWidth);
};
}, [isSmallWidthViewport]);
function onChange(editorState) {
// Call toJSON on the EditorState object, which produces a serialization safe string
const editorStateJSON = editorState.toJSON();
// However, we still have a JavaScript object, so we need to convert it to an actual string with JSON.stringify
setEditorState(JSON.stringify(editorStateJSON));
}
console.log(props.noteId)
// console.log(props.editData)
return (
<>
{isRichText && <ToolbarPlugin setIsLinkEditMode={setIsLinkEditMode} />}
<div
className={`editor-container ${showTreeView ? 'tree-view' : ''} ${
!isRichText ? 'plain-text' : ''
}`}>
{isMaxLength && <MaxLengthPlugin maxLength={30} />}
<DragDropPaste />
<AutoFocusPlugin />
<ClearEditorPlugin />
<ComponentPickerPlugin />
<EmojiPickerPlugin />
<AutoEmbedPlugin />
<MentionsPlugin />
<EmojisPlugin />
<HashtagPlugin />
<KeywordsPlugin />
<SpeechToTextPlugin />
<AutoLinkPlugin />
<CommentPlugin
providerFactory={isCollab ? createWebsocketProvider : undefined}
/>
{isRichText ? (
<>
{isCollab ? (
<CollaborationPlugin
id="main"
providerFactory={createWebsocketProvider}
shouldBootstrap={!skipCollaborationInit}
/>
) : (
<HistoryPlugin externalHistoryState={historyState} />
)}
<RichTextPlugin
contentEditable={
<div className="editor-scroller">
<div className="editor" ref={onRef}>
<ContentEditable />
</div>
</div>
}
placeholder={placeholder}
ErrorBoundary={LexicalErrorBoundary}
/>
<MarkdownShortcutPlugin />
<CodeHighlightPlugin />
<ListPlugin />
<CheckListPlugin />
<ListMaxIndentLevelPlugin maxDepth={7} />
<TablePlugin
hasCellMerge={tableCellMerge}
hasCellBackgroundColor={tableCellBackgroundColor}
/>
<TableCellResizer />
<ImagesPlugin />
<InlineImagePlugin />
<LinkPlugin />
<PollPlugin />
<TwitterPlugin />
<YouTubePlugin />
<FigmaPlugin />
{!isEditable && <LexicalClickableLinkPlugin />}
<HorizontalRulePlugin />
<EquationsPlugin />
<ExcalidrawPlugin />
<TabFocusPlugin />
<TabIndentationPlugin />
<CollapsiblePlugin />
<PageBreakPlugin />
<LayoutPlugin />
<OnChangePlugin onChange={onChange}/>
<GlobalEventsPlugin />
{floatingAnchorElem && !isSmallWidthViewport && (
<>
<DraggableBlockPlugin anchorElem={floatingAnchorElem} />
<CodeActionMenuPlugin anchorElem={floatingAnchorElem} />
<FloatingLinkEditorPlugin
anchorElem={floatingAnchorElem}
isLinkEditMode={isLinkEditMode}
setIsLinkEditMode={setIsLinkEditMode}
/>
<TableCellActionMenuPlugin
anchorElem={floatingAnchorElem}
cellMerge={true}
/>
<FloatingTextFormatToolbarPlugin
anchorElem={floatingAnchorElem}
/>
</>
)}
</>
) : (
<>
<PlainTextPlugin
contentEditable={<ContentEditable />}
placeholder={placeholder}
ErrorBoundary={LexicalErrorBoundary}
/>
<HistoryPlugin externalHistoryState={historyState} />
</>
)}
{(isCharLimit || isCharLimitUtf8) && (
<CharacterLimitPlugin
charset={isCharLimit ? 'UTF-16' : 'UTF-8'}
maxLength={5}
/>
)}
{isAutocomplete && <AutocompletePlugin />}
<div>{showTableOfContents && <TableOfContentsPlugin />}</div>
{shouldUseLexicalContextMenu && <ContextMenuPlugin />}
<ActionsPlugin isRichText={isRichText} noteId={props.noteId} noteTitle={props.noteTitle} editData ={props.editData} handleLawClick_item3={props.handleLawClick_item2}/>
</div>
{showTreeView && <TreeViewPlugin />}
</>
);
}