import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
// Orientation is applied to the pairs rather than to the <dl>, so a
// hand-composed child that carries the same data-slot lines up with the ones
// built from `items`.
const descriptionListVariants = cva("grid", {
variants: {
columns: {
1: "grid-cols-1",
2: "grid-cols-1 sm:grid-cols-2",
3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
},
orientation: {
horizontal:
"*:data-[slot=description-list-item]:grid *:data-[slot=description-list-item]:grid-cols-[minmax(0,8rem)_minmax(0,1fr)] *:data-[slot=description-list-item]:items-baseline",
vertical: "*:data-[slot=description-list-item]:flex *:data-[slot=description-list-item]:flex-col",
},
size: {
default: "gap-x-6 gap-y-4 text-sm *:data-[slot=description-list-item]:gap-x-4 *:data-[slot=description-list-item]:gap-y-0.5",
sm: "gap-x-5 gap-y-3 text-xs *:data-[slot=description-list-item]:gap-x-3 *:data-[slot=description-list-item]:gap-y-0.5",
},
},
defaultVariants: { columns: 1, orientation: "horizontal", size: "default" },
})
export type DescriptionListItem = {
term: React.ReactNode
description: React.ReactNode
}
export type DescriptionListProps = React.ComponentProps<"dl"> & {
/** The pairs to render. Leave it unset and hand-compose the children instead. */
items?: DescriptionListItem[]
columns?: NonNullable<VariantProps<typeof descriptionListVariants>["columns"]>
orientation?: NonNullable<VariantProps<typeof descriptionListVariants>["orientation"]>
size?: NonNullable<VariantProps<typeof descriptionListVariants>["size"]>
}
/** A definition list of term/value pairs — the panel a detail page puts its facts in. */
function DescriptionList({
className,
items,
columns = 1,
orientation = "horizontal",
size = "default",
children,
...props
}: DescriptionListProps) {
return (
<dl
data-slot="description-list"
data-columns={columns}
data-orientation={orientation}
data-size={size}
className={cn(descriptionListVariants({ columns, orientation, size }), className)}
{...props}
>
{items?.map((item, index) => (
<div key={index} data-slot="description-list-item">
<DescriptionTerm>{item.term}</DescriptionTerm>
<DescriptionDetails>{item.description}</DescriptionDetails>
</div>
))}
{children}
</dl>
)
}
/** The quieter half of a pair: what the value beside it is. */
function DescriptionTerm({ className, ...props }: React.ComponentProps<"dt">) {
return (
<dt
data-slot="description-term"
className={cn("min-w-0 text-muted-foreground", className)}
{...props}
/>
)
}
/** The value itself, wrapping rather than overflowing its column. */
function DescriptionDetails({ className, ...props }: React.ComponentProps<"dd">) {
return (
<dd
data-slot="description-details"
className={cn("min-w-0 break-words text-foreground", className)}
{...props}
/>
)
}
export { DescriptionList, DescriptionDetails, DescriptionTerm, descriptionListVariants }