2026-07-19 21:17:57 +08:00
|
|
|
// Pill: small rounded label chip (view switcher tabs, filters, badges).
|
|
|
|
|
|
|
|
|
|
import type { ButtonHTMLAttributes, ReactNode } from 'react'
|
|
|
|
|
import clsx from 'clsx'
|
|
|
|
|
import css from './Pill.module.css'
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render a pill chip. Interactive when onClick is supplied (renders a button);
|
|
|
|
|
* otherwise a static span.
|
|
|
|
|
* @param props.active - selected/active visual state.
|
|
|
|
|
* @returns pill element.
|
|
|
|
|
*/
|
|
|
|
|
export function Pill({ active = false, className, children, onClick, ...rest }: {
|
|
|
|
|
active?: boolean
|
2026-07-28 14:58:06 +08:00
|
|
|
// `| undefined` so a caller can forward an optional class straight through
|
|
|
|
|
// under exactOptionalPropertyTypes (a CSS-module lookup is string|undefined).
|
|
|
|
|
className?: string | undefined
|
2026-07-19 21:17:57 +08:00
|
|
|
children?: ReactNode
|
|
|
|
|
} & ButtonHTMLAttributes<HTMLButtonElement>) {
|
|
|
|
|
if (!onClick) {
|
|
|
|
|
return <span className={clsx(css.pill, active && css.active, className)}>{children}</span>
|
|
|
|
|
}
|
|
|
|
|
return (
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className={clsx(css.pill, css.interactive, active && css.active, className)}
|
|
|
|
|
onClick={onClick}
|
|
|
|
|
{...rest}
|
|
|
|
|
>
|
|
|
|
|
{children}
|
|
|
|
|
</button>
|
|
|
|
|
)
|
|
|
|
|
}
|