"use client";
/**
* Thin settings primitives (thin settings wave): the minimal control kit
* the settings page needs — deliberately plain. No design system, no
* animation polish: this wave is a WORKING validation surface over the
* settings record, not the designed settings app (that's a later wave).
*
* Everything SSRs clean (render tests pin the sections' markup).
*/
import { cn } from "@/lib/utils";
/** A section block: header + rows, separated by the app's border color. */
export function SettingsSection({
title,
hint,
children,
testid,
}: {
title: string;
/** One-line quiet note under the header (what the section controls). */
hint?: string;
children: React.ReactNode;
testid?: string;
}) {
return (
{title}
{hint &&
{hint}
}
{children}
);
}
/** One label + one control. Label left (with optional muted hint), control
* right — the settings row shape. */
export function SettingsRow({
label,
hint,
children,
testid,
}: {
label: string;
hint?: string;
children: React.ReactNode;
testid?: string;
}) {
return (
{label}
{hint && {hint}}
{children}
);
}
/** The on/off switch — a plain button in the switch role. */
export function Toggle({
checked,
disabled,
onChange,
label,
}: {
checked: boolean;
disabled?: boolean;
onChange: (next: boolean) => void;
/** Accessible name for the switch role. */
label: string;
}) {
return (
);
}
/** A thin select — native element, options as given. */
export function ThinSelect({
value,
onChange,
children,
ariaLabel,
testid,
disabled,
}: {
value: string;
onChange: (next: string) => void;
children: React.ReactNode;
ariaLabel: string;
testid?: string;
disabled?: boolean;
}) {
return (
);
}
/** A thin hex/text input committing on blur + Enter (settings pace, not
* typing pace — every commit is a section PUT). */
export function CommitInput({
value,
placeholder,
onCommit,
ariaLabel,
testid,
type = "text",
}: {
/** "" = unset (the factory default). */
value: string;
placeholder?: string;
onCommit: (next: string) => void;
ariaLabel: string;
testid?: string;
type?: "text" | "number";
}) {
return (
{
const next = e.target.value.trim();
if (next !== value) onCommit(next);
}}
onKeyDown={(e) => {
if (e.key === "Enter") e.currentTarget.blur();
if (e.key === "Escape") {
e.currentTarget.value = value;
e.currentTarget.blur();
}
}}
className="h-7 w-40 rounded-sm border border-border bg-background px-2 font-ui text-xs text-foreground outline-none placeholder:text-muted-foreground/60"
/>
);
}