"use client"; import type { LucideIcon } from "lucide-react"; import { cn } from "@/lib/utils"; export interface ViewToggleSegment { value: T; label: string; icon: LucideIcon; } export interface ViewToggleProps { view: T; onChange: (view: T) => void; segments: ViewToggleSegment[]; /** Accessible name for the segmented-control group. */ groupLabel: string; /** `data-slot` prefix per segment, rendered as `${dataSlotPrefix}-${value}`. */ dataSlotPrefix: string; } /** * Shared icon-only segmented view toggle (e.g. cards vs table/list). A small * two-segment control: the active segment carries the filled surface, the * inactive one stays ghost. `aria-pressed` announces the state per segment; * the group is named for screen readers. Segments keep the 44-px mobile tap * floor (`size-11`), shrinking to the 36-px control height on desktop * (`sm:size-9`) like a neighbouring Add button — the same floor the intake * kebab and history-rail delete controls raised in this release window * (L3, `.planning/audits/2026-07-18-qa-ui.md`). * * Previously forked between the medications module * (`medications/medication-view-toggle.tsx`) and the Vorsorge/Illness/Labs * settings pages (`module-list/module-view-toggle.tsx`) — verbatim * copy-paste that only diverged in icons + i18n keys and had already * drifted. Both are now thin wrappers over this one primitive. */ export function ViewToggle({ view, onChange, segments, groupLabel, dataSlotPrefix, }: ViewToggleProps) { return (
{segments.map(({ value, label, icon: Icon }) => { const active = view === value; return ( ); })}
); }