From 731489554950980b98d90bb97c1acc8e99566e48 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Mon, 14 Oct 2024 16:53:29 +0800 Subject: [PATCH] =?UTF-8?q?=E9=82=AE=E4=BB=B6=E7=BC=96=E8=BE=91:=20?= =?UTF-8?q?=E5=AD=97=E4=BD=93=E9=A2=9C=E8=89=B2;=20=E8=83=8C=E6=99=AF?= =?UTF-8?q?=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LexicalEditor/plugins/ToolbarPlugin.jsx | 520 ++++++++++-------- src/components/LexicalEditor/styles.css | 38 +- .../LexicalEditor/ui/ColorPicker.css | 88 +++ .../LexicalEditor/ui/ColorPicker.tsx | 364 ++++++++++++ src/components/LexicalEditor/ui/DropDown.tsx | 259 +++++++++ .../LexicalEditor/ui/DropdownColorPicker.tsx | 41 ++ src/components/LexicalEditor/ui/Input.css | 32 ++ src/components/LexicalEditor/ui/TextInput.tsx | 46 ++ 8 files changed, 1168 insertions(+), 220 deletions(-) create mode 100644 src/components/LexicalEditor/ui/ColorPicker.css create mode 100644 src/components/LexicalEditor/ui/ColorPicker.tsx create mode 100644 src/components/LexicalEditor/ui/DropDown.tsx create mode 100644 src/components/LexicalEditor/ui/DropdownColorPicker.tsx create mode 100644 src/components/LexicalEditor/ui/Input.css create mode 100644 src/components/LexicalEditor/ui/TextInput.tsx diff --git a/src/components/LexicalEditor/plugins/ToolbarPlugin.jsx b/src/components/LexicalEditor/plugins/ToolbarPlugin.jsx index bafc0ef..94c2474 100644 --- a/src/components/LexicalEditor/plugins/ToolbarPlugin.jsx +++ b/src/components/LexicalEditor/plugins/ToolbarPlugin.jsx @@ -1,5 +1,5 @@ -import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { CAN_REDO_COMMAND, CAN_UNDO_COMMAND, @@ -8,80 +8,71 @@ import { SELECTION_CHANGE_COMMAND, FORMAT_TEXT_COMMAND, FORMAT_ELEMENT_COMMAND, + OUTDENT_CONTENT_COMMAND, + INDENT_CONTENT_COMMAND, $getSelection, + $isElementNode, $isRangeSelection, $createParagraphNode, - $getNodeByKey -} from "lexical"; -import { $isLinkNode, TOGGLE_LINK_COMMAND } from "@lexical/link"; + $getNodeByKey, +} from 'lexical'; +import { $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link'; import { + $getSelectionStyleValueForProperty, $isParentElementRTL, - $wrapNodes, - $isAtNodeEnd -} from "@lexical/selection"; -import { $getNearestNodeOfType, mergeRegister, } from "@lexical/utils"; -import { - INSERT_ORDERED_LIST_COMMAND, - INSERT_UNORDERED_LIST_COMMAND, - REMOVE_LIST_COMMAND, - $isListNode, - ListNode -} from "@lexical/list"; -import { createPortal } from "react-dom"; -import { - $createHeadingNode, - $createQuoteNode, - $isHeadingNode -} from "@lexical/rich-text"; -import { - $createCodeNode, - $isCodeNode, - getDefaultCodeLanguage, - getCodeLanguages -} from "@lexical/code"; -import { INSERT_HORIZONTAL_RULE_COMMAND, } from '@lexical/react/LexicalHorizontalRuleNode'; + $patchStyleText, + $setBlocksType, + // $wrapNodes, + $isAtNodeEnd, +} from '@lexical/selection'; +import { $findMatchingParent, $getNearestNodeOfType, mergeRegister } from '@lexical/utils'; +import { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, REMOVE_LIST_COMMAND, $isListNode, ListNode } from '@lexical/list'; +import { createPortal } from 'react-dom'; +import { $createHeadingNode, $createQuoteNode, $isHeadingNode } from '@lexical/rich-text'; +import { $createCodeNode, $isCodeNode, getDefaultCodeLanguage, getCodeLanguages } from '@lexical/code'; +import { INSERT_HORIZONTAL_RULE_COMMAND } from '@lexical/react/LexicalHorizontalRuleNode'; +import DropDown, { DropDownItem } from './../ui/DropDown'; +import DropdownColorPicker from '../ui/DropdownColorPicker'; const LowPriority = 1; -const supportedBlockTypes = new Set([ - "paragraph", - "quote", - "code", - "h1", - "h2", - "h3", - "ul", - "ol" -]); +const supportedBlockTypes = new Set(['paragraph', 'quote', 'code', 'h1', 'h2', 'h3', 'ul', 'ol']); const blockTypeToBlockName = { - code: "Code Block", - h1: "Large Heading", - h2: "Small Heading", - h3: "Heading", - h4: "Heading", - h5: "Heading", - ol: "Numbered List", - paragraph: "Normal", - quote: "Quote", - ul: "Bulleted List" + code: 'Code Block', + h1: 'Large Heading', + h2: 'Small Heading', + h3: 'Heading', + h4: 'Heading', + h5: 'Heading', + ol: 'Numbered List', + paragraph: 'Normal', + quote: 'Quote', + ul: 'Bulleted List', +}; + +const ELEMENT_FORMAT_OPTIONS = { + center: { icon: 'center-align', iconRTL: 'center-align', name: 'Center Align' }, + end: { icon: 'right-align', iconRTL: 'left-align', name: 'End Align' }, + justify: { icon: 'justify-align', iconRTL: 'justify-align', name: 'Justify Align' }, + left: { icon: 'left-align', iconRTL: 'left-align', name: 'Left Align' }, + right: { icon: 'right-align', iconRTL: 'right-align', name: 'Right Align' }, + start: { icon: 'left-align', iconRTL: 'right-align', name: 'Start Align' }, }; function Divider() { - return
; + return
; } function positionEditorElement(editor, rect) { if (rect === null) { - editor.style.opacity = "0"; - editor.style.top = "-1000px"; - editor.style.left = "-1000px"; + editor.style.opacity = '0'; + editor.style.top = '-1000px'; + editor.style.left = '-1000px'; } else { - editor.style.opacity = "1"; + editor.style.opacity = '1'; editor.style.top = `${rect.top + rect.height + window.pageYOffset + 10}px`; - editor.style.left = `${ - rect.left + window.pageXOffset - editor.offsetWidth / 2 + rect.width / 2 - }px`; + editor.style.left = `${rect.left + window.pageXOffset - editor.offsetWidth / 2 + rect.width / 2}px`; } } @@ -89,7 +80,7 @@ function FloatingLinkEditor({ editor }) { const editorRef = useRef(null); const inputRef = useRef(null); const mouseDownRef = useRef(false); - const [linkUrl, setLinkUrl] = useState(""); + const [linkUrl, setLinkUrl] = useState(''); const [isEditMode, setEditMode] = useState(false); const [lastSelection, setLastSelection] = useState(null); @@ -103,7 +94,7 @@ function FloatingLinkEditor({ editor }) { } else if ($isLinkNode(node)) { setLinkUrl(node.getURL()); } else { - setLinkUrl(""); + setLinkUrl(''); } } const editorElem = editorRef.current; @@ -115,12 +106,7 @@ function FloatingLinkEditor({ editor }) { } const rootElement = editor.getRootElement(); - if ( - selection !== null && - !nativeSelection.isCollapsed && - rootElement !== null && - rootElement.contains(nativeSelection.anchorNode) - ) { + if (selection !== null && !nativeSelection.isCollapsed && rootElement !== null && rootElement.contains(nativeSelection.anchorNode)) { const domRange = nativeSelection.getRangeAt(0); let rect; if (nativeSelection.anchorNode === rootElement) { @@ -137,11 +123,11 @@ function FloatingLinkEditor({ editor }) { positionEditorElement(editorElem, rect); } setLastSelection(selection); - } else if (!activeElement || activeElement.className !== "link-input") { + } else if (!activeElement || activeElement.className !== 'link-input') { positionEditorElement(editorElem, null); setLastSelection(null); setEditMode(false); - setLinkUrl(""); + setLinkUrl(''); } return true; @@ -179,25 +165,25 @@ function FloatingLinkEditor({ editor }) { }, [isEditMode]); return ( -
+
{isEditMode ? ( { setLinkUrl(event.target.value); }} onKeyDown={(event) => { - if (event.key === "Enter") { + if (event.key === 'Enter') { event.preventDefault(); if (lastSelection !== null) { - if (linkUrl !== "") { + if (linkUrl !== '') { editor.dispatchCommand(TOGGLE_LINK_COMMAND, linkUrl); } setEditMode(false); } - } else if (event.key === "Escape") { + } else if (event.key === 'Escape') { event.preventDefault(); setEditMode(false); } @@ -205,13 +191,13 @@ function FloatingLinkEditor({ editor }) { /> ) : ( <> -
- +
+ {linkUrl}
event.preventDefault()} onClick={() => { @@ -228,7 +214,7 @@ function FloatingLinkEditor({ editor }) { function Select({ onChange, className, options, value }) { return ( - + { + onChange(e.target.value); + }} + data-test-id={dataTestId} + /> +
+ ); +}