1
- import { MouseEvent , RefObject , useEffect , useRef } from 'react' ;
1
+ import { MouseEvent , RefObject , useCallback , useEffect , useRef , useState } from 'react' ;
2
2
import { TMonitor , useDrag , useDrop } from 'react-use-drag-and-drop' ;
3
- import { useObserverValue } from 'react-observing' ;
3
+ import { useObserver , useObserverValue } from 'react-observing' ;
4
+ import { useFrame } from 'react-frame-component' ;
4
5
5
6
import { TDraggableElement , TElement , TParentElement } from '../../../types' ;
6
7
import { useUiEditorContext } from '../../../UiEditorContext' ;
@@ -28,9 +29,10 @@ interface IEditProps {
28
29
}
29
30
export const Edit = ( { element, parents, onMouseOver, onMouseLeave, onSelect, onDragLeave, onDragOver, onDrop, onHoverBar, onSelectBar } : IEditProps ) => {
30
31
const elementRef = useRef < HTMLElement > ( null ) ;
32
+ const { window, document } = useFrame ( ) ;
31
33
34
+ const [ text , setText ] = useObserver ( element . text ) ;
32
35
const name = useObserverValue ( element . name ) ;
33
- const text = useObserverValue ( element . text ) ;
34
36
const id = useObserverValue ( element . id ) ;
35
37
36
38
const { onDragStart, onDragEnd } = useUiEditorContext ( ) ;
@@ -39,6 +41,14 @@ export const Edit = ({ element, parents, onMouseOver, onMouseLeave, onSelect, on
39
41
const { hoveredId } = useHoverBar ( ) ;
40
42
41
43
44
+ const [ editable , setEditable ] = useState ( false ) ;
45
+ useEffect ( ( ) => {
46
+ if ( ! elementRef . current || ! editable ) return ;
47
+ elementRef . current . focus ( ) ;
48
+ onSelectBar ( element , null )
49
+ } , [ editable , onSelectBar ] ) ;
50
+
51
+
42
52
useMatchEffect ( {
43
53
value : hoveredId ,
44
54
matchWidthValue : element ?. id ,
@@ -49,16 +59,17 @@ export const Edit = ({ element, parents, onMouseOver, onMouseLeave, onSelect, on
49
59
value : selectedId ,
50
60
matchWidthValue : element ?. id ,
51
61
effect : ( ) => onSelectBar ( element , elementRef . current ) ,
52
- } , [ selectedId , element ] ) ;
62
+ } , [ selectedId , element , text ] ) ;
53
63
54
64
55
65
const { isDragging, preview } = useDrag < TDraggableElement > ( {
56
66
id,
67
+ canDrag : ! editable ,
57
68
element : elementRef ,
58
69
data : { element, parents, } ,
59
70
start : ( ) => { onDragStart ( ) } ,
60
71
end : ( ) => { hideInsertBar ( ) ; onDragEnd ( ) ; } ,
61
- } , [ id , element , parents , hideInsertBar , onDragStart , onDragEnd ] ) ;
72
+ } , [ id , editable , element , parents , hideInsertBar , onDragStart , onDragEnd ] ) ;
62
73
useEffect ( ( ) => {
63
74
preview (
64
75
( ) => getCustomDragLayer ( name ) ,
@@ -76,19 +87,58 @@ export const Edit = ({ element, parents, onMouseOver, onMouseLeave, onSelect, on
76
87
} , [ element , parents , onDrop , onDragOver , onDragLeave ] ) ;
77
88
78
89
90
+ const handleFocus = useCallback ( ( e : React . FormEvent < HTMLSpanElement > ) => {
91
+ if ( ! window || ! document ) return ;
92
+
93
+ const selection = window . getSelection ( ) ;
94
+ if ( ! selection ) return ;
95
+
96
+ const range = document . createRange ( ) ;
97
+ const span = e . currentTarget ;
98
+
99
+ range . selectNodeContents ( span ) ;
100
+ selection . removeAllRanges ( ) ;
101
+ selection . addRange ( range ) ;
102
+ } , [ window , document ] ) ;
103
+
104
+ const handleKeyDown = useCallback ( ( e : React . KeyboardEvent < HTMLSpanElement > ) => {
105
+ e . stopPropagation ( ) ;
106
+
107
+ if ( e . code === 'Escape' || e . code === 'Enter' || e . code === 'NumpadEnter' ) {
108
+ setEditable ( false ) ;
109
+ onSelectBar ( element , e . currentTarget )
110
+ }
111
+ } , [ onSelectBar , element ] ) ;
112
+
113
+ const handleBlur = useCallback ( ( e : React . FocusEvent < HTMLSpanElement > ) => {
114
+ setEditable ( false ) ;
115
+ setText ( e . currentTarget . innerText ) ;
116
+ onSelectBar ( element , e . currentTarget )
117
+ } , [ onSelectBar , element ] ) ;
118
+
119
+
79
120
return (
80
121
< span
81
- children = { text }
122
+ contentEditable = { editable }
123
+ dangerouslySetInnerHTML = { { __html : text } }
124
+
125
+ onBlur = { handleBlur }
126
+ onFocus = { handleFocus }
127
+ onKeyDown = { handleKeyDown }
128
+ onDoubleClick = { ( ) => setEditable ( true ) }
129
+
82
130
ref = { elementRef }
83
131
onMouseLeave = { onMouseLeave }
84
- onClick = { e => onSelect ( e , element ) }
85
- onMouseOver = { e => onMouseOver ( e , element , elementRef . current ) }
132
+ onClick = { e => ! editable ? onSelect ( e , element ) : e . stopPropagation ( ) }
133
+ onMouseOver = { e => ! editable ? onMouseOver ( e , element , elementRef . current ) : e . stopPropagation ( ) }
86
134
style = { {
87
135
resize : 'none' ,
88
136
cursor : 'default' ,
89
- userSelect : 'none' ,
90
137
pointerEvents : 'all' ,
138
+
91
139
opacity : isDragging ? 0.5 : undefined ,
140
+ borderRadius : editable ? 4 : undefined ,
141
+ boxShadow : editable ? '0 0 6px 2px orange' : undefined ,
92
142
} }
93
143
/>
94
144
) ;
0 commit comments