import * as React from 'react'; import { cn } from '@/lib/utils'; import { Switch } from '@/components/ui/switch'; /** * Toggle — a labelled switch row for settings. * * Wraps the Switch primitive with the label/description layout it is almost * always used with, and makes the whole row a label so the hit target is the * full width rather than the 36px control. */ /** @param {any} props */ export function Toggle({ checked, onCheckedChange, label, description, disabled, /** `end` puts the switch on the right (settings rows); `start` on the left. */ align = 'end', className, id: providedId, }) { const reactId = React.useId(); const id = providedId || reactId; const descriptionId = description ? `${id}-description` : undefined; const control = ( ); const text = ( {label} {description && ( {description} )} ); return ( ); } /** * SegmentedToggle — a small pill group for switching between 2–4 mutually * exclusive views. Used where Tabs would be too heavy (chart ranges, EN/ES). */ /** * Two treatments for the same control. * * `brand` states a choice that changes what the data *says* — a date range, a * scope — so the selection carries the page's accent colour and reads as a * filter. `surface` states a choice that changes only how the same data is * *drawn*, so the selection is a raised white chip on a sunken track: present * enough to show which mode is on, quiet enough not to compete with the real * filters sitting beside it in the same toolbar. */ const SEGMENT_VARIANTS = { brand: { track: 'bg-surface-sunken border-border', active: 'bg-krow-blue text-white shadow-sm', inactive: 'text-ink-3 hover:text-ink-1', }, surface: { track: 'bg-surface-sunken border-border', active: 'bg-surface text-ink-1 shadow-xs', inactive: 'text-ink-4 hover:text-ink-2', }, }; /** @param {any} props */ export function SegmentedToggle({ options = [], value = null, onChange = null, size = 'default', variant = 'brand', className = '', ariaLabel = '', }) { const normalized = options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o)); const tone = SEGMENT_VARIANTS[variant] || SEGMENT_VARIANTS.brand; return (
{normalized.map((option) => { const active = option.value === value; const Icon = option.icon; /* Icon-only options carry their name on the button instead of beside it, so the control stays compact without becoming unlabelled. */ const iconOnly = Boolean(Icon) && !option.label; return ( ); })}
); }