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 (
);
})}