diff --git a/packages/@core/composables/src/use-resizable.ts b/packages/@core/composables/src/use-resizable.ts index eeda2df9..9939819d 100644 --- a/packages/@core/composables/src/use-resizable.ts +++ b/packages/@core/composables/src/use-resizable.ts @@ -1,4 +1,4 @@ -import { onUnmounted, ref } from 'vue'; +import { onUnmounted } from 'vue'; interface ResizableOptions { max?: number; @@ -9,40 +9,70 @@ interface ResizableOptions { export function useResizable(options: ResizableOptions = {}) { const { min = 0, max = 999, onChange } = options; - const isDragging = ref(false); - - let cleanup: (() => void) | null = null; - + let startX = 0; + let startWidth = 0; + let targetTransition = ''; + let dragBarTransition = ''; + let dragBarOffsetLeft = 0; + let dragBarLeft = ''; + let dragBarRight = ''; let userSelect = ''; let cursor = ''; + let cleanup: (() => void) | null = null; + + const startDrag = ( + e: MouseEvent, + currentWidth: number, + targetElement: HTMLElement | null, + dragBarElement: HTMLElement | null, + ) => { + cleanup?.(); - const startDrag = (e: MouseEvent, width: number) => { e.preventDefault(); e.stopPropagation(); - isDragging.value = true; - const startX = e.clientX; - const startWidth = width; + if (!dragBarElement || !targetElement) return; + + startX = e.clientX; + startWidth = currentWidth; + + targetTransition = targetElement.style.transition; + dragBarTransition = dragBarElement.style.transition; + + dragBarOffsetLeft = dragBarElement.offsetLeft; + dragBarLeft = dragBarElement.style.left; + dragBarRight = dragBarElement.style.right; userSelect = document.body.style.userSelect; cursor = document.body.style.cursor; + targetElement.style.transition = 'none'; + dragBarElement.style.transition = 'none'; + + dragBarElement.style.left = `${dragBarOffsetLeft}px`; + dragBarElement.style.right = 'auto'; + document.body.style.userSelect = 'none'; document.body.style.cursor = 'col-resize'; const onMouseMove = (moveEvent: MouseEvent) => { - if (!isDragging.value) return; - const deltaX = moveEvent.clientX - startX; - let newWidth = startWidth + deltaX; - - newWidth = Math.min(max, Math.max(min, newWidth)); - - onChange?.(newWidth); + const newLeft = dragBarOffsetLeft + deltaX; + dragBarElement.style.left = `${newLeft}px`; }; - const onMouseUp = () => { - if (!isDragging.value) return; + const onMouseUp = (upEvent: MouseEvent) => { + const deltaX = upEvent.clientX - startX; + let newWidth = startWidth + deltaX; + newWidth = Math.min(max, Math.max(min, newWidth)); + + if (dragBarElement) { + dragBarElement.style.left = dragBarLeft; + dragBarElement.style.right = dragBarRight; + } + + onChange?.(newWidth); + cleanup?.(); }; @@ -53,10 +83,18 @@ export function useResizable(options: ResizableOptions = {}) { document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); + if (targetElement) { + targetElement.style.transition = targetTransition; + } + if (dragBarElement) { + dragBarElement.style.transition = dragBarTransition; + dragBarElement.style.left = dragBarLeft; + dragBarElement.style.right = dragBarRight; + } + document.body.style.userSelect = userSelect; document.body.style.cursor = cursor; - isDragging.value = false; cleanup = null; }; }; @@ -66,7 +104,6 @@ export function useResizable(options: ResizableOptions = {}) { }); return { - isDragging, startDrag, }; } diff --git a/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue b/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue index c3930ac9..2f56bdc6 100644 --- a/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue +++ b/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue @@ -118,8 +118,8 @@ const extraVisible = defineModel('extraVisible'); const isLocked = useScrollLock(document.body); const slots = useSlots(); -// @ts-expect-error unused -const asideRef = shallowRef(); +const asideRef = shallowRef(null); +const dragBarRef = shallowRef(null); const hiddenSideStyle = computed((): CSSProperties => calcMenuWidthStyle(true)); @@ -256,7 +256,7 @@ function handleMouseleave() { extraVisible.value = false; } -const { isDragging, startDrag } = useResizable({ +const { startDrag } = useResizable({ min: 160, max: 320, onChange: (newWidth) => { @@ -265,8 +265,9 @@ const { isDragging, startDrag } = useResizable({ }); const handleDragSidebar = (e: MouseEvent) => { - const { width } = props; - startDrag(e, width); + const { isSidebarMixed, extraWidth, width } = props; + const currentWidth = isSidebarMixed ? extraWidth : width; + startDrag(e, currentWidth, asideRef.value, dragBarRef.value); }; @@ -278,9 +279,9 @@ const handleDragSidebar = (e: MouseEvent) => { class="h-full transition-all duration-150" > diff --git a/packages/effects/layouts/src/basic/layout.vue b/packages/effects/layouts/src/basic/layout.vue index cedd0cd6..874951f9 100644 --- a/packages/effects/layouts/src/basic/layout.vue +++ b/packages/effects/layouts/src/basic/layout.vue @@ -211,14 +211,6 @@ const slots: SetupContext['slots'] = useSlots(); const headerSlots = computed(() => { return Object.keys(slots).filter((key) => key.startsWith('header-')); }); - -function handleUpdateSidebarWidth(newWidth: number) { - updatePreferences({ - sidebar: { - width: newWidth, - }, - }); -}