Files
supabase/apps/docs/features/ui/useStickyTabs.utils.ts
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

54 lines
1.3 KiB
TypeScript

import { useCallback, useRef } from 'react'
import { useInView } from 'react-intersection-observer'
const useSticky = <Element extends HTMLElement>({
enabled = true,
style = {} as CSSStyleDeclaration,
}: {
enabled?: boolean
style?: CSSStyleDeclaration
} = {}) => {
const stickyRef = useRef<Element>(null)
const handleSticking = useCallback(
(inView: boolean) => {
if (!stickyRef.current) return
if (inView) {
stickyRef.current.style.position = 'sticky'
stickyRef.current.style.top = '100px'
stickyRef.current.style.zIndex = '5'
for (const property in style) {
// @ts-ignore
stickyRef.current.style[property] = style[property]
}
} else {
stickyRef.current.style.position = ''
stickyRef.current.style.top = ''
stickyRef.current.style.zIndex = ''
for (const property in style) {
// @ts-ignore
stickyRef.current.style[property] = ''
}
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[JSON.stringify(style)]
)
const { ref: observedRef, inView } = useInView({
threshold: 0.1,
onChange: handleSticking,
skip: !enabled,
})
return {
inView,
observedRef,
stickyRef,
}
}
export { useSticky }