From 08551a37a2ad01fafdbb986136da9bf2e59043c4 Mon Sep 17 00:00:00 2001 From: xc2 Date: Sun, 6 Oct 2024 01:11:43 +0800 Subject: [PATCH] refactor: make resizing more natural --- .../src/components/ui/modal/stacked/hooks.tsx | 32 +++++++++++++++++-- .../src/components/ui/modal/stacked/modal.tsx | 15 ++++++--- .../src/modules/settings/modal/layout.tsx | 22 +++++++++---- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/apps/renderer/src/components/ui/modal/stacked/hooks.tsx b/apps/renderer/src/components/ui/modal/stacked/hooks.tsx index 0598c5868c..79d59d7da4 100644 --- a/apps/renderer/src/components/ui/modal/stacked/hooks.tsx +++ b/apps/renderer/src/components/ui/modal/stacked/hooks.tsx @@ -1,3 +1,5 @@ +import type { DragControls } from "framer-motion" +import type { ResizeCallback, ResizeStartCallback } from "re-resizable" import { useCallback, useContext, useId, useRef, useState } from "react" import { flushSync } from "react-dom" import { useEventCallback } from "usehooks-ts" @@ -87,14 +89,17 @@ export const useResizeableModal = ( modalElementRef: React.RefObject, { enableResizeable, + dragControls, }: { enableResizeable: boolean + dragControls?: DragControls }, ) => { const [resizeableStyle, setResizeableStyle] = useState({} as React.CSSProperties) const [isResizeable, setIsResizeable] = useState(false) + const [preferDragDir, setPreferDragDir] = useState<"x" | "y" | null>(null) - const handlePointDown = useEventCallback(() => { + const relocateModal = useEventCallback(() => { if (!enableResizeable) return if (isResizeable) return const $modalElement = modalElementRef.current @@ -112,10 +117,33 @@ export const useResizeableModal = ( }) }) }) + const handleResizeStart = useEventCallback(((e, dir) => { + if (!enableResizeable) return + relocateModal() + + const hasTop = /top/i.test(dir) + const hasLeft = /left/i.test(dir) + if (hasTop || hasLeft) { + dragControls?.start(e as any) + if (hasTop && hasLeft) { + setPreferDragDir(null) + } else if (hasTop) { + setPreferDragDir("y") + } else if (hasLeft) { + setPreferDragDir("x") + } + } + }) satisfies ResizeStartCallback) + const handleResizeStop = useEventCallback((() => { + setPreferDragDir(null) + }) satisfies ResizeCallback) return { resizeableStyle, isResizeable, - handlePointDown, + relocateModal, + handleResizeStart, + handleResizeStop, + preferDragDir, } } diff --git a/apps/renderer/src/components/ui/modal/stacked/modal.tsx b/apps/renderer/src/components/ui/modal/stacked/modal.tsx index 8bfcbe70be..5cac9b0192 100644 --- a/apps/renderer/src/components/ui/modal/stacked/modal.tsx +++ b/apps/renderer/src/components/ui/modal/stacked/modal.tsx @@ -109,12 +109,17 @@ export const ModalInternal = memo( const modalElementRef = useRef(null) + const dragController = useDragControls() const { - handlePointDown: handleResizeEnable, + handleResizeStop, + handleResizeStart, + relocateModal, + preferDragDir, isResizeable, resizeableStyle, } = useResizeableModal(modalElementRef, { enableResizeable: resizeable, + dragControls: dragController, }) const animateController = useAnimationControls() useEffect(() => { @@ -137,7 +142,6 @@ export const ModalInternal = memo( }) }, [animateController]) - const dragController = useDragControls() const handleDrag: PointerEventHandler = useCallback( (e) => { if (draggable) { @@ -347,7 +351,7 @@ export const ModalInternal = memo( onClick={stopPropagation} onSelect={handleSelectStart} onKeyUp={handleDetectSelectEnd} - drag + drag={draggable && (preferDragDir || draggable)} dragControls={dragController} dragElastic={0} dragListener={false} @@ -360,14 +364,15 @@ export const ModalInternal = memo( >
{icon && {icon}} diff --git a/apps/renderer/src/modules/settings/modal/layout.tsx b/apps/renderer/src/modules/settings/modal/layout.tsx index be7183bf00..56f47baf39 100644 --- a/apps/renderer/src/modules/settings/modal/layout.tsx +++ b/apps/renderer/src/modules/settings/modal/layout.tsx @@ -29,8 +29,17 @@ export function SettingModalLayout( const tab = useSettingTab() const elementRef = useRef(null) const edgeElementRef = useRef(null) - const { handlePointDown, isResizeable, resizeableStyle } = useResizeableModal(elementRef, { + const dragController = useDragControls() + const { + handleResizeStart, + handleResizeStop, + preferDragDir, + relocateModal, + isResizeable, + resizeableStyle, + } = useResizeableModal(elementRef, { enableResizeable: true, + dragControls: dragController, }) useEffect(() => { @@ -47,15 +56,14 @@ export function SettingModalLayout( draggable: state.modalDraggable, overlay: state.modalOverlay, })) - const dragController = useDragControls() const handleDrag: PointerEventHandler = useCallback( (e) => { if (draggable) { dragController.start(e) - handlePointDown() + relocateModal() } }, - [dragController, draggable, handlePointDown], + [dragController, draggable, relocateModal], ) const measureDragConstraints = useCallback((constraints: BoundingBox) => { if (getOS() === "Windows") { @@ -80,7 +88,7 @@ export function SettingModalLayout( )} style={resizeableStyle} onContextMenu={preventDefault} - drag={draggable} + drag={draggable && (preferDragDir || draggable)} dragControls={dragController} dragListener={false} dragMomentum={false} @@ -93,9 +101,9 @@ export function SettingModalLayout( >