/** * Fluksio: the controls. * * Every control is a pill, and a press is answered by the colour changing and * nothing else — no ripple, no glow, no lift. That restraint is the house * style rather than an omission: the one accent is spent on saying what is * selected, not on saying that something was touched. * * Every one of these is a `ui/core` hook in a different coat — the state, the * keyboard and the `aria-` come from there. */ import * as SelectPrimitive from "@radix-ui/react-select" import { Check, ChevronDown } from "lucide-react" import { motion } from "motion/react" import { cn } from "@/lib/utils" import { asOriginal, text } from "../core/config" import type { ButtonProps, InputProps, SegmentedProps, SelectProps, SliderProps, SwitchProps, } from "../core/contract" import { useSegmented, useSliderDrag, useSwitch } from "../core/controls" import { useLook } from "../core/look" import { LOOK } from "../core/motion" export function Button({ variant = "tonal", pressed, disabled, label, onClick, children, }: ButtonProps) { return ( ) } export function Switch(props: SwitchProps) { const { buttonProps } = useSwitch(props) return ( ) } export function Slider(props: SliderProps) { const { fraction, inputProps, marks } = useSliderDrag(props) const orientation = props.orientation ?? "horizontal" return (
{/* The control itself, laid transparent over what is drawn: it keeps the keyboard, the pointer and every `aria-`, and owes the look nothing. */}
{marks.length > 0 ? ( // Decoration: the input itself announces min, max and where it stands.
{marks.map((mark) => ( {mark.label} ))}
) : null}
) } export function Segmented(props: SegmentedProps) { const { chosen, thumbId, groupProps, itemProps } = useSegmented(props) const vertical = props.orientation === "vertical" return (
{props.options.map(([value, label], index) => ( ))}
) } export function Select({ value, options, label, disabled, onChange, }: SelectProps) { // The menu is portalled to `body`, which is outside the canvas — so it // re-states the dashboard's own colours rather than borrowing the app's. const { style } = useLook() return ( onChange(asOriginal(selected, options))} > {options.map((option) => ( {option.label ?? text(option.value)} ))} ) } export function Input({ value, type, label, disabled, onChange, onCommit, }: InputProps) { return ( onChange(event.target.value)} onBlur={onCommit} onKeyDown={(event) => { if (event.key === "Enter") onCommit() }} /> ) }