Skip to content

Release v0.4.1

Latest

Choose a tag to compare

@github-actions github-actions released this 20 May 05:52

Release Notes v0.4.1

Released: 2026-05-20

Point release adding an iced adapter to round out Opaline's GUI story, plus targeted correctness and rustdoc fixes uncovered by cross-feature builds. The docs site also gets a v0.4 refresh with the full 39-theme catalog and visual polish.

🌟 Highlights

✨ Iced Adapter (closes #1)

New opaline::adapters::iced module behind the iced feature flag (iced_core = 0.14). It maps Opaline's 26-token contract onto iced's 6-field Palette (bg.basebackground, text.primarytext, accent.primaryprimary, plus success, warning, and errordanger) and ships three entry points:

  • From<OpalineColor> for iced_core::Color (plus a & variant)
  • to_iced_palette(&Theme) -> Palette
  • to_iced_extended(&Theme) -> Extended via Extended::generate
  • to_iced_custom(&Theme) -> Custom for drop-in use with iced::Theme::Custom(Arc::new(...))

Integration coverage in tests/iced_tests.rs reads palettes back through IcedTheme::Custom and sweeps all 39 builtin themes.

🐛 Ratatui Span Resolvable Without Gradients

Theme::span previously imported Span only under #[cfg(feature = "gradients")], which broke rustdoc and the intra-doc [Span] link for the common ratatui-without-gradients feature combo. The import now sits alongside Line and Text, and the return type drops the fully-qualified ratatui_core::text::Span path. Verified clean under all-features, ratatui-only, egui-only, iced-only, and --no-default-features.

⚡️ Cheaper Resolver Cycle Check

resolve_token no longer allocates a String per recursive lookup just to test chain membership. chain.contains(&name.to_string()) is replaced with chain.iter().any(|entry| entry == name), removing heap traffic from the hot path for themes with deep token indirection (palette → token → token chains).

🔧 Correctness and Lints

  • OpalineStyle::modifier_bits is now #[cfg(feature = "ratatui")]. The bitfield only feeds the ratatui adapter, so non-ratatui feature subsets (cli-only, css-only) no longer emit dead_code warnings.
  • Scoped test imports in tests/builtins_tests.rs: std::sync::{Mutex, MutexGuard, OnceLock} now sit behind the same #[cfg(all(feature = "builtin-themes", feature = "discovery", feature = "global-state"))] as their consumer, silencing unused-import warnings on lean feature sets.
  • Theme rustdoc: the struct doc no longer links Self::gradient (a method that only exists when gradients is enabled). Reworded as an inline code reference with a feature note.
  • Removed redundant-explicit-link-target warnings across ratatui, egui, and iced adapter docs.

♻️ Widget Tests Move Out of src/

The wrap_text helper in src/widgets/theme_selector.rs was the last source-tree test holdout. It is now exposed via a #[doc(hidden)] re-export from src/widgets/mod.rs and driven from tests/theme_selector_tests.rs, matching the project convention of integration tests under tests/. Test cases were renamed to match the broader naming pattern. The function remains out of the public docs surface.

📝 Documentation

  • API reference fixes for copy-paste correctness: OpalineStyle::strikethrough() is actually crossed_out(), and OpalineColor::lerp takes self by value (not two & refs). The ratatui modifier table is corrected to match.
  • README quickstart bumped from opaline = "0.2" to 0.4.
  • CONTRIBUTING.md contract claim corrected from "40+ tokens, 18 styles" to the actual 26 tokens, 13 styles.
  • AGENTS.md file map drops the long-removed tests/export_tests.rs entry.
  • VitePress site refresh for v0.4: full 39-theme gallery with accent swatches and code examples, broadened framing from Ratatui-specific to a multi-framework Rust engine with seven adapters, gradient hero buttons and animated glow, feature-card hover lift, gradient h1 and active-nav accents, and full light-mode variants for the new visual treatments. Prettier check and format steps added to the justfile.

📦 Upgrade Notes

  • No breaking changes. Drop-in upgrade from v0.4.0.
  • To use the new adapter, enable the iced feature:
    opaline = { version = "0.4.1", features = ["iced"] }
    Then:
    use iced::Theme;
    use std::sync::Arc;
    
    let theme = opaline::Theme::default();
    let custom = opaline::adapters::iced::to_iced_custom(&theme);
    let iced_theme = Theme::Custom(Arc::new(custom));
  • If your code referenced OpalineStyle::strikethrough() based on the previous docs, the correct name is crossed_out() (the API itself is unchanged from v0.4.0; only the documentation was wrong).