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.base→background, text.primary→text, accent.primary→primary, plus success, warning, and error→danger) and ships three entry points:
From<OpalineColor> for iced_core::Color(plus a&variant)to_iced_palette(&Theme) -> Paletteto_iced_extended(&Theme) -> ExtendedviaExtended::generateto_iced_custom(&Theme) -> Customfor drop-in use withiced::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_bitsis now#[cfg(feature = "ratatui")]. The bitfield only feeds the ratatui adapter, so non-ratatui feature subsets (cli-only, css-only) no longer emitdead_codewarnings.- 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 whengradientsis enabled). Reworded as an inline code reference with a feature note. - Removed redundant-explicit-link-target warnings across
ratatui,egui, andicedadapter 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 actuallycrossed_out(), andOpalineColor::lerptakesselfby value (not two&refs). The ratatui modifier table is corrected to match. - README quickstart bumped from
opaline = "0.2"to0.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.rsentry. - 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
icedfeature:Then:opaline = { version = "0.4.1", features = ["iced"] }
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 iscrossed_out()(the API itself is unchanged from v0.4.0; only the documentation was wrong).