'use client' import type { ReactNode } from 'react' import { cn } from '../../lib/cn' import { Button } from '../Button' import { Chip } from '../Chip' import { Text } from '../Text' export interface FilterChip { value: T label: string /** Count of matching records, shown after the label. */ count?: number } export interface FilterBarProps { /** Quick toggles shown as Chips. */ filters?: FilterChip[] /** Currently active filter values. */ value?: T[] /** Called with the active filter ids. */ onValueChange?: (value: T[]) => void /** Extra controls — a Select, a SearchField, a date range. */ children?: ReactNode /** Total matching records, announced when it changes. */ resultCount?: number /** Noun for the result count, e.g. transactions. */ resultLabel?: string /** Shown when anything is active. */ onClear?: () => void /** Accessible name for the region. */ label?: string /** Merged last, so it wins. */ className?: string } /** * The control strip above a list: quick toggles, any extra controls, the result * count, and one way to clear everything. * * The count is a live region, because filtering changes the list below without * moving focus — otherwise a screen reader user gets no confirmation that * anything happened. */ export function FilterBar({ filters = [], value = [], onValueChange, children, resultCount, resultLabel = 'results', onClear, label = 'Filters', className, }: FilterBarProps) { const active = value.length > 0 const toggle = (entry: T) => { onValueChange?.( value.includes(entry) ? value.filter((item) => item !== entry) : [...value, entry], ) } return (
{filters.length > 0 && (
{filters.map((filter) => ( toggle(filter.value)} /> ))}
)} {children}
{resultCount !== undefined && ( {resultCount} {resultLabel} )} {onClear && active && ( )}
) }