Stepper field (external piece)

stepper(value) is a numeric stepper field: a text field with increment/decrement arrows, bound two-way to any Binding<f64> (a Signal<f64>, a day-model Field, or an app’s own binding over a selection). Each arrow click, and each settled edit (Return, focus loss), lands through write_commit, so under an undo stack every click is one undoable step.

The UI snippets use generated res::str accessors from an app’s Fluent catalog; see the example messages and catalog setup.

Authoring

use day_piece_stepper::stepper;

let width = Signal::new(1.0f64);

labeled(
    res::str::stroke_width(),
    stepper(width)
        .range(0.0..=64.0) // typed and stepped values both clamp (default 0..=100)
        .step(1.0) // one arrow click (default 1)
        .decimals(0) // fraction digits shown (default 0)
        .id(id!(insp_stroke_w)), // the field's dayscript id, both idioms
)
  • .native() / .composed() / .idiom(…) pin one idiom; the default is Automatic: native where an arm exists (support() answers Native on appkit, gtk, qt), composed everywhere else. Native is literal: pinned on a toolkit with no renderer it draws Day’s visible placeholder.
  • .id(…) names the interactive field for dayscript on both idioms, wherever it sits in the chain.

Driving and asserting from dayscript

The native leaf accepts input: (typed text, parsed and clamped), set_value: (ValueChanged previews, ValueCommitted commits), and mirrors its state into the probe through day-core’s set_probe_value hook, so assert_text sees the display form (fmt_value’s fixed-decimal text) and assert_value the number, exactly like a built-in control. The composed idiom is a real text field and needs nothing special. One script drives both idioms by the same key.

One scripted input commits once. The native event handler accepts stepper:value (and the legacy bridge’s empty tag), but ignores unrelated custom events, including the day:synthesized-text paint notification that precedes TextChanged. Treating both as edits would create duplicate undo entries. set_value: still delivers one preview followed by one commit, so a binding can retain the value from before the gesture for undo.

Verification status

The AppKit, GTK and Qt arms plus the composed row are exercised by Day-Sketch’s walkthrough (the stroke-width row of its inspector). There is no XAML or web arm yet. Both platforms have native spin controls (a WinUI NumberBox, <input type="number">), and arms for them are welcome, but the composed row already behaves correctly there, so they are an upgrade rather than a gap.