Files
zeekayandHanzo Dev bfe539744a Type the tab wrappers and variant spreads as the packages declare them
React passes ref as a prop, and a forwardRef over props with an index
signature drops every named prop through Omit; the font extras are
optional in a spread function's config.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 21:34:25 -07:00

134 lines
2.7 KiB
TypeScript

import { useStore, useStoreSelector } from '@hanzogui/use-store'
import type { TabsProps, TabsTabProps } from '@hanzo/gui'
import { Paragraph, Tabs, XStack, styled, withStaticProperties } from '@hanzo/gui'
import { type Href, useParams, useRouter } from 'one'
class TabsStore {
active = 'styled'
}
function TabsComponent(props: TabsProps) {
const router = useRouter()
const query = useParams()
const store = useStore(TabsStore)
const id = props.id || 'value'
const updateUrl = (newValue: string) => {
store.active = newValue
const url = new URL(location.href)
url.searchParams.set(id, newValue)
url.hash = '' // having this set messes with the scroll
const params = Object.fromEntries(url.searchParams?.entries() ?? [])
router.replace(
{
pathname: location.pathname,
params,
} as Href,
{
scroll: false,
}
)
}
const value =
typeof query[id] === 'string' ? (query[id] as string) : (props.defaultValue ?? '')
return (
<Tabs
activationMode="manual"
onValueChange={updateUrl}
unstyled
orientation="horizontal"
flexDirection="column"
borderWidth={0}
{...props}
value={value ?? ''}
/>
)
}
const Tab = (props: TabsTabProps) => {
const isActive = useStoreSelector(TabsStore, (x) => x.active === props.value)
return (
<Tabs.Tab
size="$3"
flex={1}
px="$5"
pointerEvents="auto"
rounded="$5"
{...props}
focusStyle={{
outlineColor: '$outlineColor',
outlineWidth: 2,
outlineStyle: 'solid',
}}
{...(isActive && {
backgroundColor: '$color7',
hoverStyle: {
backgroundColor: '$color7',
},
focusStyle: {
backgroundColor: '$color7',
},
})}
>
<Paragraph size="$3">{props.children}</Paragraph>
</Tabs.Tab>
)
}
const TabsListFrame = styled(XStack, {
pointerEvents: 'none',
maxW: '100%',
height: '$4',
self: 'stretch',
mr: 0,
mb: 0,
pb: '$2',
z: 10000,
position: 'sticky' as any,
px: '$2',
items: 'center',
borderColor: '$color4',
borderBottomWidth: '$1',
rounded: '$2',
$sm: {
minW: '100%',
self: 'stretch',
mt: 0,
},
})
const TabsList = (props) => {
return (
<TabsListFrame className="sticky">
<Tabs.List gap="$3" {...props} />
</TabsListFrame>
)
}
const TabsContent = (props) => {
return (
<Tabs.Content
width="100%"
justify="flex-start"
items="stretch"
t="$-2"
pt="$4"
{...props}
/>
)
}
export const InlineTabs = withStaticProperties(TabsComponent, {
List: TabsList,
Tab,
Content: TabsContent,
})