11import { EditorComponent , ImageTool , Tool , editor } from 'edkit' ;
22import { computed , observable } from 'mobx' ;
33import { observer } from 'mobx-react' ;
4- import { InputHTMLAttributes , Component , createRef } from 'react' ;
4+ import { FormComponent , FormComponentProps } from 'mobx-react-helper' ;
5+ import { createRef } from 'react' ;
56import { Constructor , parseDOM } from 'web-utility' ;
67
78import { AudioTool , DefaultTools , VideoTool } from './tools' ;
89
9- export interface EditorProps
10- extends Pick <
11- InputHTMLAttributes < HTMLInputElement > ,
12- 'name' | 'defaultValue'
13- > {
10+ export interface EditorProps extends FormComponentProps {
1411 tools ?: Constructor < Tool > [ ] ;
15- onChange ?: ( value : string ) => any ;
1612}
1713
1814export interface Editor extends EditorComponent { }
1915
2016@observer
2117@editor
22- export class Editor extends Component < EditorProps > implements EditorComponent {
18+ export class Editor
19+ extends FormComponent < EditorProps >
20+ implements EditorComponent
21+ {
2322 static displayName = 'Editor' ;
2423
2524 box = createRef < HTMLDivElement > ( ) ;
2625
2726 @observable
28- accessor toolList : Tool [ ] = [ ] ;
27+ accessor cursorPoint = '' ;
28+
29+ @computed
30+ get toolList ( ) : Tool [ ] {
31+ return ( this . observedProps . tools || DefaultTools ) . map (
32+ ToolButton => new ToolButton ( )
33+ ) ;
34+ }
2935
3036 @computed
3137 get imageTool ( ) {
@@ -48,47 +54,41 @@ export class Editor extends Component<EditorProps> implements EditorComponent {
4854 ) as VideoTool ;
4955 }
5056
51- defaultValue = this . props . defaultValue ;
52-
53- @observable
54- accessor innerValue = this . defaultValue ;
55-
5657 componentDidMount ( ) {
57- this . bootTools ( ) ;
58+ super . componentDidMount ( ) ;
5859
59- if ( this . defaultValue != null )
60- this . box . current . append ( ...parseDOM ( this . defaultValue + '' ) ) ;
60+ const { defaultValue } = this . props ;
6161
62- document . addEventListener ( 'selectionchange' , this . updateTools ) ;
63- }
62+ if ( defaultValue != null )
63+ this . box . current . append ( ... parseDOM ( defaultValue + '' ) ) ;
6464
65- componentDidUpdate ( { tools } : Readonly < EditorProps > ) {
66- if ( tools !== this . props . tools ) this . bootTools ( ) ;
65+ document . addEventListener ( 'selectionchange' , this . updateTools ) ;
6766 }
6867
6968 componentWillUnmount ( ) {
69+ super . componentWillUnmount ( ) ;
70+
7071 document . removeEventListener ( 'selectionchange' , this . updateTools ) ;
7172 }
7273
73- bootTools ( ) {
74- const { tools = DefaultTools } = this . props ;
74+ updateTools = ( ) => {
75+ if ( this . box . current !== document . activeElement ) return ;
7576
76- this . toolList = tools . map ( ToolButton => new ToolButton ( ) ) ;
77- }
77+ const { endContainer } = getSelection ( ) . getRangeAt ( 0 ) || { } ;
78+ const { x, y } =
79+ ( endContainer instanceof Element
80+ ? endContainer
81+ : endContainer . parentElement
82+ ) ?. getBoundingClientRect ( ) || { } ;
7883
79- updateTools = ( ) => {
80- if ( this . box . current === document . activeElement )
81- this . toolList = [ ...this . toolList ] ;
84+ this . cursorPoint = [ x , y ] + '' ;
8285 } ;
8386
84- updateValue ( markup : string ) {
85- this . innerValue = markup = markup . trim ( ) ;
86-
87- this . props . onChange ?.( markup ) ;
88- }
87+ updateValue = ( markup : string ) => ( this . innerValue = markup . trim ( ) ) ;
8988
9089 render ( ) {
91- const { toolList, innerValue } = this ,
90+ // Don't remove unused variable `cursorPoint`, which is used for triggering updates
91+ const { cursorPoint, toolList, innerValue } = this ,
9292 { name } = this . props ;
9393
9494 return (
0 commit comments