) {
+ e.stopPropagation();
+ isActive.current = true;
+ const eventTarget = e.currentTarget as HTMLElement;
+ positionRef.current = { x, y };
- const classes =
- (e.target as HTMLElement).getAttribute('class')?.split(' ') || [];
- if (
- (dragHandleClassName && classes.includes(dragHandleClassName)) ||
- !dragHandleClassName
- ) {
- const _parentElement = parentElement || eventTarget?.parentElement;
- if (_parentElement) {
- const parentBounding = _parentElement.getBoundingClientRect();
- const currentBounding = eventTarget?.getBoundingClientRect();
- const startPosition: Position = {
- x:
- parentBounding.x +
- (!fromEdge ? e.clientX - currentBounding.x : 0),
- y:
- parentBounding.y +
- (!fromEdge ? e.clientY - currentBounding.y : 0),
- };
+ const classes =
+ (e.target as HTMLElement).getAttribute('class')?.split(' ') || [];
+ if (
+ (dragHandleClassName && classes.includes(dragHandleClassName)) ||
+ !dragHandleClassName
+ ) {
+ const _parentElement = parentElement || eventTarget?.parentElement;
+ if (_parentElement) {
+ const parentBounding = _parentElement.getBoundingClientRect();
+ const currentBounding = eventTarget?.getBoundingClientRect();
+ const startPosition: Position = {
+ x: parentBounding.x + (!fromEdge ? e.clientX - currentBounding.x : 0),
+ y: parentBounding.y + (!fromEdge ? e.clientY - currentBounding.y : 0),
+ };
- if (parentBounding) {
- positionRef.current = startPosition;
- }
- setPosition((prevPortion) => ({ ...prevPortion, action: 'start' }));
+ if (parentBounding) {
+ positionRef.current = startPosition;
}
-
- window.addEventListener('pointermove', moveCallback);
- window.addEventListener('pointerup', upCallback);
+ onChange({ position: { x, y }, action: 'start', isActive: true });
}
- function upCallback(e: PointerEvent) {
- e.stopPropagation();
- if (isActive.current) {
- setPosition({
- value: {
- x: e.clientX - positionRef.current.x,
- y: e.clientY - positionRef.current.y,
- },
- action: 'end',
- });
- isActive.current = false;
- }
+ window.addEventListener('pointermove', moveCallback);
+ window.addEventListener('pointerup', upCallback);
+ }
- window.removeEventListener('pointermove', moveCallback);
- window.removeEventListener('pointerup', upCallback);
+ function upCallback(e: PointerEvent) {
+ e.stopPropagation();
+ if (isActive.current) {
+ onChange({
+ position: {
+ x: e.clientX - positionRef.current.x,
+ y: e.clientY - positionRef.current.y,
+ },
+ action: 'end',
+ isActive: false,
+ });
+ isActive.current = false;
}
- function moveCallback(e: PointerEvent) {
- e.stopPropagation();
- if (isActive.current) {
- setPosition({
- value: {
- x: e.clientX - positionRef.current.x,
- y: e.clientY - positionRef.current.y,
- },
- action: 'move',
- });
- }
+ window.removeEventListener('pointermove', moveCallback);
+ window.removeEventListener('pointerup', upCallback);
+ }
+ function moveCallback(e: PointerEvent) {
+ e.stopPropagation();
+
+ if (isActive.current) {
+ onChange({
+ position: {
+ x: e.clientX - positionRef.current.x,
+ y: e.clientY - positionRef.current.y,
+ },
+ action: 'move',
+ isActive: true,
+ });
}
- },
- [dragHandleClassName, fromEdge, parentElement],
- );
+ }
+ }
- return useMemo(
- () => ({
- onPointerDown,
- position,
- isActive: isActive.current,
- }),
- [onPointerDown, position],
- );
+ return { onPointerDown };
}
diff --git a/src/component/elements/resizer/DivResizer.tsx b/src/component/elements/resizer/DivResizer.tsx
deleted file mode 100644
index 6429b1531..000000000
--- a/src/component/elements/resizer/DivResizer.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from '@emotion/react';
-import { CSSProperties } from 'react';
-
-import { Draggable } from '../draggable/useDraggable';
-
-import { ResizerProps, Position } from './Resizer';
-import useResizer from './useResizer';
-
-const anchorStyle: CSSProperties = {
- marginLeft: '5px',
- width: '2px',
- height: '100%',
- pointerEvents: 'none',
- position: 'relative',
-};
-const styles = {
- container: (position: number) => css`
- position: absolute;
- height: 100%;
- width: 10px;
- left: -5px;
- cursor: e-resize;
- transform: translateX(${position}px);
- user-select: none;
- z-index: 99999999;
-
- &:hover {
- div {
- background-color: red;
- }
- }
- `,
-
- content: (left: Draggable, right: Draggable, prevPosition: Position) => {
- const width = prevPosition.x2 - prevPosition.x1;
-
- const baseCss = css`
- position: absolute;
- width: ${width}px;
- overflow: hidden;
- `;
- if (right.position.action === 'move' || left.position.action === 'move') {
- const scale = (right.position.value.x - left.position.value.x) / width;
- return [
- baseCss,
- css`
- transform: translateX(${left.position.value.x}px) scaleX(${scale});
- transform-origin: left center;
- `,
- ];
- } else {
- return css([
- baseCss,
- css`
- transform: translateX(${left.position.value.x}px);
- `,
- ]);
- }
- },
-};
-
-export default function DivResizer(props: ResizerProps) {
- const { children, disabled } = props;
- const { left, right, prevPosition, currentPosition, isActive } =
- useResizer(props);
-
- return (
- <>
- {!disabled && (
-
- )}
-
- {typeof children === 'function'
- ? children?.(currentPosition, isActive)
- : children}
-
- {!disabled && (
-
- )}
- >
- );
-}
diff --git a/src/component/elements/resizer/Resizer.tsx b/src/component/elements/resizer/Resizer.tsx
deleted file mode 100644
index 112367e78..000000000
--- a/src/component/elements/resizer/Resizer.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import DivResizer from './DivResizer';
-import SVGResizer from './SVGResizer';
-
-export interface Position {
- x1: number;
- x2: number;
-}
-
-type ChildType = React.ReactElement[] | React.ReactElement | boolean | null;
-
-export interface ResizerProps {
- children?: ChildType | ((position: Position, isActive: boolean) => ChildType);
- initialPosition?: Position;
- position?: Position;
- onStart?: PositionChangeHandler;
- onMove?: PositionChangeHandler;
- onEnd?: PositionChangeHandler;
- tag?: 'div' | 'svg';
- parentElement?: HTMLElement | null;
- dragHandleClassName?: string;
- disabled?: boolean;
-}
-
-type PositionChangeHandler = (data: Position) => void;
-
-export default function Resizer(props: ResizerProps) {
- const { tag = 'div', ...resProps } = props;
- if (tag === 'div') {
- return ;
- } else {
- return ;
- }
-}
diff --git a/src/component/elements/resizer/SVGResizer.tsx b/src/component/elements/resizer/SVGResizer.tsx
index 07575f694..49e09600b 100644
--- a/src/component/elements/resizer/SVGResizer.tsx
+++ b/src/component/elements/resizer/SVGResizer.tsx
@@ -1,8 +1,8 @@
+/* eslint-disable react/no-unused-prop-types */
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import { CSSProperties } from 'react';
-import { ResizerProps } from './Resizer';
import useResizer from './useResizer';
const style: Record<'anchor' | 'innerContainer', CSSProperties> = {
@@ -33,22 +33,40 @@ const styles = {
`,
};
+export interface Position {
+ x1: number;
+ x2: number;
+}
+
+type ChildType = React.ReactElement[] | React.ReactElement | boolean | null;
+
+export interface ResizerProps {
+ children?: ChildType | ((position: Position, isActive: boolean) => ChildType);
+ position: Position;
+ onStart?: PositionChangeHandler;
+ onMove?: PositionChangeHandler;
+ onEnd?: PositionChangeHandler;
+ parentElement?: HTMLElement | null;
+ dragHandleClassName?: string;
+ disabled?: boolean;
+}
+
+type PositionChangeHandler = (data: Position) => void;
+
export default function SVGResizer(props: ResizerProps) {
- const { children, disabled } = props;
- const { left, right, currentPosition, isActive } = useResizer(props);
+ const { children, disabled, position } = props;
+ const { left, right, isActive } = useResizer(props);
return (
-
- {typeof children === 'function'
- ? children(currentPosition, isActive)
- : children}
+
+ {typeof children === 'function' ? children(position, isActive) : children}
{!disabled && (
<>
{' '}
>
)}
diff --git a/src/component/elements/resizer/useResizer.tsx b/src/component/elements/resizer/useResizer.tsx
index 430fa85a2..38b5d884a 100644
--- a/src/component/elements/resizer/useResizer.tsx
+++ b/src/component/elements/resizer/useResizer.tsx
@@ -1,31 +1,27 @@
-import { useEffect, useRef } from 'react';
+import { useRef } from 'react';
import useDraggable, { Draggable } from '../draggable/useDraggable';
-import { ResizerProps, Position } from './Resizer';
+import { ResizerProps, Position } from './SVGResizer';
interface UseResizer {
right: Draggable;
left: Draggable;
- prevPosition: Position;
- currentPosition: Position;
isActive: boolean;
}
export default function useResizer(props: ResizerProps): UseResizer {
const {
- initialPosition = { x1: 10, x2: 40 },
+ position = { x1: 0, x2: 0 },
onStart,
onMove,
onEnd,
parentElement,
} = props;
- const currentPosition = useRef<{ x1: number; x2: number }>(initialPosition);
- const prevPosition = useRef<{ x1: number; x2: number }>(initialPosition);
const activeRef = useRef(false);
- const triggerEvent = useRef((position: Position, status: string | null) => {
+ function triggerEvent(position: Position, status: string | null) {
switch (status) {
case 'start':
onStart?.(position);
@@ -35,7 +31,6 @@ export default function useResizer(props: ResizerProps): UseResizer {
onMove?.(position);
break;
case 'end':
- prevPosition.current = position;
activeRef.current = false;
onEnd?.(position);
@@ -43,55 +38,44 @@ export default function useResizer(props: ResizerProps): UseResizer {
default:
break;
}
- });
+ }
const right = useDraggable({
- position: { x: initialPosition.x2, y: 0 },
+ position: { x: position.x2, y: 0 },
parentElement,
fromEdge: true,
+ onChange: (dragEvent) => {
+ const {
+ action,
+ position: { x },
+ } = dragEvent;
+ const resizerBoundaries: Position = {
+ x1: position.x1,
+ x2: x,
+ };
+ triggerEvent(resizerBoundaries, action);
+ },
});
const left = useDraggable({
- position: { x: initialPosition.x1, y: 0 },
+ position: { x: position.x1, y: 0 },
parentElement,
fromEdge: true,
+ onChange(dragEvent) {
+ const {
+ action,
+ position: { x },
+ } = dragEvent;
+ const resizerBoundaries: Position = {
+ x1: x,
+ x2: position.x2,
+ };
+ triggerEvent(resizerBoundaries, action);
+ },
});
- useEffect(() => {
- currentPosition.current = {
- x1: left.position.value.x,
- x2: right.position.value.x,
- };
- }, [left.position.value.x, right.position.value.x]);
-
- useEffect(() => {
- const {
- value: { x },
- action,
- } = left.position;
- const position: Position = {
- x1: x,
- x2: currentPosition.current.x2,
- };
- triggerEvent.current(position, action);
- }, [left.position]);
-
- useEffect(() => {
- const {
- value: { x },
- action,
- } = right.position;
- const position: Position = {
- x1: currentPosition.current.x1,
- x2: x,
- };
- triggerEvent.current(position, action);
- }, [right.position]);
-
return {
left,
right,
- prevPosition: prevPosition.current,
- currentPosition: currentPosition.current,
isActive: activeRef.current,
};
}