mirror of
https://github.com/hanzoai/gui.git
synced 2026-10-25 02:31:41 +00:00
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]>
134 lines
2.7 KiB
TypeScript
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,
|
|
})
|