Skip to content

Commit 1e03c89

Browse files
committed
[#115] refactor: drag & drop 이벤트 구현을 mouse 이벤트에서 drag api로 변경
1 parent 5269217 commit 1e03c89

File tree

6 files changed

+63
-73
lines changed

6 files changed

+63
-73
lines changed

frontend/.eslintrc

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
"import/no-unresolved": 0,
3939
"import/prefer-default-export": "off",
4040
"jsx-a11y/no-static-element-interactions": 0,
41-
"@typescript-eslint/indent": 0
41+
"@typescript-eslint/indent": 0,
42+
"no-param-reassign": 0
4243
},
4344
"settings": {
4445
"import/resolver": {

frontend/src/components/atoms/BlockContent/BlockContent.tsx

+38-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
/** @jsx jsx */
22
/** @jsxRuntime classic */
3-
import { jsx, css, SerializedStyles } from '@emotion/react';
4-
import { useEffect, useRef, FormEvent, KeyboardEvent } 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';
511
import { useRecoilState, useRecoilValue } from 'recoil';
612

713
import {
@@ -25,10 +31,11 @@ const isGridOrColumn = (block: Block): boolean =>
2531
block.type === BlockType.GRID || block.type === BlockType.COLUMN;
2632

2733
const blockContentCSS = css`
34+
position: relative;
2835
display: flex;
2936
align-items: stretch;
3037
`;
31-
const editableDivCSS = (block: Block): SerializedStyles => css`
38+
const editableDivCSS = (block: Block) => css`
3239
margin: 5;
3340
font-size: ${fontSize[block.type]};
3441
display: ${!isGridOrColumn(block) ? 'flex' : 'none'};
@@ -55,6 +62,13 @@ const editableDivCSS = (block: Block): SerializedStyles => css`
5562
cursor: text;
5663
}
5764
`;
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+
`;
5872

5973
function BlockContent(blockDTO: Block) {
6074
const contentEditableRef = useRef(null);
@@ -65,6 +79,7 @@ function BlockContent(blockDTO: Block) {
6579
const [Dispatcher] = useCommand();
6680
const draggingBlock = useRecoilValue(draggingBlockState);
6781
const [{ blockIndex }] = useManager(blockDTO.id);
82+
const [dragOverToggle, setDragOverToggle] = useState(false);
6883

6984
useEffect(() => {
7085
blockRefState[blockDTO.id] = contentEditableRef;
@@ -224,7 +239,16 @@ function BlockContent(blockDTO: Block) {
224239
}
225240
}, [blockDTO.value]);
226241

227-
const dropDraggingBlockHandler = async () => {
242+
const dragOverHandler = (event: React.DragEvent<HTMLDivElement>) => {
243+
event.dataTransfer.dropEffect = 'move';
244+
245+
event.preventDefault();
246+
};
247+
248+
const dropHandler = async (event: React.DragEvent<HTMLDivElement>) => {
249+
setDragOverToggle(false);
250+
event.dataTransfer.dropEffect = 'move';
251+
228252
const blockId = draggingBlock?.id;
229253
if (!blockId || blockId === blockDTO.id) {
230254
return;
@@ -242,10 +266,18 @@ function BlockContent(blockDTO: Block) {
242266
next[to.id] = to;
243267
return next;
244268
});
269+
270+
event.preventDefault();
245271
};
246272

247273
return (
248-
<div css={blockContentCSS} onMouseUp={dropDraggingBlockHandler}>
274+
<div
275+
css={blockContentCSS}
276+
onDragOver={dragOverHandler}
277+
onDrop={dropHandler}
278+
onDragEnter={() => setDragOverToggle(true)}
279+
onDragLeave={() => setDragOverToggle(false)}
280+
>
249281
{listBlockType(blockDTO, listCnt.current)}
250282
<div
251283
ref={contentEditableRef}
@@ -259,6 +291,7 @@ function BlockContent(blockDTO: Block) {
259291
>
260292
{blockDTO.value}
261293
</div>
294+
{dragOverToggle && <div css={dragOverCss()} />}
262295
</div>
263296
);
264297
}

frontend/src/components/molecules/BlockComponent/BlockComponent.tsx

+16-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/** @jsx jsx */
22
/** @jsxRuntime classic */
3-
import { jsx, css, SerializedStyles } from '@emotion/react';
3+
import { jsx, css } from '@emotion/react';
4+
import React from 'react';
5+
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
46

57
import { BlockContent } from '@atoms/index';
68
import { BlockHandler, HoverArea } from '@components/molecules';
@@ -12,7 +14,6 @@ import {
1214
blockMapState,
1315
draggingBlockState,
1416
} from '@stores/page';
15-
import { useRecoilState, useRecoilValue } from 'recoil';
1617

1718
const isGridOrColumn = (block: Block): boolean =>
1819
block.type === BlockType.GRID || block.type === BlockType.COLUMN;
@@ -27,7 +28,7 @@ const blockCss = css`
2728
color: inherit;
2829
fill: inherit;
2930
`;
30-
const descendantsCss = (block: Block): SerializedStyles => css`
31+
const descendantsCss = (block: Block) => css`
3132
display: flex;
3233
padding-left: ${!isGridOrColumn(block) ? '1.5rem' : 0};
3334
flex-direction: ${block.type !== BlockType.GRID ? 'column' : 'row'};
@@ -44,10 +45,18 @@ function BlockComponent({ blockDTO }: Props): JSX.Element {
4445
const [focusId, setFocusId] = useRecoilState<string>(focusState);
4546
const [hoverId, setHoverId] = useRecoilState(hoverState);
4647
const blockRef: any = blockRefState[blockDTO.id];
47-
const draggingBlock = useRecoilValue(draggingBlockState);
48+
const setDraggingBlock = useSetRecoilState(draggingBlockState);
49+
50+
const dragStartHandler = (event: React.DragEvent<HTMLDivElement>) => {
51+
event.dataTransfer.effectAllowed = 'move';
52+
event.dataTransfer.dropEffect = 'move';
53+
event.dataTransfer.setData('text/html', event.currentTarget.innerHTML);
54+
55+
setDraggingBlock(blockDTO);
56+
};
4857

4958
return (
50-
<div css={blockCss}>
59+
<div css={blockCss} draggable="true" onDragStart={dragStartHandler}>
5160
<div
5261
css={{ position: 'relative' }}
5362
onMouseEnter={() => setHoverId(blockDTO.id)}
@@ -57,13 +66,8 @@ function BlockComponent({ blockDTO }: Props): JSX.Element {
5766
}}
5867
>
5968
<BlockContent {...blockDTO} />
60-
<HoverArea
61-
block={blockDTO}
62-
clickHandler={() => blockRef.current.focus()}
63-
/>
64-
{!draggingBlock && hoverId === blockDTO.id && (
65-
<BlockHandler block={blockDTO} />
66-
)}
69+
<HoverArea clickHandler={() => blockRef.current.focus()} />
70+
{hoverId === blockDTO.id && <BlockHandler />}
6771
</div>
6872
{blockDTO.childIdList.length ? (
6973
<div css={descendantsCss(blockDTO)}>

frontend/src/components/molecules/BlockHandler/BlockHandler.tsx

+2-15
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ import React from 'react';
55

66
import { ReactComponent as DraggableIcon } from '@assets/draggable.svg';
77
import { ReactComponent as PlusIcon } from '@assets/plus.svg';
8-
import { Block } from '@/schemes';
9-
import { useSetRecoilState } from 'recoil';
10-
import { draggingBlockState } from '@/stores';
118

129
const buttonWrapperCss = () => css`
1310
display: flex;
@@ -30,21 +27,11 @@ const buttonCss = () => css`
3027
height: 16px;
3128
`;
3229

33-
interface Props {
34-
block: Block;
35-
}
36-
37-
function BlockHandler({ block }: Props): JSX.Element {
38-
const setDraggingBlock = useSetRecoilState(draggingBlockState);
39-
40-
const setDraggingBlockHandler = () => {
41-
setDraggingBlock(block);
42-
};
43-
30+
function BlockHandler(): JSX.Element {
4431
return (
4532
<div css={buttonWrapperCss()}>
4633
<PlusIcon css={buttonCss()} />
47-
<div css={buttonCss()} onMouseDown={setDraggingBlockHandler}>
34+
<div css={buttonCss()}>
4835
<DraggableIcon css={buttonCss()} />
4936
</div>
5037
</div>

frontend/src/components/molecules/HoverArea/HoverArea.tsx

+3-28
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
/** @jsxRuntime classic */
33
import { jsx, css } from '@emotion/react';
44
import { MouseEvent } from 'react';
5-
import { Block } from '@/schemes';
6-
import { useRecoilValue } from 'recoil';
7-
import { draggingBlockState, hoverState } from '@/stores';
85

96
const leftHoverAreaCss = css`
107
position: absolute;
@@ -25,40 +22,18 @@ const commonHoverAreaCss = css`
2522
cursor: text;
2623
}
2724
`;
28-
const draggingHoverUnderlineCss = () => css`
29-
position: absolute;
30-
bottom: 0;
31-
width: 100%;
32-
height: 15%;
33-
background-color: rgba(80, 188, 223, 0.7);
34-
`;
3525

3626
interface Props {
37-
block: Block;
3827
clickHandler: (
3928
event: MouseEvent<HTMLDivElement, globalThis.MouseEvent>,
4029
) => void;
4130
}
4231

43-
function HoverArea({ block, clickHandler }: Props): JSX.Element {
44-
const draggingBlock = useRecoilValue(draggingBlockState);
45-
const hoverId = useRecoilValue(hoverState);
46-
47-
const leftDragEndHandler = () => {
48-
console.log(draggingBlock?.value);
49-
};
50-
51-
const rightDragEndHandler = () => {
52-
console.log(draggingBlock?.value);
53-
};
54-
32+
function HoverArea({ clickHandler }: Props): JSX.Element {
5533
return (
5634
<div css={commonHoverAreaCss} onClick={clickHandler} onKeyDown={() => {}}>
57-
<div css={leftHoverAreaCss} onMouseUp={leftDragEndHandler} />
58-
<div css={rightHoverAreaCss} onMouseUp={rightDragEndHandler} />
59-
{draggingBlock && hoverId === block.id && (
60-
<div css={draggingHoverUnderlineCss()} />
61-
)}
35+
<div css={leftHoverAreaCss} />
36+
<div css={rightHoverAreaCss} />
6237
</div>
6338
);
6439
}

frontend/src/components/pages/PageComponent/PageComponent.tsx

+2-12
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@ import { jsx, css } from '@emotion/react';
55
import { Header, Title, Editor } from '@components/molecules';
66
import { HeaderMenu } from '@components/organisms';
77
import { useRecoilValue, useSetRecoilState } from 'recoil';
8-
import {
9-
blockMapState,
10-
draggingBlockState,
11-
pageState,
12-
staticMenuToggleState,
13-
} from '@/stores';
8+
import { blockMapState, pageState, staticMenuToggleState } from '@/stores';
149
import { createBlock } from '@/utils';
1510

1611
const staticMenuAreaCss = () => css`
@@ -45,7 +40,6 @@ function PageComponent(): JSX.Element {
4540
const staticMenuToggle = useRecoilValue(staticMenuToggleState);
4641
const page = useRecoilValue(pageState);
4742
const setBlockMap = useSetRecoilState(blockMapState);
48-
const setDraggingBlock = useSetRecoilState(draggingBlockState);
4943

5044
const createBlockHandler = async () => {
5145
const { parent, block } = await createBlock({ parentBlockId: page.rootId });
@@ -57,12 +51,8 @@ function PageComponent(): JSX.Element {
5751
});
5852
};
5953

60-
const resetDraggingBlockHandler = () => {
61-
setDraggingBlock(null);
62-
};
63-
6454
return (
65-
<div onMouseUp={resetDraggingBlockHandler}>
55+
<div>
6656
<div css={staticMenuAreaCss()}>
6757
<HeaderMenu />
6858
</div>

0 commit comments

Comments
 (0)