diff --git a/packages/@core/composables/src/index.ts b/packages/@core/composables/src/index.ts index 2dbd4b80..2f6826f2 100644 --- a/packages/@core/composables/src/index.ts +++ b/packages/@core/composables/src/index.ts @@ -2,6 +2,7 @@ export * from './use-is-mobile'; export * from './use-layout-style'; export * from './use-namespace'; export * from './use-priority-value'; +export * from './use-resizable'; export * from './use-scroll-lock'; export * from './use-simple-locale'; export * from './use-sortable'; diff --git a/packages/@core/composables/src/use-resizable.ts b/packages/@core/composables/src/use-resizable.ts new file mode 100644 index 00000000..eeda2df9 --- /dev/null +++ b/packages/@core/composables/src/use-resizable.ts @@ -0,0 +1,72 @@ +import { onUnmounted, ref } from 'vue'; + +interface ResizableOptions { + max?: number; + min?: number; + onChange?: (newWidth: number) => void; +} + +export function useResizable(options: ResizableOptions = {}) { + const { min = 0, max = 999, onChange } = options; + + const isDragging = ref(false); + + let cleanup: (() => void) | null = null; + + let userSelect = ''; + let cursor = ''; + + const startDrag = (e: MouseEvent, width: number) => { + e.preventDefault(); + e.stopPropagation(); + + isDragging.value = true; + const startX = e.clientX; + const startWidth = width; + + userSelect = document.body.style.userSelect; + cursor = document.body.style.cursor; + + 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 onMouseUp = () => { + if (!isDragging.value) return; + cleanup?.(); + }; + + document.addEventListener('mousemove', onMouseMove, { passive: true }); + document.addEventListener('mouseup', onMouseUp); + + cleanup = () => { + document.removeEventListener('mousemove', onMouseMove); + document.removeEventListener('mouseup', onMouseUp); + + document.body.style.userSelect = userSelect; + document.body.style.cursor = cursor; + + isDragging.value = false; + cleanup = null; + }; + }; + + onUnmounted(() => { + cleanup?.(); + }); + + 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 dddb282b..c3930ac9 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 @@ -1,8 +1,9 @@