Files
supabase/apps/studio/components/ui/AIAssistantPanel/hooks.ts
Gildas Garcia 86a3f8b03d chore: upgrade to react-19 (#45886)
- Most changes are related to either types or `useRef` usages (it now
requires an initial value).
- also updated `vaul` to its latest version and haven't noticed any
change ([design-system
demo](https://design-system-git-react-19-supabase.vercel.app/design-system/docs/components/drawer))

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Upgraded workspace to React 19.

* **Bug Fixes**
* Improved null-safety and ref handling across editors, UI components,
shortcuts, and markdown/image rendering to reduce runtime errors.
* Safer event/timeout/interval cleanup and more robust command/context
handling.

* **Chores**
  * Bumped vaul dependency versions.

* **Documentation**
* Type and TypeScript accuracy improvements for clearer developer
feedback.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45886)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-15 16:04:41 +02:00

74 lines
1.9 KiB
TypeScript

import { useCallback, useEffect, useRef, useState } from 'react'
interface UseAutoScrollProps {
enabled?: boolean
}
export function useAutoScroll({ enabled = true }: UseAutoScrollProps = {}) {
const [container, setContainer] = useState<HTMLDivElement | null>(null)
const [isSticky, setIsSticky] = useState(true)
const isStickyRef = useRef(true)
const lastScrollHeightRef = useRef<number>(null)
const ref = useCallback((element: HTMLDivElement | null) => {
if (element) {
setContainer(element)
}
}, [])
const scrollToEnd = useCallback(() => {
if (container) {
isStickyRef.current = true
setIsSticky(true)
container.scrollTo({
top: container.scrollHeight,
behavior: 'smooth',
})
}
}, [container])
useEffect(() => {
if (!container || !enabled) return
let timeoutId: NodeJS.Timeout
const resizeObserver = new ResizeObserver(() => {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
if (
lastScrollHeightRef.current != null &&
container.scrollHeight !== lastScrollHeightRef.current
) {
lastScrollHeightRef.current = container.scrollHeight
if (isStickyRef.current) {
scrollToEnd()
}
}
}, 100)
})
const handleScroll = () => {
const isAtBottom =
Math.abs(container.scrollHeight - container.scrollTop - container.clientHeight) < 10
isStickyRef.current = isAtBottom
setIsSticky(isAtBottom)
}
// Observe all children of the container
Array.from(container.children).forEach((child) => {
resizeObserver.observe(child)
})
container.addEventListener('scroll', handleScroll)
return () => {
clearTimeout(timeoutId)
resizeObserver.disconnect()
container.removeEventListener('scroll', handleScroll)
}
}, [container, enabled, scrollToEnd])
return { ref, isSticky, scrollToEnd, setIsSticky }
}