50 lines
2.1 KiB
TypeScript
50 lines
2.1 KiB
TypeScript
"use client"
|
|
|
|
import { createContext, useContext, useId, type ComponentProps } from "react"
|
|
import {
|
|
Stepper as RegistryStepper,
|
|
StepperNav as RegistryNav,
|
|
StepperContent as RegistryContent,
|
|
StepperTrigger as RegistryTrigger,
|
|
useStepItem,
|
|
type StepperProps,
|
|
} from "@/components/reui/stepper"
|
|
|
|
export { StepperItem, StepperIndicator, StepperSeparator, StepperTitle, StepperPanel } from "@/components/reui/stepper"
|
|
|
|
// The registry Nav/Content do not forward HTML attributes. Keep its layout,
|
|
// focus handling and styling; supply tab semantics in transparent wrappers.
|
|
const Context = createContext<{ prefix: string; orientation: "horizontal" | "vertical" } | null>(null)
|
|
function useScope() {
|
|
const context = useContext(Context)
|
|
if (!context) throw new Error("Шаги должны находиться внутри Stepper")
|
|
return context
|
|
}
|
|
|
|
export function Stepper({ orientation = "horizontal", ...props }: StepperProps) {
|
|
const prefix = useId()
|
|
return <Context.Provider value={{ prefix, orientation }}>
|
|
<RegistryStepper {...props} orientation={orientation} role="group" aria-orientation={undefined} />
|
|
</Context.Provider>
|
|
}
|
|
|
|
export function StepperNav({ children, className }: Pick<ComponentProps<typeof RegistryNav>, "children" | "className">) {
|
|
const { orientation } = useScope()
|
|
return <RegistryNav className={className}>
|
|
<div role="tablist" aria-label="Шаги формы" aria-orientation={orientation} className="contents">{children}</div>
|
|
</RegistryNav>
|
|
}
|
|
|
|
export function StepperTrigger(props: ComponentProps<typeof RegistryTrigger>) {
|
|
const { prefix } = useScope()
|
|
const { step } = useStepItem()
|
|
return <RegistryTrigger {...props} id={`${prefix}-tab-${step}`} aria-controls={`${prefix}-panel-${step}`} />
|
|
}
|
|
|
|
export function StepperContent({ value, children, className }: Pick<ComponentProps<typeof RegistryContent>, "value" | "children" | "className">) {
|
|
const { prefix } = useScope()
|
|
return <RegistryContent value={value} forceMount className={className}>
|
|
<div role="tabpanel" id={`${prefix}-panel-${value}`} aria-labelledby={`${prefix}-tab-${value}`} className="contents">{children}</div>
|
|
</RegistryContent>
|
|
}
|