import * as React from 'react'; /** * The two helpers every axis-filtered gallery page needs. * * `/alerts`, `/avatars`, `/badges`, `/buttons` and `/toasts` all put the same * toolbar above their grids — a search box that narrows the axes, and a few * labelled selects beside it — and each page had grown its own byte-identical * copy of the pair. Changing how the search behaves meant editing five files * and being silently wrong in the four you forgot; nothing here is covered by a * test, so nothing would have said so. * * What deliberately stayed on the pages: `EVERY_TOKEN` and `TABS`. Those look * duplicated too, but their *members* differ per page — the token list is built * from that page's own axes, and a page's tab set is its own vocabulary. Moving * them here would mean parameterising them back into what they already are. * * The frame around the grids — the column, the header and the tab strip those * same five pages share — came out for the same reason and lives next door, in * `chrome/ui/gallery-page.tsx`. */ /** * Narrows an axis by the search text. * * The search box narrows each axis on its own, and an axis the needle misses is * left whole — typing `red` must not empty the variant list and take the grid * with it. */ export function narrow(values: readonly T[], needle: string): readonly T[] { if (!needle) return values; const hit = values.filter((value) => value.toLowerCase().includes(needle)); return hit.length > 0 ? hit : values; } /** * A labelled control in the filter row. * * `FilterField` rather than `Field`: the kit ships a public `Field` * (`/field`) that the showcase also uses, in `registry/forms.tsx`. Two * unrelated components under one name meant the import line was the only thing * saying which one a page had reached for. * * The `