import { clsx } from 'clsx'
import { Icon } from '@/components/icon'
export interface ListProps extends React.ComponentPropsWithoutRef<'ul'> {
variant?: 'default' | 'bulleted' | 'numbered' | 'unstyled'
spacing?: 'tight' | 'normal' | 'loose'
gap?: string
fontSize?: string
color?: string | undefined
fontFamily?: string
fontWeight?: string
fontStyle?: string
lineHeight?: string
textAlign?: string
margin?: string
className?: string
ordered?: boolean
}
export interface LiProps extends React.ComponentPropsWithoutRef<'li'> {
className?: string
icon?:
| React.ComponentType<{ className?: string }>
| { body: string; width?: number; height?: number }
iconSize?: string
iconGap?: string
}
export function List({
className = '',
variant = 'default',
spacing = 'normal',
gap = '',
fontSize = '',
color = '',
fontFamily = '',
fontWeight = '',
fontStyle = '',
lineHeight = '',
textAlign = '',
margin = '',
ordered = false,
children,
...props
}: ListProps) {
const variantClasses = {
default: 'list-disc',
bulleted: 'list-disc',
numbered: 'list-decimal',
unstyled: 'list-none',
}
const spacingClasses = {
tight: 'space-y-1',
normal: 'space-y-2',
loose: 'space-y-4',
}
const finalFontSize = fontSize || 'text-base'
const finalColor = color || 'text-contrast'
const finalFontFamily = fontFamily || ''
const finalFontWeight = fontWeight || 'font-normal'
const finalFontStyle = fontStyle || ''
const finalLineHeight = lineHeight || ''
const finalTextAlign = textAlign || ''
const finalMargin = margin || 'mb-8'
const finalGap = gap || 'gap-y-2'
const Component = ordered ? 'ol' : 'ul'
return (
<Component
className={clsx(
'content-wrapper [&>li]:mb-0 grid',
'[&_a]:underline',
ordered ? 'list-decimal' : variantClasses[variant],
spacingClasses[spacing],
variant !== 'unstyled' && '[&>li]:ml-6',
finalFontSize,
finalColor,
finalFontFamily,
finalFontWeight,
finalFontStyle,
finalLineHeight,
finalTextAlign,
finalMargin,
finalGap,
className
)}
{...props}
>
{children}
</Component>
)
}
export function Li({
className = '',
icon,
iconSize = 'w-5 h-5',
iconGap = 'gap-x-3',
children,
...props
}: LiProps) {
const isIconifyIcon = icon && typeof icon === 'object' && 'body' in icon
const IconComponent = !isIconifyIcon
? (icon as React.ComponentType<{ className?: string }>)
: null
return (
<li
className={clsx(
'[&>ul]:mt-2',
icon && 'flex',
icon && iconGap,
className
)}
{...props}
>
{isIconifyIcon && (
<Icon
icon={icon as { body: string; width?: number; height?: number }}
className={clsx(iconSize, 'flex-none mt-1.5')}
/>
)}
{IconComponent && (
<IconComponent className={clsx(iconSize, 'flex-none mt-1.5')} />
)}
{icon ? <span>{children}</span> : children}
</li>
)
}