1- import "doc-editor-plugin/dist/styles/index" ;
2-
31import { Modal } from "@arco-design/web-react" ;
42import { IconLaunch } from "@arco-design/web-react/icon" ;
5- import { useMemoizedFn } from "ahooks" ;
6- import { Editable , useMakeEditor } from "doc-editor-core" ;
7- import type { BaseNode , BlockElement } from "doc-editor-delta" ;
8- import {
9- BoldPlugin ,
10- FontBasePlugin ,
11- HeadingPlugin ,
12- HyperLinkPlugin ,
13- InlineCodePlugin ,
14- ItalicPlugin ,
15- LineHeightPlugin ,
16- MenuToolBar ,
17- OrderedListPlugin ,
18- ParagraphPlugin ,
19- QuoteBlockPlugin ,
20- ShortCutPlugin ,
21- StrikeThroughPlugin ,
22- UnderLinePlugin ,
23- UnorderedListPlugin ,
24- } from "doc-editor-plugin" ;
3+ import type { Delta as BlockDelta } from "@block-kit/delta" ;
254import type { FC } from "react" ;
265import React , { useMemo , useRef , useState } from "react" ;
27- import type { DeltaState , Editor } from "sketching-core" ;
28- import type { DeltaAttributes } from "sketching-delta " ;
29- import { Op , OP_TYPE } from "sketching-delta " ;
6+ import type { DeltaState } from "sketching-core" ;
7+ import type { Editor } from "sketching-core " ;
8+ import type { RichTextLines } from "sketching-plugin " ;
309import { TEXT_ATTRS } from "sketching-plugin" ;
31- import { debounce , TSON } from "sketching-utils" ;
10+ import { TSON } from "sketching-utils" ;
3211
33- import { useIsMounted } from "../../../../hooks/is-mounted" ;
3412import styles from "../index.m.scss" ;
35- import { schema } from "./config/schema " ;
36- import { DividingLinePlugin } from "./plugins/dividing-line " ;
37- import { blocksToLines } from "./slate-kit " ;
13+ import { RichTextEditor } from "./modules/editor " ;
14+ import { getDefaultTextDelta } from "./utils/constant " ;
15+ import { sketchToTextDelta } from "./utils/transform " ;
3816
3917export const Text : FC < { editor : Editor ; state : DeltaState } > = ( { editor, state } ) => {
40- const { isMounted } = useIsMounted ( ) ;
4118 const [ visible , setVisible ] = useState ( false ) ;
42- const dataRef = useRef < BlockElement [ ] > ( [ ] ) ;
43-
44- useMemo ( ( ) => {
45- const data = state . getAttr ( TEXT_ATTRS . ORIGIN_DATA ) ;
46- const blocks = data && TSON . parse < BlockElement [ ] > ( data ) ;
47- if ( blocks ) dataRef . current = blocks ;
48- else dataRef . current = [ { children : [ { text : "" } ] } ] as BlockElement [ ] ;
49- } , [ state ] ) ;
19+ const dataRef = useRef < BlockDelta | null > ( null ) ;
5020
51- const richText = useMakeEditor ( schema , dataRef . current ) ;
5221 useMemo ( ( ) => {
53- richText . plugin . register (
54- ParagraphPlugin ( ) ,
55- HeadingPlugin ( richText ) ,
56- BoldPlugin ( ) ,
57- QuoteBlockPlugin ( richText ) ,
58- HyperLinkPlugin ( richText , false ) ,
59- UnderLinePlugin ( ) ,
60- StrikeThroughPlugin ( ) ,
61- ItalicPlugin ( ) ,
62- InlineCodePlugin ( ) ,
63- OrderedListPlugin ( richText ) ,
64- UnorderedListPlugin ( richText ) ,
65- DividingLinePlugin ( ) ,
66- FontBasePlugin ( ) ,
67- LineHeightPlugin ( ) ,
68- ShortCutPlugin ( richText )
69- ) ;
70- } , [ richText ] ) ;
71-
72- const onChange = useMemoizedFn ( ( attrs : DeltaAttributes ) => {
73- // COMPAT: 避免初始化时即触发`onChange`
74- if ( ! isMounted ( ) ) return void 0 ;
75- let allEqual = true ;
76- for ( const [ key , value ] of Object . entries ( attrs ) ) {
77- if ( state . getAttr ( key ) !== value ) {
78- allEqual = false ;
79- break ;
80- }
22+ const data = state . getAttr ( TEXT_ATTRS . DATA ) ;
23+ const blockDelta = data && TSON . parse < RichTextLines > ( data ) ;
24+ if ( blockDelta ) {
25+ dataRef . current = sketchToTextDelta ( blockDelta ) ;
26+ } else {
27+ dataRef . current = getDefaultTextDelta ( ) ;
8128 }
82- if ( allEqual ) return void 0 ;
83- editor . state . apply ( new Op ( OP_TYPE . REVISE , { id : state . id , attrs } ) ) ;
84- } ) ;
85-
86- const updateText = useMemo (
87- ( ) =>
88- debounce ( ( text : BaseNode [ ] ) => {
89- dataRef . current = text as BlockElement [ ] ;
90- // fix: 切换面板会重建`Editable`需要更新初始值
91- richText . init = dataRef . current ;
92- // 双写-空间换时间
93- // @ts -expect-error BlockElement
94- if ( text . length === 1 && text [ 0 ] . children . length === 1 && ! text [ 0 ] . children [ 0 ] . text ) {
95- onChange ( { [ TEXT_ATTRS . DATA ] : null , [ TEXT_ATTRS . ORIGIN_DATA ] : null } ) ;
96- } else {
97- onChange ( {
98- [ TEXT_ATTRS . DATA ] : TSON . stringify ( blocksToLines ( richText , text as BlockElement [ ] ) ) ,
99- [ TEXT_ATTRS . ORIGIN_DATA ] : TSON . stringify ( text ) ,
100- } ) ;
101- }
102- } , 300 ) ,
103- [ onChange , richText ]
104- ) ;
29+ } , [ state ] ) ;
10530
10631 const TextEditor = (
10732 < React . Fragment key = { state . id } >
@@ -111,10 +36,7 @@ export const Text: FC<{ editor: Editor; state: DeltaState }> = ({ editor, state
11136 < IconLaunch className = { styles . launch } onClick = { ( ) => setVisible ( true ) } />
11237 </ div >
11338 ) }
114- < div onClick = { e => e . stopPropagation ( ) } >
115- < MenuToolBar readonly = { false } editor = { richText } > </ MenuToolBar >
116- </ div >
117- < Editable editor = { richText } onChange = { updateText } placeholder = "Enter text ..." > </ Editable >
39+ < RichTextEditor editor = { editor } state = { state } dataRef = { dataRef } > </ RichTextEditor >
11840 </ React . Fragment >
11941 ) ;
12042
0 commit comments