Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 95x 1056x 1056x 6x | import type {
TaxonomyType,
TaxonomyConfig,
} from "../../pages/admin/taxonomy.config";
interface TaxonomyTypeSelectorProps {
configs: TaxonomyConfig[];
activeTab: TaxonomyType;
onTabChange: (tab: TaxonomyType) => void;
}
/**
* `.tabrail` — the Job Book's 2px underline rail.
*
* This used to be a row of filled `rounded-md` buttons inside a boxed card:
* the selected one went solid `primary-600`, which reads as a pill and spends
* a filled block on something that is navigation, not state. The mockups print
* a tab as a label over a 2px bottom rule (`.tabrail` / `.tabrail-tab` in
* `.context/mockups/_base.css` §7.8); the current tab carries the rule, hovers
* tint, and the whole thing sits on a hairline rather than in a box.
*
* `aria-pressed` is what carries the selection to a screen reader, so the
* state is never in the colour alone. It is deliberately NOT `role="tab"`:
* a real tablist owes the user arrow-key navigation and a matching tabpanel,
* and these buttons swap the page's data rather than reveal a panel. Same
* decision as `components/admin/FacetRow.tsx`.
*/
export function TaxonomyTypeSelector({
configs,
activeTab,
onTabChange,
}: TaxonomyTypeSelectorProps) {
return (
// `fieldset` rather than `div role="group"`: native grouping semantics,
// which Biome's useSemanticElements rightly prefers. The resets undo the
// UA stylesheet so the rail stays a hairline.
<fieldset className="m-0 flex min-w-0 items-stretch gap-0.5 overflow-x-auto border-0 border-b border-border-default p-0">
<legend className="sr-only">Taxonomy type</legend>
{configs.map((config) => {
const isActive = activeTab === config.key;
return (
<button
key={config.key}
type="button"
aria-pressed={isActive}
onClick={() => onTabChange(config.key)}
className={`-mb-px inline-flex min-h-10 items-center whitespace-nowrap border-b-2 px-3 text-sm font-semibold transition-colors hover:bg-foreground-default/7 ${
isActive
? "border-secondary-600 text-foreground-default"
: "border-transparent text-foreground-muted hover:text-foreground-default"
}`}
>
{config.label}
</button>
);
})}
</fieldset>
);
}
|