Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 1x 1x 1x 18x 18x 18x 18x | 'use client'
// StudioCheckbox — the studio's on/off box (Gitea #43). Same props as the toy
// debug panel's `DebugCheckbox` (which the rails borrowed, indigo and all), plus
// an optional `description`, styled from theme.ts.
//
// The label is label-type but in `text2`, not `muted`: a checkbox's text is the
// CHOICE, not a caption for something else, so it reads a step brighter than the
// labels that sit above selects and sliders. The description, when there is one,
// is note-type under the row and indented to the label's column, and it is tied
// to the input with `aria-describedby` rather than being swept into the
// accessible name — a screen reader should hear "Slow first layer, checkbox",
// then the reason, not one run-on sentence.
import { type ReactNode, useId } from 'react'
import { STUDIO } from './theme'
export interface StudioCheckboxProps {
label: string
checked: boolean
onChange: (checked: boolean) => void
dataElement?: string
dataAction?: string
disabled?: boolean
/** one-line reason under the row */
description?: ReactNode
}
export function StudioCheckbox({
label,
checked,
onChange,
dataElement = 'debug-checkbox',
dataAction,
disabled = false,
description,
}: StudioCheckboxProps) {
const descriptionId = useId()
return (
<div
data-component="studio-checkbox"
data-element={dataElement}
style={{
display: 'flex',
flexDirection: 'column',
gap: 4,
opacity: disabled ? 0.55 : 1,
}}
>
<label
style={{
display: 'flex',
alignItems: 'center',
gap: 8,
cursor: disabled ? 'default' : 'pointer',
userSelect: 'none',
}}
>
<input
type="checkbox"
checked={checked}
disabled={disabled}
data-action={dataAction}
aria-describedby={description != null ? descriptionId : undefined}
onChange={(e) => onChange(e.target.checked)}
style={{
accentColor: STUDIO.color.accent,
width: 14,
height: 14,
cursor: disabled ? 'default' : 'pointer',
}}
/>
<span style={{ ...STUDIO.type.label, color: STUDIO.color.text2 }}>{label}</span>
</label>
{description != null && (
<span id={descriptionId} style={{ ...STUDIO.type.note, paddingLeft: 22 }}>
{description}
</span>
)}
</div>
)
}
|