Slider
ui.widgets.Slider在连续或离散范围中选择数值。
BEHAVIOR CONTRACT
min / max / step、disabled、数值显示和 track / thumb 命中保持同步。
RECORDED INTERACTION
Harness 点击轨道 82% 位置,thumb 与数值一起更新。
pub fn buildSlider(scope: *ui.Scope, cx: *ui.Cx) anyerror!*ui.Node {
const a = cx.allocator;
const c = try col(cx, 16);
const s1 = try ui.widgets.Slider(.{
.min = 0,
.max = 100,
.initial_value = 40,
.width = 320,
.show_value = true,
.test_id = "story.slider.track",
}).mount(scope, cx);
s1.wrapper.meta.ownership.meta.test_id = "story.slider.basic";
const s2 = try ui.widgets.Slider(.{
.min = 0,
.max = 10,
.step = 1,
.initial_value = 5,
.width = 320,
.show_value = true,
.test_id = "story.slider.stepped.track",
}).mount(scope, cx);
s2.wrapper.meta.ownership.meta.test_id = "story.slider.stepped";
const continuous = try ui.widgets.Slider(.{
.min = 0,
.max = 10,
.step = 0,
.initial_value = 5,
.width = 320,
.show_value = true,
.test_id = "story.slider.continuous.track",
}).mount(scope, cx);
const status = try label(cx, "");
status.meta.ownership.meta.test_id = "story.slider.feedback.status";
const pattern_status = try label(cx, "");
pattern_status.meta.ownership.meta.test_id = "story.slider.feedback.pattern";
const state = try scope.allocator.create(SliderFeedbackStory);
state.* = .{ .basic = s1, .stepped = s2, .continuous = continuous, .status = status, .pattern_status = pattern_status };
try scope.adoptResource(state, SliderFeedbackStory.destroy);
s2.state.on_change = ui.Cx.handlerFrom(SliderFeedbackStory, state, SliderFeedbackStory.refresh);
continuous.state.on_change = ui.Cx.handlerFrom(SliderFeedbackStory, state, SliderFeedbackStory.refresh);
state.refresh();
try c.appendChild(a, try label(cx, "Haptic feedback — opt in to try"));
const toggle = try ui.widgets.Switch(.{
.label_text = "Enable trackpad feedback",
.initial_checked = false,
.on_change = ui.Cx.boolHandlerFrom(SliderFeedbackStory, state, SliderFeedbackStory.toggle),
}).mount(scope, cx);
toggle.meta.ownership.meta.test_id = "story.slider.feedback.toggle";
try c.appendChild(a, toggle);
const pattern_options = [_]ui.widgets.checkbox.RadioOption{
.{ .value = "alignment", .label_text = "Alignment" },
.{ .value = "generic", .label_text = "Generic" },
.{ .value = "level_change", .label_text = "Level change" },
};
const patterns = try ui.widgets.RadioGroup(.{
.options = &pattern_options,
.value = "alignment",
.horizontal = true,
.on_change = ui.Cx.strHandlerFrom(SliderFeedbackStory, state, SliderFeedbackStory.selectPattern),
}).mount(scope, cx);
for (patterns.children.items, [_][]const u8{
"story.slider.pattern.alignment", "story.slider.pattern.generic", "story.slider.pattern.level_change",
}) |option, test_id| option.meta.ownership.meta.test_id = test_id;
try c.appendChild(a, patterns);
try c.appendChild(a, pattern_status);
try c.appendChild(a, try label(cx, "Native patterns, not intensity levels. Alignment is the default for step snapping."));
try c.appendChild(a, status);
try c.appendChild(a, try label(cx, "macOS Force Touch trackpad; device and system settings determine the feel."));
try c.appendChild(a, try label(cx, "0–100, value 40"));
try c.appendChild(a, s1.wrapper);
try c.appendChild(a, try label(cx, "0–10 step 1, value 5"));
try c.appendChild(a, s2.wrapper);
try c.appendChild(a, try label(cx, "Continuous (step 0) — no feedback"));
try c.appendChild(a, continuous.wrapper);
const reset = try ui.widgets.Button(.{
.label = "Reset both to 5 (no feedback)",
.variant = .secondary,
.on_click = ui.Cx.handlerFrom(SliderFeedbackStory, state, SliderFeedbackStory.reset),
}).mount(scope, cx);
reset.meta.ownership.meta.test_id = "story.slider.feedback.reset";
try c.appendChild(a, reset);
const s3 = try ui.widgets.Slider(.{ .initial_value = 30, .width = 320, .disabled = true }).mount(scope, cx);
try c.appendChild(a, try label(cx, "Disabled"));
try c.appendChild(a, s3.wrapper);
return c;
}这是 Storybook 中该 story 的原样代码(zenit 5f9add5+wip 2026-09-30)。其中 W 即 ui.widgets,col / row / label 是 Storybook 内的布局小工具。
SliderProps
ui.widgets.Sliderfn Slider(props: SliderProps) SliderBuilder字段
类型
默认值
说明
minf320—
maxf32100—
stepf321Positive values snap to discrete steps. Zero disables snapping.
haptic_feedbackboolfalseOpt in to native feedback when pointer input changes a snapped value. Applications may bind this to their user's preference.
haptic_patternHapticFeedbackPattern.alignmentNative semantic pattern, not a weak/medium/strong intensity scale.
initial_valuef320初始值。**只在 mount 时读取一次** —— 之后组件持有自己的 SliderState。需要外部驱动请用 mount 返回的 `result.state.setValue()` (那条路径会同步视觉与 a11y 数值)。
disabledboolfalse—
widthf32200—
track_heightf324—
thumb_sizef3216—
show_valueboolfalse—
on_change?core.HandlerRefnull—
test_id?[]const u8null给 track 节点设置的 test_id(供 E2E 测试定位)
SliderResult
ui.widgets.Slider字段
类型
默认值
说明
wrapper*Node—
—
state*SliderState—
—