Files
supabase/apps/docs/features/ui/useStickyTabs.tsx
Gildas Garcia 4b7cb27ba9 chore: refactor docs tabs (#47557)
## Problem

Now that `docs` is the only place where we use the deprecated `ui/Tabs`,
we can move this component and the related HOC from `ui-patterns` in
`docs`

## Solution

- Move `ui/Tabs`, `ui-patterns/ComplexTabs/withQueryParams` and
`ui-patterns/ComplexTabs/withSticky` to `docs`
- Refactor `ui-patterns/ComplexTabs/withQueryParams` and
`ui-patterns/ComplexTabs/withSticky` HOCs as hooks to make them easier
to understand
- Refactor `Tabs` accordingly

No visual nor functional changes.

## How to test

On
https://docs-git-chore-refactor-docs-tabs-supabase.vercel.app/docs/guides/auth/passwords
(Tabs are driven by URL and the flow tabs should have sticky headers
even though there's a CSS bug already reported)
- check that by default, the first tab in each tabs is active
- change the tabs in different groups and validate it works
- refresh the page and check that previously selected tabs are active
(URL based selection)
- In a new tab, visit
https://docs-git-chore-refactor-docs-tabs-supabase.vercel.app/docs/guides/auth/passwords
again and check that previously selected tabs are active (LocalStorage
based selection)

Do the same on
https://docs-git-chore-refactor-docs-tabs-supabase.vercel.app/docs/guides/database/database-advisors
(This one is driven by URL but does not have sticky tab headers)

Do the same on
https://docs-git-chore-refactor-docs-tabs-supabase.vercel.app/docs/guides/deployment/terraform/reference
(this one is not driven by URL nor has sticky tab headers)

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

* **New Features**
* Docs tabs now persist and restore the active tab via URL query
parameters.
* Added optional “sticky” tab behavior that keeps the active panel in
view.
  * Enhanced keyboard interaction for selecting tabs.
* **Bug Fixes**
* Improved active-tab initialization and synchronization when the URL
query changes.
* **Chores**
* Refreshed the tabs UI implementation and styling to improve
consistency and remove deprecated tab exports from shared UI packages.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-04 02:44:29 +10:00

46 lines
1.3 KiB
TypeScript

'use client'
import { useCallback, useMemo, type FC } from 'react'
import { useSticky } from './useStickyTabs.utils'
export type UseStickyTabsOptions = { scrollMarginTop?: string; style?: CSSStyleDeclaration }
export const useStickyTabs = (options?: UseStickyTabsOptions) => {
const enabled = !!options
const { scrollMarginTop, style } = options || {}
const { inView, observedRef, stickyRef } = useSticky<HTMLDivElement>({
enabled,
style,
})
const onTabSelected = useCallback(() => {
if (enabled && inView && stickyRef.current) {
let elem = stickyRef.current as Element | null
while (elem && !elem.matches('[role="tabpanel"][data-state="active"]')) {
elem = elem.nextElementSibling
}
if (!elem) return
const top = elem.getBoundingClientRect().top
;(elem as HTMLElement).style.scrollMarginTop = scrollMarginTop || '0px'
if (top < 0) {
elem.scrollIntoView({
behavior: window.matchMedia('(prefers-reduced-motion: no-preference)').matches
? 'smooth'
: 'instant',
})
}
}
}, [enabled, inView, scrollMarginTop, stickyRef])
return useMemo(
() => ({
observedRef,
stickyRef,
onTabSelected,
}),
[observedRef, stickyRef, onTabSelected]
)
}