import "./checkbox.css"; import type * as React from "react"; import { useRender } from "@base-ui/react/use-render"; import { type StyleProps } from "./style_props"; import { type InkColor } from "./text_ink"; /** What a `render` callback is handed — the kit's own, in BOTH modes. */ export type CheckboxState = { checked: boolean; indeterminate: boolean | undefined; filled: boolean; disabled: boolean | undefined; }; interface CheckboxBase extends StyleProps { checked: boolean; /** * The third position. On a box it is the mixed state of a select-all; on a * ring it half-fills — a step whose vocabulary reads "No portal account → * Account created → Filed online" is not finished at "Account created", but it * is emphatically not untouched either, and an empty ring says untouched. */ indeterminate?: boolean; /** * A SQUARE means CHOSEN and a CIRCLE means FINISHED, and the two readings are * not interchangeable: the ring is the signature mark of a task, a to-do or a * checklist item (pair it with a title that strikes and mutes on the same * state), the box is a pick. Both are 24px, so a leading gutter reserves one * width whichever a surface hosts. */ shape?: "box" | "ring"; /** The fill's ink ROLE. Defaults to `--primary` — the same claim the one * filled button makes — so a themed app gets a branded mark for free; a run * with a colour of its own (a `Stepper`'s) passes it. */ color?: InkColor; disabled?: boolean; testID?: string; ref?: React.Ref; /** * The state is {@link CheckboxState}, not Base UI's — this entry is a Base UI * control in one mode and a drawn mark in the other, and a callback whose * argument changed shape with `onChange` would be unwritable. */ render?: useRender.RenderProp; } /** The DRAWN mark — what a pressable row or a select-all cell already names. */ export interface CheckboxMarkProps extends CheckboxBase { onChange?: undefined; /** * Names the mark for a reader, as `role="img"`. * * Give it one where nothing AROUND the mark says what it reports — a * register's done column, where the cell would otherwise read as empty. Leave * it off inside a row that already names the state, and the mark stays out of * the accessibility tree entirely, which is what keeps that row one control. */ accessibilityLabel?: string; } /** The mark as a CONTROL: `role="checkbox"`, a tab stop, Space. */ export interface CheckboxControlProps extends CheckboxBase { onChange: (checked: boolean) => void; /** * Accessible name. Required OUTSIDE a `FormField`, and its absence there * THROWS: an unlabelled checkbox announces only its state, so the reader has * no idea what is being checked and nothing on screen says so. Inside a field * the visible label names it and this is ignored — passing it there is a * second copy free to drift from what is on screen (WCAG 2.5.3), which is why * it is optional rather than required. Same rule as `Switch`. */ accessibilityLabel?: string; } export type CheckboxProps = CheckboxMarkProps | CheckboxControlProps; /** * The tick mark. * * **With no `onChange` it is a DRAWN mark** — no tab stop, nothing to operate — * which is what lets one sit inside a pressable row or a select-all cell that * already names the state, without giving that row a second control. Same axis * as `Switch`, and the same reason. * * With one it is the control a form, a selectable row, a select-all cell or a * task list reaches for: it announces `role="checkbox"` with its own * `aria-checked`, `mixed` included, takes Space like a native one, and stops the * press so it works inside a pressable row. Inside a `FormField` it takes its * name and its id from the field. */ export declare function Checkbox(props: CheckboxProps): React.JSX.Element; export {};