Skip to content

ghenry/sweeten

 
 

Repository files navigation

sweeten your daily iced brew

Crates.io Documentation License Made with iced

Overview

sweeten provides drop-in replacements for common iced widgets with extra features for more complex use cases. Each widget is designed to feel like the upstream version with extra capabilities layered on top.

Installation

If you're using the latest iced release:

cargo add sweeten

If you're tracking iced from git, add this to your Cargo.toml:

sweeten = { git = "https://github.com/airstrike/sweeten", branch = "master" }

Widgets

Button

Adds focus and blur methods:

  • .on_focus(Message) fires when the button gains keyboard focus
  • .on_blur(Message) fires when it loses focus

Pairs with sweeten::widget::operation::{focus_next, focus_previous} to build keyboard-navigable forms across any focusable widget.

Toggler

Animates state changes. The handle slides between positions and the fill color crossfades between the off and on styles.

toggler(self.is_on)
    .label("Enable notifications")
    .on_toggle(Message::Toggled)

Checkbox

Animated checkmark with fade and scale on toggle, and a crossfaded fill and border.

checkbox(self.is_checked)
    .label("Subscribe to updates")
    .on_toggle(Message::Toggled)

The press and release gesture matches native checkboxes: pressing inside arms the checkbox and releasing inside fires the toggle. Pressing outside and dragging in, or pressing inside and dragging out before release, cancels.

Five built-in styles ship: primary, secondary, success, danger, and text (a monochrome variant that uses the theme's body text color for the fill, pairing naturally with text-only buttons). Each variant uses <swatch>.base for the active state, <swatch>.strong for hovered, and fades toward the page background when disabled.

ProgressBar

Animates between values. Each render whose value differs from the currently-displayed value eases toward the new target over 150ms, so stepping the bar through discrete checkpoints reveals a smooth fill instead of jumps.

progress_bar(0.0..=100.0, self.progress)
    .girth(4.0)
    .on_idle(Message::LoadingSettled)

The optional .on_idle(f32) fires once the easing animation settles at its target, making it useful for gating follow-up actions (dismissing a splash, navigating, etc.) on the bar reaching a specific value.

MouseArea

Adds on_press_with for capturing the click position via a closure:

mouse_area("Click me and I'll tell you where!",)
    .on_press_with(|point| Message::ClickWithPoint(point)),

PickList

Accepts an optional closure to disable some items:

pick_list(
    &Language::ALL[..],
    Some(|languages: &[Language]| {
        languages
            .iter()
            .map(|lang| matches!(lang, Language::Javascript))
            .collect()
    }),
    self.selected_language,
    Message::Pick,
)
.placeholder("Choose a language...");

Note that the compiler cannot currently infer the type of the closure, so you may need to specify it explicitly as shown above.

TextInput

Adds focus-related features:

  • .on_focus and .on_blur methods for handling focus events
  • Sweetened focus_next and focus_previous focus management functions, which return the ID of the focused element

Row and Column

Adds drag-and-drop reordering of children via .on_drag:

use sweeten::widget::column;
use sweeten::widget::drag::DragEvent;

column(items.iter().map(|s| s.as_str().into()))
    .spacing(5)
    .on_drag(Message::Reorder)
    .into()

FitText

A text widget that auto-scales its font size to fit the bounds it is laid out into. Like CSS' clamp(min, ideal, max), but the "ideal" is solved for instead of specified: sweeten binary-searches the size range and picks the largest font that still fits.

use iced::Fill;
use sweeten::widget::fit_text;

fit_text("Big headline")
    .max_size(120)
    .min_size(16)
    .width(Fill)
    .height(Fill)
    .center()

Both min_size and max_size are optional; call neither and the font scales within [1.0, 1024.0] pixels by default.

Transition

A single-slot container that animates a slide whenever its child value changes. The new content slides into the canonical position from the edge opposite the configured Direction, while the previous content slides off the same-side edge.

use sweeten::widget::transition::{self, Direction};

transition::transition(self.phrase.clone(), |s: &String| {
    text(s.clone()).size(22).into()
})
.direction(Direction::Up)
.into()

Direction is sugar for the more general Mode knob (.mode(Mode::Slide(d))).

Examples

See examples/ for the full list, or run one directly:

cargo run --example mouse_area
cargo run --example pick_list
cargo run --example text_input
cargo run --example fit_text
cargo run --example transition
cargo run --example checkbox
cargo run --example progress_bar

Contributing

Contributions are welcome. Fork the repository, create a feature branch, implement your changes with tests, and submit a PR.

License

MIT

Acknowledgements

About

sweeten your daily iced brew

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Rust 96.0%
  • HTML 2.3%
  • CSS 1.7%