이 컴포넌트로 감싼 요소는 마우스로 드래그하여 스크롤 할 수 있음.
<DragScroll>
...
</DragScroll>
import React, { useRef } from 'react';
import useDragScroll from '@src/Hooks/useDragScroll';
import { DefaultProps } from 'iscrim_ui/lib/types';
import styled, { StyledComponent } from 'styled-components';
export interface DragScrollProps extends DefaultProps {
maxHeight?: string;
forceScrollTo?: { x?:number, y?:number }
isTextDraggable?: boolean;
isHideScrollBar?: boolean;
};
interface ContainerProps extends DragScrollProps {
isDragging: boolean;
}
const Container: StyledComponent<'div', DefaultProps, ContainerProps> = styled.div`
max-height: ${(props:any) => props.maxHeight};
overflow: scroll;
-webkit-overflow-scrolling: touch;
-moz-overflow-scrolling: touch;
-ms-overflow-scrolling: touch;
-ms-overflow-style: none;
${({ isTextDraggable }: ContainerProps)=> !isTextDraggable && `
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
`};
${({ isHideScrollBar }: ContainerProps)=> isHideScrollBar && `
&::-webkit-scrollbar{ display:none; }
-ms-overflow-style: none;
`};
cursor: grab;
${(props:any) => props.isDragging && `
cursor: grabbing !important;
* {
pointer-events: none;
}
`};
`;
const DragScroll: React.FC<DragScrollProps> = ({ maxHeight, forceScrollTo, isTextDraggable, isHideScrollBar, className, style, children }) => {
const bracketContainer = useRef<HTMLDivElement>(null);
const { isDragging, handleMouseMove, handleMouseDown, handleMouseUp, handleMouseLeave } = useDragScroll({ ref: bracketContainer, forceScrollTo });
return (
<Container
ref={bracketContainer}
style={style}
className={className}
isDragging={isDragging}
isTextDraggable={isTextDraggable}
isHideScrollBar={isHideScrollBar}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onMouseLeave={handleMouseLeave}
maxHeight={maxHeight}
>
{children}
</Container>
)
}
export default DragScroll;
import { MutableRefObject, useEffect, useState } from "react"
interface Options {
ref: MutableRefObject<any>;
forceScrollTo?: { x?:number, y?:number };
}
const getLimit = (value:number, limit:number) => {
if (value < 0) return 0;
else if (value > limit) return limit;
else return value;
}
export default ({ ref, forceScrollTo }: Options) => {
const [state, setState] = useState({ x: 0, y: 0 });
const [drag, setDrag] = useState({ x: 0, y: 0 });
const [dragPoint, setDragPoint] = useState({ x: 0, y: 0 });
const [grapPoint, setGrapPoint] = useState<null | {x:number, y:number}>(null);
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
e.persist();
const target = e.currentTarget;
const rect = target.getBoundingClientRect();
const x = e.clientX - Math.floor(rect.x);
const y = e.clientY - Math.floor(rect.y);
setState(state => ({ ...state, x, y }));
if ( grapPoint ) {
const dragOffsetX = grapPoint.x - x;
const dragOffsetY = grapPoint.y - y;
const dragX = getLimit(dragOffsetX, target.scrollWidth + rect.width);
const dragY = getLimit(dragOffsetY, target.scrollHeight + rect.height);
setDrag({ x: dragX, y: dragY });
}
}
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
const top = e.currentTarget.scrollTop;
const left = e.currentTarget.scrollLeft;
setDragPoint(drag);
setGrapPoint({ x: state.x + left, y: state.y + top });
}
const handleMouseUp = (e: React.MouseEvent<HTMLDivElement>) => {
setDragPoint(drag);
setGrapPoint(null);
}
const handleMouseLeave = (e: React.MouseEvent<HTMLDivElement>) => {
setDragPoint(drag);
setGrapPoint(null);
}
useEffect(() => {
if ( ref && ref.current ) {
ref.current.scrollTo(drag.x, drag.y);
}
}, [drag]);
useEffect(() => {
if ( forceScrollTo !== undefined ) {
setDrag({
x: forceScrollTo.x === undefined ? drag.x : forceScrollTo.x,
y: forceScrollTo.y === undefined ? drag.y : forceScrollTo.y,
});
}
}, [forceScrollTo]);
return {
drag: drag,
isDragging: drag.x !== dragPoint.x || drag.y !== dragPoint.y,
handleMouseMove,
handleMouseDown,
handleMouseUp,
handleMouseLeave,
}
}