Skip to content

Commit

Permalink
refactor: tab cls
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <[email protected]>
  • Loading branch information
Innei committed Apr 19, 2024
1 parent 70e282c commit 5ba3f17
Showing 1 changed file with 43 additions and 62 deletions.
105 changes: 43 additions & 62 deletions src/components/ui/markdown/renderers/tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,89 +1,70 @@
'use client'

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

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

import { Markdown } from '../Markdown'

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()

useEffect(() => {
if (!tabs.length) return
if (!activeTab) {
setActiveTab(tabs[0])
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)
}
}, [tabs.length])
return labels
}, [children])
const [activeTab, setActiveTab] = useState<string | null>(tabs[0])
return (
<TabActionContext.Provider
value={{
addTab: useCallback((label) => {
setTabs((tabs) => [...tabs, label])

return () => {
setTabs((tabs) => tabs.filter((tab) => tab !== label))
}
}, []),
}}
>
<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}
<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}

{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>
{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>
</TabActionContext.Provider>
{children}
</RadixTabs.Root>
)
}

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

return (
<RadixTabs.Content value={label}>
<Markdown wrapper={null} removeWrapper>
Expand Down

0 comments on commit 5ba3f17

Please sign in to comment.