1
1
/** @jsx jsx */
2
2
/** @jsxRuntime classic */
3
- import { jsx , css , SerializedStyles } from '@emotion/react' ;
4
- import { useEffect , useRef , FormEvent , KeyboardEvent , useState } from 'react' ;
3
+ import { jsx , css } from '@emotion/react' ;
4
+ import React , {
5
+ useEffect ,
6
+ useRef ,
7
+ FormEvent ,
8
+ KeyboardEvent ,
9
+ useState ,
10
+ } from 'react' ;
5
11
import { useRecoilState , useRecoilValue } from 'recoil' ;
6
12
7
- import { blockRefState , throttleState , blockMapState } from '@/stores' ;
13
+ import {
14
+ blockMapState ,
15
+ blockRefState ,
16
+ draggingBlockState ,
17
+ throttleState ,
18
+ } from '@/stores' ;
8
19
import { Block , BlockType } from '@/schemes' ;
9
- import { updateBlock } from '@/utils' ;
10
20
import {
11
21
regex ,
12
22
fontSize ,
13
23
placeHolder ,
14
24
listBlockType ,
15
25
} from '@utils/blockContent' ;
16
- import { useCommand } from '@/hooks' ;
26
+ import { useCommand , useManager } from '@/hooks' ;
17
27
import { focusState } from '@/stores/page' ;
28
+ import { moveBlock , updateBlock } from '@/utils' ;
18
29
19
30
const isGridOrColumn = ( block : Block ) : boolean =>
20
31
block . type === BlockType . GRID || block . type === BlockType . COLUMN ;
21
32
22
33
const blockContentCSS = css `
34
+ position : relative;
23
35
display : flex;
24
36
align-items : stretch;
25
37
` ;
26
- const editableDivCSS = ( block : Block ) : SerializedStyles => css `
38
+ const editableDivCSS = ( block : Block ) => css `
27
39
margin : 5 ;
28
40
font-size : ${ fontSize [ block . type ] } ;
29
41
display : ${ ! isGridOrColumn ( block ) ? 'flex' : 'none' } ;
@@ -50,6 +62,13 @@ const editableDivCSS = (block: Block): SerializedStyles => css`
50
62
cursor : text;
51
63
}
52
64
` ;
65
+ const dragOverCss = ( ) => css `
66
+ position : absolute;
67
+ bottom : 0 ;
68
+ width : 100% ;
69
+ height : 15% ;
70
+ background-color : rgba (80 , 188 , 223 , 0.7 );
71
+ ` ;
53
72
54
73
function BlockContent ( blockDTO : Block ) {
55
74
const contentEditableRef = useRef ( null ) ;
@@ -59,6 +78,29 @@ function BlockContent(blockDTO: Block) {
59
78
const listCnt = useRef ( 1 ) ;
60
79
const [ Dispatcher ] = useCommand ( ) ;
61
80
const [ isBlur , setIsBlur ] = useState ( false ) ;
81
+ const draggingBlock = useRecoilValue ( draggingBlockState ) ;
82
+ const [ { blockIndex } ] = useManager ( blockDTO . id ) ;
83
+ const [ dragOverToggle , setDragOverToggle ] = useState ( false ) ;
84
+
85
+ useEffect ( ( ) => {
86
+ blockRefState [ blockDTO . id ] = contentEditableRef ;
87
+ return ( ) => {
88
+ blockRefState [ blockDTO . id ] = null ;
89
+ } ;
90
+ } , [ ] ) ;
91
+
92
+ useEffect ( ( ) => {
93
+ if ( focusId === blockDTO . id ) contentEditableRef . current . focus ( ) ;
94
+ } , [ focusId ] ) ;
95
+
96
+ useEffect ( ( ) => {
97
+ const selection = window . getSelection ( ) ;
98
+ const nodeLength = selection . focusNode ?. nodeValue ?. length ?? 0 ;
99
+ if ( caretRef . current > nodeLength ) {
100
+ caretRef . current = nodeLength ;
101
+ }
102
+ selection . collapse ( selection . focusNode , caretRef . current ) ;
103
+ } , [ blockDTO . value ] ) ;
62
104
63
105
const indexInSibling : number = blockMap [
64
106
blockDTO . parentId
@@ -207,8 +249,45 @@ function BlockContent(blockDTO: Block) {
207
249
}
208
250
} , [ blockDTO . value ] ) ;
209
251
252
+ const dragOverHandler = ( event : React . DragEvent < HTMLDivElement > ) => {
253
+ event . dataTransfer . dropEffect = 'move' ;
254
+
255
+ event . preventDefault ( ) ;
256
+ } ;
257
+
258
+ const dropHandler = async ( event : React . DragEvent < HTMLDivElement > ) => {
259
+ setDragOverToggle ( false ) ;
260
+ event . dataTransfer . dropEffect = 'move' ;
261
+
262
+ const blockId = draggingBlock ?. id ;
263
+ if ( ! blockId || blockId === blockDTO . id ) {
264
+ return ;
265
+ }
266
+
267
+ const { block, from : fromBlock , to } = await moveBlock ( {
268
+ blockId,
269
+ toId : blockDTO . parentId ,
270
+ index : blockIndex + 1 ,
271
+ } ) ;
272
+ setBlockMap ( ( prev ) => {
273
+ const next = { ...prev } ;
274
+ next [ block . id ] = block ;
275
+ fromBlock && ( next [ fromBlock . id ] = fromBlock ) ;
276
+ next [ to . id ] = to ;
277
+ return next ;
278
+ } ) ;
279
+
280
+ event . preventDefault ( ) ;
281
+ } ;
282
+
210
283
return (
211
- < div css = { blockContentCSS } >
284
+ < div
285
+ css = { blockContentCSS }
286
+ onDragOver = { dragOverHandler }
287
+ onDrop = { dropHandler }
288
+ onDragEnter = { ( ) => setDragOverToggle ( true ) }
289
+ onDragLeave = { ( ) => setDragOverToggle ( false ) }
290
+ >
212
291
{ listBlockType ( blockDTO , listCnt . current ) }
213
292
< div
214
293
ref = { contentEditableRef }
@@ -223,6 +302,7 @@ function BlockContent(blockDTO: Block) {
223
302
>
224
303
{ blockDTO . value }
225
304
</ div >
305
+ { dragOverToggle && < div css = { dragOverCss ( ) } /> }
226
306
</ div >
227
307
) ;
228
308
}
0 commit comments