Skip to content

Commit 197e632

Browse files
authored
[FEAT] 마우스로 드래그 앤 드랍 가능하게 변경 및 Dnd 관련 로직 및 컴포넌트 한 폴더로 이동 (#28)
* refactor: Dnd 관련 로직 한 폴더로 이동 * refactor: props를 context로 교체 * refactor: Dnd 관련 폴더로 pointerWithinWithClosestCenter 이동 * chore: lint에서 ! assertion 허용 * feat: drag-select 기능 구현 (아직 DragOverlay 관련 로직 미구현) * chore: lint script warn 이상만 찍히게 변경 * feat: DragSelect 적용 * feat: 사용하지 않는 SelectProvider 제거 * feat: getAbsoluteCoordinates 로직 수정 * fix: DragSelectOverlay 초기값 null로 변경 * design: 마우스 selection 색 변경 * feat: NonSelectArea 구현 및 적용 * chore: DragSelectOverlay will-change 속성 추가 * feat: DragSelect에서 함수 분리 및 스크롤 될 때도 영역 계산 * fix: NonDragSelectArea에서 drag-select 방지 * feat: drag-select 내부에서 사용하는 data context 추가 * feat: useDragSelect hook 구현 및 drag-select 내부에 적용 * feat: 사용하지 않는 drag-select 관련 컴포넌트 제거 * refactor: NonDragSelectArea에서 side-effect 발생 로직 제거 * feat: drag-select 기능 컴포넌트에 적용 * feat: Context로 element를 넘기기 및 DragSelectOver가로 길이 지정 * refactor: 타입명 수정 * refactor: DragSelectOverlay 스타일 외부에서 커스텀하게 변경 * fix: getBoudingClientRect시 container 기준으로 계산 * feat: drag-select로 기능 적용 * feat: distance 추가해서 이벤트 시작 로직 구현 * docs: drag-select 문서 작성 * chore: 주석 제거 * refactor: DragSelectContext 함수 분리
1 parent 452f801 commit 197e632

43 files changed

Lines changed: 784 additions & 70 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

biome.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
"all": true,
3131
"noBarrelFile": "error",
3232
"noReExportAll": "error"
33-
}
33+
},
34+
"style": { "noNonNullAssertion": "info" }
3435
}
3536
},
3637
"javascript": {

techpick/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"dev:https": "dotenv -e .env.development -- bash -c 'yarn next dev -H $NEXT_PUBLIC_DOMAIN -p 3000 --experimental-https'",
88
"build": "next build",
99
"start": "next start",
10-
"lint": "biome lint ./src",
10+
"lint": "biome lint --diagnostic-level=warn ./src",
1111
"storybook": "storybook dev -p 6006",
1212
"build-storybook": "storybook build",
1313
"test": "yarn jest",
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { style } from '@vanilla-extract/css';
2+
3+
export const dragSelectOverlayStyle = style({
4+
backgroundColor: 'rgba(0, 123, 255, 0.3)',
5+
border: '1px solid rgba(0, 123, 255, 0.8)',
6+
pointerEvents: 'none',
7+
willChange: 'left, top, width, height',
8+
});

techpick/src/app/(signed)/folders/[folderId]/page.tsx

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,59 @@ import { PickContentLayout } from '@/components/PickContentLayout';
66
import { PickDraggableInfiniteScrollList } from '@/components/PickDraggableInfiniteScrollList';
77
import { useClearSelectedPickIdsOnMount } from '@/hooks/useClearSelectedPickIdsOnMount';
88
import { useResetPickFocusOnOutsideClick } from '@/hooks/useResetPickFocusOnOutsideClick';
9+
import { DragSelectContext } from '@/libs/@drag-select/DragSelectContext';
10+
import { DragSelectOverlay } from '@/libs/@drag-select/DragSelectOverlay';
11+
import type { DragSelectMoveEvent } from '@/libs/@drag-select/type';
12+
import { usePickStore } from '@/stores/pickStore';
13+
import { isPickInfoObject } from '@/utils/isPickInfoObject';
914
import { useParams } from 'next/navigation';
15+
import { useEffect, useRef, useState } from 'react';
16+
import { dragSelectOverlayStyle } from './page.css';
1017

1118
export default function FolderDetailPage() {
1219
const { folderId: stringFolderId } = useParams<{ folderId: string }>();
1320
const folderId = Number(stringFolderId);
1421
useResetPickFocusOnOutsideClick();
1522
useClearSelectedPickIdsOnMount();
23+
const setSelectedPickIdList = usePickStore(
24+
(state) => state.setSelectedPickIdList,
25+
);
26+
const setFocusedPickId = usePickStore((state) => state.setFocusedPickId);
27+
const containerRef = useRef<HTMLDivElement>(null);
28+
const [container, setContainer] = useState<HTMLElement | null>(null);
29+
30+
useEffect(() => {
31+
setContainer(containerRef.current);
32+
}, []);
33+
34+
const onDragSelectEnd = ({ dragSelectItems }: DragSelectMoveEvent) => {
35+
const selectedPickIdList: number[] = [];
36+
37+
for (const dragSelectItem of dragSelectItems) {
38+
const pickInfo = dragSelectItem.data?.pickInfo;
39+
if (isPickInfoObject(pickInfo)) {
40+
selectedPickIdList.push(pickInfo.id);
41+
}
42+
}
43+
44+
setSelectedPickIdList(selectedPickIdList);
45+
if (selectedPickIdList[0]) {
46+
setFocusedPickId(selectedPickIdList[0]);
47+
}
48+
};
1649

1750
return (
18-
<FolderContentLayout>
19-
<FolderContentHeader folderId={folderId} />
20-
<PickContentLayout>
21-
<PickDraggableInfiniteScrollList folderId={folderId} />
22-
</PickContentLayout>
51+
<FolderContentLayout ref={containerRef}>
52+
<DragSelectContext
53+
container={container!}
54+
onDragSelectEnd={onDragSelectEnd}
55+
>
56+
<FolderContentHeader folderId={folderId} />
57+
<PickContentLayout>
58+
<PickDraggableInfiniteScrollList folderId={folderId} />
59+
</PickContentLayout>
60+
<DragSelectOverlay className={dragSelectOverlayStyle} />
61+
</DragSelectContext>
2362
</FolderContentLayout>
2463
);
2564
}

techpick/src/app/(signed)/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { getBasicFolders } from '@/apis/folder/getBasicFolders';
22
import { getFolders } from '@/apis/folder/getFolders';
33
import { getTagList } from '@/apis/tag/getTagList';
44
import { FeedbackToolbar } from '@/components/FeedbackToolbar';
5-
import { FolderAndPickDndContextProvider } from '@/components/FolderAndPickDndContextProvider';
5+
import { FolderAndPickDndContextProvider } from '@/components/FolderAndPickDndContextProvider/FolderAndPickDndContextProvider';
66
import { MobileNavigationBar } from '@/components/MobileNavigationBar';
77
import ShortcutKey from '@/components/ShortcutKey';
88
import { SideNavigationBar } from '@/components/SideNavigationBar/SideNavigationBar';

techpick/src/app/layout.css.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { style } from '@vanilla-extract/css';
2+
import { globalStyle } from '@vanilla-extract/css';
23

34
export const preventOverscrollBehaviorY = style({
45
overscrollBehaviorY: 'none',
56
});
7+
8+
globalStyle('::selection', {
9+
backgroundColor: '#e0edfb',
10+
});

techpick/src/components/DndMonitorContext.tsx

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use client';
2+
3+
import { memo } from 'react';
4+
import { useFolderToFolderDndMonitor } from './useFolderToFolderDndMonitor';
5+
import { usePickToFolderDndMonitor } from './usePickToFolderDndMonitor';
6+
import { usePickToPickDndMonitor } from './usePickToPickDndMonitor';
7+
import { useRecommendPickToFolderDndMonitor } from './useRecommendPickToFolderDndMonitor';
8+
9+
export const DndMonitorContext = memo(function DndMonitorContext() {
10+
usePickToPickDndMonitor();
11+
useFolderToFolderDndMonitor();
12+
usePickToFolderDndMonitor();
13+
useRecommendPickToFolderDndMonitor();
14+
return null;
15+
});

techpick/src/components/DragOverlay/DragOverlay.tsx renamed to techpick/src/components/FolderAndPickDndContextProvider/DragOverlay/DragOverlay.tsx

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
'use client';
2-
32
import { useGetDragOverStyle } from '@/hooks/useGetDragOverStyle';
43
import { useFetchFolders } from '@/queries/useFetchFolders';
54
import { usePickStore } from '@/stores/pickStore';
@@ -13,24 +12,26 @@ import {
1312
type DragStartEvent,
1413
useDndMonitor,
1514
} from '@dnd-kit/core';
16-
import { useState } from 'react';
15+
import { memo, useState } from 'react';
16+
import { useElementClickPosition } from '../useElementClickPosition';
1717
import { FolderItemOverlay } from './FolderItemOverlay';
1818
import { PickCarouselCardOverlay } from './PickCarouselCardOverlay';
1919
import { PickDragOverlayShadowList } from './PickDragOverlayShadowList';
2020
import { PickRecordOverlay } from './PickRecordOverlay';
2121
import { dragCountStyle, stackedOverlayStyle } from './dragOverlay.css';
2222

23-
export function DargOverlay({ elementClickPosition }: DargOverlayProps) {
23+
export const DargOverlay = memo(function DragOverlay() {
24+
const { elementClickPosition } = useElementClickPosition();
2425
const isPickDragging = usePickStore((state) => state.isDragging);
2526
const draggingPickInfo = usePickStore((state) => state.draggingPickInfo);
2627
const selectedPickIdList = usePickStore((state) => state.selectedPickIdList);
2728
const [draggingObjectType, setDraggingObjectType] =
2829
useState<DraggingObjectType>(null);
2930
const [draggingRecommendPickInfo, setDraggingRecommendPickInfo] =
3031
useState<RecommendPickType | null>(null);
31-
const { data: folderRecord } = useFetchFolders();
3232
const [draggingFolderInfo, setDraggingFolderInfo] =
3333
useState<FolderType | null>(null);
34+
const { data: folderRecord } = useFetchFolders();
3435

3536
const onDragStart = (event: DragStartEvent) => {
3637
const { active } = event;
@@ -66,15 +67,15 @@ export function DargOverlay({ elementClickPosition }: DargOverlayProps) {
6667
isDragging: isPickDragging,
6768
scale: 0.7,
6869
});
69-
const { overlayStyle: folderOverlayStyle } = useGetDragOverStyle({
70-
elementClickPosition,
71-
isDragging: draggingObjectType === 'folder',
72-
});
7370
const { overlayStyle: recommendPickOverlayStyle } = useGetDragOverStyle({
7471
elementClickPosition,
7572
isDragging: draggingObjectType === 'recommendPick',
7673
scale: 0.4,
7774
});
75+
const { overlayStyle: folderOverlayStyle } = useGetDragOverStyle({
76+
elementClickPosition,
77+
isDragging: draggingObjectType === 'folder',
78+
});
7879
const selectedPickListCount = selectedPickIdList.length - 1;
7980
const shadowCount = Math.min(selectedPickListCount, 5);
8081

@@ -94,28 +95,21 @@ export function DargOverlay({ elementClickPosition }: DargOverlayProps) {
9495
);
9596
}
9697

97-
if (draggingObjectType === 'folder' && draggingFolderInfo) {
98+
if (draggingObjectType === 'recommendPick' && draggingRecommendPickInfo) {
9899
return (
99-
<DragOverlayPrimitive style={folderOverlayStyle}>
100-
<FolderItemOverlay name={draggingFolderInfo.name} />
100+
<DragOverlayPrimitive style={recommendPickOverlayStyle}>
101+
<PickCarouselCardOverlay recommendPick={draggingRecommendPickInfo} />
101102
</DragOverlayPrimitive>
102103
);
103104
}
104105

105-
if (draggingObjectType === 'recommendPick' && draggingRecommendPickInfo) {
106+
if (draggingObjectType === 'folder' && draggingFolderInfo) {
106107
return (
107-
<DragOverlayPrimitive style={recommendPickOverlayStyle}>
108-
<PickCarouselCardOverlay recommendPick={draggingRecommendPickInfo} />
108+
<DragOverlayPrimitive style={{ ...folderOverlayStyle }}>
109+
<FolderItemOverlay name={draggingFolderInfo.name} />
109110
</DragOverlayPrimitive>
110111
);
111112
}
112-
}
113-
114-
interface DargOverlayProps {
115-
elementClickPosition: {
116-
x: number;
117-
y: number;
118-
};
119-
}
113+
});
120114

121115
type DraggingObjectType = 'recommendPick' | 'pick' | 'folder' | null;

techpick/src/components/DragOverlay/FolderItemOverlay.tsx renamed to techpick/src/components/FolderAndPickDndContextProvider/DragOverlay/FolderItemOverlay.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FolderOpen as FolderOpenIcon } from 'lucide-react';
2-
import { NavigationItem } from '../SideNavigationBar/NavigationItem';
2+
import { NavigationItem } from '../../SideNavigationBar/NavigationItem';
33
import { folderItemOverlay } from './folderItemOverlay.css';
44

55
export function FolderItemOverlay({ name }: FolderItemOverlayProps) {

0 commit comments

Comments
 (0)