127 lines
No EOL
3.2 KiB
TypeScript
Executable file
127 lines
No EOL
3.2 KiB
TypeScript
Executable file
"use client"
|
|
|
|
import * as React from "react"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
const TabsContext = React.createContext<{
|
|
value: string
|
|
onValueChange: (value: string) => void
|
|
} | null>(null)
|
|
|
|
interface TabsProps {
|
|
value: string
|
|
onValueChange: (value: string) => void
|
|
children: React.ReactNode
|
|
className?: string
|
|
}
|
|
|
|
const Tabs = React.forwardRef<HTMLDivElement, TabsProps>(
|
|
({ className, value, onValueChange, children, ...props }, ref) => {
|
|
return (
|
|
<TabsContext.Provider value={{ value, onValueChange }}>
|
|
<div ref={ref} className={cn("", className)} {...props}>
|
|
{children}
|
|
</div>
|
|
</TabsContext.Provider>
|
|
)
|
|
}
|
|
)
|
|
Tabs.displayName = "Tabs"
|
|
|
|
interface TabsListProps {
|
|
children: React.ReactNode
|
|
className?: string
|
|
}
|
|
|
|
const TabsList = React.forwardRef<HTMLDivElement, TabsListProps>(
|
|
({ className, children, ...props }, ref) => {
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
|
|
className
|
|
)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</div>
|
|
)
|
|
}
|
|
)
|
|
TabsList.displayName = "TabsList"
|
|
|
|
interface TabsTriggerProps {
|
|
value: string
|
|
children: React.ReactNode
|
|
className?: string
|
|
}
|
|
|
|
const TabsTrigger = React.forwardRef<HTMLButtonElement, TabsTriggerProps>(
|
|
({ className, children, value, ...props }, ref) => {
|
|
const context = React.useContext(TabsContext)
|
|
|
|
if (!context) {
|
|
throw new Error("TabsTrigger must be used within Tabs")
|
|
}
|
|
|
|
const { value: currentValue, onValueChange } = context
|
|
const isActive = currentValue === value
|
|
|
|
return (
|
|
<button
|
|
ref={ref}
|
|
className={cn(
|
|
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
isActive
|
|
? "bg-background text-foreground shadow-sm"
|
|
: "text-muted-foreground hover:bg-background/50 hover:text-foreground",
|
|
className
|
|
)}
|
|
onClick={() => onValueChange(value)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</button>
|
|
)
|
|
}
|
|
)
|
|
TabsTrigger.displayName = "TabsTrigger"
|
|
|
|
interface TabsContentProps {
|
|
value: string
|
|
children: React.ReactNode
|
|
className?: string
|
|
}
|
|
|
|
const TabsContent = React.forwardRef<HTMLDivElement, TabsContentProps>(
|
|
({ className, children, value, ...props }, ref) => {
|
|
const context = React.useContext(TabsContext)
|
|
|
|
if (!context) {
|
|
throw new Error("TabsContent must be used within Tabs")
|
|
}
|
|
|
|
const { value: currentValue } = context
|
|
|
|
if (currentValue !== value) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
className
|
|
)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</div>
|
|
)
|
|
}
|
|
)
|
|
TabsContent.displayName = "TabsContent"
|
|
|
|
export { Tabs, TabsList, TabsTrigger, TabsContent }
|