diff --git a/resources/js/components/ui/Combobox/Combobox.vue b/resources/js/components/ui/Combobox/Combobox.vue index 3674f036e0..6d8764d326 100644 --- a/resources/js/components/ui/Combobox/Combobox.vue +++ b/resources/js/components/ui/Combobox/Combobox.vue @@ -447,6 +447,7 @@ defineExpose({ diff --git a/resources/js/components/ui/Combobox/Scrollbar.vue b/resources/js/components/ui/Combobox/Scrollbar.vue index cbfba69c3c..a568c91f69 100644 --- a/resources/js/components/ui/Combobox/Scrollbar.vue +++ b/resources/js/components/ui/Combobox/Scrollbar.vue @@ -8,6 +8,9 @@ const props = defineProps({ const isVisible = ref(false); const thumbHeight = ref(0); const thumbTop = ref(0); +const isDragging = ref(false); + +let resizeObserver = null; function update() { const element = props.viewport?.$el || props.viewport; @@ -32,13 +35,58 @@ function update() { } } +function handleMouseDown(event) { + event.preventDefault(); + isDragging.value = true; + + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); +} + +function handleMouseMove(event) { + if (!isDragging.value) return; + + const element = props.viewport?.$el || props.viewport; + if (!element) return; + + const scrollbarTrack = element.parentElement.querySelector('.absolute.top-0.right-0'); + if (!scrollbarTrack) return; + + const trackRect = scrollbarTrack.getBoundingClientRect(); + const mouseY = event.clientY - trackRect.top; + const trackHeight = trackRect.height; + + // Calculate scroll position based on mouse position + const scrollPercent = Math.max(0, Math.min(1, mouseY / trackHeight)); + const maxScroll = element.scrollHeight - element.clientHeight; + + element.scrollTop = scrollPercent * maxScroll; +} + +function handleMouseUp() { + isDragging.value = false; + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); +} + watch( () => props.viewport, - (viewport) => { + (viewport, oldViewport) => { + const oldElement = oldViewport?.$el || oldViewport; + + if (oldElement) { + oldElement.removeEventListener('scroll', update); + resizeObserver?.disconnect(); + } + if (viewport) { const element = viewport.$el || viewport; if (element) { element.addEventListener('scroll', update); + + resizeObserver = new ResizeObserver(() => update()); + resizeObserver.observe(element); + nextTick(() => update()); } } @@ -52,21 +100,29 @@ onUnmounted(() => { if (element) { element.removeEventListener('scroll', update); } + + resizeObserver?.disconnect(); + + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); }); defineExpose({ update, + isVisible, }); \ No newline at end of file