81 lines
1.6 KiB
TypeScript
81 lines
1.6 KiB
TypeScript
import { type LucideIcon } from 'lucide-react'
|
|
import { createContext, useContext, type ReactNode } from 'react'
|
|
|
|
import { cn } from '@repo/ui/lib/utils'
|
|
|
|
type StepContextValue = {
|
|
activeIndex: number
|
|
}
|
|
|
|
const StepContext = createContext<StepContextValue | null>(null)
|
|
|
|
function useStep() {
|
|
const ctx = useContext(StepContext)
|
|
if (!ctx) {
|
|
throw new Error('StepItem must be used inside <Step />')
|
|
}
|
|
return ctx
|
|
}
|
|
|
|
export function Step({
|
|
children,
|
|
className,
|
|
activeIndex
|
|
}: {
|
|
children: ReactNode
|
|
className?: string
|
|
activeIndex: number
|
|
}) {
|
|
return (
|
|
<StepContext.Provider value={{ activeIndex }}>
|
|
<ul
|
|
className={cn(
|
|
'flex max-lg:flex-col lg:items-center gap-1.5 lg:gap-4',
|
|
className
|
|
)}
|
|
>
|
|
{children}
|
|
</ul>
|
|
</StepContext.Provider>
|
|
)
|
|
}
|
|
|
|
export function StepSeparator() {
|
|
return (
|
|
<div className="max-lg:w-px max-lg:ml-[19px] h-3 lg:h-px lg:w-full bg-foreground/25" />
|
|
)
|
|
}
|
|
|
|
export function StepItem({
|
|
children,
|
|
icon: Icon,
|
|
index
|
|
}: {
|
|
children: ReactNode
|
|
icon: LucideIcon
|
|
index: number
|
|
}) {
|
|
const { activeIndex } = useStep()
|
|
const active = index === activeIndex
|
|
|
|
return (
|
|
<li
|
|
className={cn(
|
|
'flex items-center gap-2 flex-none text-muted-foreground',
|
|
active && 'dark:text-white'
|
|
)}
|
|
>
|
|
<div
|
|
className={cn(
|
|
'p-3 rounded-full',
|
|
active ? 'bg-primary text-white' : 'bg-accent'
|
|
)}
|
|
>
|
|
<Icon className="size-4" />
|
|
</div>
|
|
|
|
<div className="text-sm">{children}</div>
|
|
</li>
|
|
)
|
|
}
|