Skip to content

Commit

Permalink
fix: tab impl
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <i@innei.in>
  • Loading branch information
Innei committed Apr 19, 2024
1 parent 58de110 commit afedffe
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 82 deletions.
50 changes: 25 additions & 25 deletions markdown/sections/usage/custom-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,31 @@ export const markdownComponents: MarkdownToJSX.Overrides = {
### Tab

<Tabs>
<Tab label="layout.tsx">
```tsx filename="app/server-action/layout.tsx"
import type { PropsWithChildren } from 'react'

export default async ({ children }: PropsWithChildren) => {
return (
<div className="m-auto mt-12 max-w-[800px]">
<div>Layout Render At: {Date.now()}</div>
{children}
</div>
)
}
```
</Tab>
<Tab label="action.tsx">
```tsx filename="app/server-action/action.tsx"
'use server'

import { revalidatePath } from 'next/cache'

export const actionRevalidate = async () => {
revalidatePath('/server-action')
}
```
</Tab>
<Tab label="layout.tsx">
```tsx filename="app/server-action/layout.tsx"
import type { PropsWithChildren } from 'react'

export default async ({ children }: PropsWithChildren) => {
return (
<div className="m-auto mt-12 max-w-[800px]">
<div>Layout Render At: {Date.now()}</div>
{children}
</div>
)
}
```
</Tab>
<Tab label="action.tsx">
```tsx filename="app/server-action/action.tsx"
'use server'

import { revalidatePath } from 'next/cache'

export const actionRevalidate = async () => {
revalidatePath('/server-action')
}
```
</Tab>
</Tabs>

代码为:
Expand Down
103 changes: 46 additions & 57 deletions src/components/tabs/Tab.tsx
Original file line number Diff line number Diff line change
@@ -1,79 +1,68 @@
'use client'

import * as RadixTabs from '@radix-ui/react-tabs'
import {
createContext,
useCallback,
useContext,
useEffect,
useId,
useState,
} from 'react'
import React, { useId, useMemo, useState } from 'react'
import { m } from 'framer-motion'
import type { FC, PropsWithChildren } from 'react'

import { clsxm } from '~/lib/helper'

const TabActionContext = createContext<{
addTab: (label: string) => void
}>(null!)
export const Tabs: FC<PropsWithChildren> = ({ children }) => {
const [tabs, setTabs] = useState<string[]>([])
const [activeTab, setActiveTab] = useState<string | null>(null)
const id = useId()
return (
<TabActionContext.Provider
value={{
addTab: useCallback(
(label) => {
setTabs((tabs) => [...tabs, label])

if (!activeTab) setActiveTab(label)
return () => {
setTabs((tabs) => tabs.filter((tab) => tab !== label))
}
},
[activeTab],
),
}}
>
<RadixTabs.Root value={activeTab || ''} onValueChange={setActiveTab}>
<RadixTabs.List>
{tabs.map((tab) => {
return (
<RadixTabs.Trigger
className={clsxm('mr-4 p-2', 'relative')}
key={tab}
value={tab}
>
{tab}
const tabs = useMemo(() => {
const labels = [] as string[]
for (const child of React.Children.toArray(children)) {
if (!child) {
continue
}
if (typeof child !== 'object') continue
if (!('props' in child)) continue
if (!('type' in child)) continue

// if (child.type !== Tab) continue
const label = child.props.label
labels.push(label)
}
return labels
}, [children])

{activeTab === tab && (
<m.div
layoutId={`tab${id}`}
layout
className="absolute bottom-0 left-0 right-0 h-[2px] rounded-md bg-accent"
/>
)}
</RadixTabs.Trigger>
)
})}
</RadixTabs.List>
const [activeTab, setActiveTab] = useState<string | null>(tabs[0])
return (
<RadixTabs.Root value={activeTab || ''} onValueChange={setActiveTab}>
<RadixTabs.List className="flex gap-2">
{tabs.map((tab) => {
return (
<RadixTabs.Trigger
className={clsxm(
'relative flex px-2 py-1 text-sm font-bold focus:outline-none',
'text-gray-600 transition-colors duration-300 dark:text-gray-300',
)}
key={tab}
value={tab}
>
{tab}

{children}
</RadixTabs.Root>
</TabActionContext.Provider>
{activeTab === tab && (
<m.div
layoutId={`tab${id}`}
layout
className="absolute inset-x-2 -bottom-1 h-[2px] rounded-md bg-accent"
/>
)}
</RadixTabs.Trigger>
)
})}
</RadixTabs.List>

{children}
</RadixTabs.Root>
)
}

export const Tab: FC<{
label: string
children: React.ReactNode
}> = ({ label, children }) => {
const { addTab } = useContext(TabActionContext)
useEffect(() => {
return addTab(label)
}, [])

return <RadixTabs.Content value={label}>{children}</RadixTabs.Content>
}

0 comments on commit afedffe

Please sign in to comment.