feat(mobile): add FilterChips primitive (horizontal chip row with Add-filter trigger)

This commit is contained in:
Matt Ciaccio
2026-04-29 14:28:33 +02:00
parent 34916d855e
commit 6237ad1567

View File

@@ -0,0 +1,67 @@
'use client';
import { X, Filter } from 'lucide-react';
import { cn } from '@/lib/utils';
export type ActiveFilter = {
id: string;
label: string;
/** Compact value rendered on the chip after the label (e.g. ": Active"). */
value?: string;
};
/**
* Horizontal chip row for active filters, with an "Add filter" trigger that
* the caller wires to a `<Drawer>`. Active chips are dismissable via the X
* button. Scrolls horizontally on mobile when there are many filters.
*/
export function FilterChips({
active,
onRemove,
onAddClick,
className,
}: {
active: ActiveFilter[];
onRemove: (id: string) => void;
onAddClick: () => void;
className?: string;
}) {
return (
<div
className={cn(
'flex items-center gap-2 overflow-x-auto -mx-3 px-3 sm:mx-0 sm:px-0 sm:flex-wrap sm:overflow-visible',
className,
)}
>
<button
type="button"
onClick={onAddClick}
className="shrink-0 inline-flex items-center gap-1.5 rounded-full border border-input bg-background px-3 h-9 text-sm font-medium text-foreground hover:bg-accent"
>
<Filter className="size-4" aria-hidden />
Add filter
</button>
{active.map((filter) => (
<span
key={filter.id}
className="shrink-0 inline-flex items-center gap-1 rounded-full bg-secondary text-secondary-foreground px-3 h-9 text-sm font-medium"
>
<span>
{filter.label}
{filter.value ? `: ${filter.value}` : ''}
</span>
<button
type="button"
onClick={() => onRemove(filter.id)}
aria-label={`Remove ${filter.label} filter`}
className="-mr-1 inline-flex size-6 items-center justify-center rounded-full hover:bg-secondary-foreground/10"
>
<X className="size-3.5" aria-hidden />
</button>
</span>
))}
</div>
);
}