Checkbox
A control that allows the user to toggle between checked and not checked.
Overview
Field 组合:label + description,整行可点;Space 键切换。
Installation
Checkbox 是单个 Rust 文件(src/checkbox.rs),只依赖 gpui-kit —— 对勾与半选横杠用 PathBuilder 手绘,无资源文件。
[dependencies]gpui-kit = "0.6.6"# checkbox.rs is self-contained — the check/dash marks are# painted with PathBuilder, no icon fonts or assets.# Download the runnable example crate, then:cargo run --locked -- --checkbox# Other demos:cargo run --locked -- --checkbox checkedcargo run --locked -- --checkbox invalidcargo run --locked -- --checkbox disabledcargo run --locked -- --checkbox groupcargo run --locked -- --checkbox tableUsage
Checkbox 是实体(cx.new),内部自持三态;点击盒子、label 或按 Space 都会翻转并发出 CheckboxChangeEvent。label/description 即 shadcn 的 Field + FieldLabel + FieldDescription 组合。
use justdo_command::checkbox::{Checkbox, CheckboxState, CheckboxChangeEvent};// Checkbox is an entity — click or Space toggles it; the// host view keeps it and subscribes for the change event.let terms = cx.new(|_| { Checkbox::new() .label("Accept terms and conditions") .description("By clicking this checkbox, you agree.")});cx.subscribe(&terms, |view, _, event: &CheckboxChangeEvent, cx| { view.accepted = event.checked; cx.notify();});div().child(terms)网页预览与桌面端运行同一份 Rust / GPUI 组件。
Composition
组合结构对齐 shadcn/ui 的 Checkbox —— box / label / description / invalid / disabled / indeterminate 三态。
Checkbox entity — box + optional Field label/description├── box 16px rounded square; checked -> primary fill + ✓ mark│ indeterminate -> fill + — dash├── label .label(..) — clicks on it toggle the box├── description .description(..) — xs muted helper text├── state Unchecked | Checked | Indeterminate├── invalid .invalid(true) — red border + label (isInvalid)├── disabled .disabled(true) — dimmed, unfocusable, inert└── emits CheckboxChangeEvent { checked } on toggle// Select-all pattern: rows emit CheckboxChangeEvent, the host// recomputes the header checkbox — all Checked, none Unchecked,// otherwise Indeterminate. Clicking the header drives every row.let header = cx.new(|_| Checkbox::new());for row in &rows { let header = header.clone(); cx.subscribe(row, move |demo, _, _ev, cx| { let states: Vec<CheckboxState> = demo.rows.iter().map(|r| r.read(cx).state).collect(); let st = if all_checked(&states) { CheckboxState::Checked } else if none_checked(&states) { CheckboxState::Unchecked } else { CheckboxState::Indeterminate }; header.update(cx, |h, cx| h.set_state(st, cx)); });}cx.subscribe(&header, move |demo, _, ev: &CheckboxChangeEvent, cx| { for row in &demo.rows { row.update(cx, |c, cx| c.set_state( if ev.checked { Checked } else { Unchecked }, cx)); }});Notes
Tri-state. 与 React Aria 一致:点击 Indeterminate 的盒子进入 Checked(不是 Unchecked)。表头 select-all 用这个语义实现全选。
Mark animation. ✓/— 标记的出现走 120ms opacity 过渡(transition keyed state,按实体区分),cx.reduce_motion() 时直接到位。
Focus. 整行可点,但只有盒子进入 Tab 顺序;focus-visible 时在盒子周围画 accent 光环 —— 与 shadcn 的 ring 样式对应。
Accessibility
Keyboard
Tab 聚焦、Space 切换(prevent_default 阻止页面滚动);disabled 的盒子完全移出焦点顺序且不响应输入。
Invalid
invalid 态不只改边框颜色 —— label 同步转红,双重信号表达校验失败,接近 data-invalid 的 Field 表现。
API Reference
实体暴露的 builder 方法、受控方法与事件。
| API | Signature | Notes |
|---|---|---|
Checkbox::new() | -> Checkbox | Unchecked, no label, enabled. |
.label(..) | &str | FieldLabel text; clicking it toggles the box. |
.description(..) | &str | FieldDescription helper text under the label. |
.checked(..) | bool | Initial state (defaultSelected equivalent). |
.indeterminate() | - | Partial-selection state (select-all header). |
.invalid(..) | bool | Red border + label (isInvalid). |
.disabled(..) | bool | Dimmed, unfocusable, ignores input. |
.set_state(..) | CheckboxState, &mut Context | Controlled update — e.g. select-all driving rows. |
CheckboxChangeEvent | { checked: bool } | Emitted on click/Space toggle; subscribe via cx.subscribe. |
CheckboxState | Unchecked | Checked | Indeterminate | Tri-state value; clicking Indeterminate goes to Checked. |
Source & inspiration
结构与视觉参考 shadcn/ui Checkbox 。本页交互由 Rust / GPUI 绘制,基础样式来自 gpui-kit 。