Skip to main content

teksilo_widgets/
styles.rs

1// SPDX-License-Identifier: MPL-2.0
2// SPDX-FileCopyrightText: 2026 FernTech
3
4//! Default `Recipe*Style` impls — the IntUI look ships here. Apps that
5//! want a different design language write their own `impl FooStyle`
6//! blocks (per-call via `Foo::style(...)` or theme-wide via
7//! `theme.style_slots`).
8//!
9//! Each impl widget composes a small subtree (or for chrome-dense
10//! widgets like Toggle, a tiny private leaf widget that paints
11//! directly) so the public `Foo` widget itself stays pure
12//! composition over the `FooStyle` trait — no `paint()` method on
13//! any themable widget.
14
15pub mod recipe_avatar_style;
16pub mod recipe_badge_style;
17pub mod recipe_banner_style;
18pub mod recipe_button_style;
19pub mod recipe_calendar_style;
20pub mod recipe_card_style;
21pub mod recipe_checkbox_style;
22pub mod recipe_color_picker_style;
23pub mod recipe_combo_box_style;
24pub mod recipe_date_edit_style;
25pub mod recipe_dialog_style;
26pub mod recipe_drop_target_style;
27pub mod recipe_drop_zone_style;
28pub mod recipe_grid_view_style;
29pub mod recipe_icon_button_style;
30pub mod recipe_link_style;
31pub mod recipe_list_container_style;
32pub mod recipe_menu_item_style;
33pub mod recipe_panel_style;
34pub mod recipe_popover_style;
35pub mod recipe_progress_bar_style;
36pub mod recipe_radio_style;
37pub mod recipe_radio_tile_style;
38pub mod recipe_rich_text_editor_style;
39pub mod recipe_scroll_bar_style;
40pub mod recipe_search_field_style;
41pub mod recipe_segmented_control_style;
42pub mod recipe_slider_style;
43pub mod recipe_snackbar_style;
44pub mod recipe_spin_box_style;
45pub mod recipe_split_button_style;
46pub mod recipe_splitter_style;
47pub mod recipe_standard_item_style;
48pub mod recipe_tab_style;
49pub mod recipe_table_style;
50pub mod recipe_text_input_style;
51pub mod recipe_text_selection_style;
52pub mod recipe_toast_style;
53pub mod recipe_toggle_style;
54pub mod recipe_tooltip_style;
55
56pub use recipe_avatar_style::{AvatarRecipe, RecipeAvatarStyle};
57pub use recipe_badge_style::{BadgeRecipe, RecipeBadgeStyle};
58pub use recipe_banner_style::{BannerRecipe, RecipeBannerStyle};
59pub use recipe_button_style::RecipeButtonStyle;
60pub use recipe_calendar_style::{CalendarRecipe, RecipeCalendarStyle};
61pub use recipe_card_style::{CardRecipe, RecipeCardStyle};
62pub use recipe_checkbox_style::{CheckboxRecipe, RecipeCheckboxStyle};
63pub use recipe_color_picker_style::{ColorPickerRecipe, RecipeColorPickerStyle};
64pub use recipe_combo_box_style::{ComboBoxRecipe, RecipeComboBoxStyle};
65pub use recipe_date_edit_style::{DateEditRecipe, RecipeDateEditStyle};
66pub use recipe_dialog_style::{DialogRecipe, RecipeDialogStyle};
67pub use recipe_drop_target_style::{DropTargetRecipe, RecipeDropTargetStyle};
68pub use recipe_drop_zone_style::{DropZoneRecipe, RecipeDropZoneStyle};
69pub use recipe_grid_view_style::RecipeGridViewStyle;
70pub use recipe_icon_button_style::{IconButtonRecipe, RecipeIconButtonStyle};
71pub use recipe_link_style::{LinkRecipe, RecipeLinkStyle};
72pub use recipe_list_container_style::RecipeListContainerStyle;
73pub use recipe_menu_item_style::{MenuItemRecipe, RecipeMenuItemStyle};
74pub use recipe_panel_style::{PanelRecipe, RecipePanelStyle};
75pub use recipe_popover_style::{PopoverRecipe, RecipePopoverStyle};
76pub use recipe_progress_bar_style::{ProgressBarRecipe, RecipeProgressBarStyle};
77pub use recipe_radio_style::{RadioRecipe, RecipeRadioStyle};
78pub use recipe_radio_tile_style::{
79    RADIO_TILE_CORNER_RADIUS, RADIO_TILE_VERTICAL_ROW_HEIGHT, RadioTileRecipe, RecipeRadioTileStyle,
80};
81pub use recipe_rich_text_editor_style::RecipeRichTextEditorStyle;
82pub use recipe_scroll_bar_style::{RecipeScrollBarStyle, ScrollBarRecipe};
83pub use recipe_search_field_style::{RecipeSearchFieldStyle, SearchFieldRecipe};
84pub use recipe_segmented_control_style::{RecipeSegmentedControlStyle, SegmentedControlRecipe};
85pub use recipe_slider_style::{RecipeSliderStyle, SliderRecipe};
86pub use recipe_snackbar_style::{RecipeSnackbarStyle, SnackbarRecipe};
87pub use recipe_spin_box_style::RecipeSpinBoxStyle;
88pub use recipe_split_button_style::RecipeSplitButtonStyle;
89pub use recipe_splitter_style::{RecipeSplitterStyle, SplitterRecipe};
90pub use recipe_standard_item_style::{RecipeStandardItemStyle, StandardItemRecipe};
91pub use recipe_tab_style::{RecipeTabStyle, TabRecipe};
92pub use recipe_table_style::{RecipeTableStyle, TableRecipe};
93pub use recipe_text_input_style::{RecipeTextInputStyle, TextInputRecipe};
94pub use recipe_text_selection_style::{RecipeTextSelectionStyle, TextSelectionRecipe};
95pub use recipe_toast_style::{RecipeToastStyle, ToastRecipe};
96pub use recipe_toggle_style::{RecipeToggleStyle, ToggleRecipe};
97pub use recipe_tooltip_style::{RecipeTooltipStyle, TooltipRecipe};
98
99use teksilo_core::build_context::BuildContext;
100use teksilo_core::signal::Signal;
101use teksilo_core::styles::PaintState;
102use teksilo_tokens::ColorTokens;
103
104/// Reactive resolution palette for recipe colours: the palette the paint
105/// walker paints with, [`Theme::paint_colors`](teksilo_core::styles::Theme::paint_colors) for the host window's
106/// current [`PaintState`] (window activation and the high-contrast
107/// preference).
108///
109/// A recipe style that **bakes** a colour into a `ColorProp::Bound(Signal)` /
110/// `PaintProp` at build time (resolving a `RecipeColor` against the theme) must
111/// resolve against this signal rather than a plain `ctx.theme_signal()`. A
112/// `Bound` colour is a concrete value that `ColorProp::resolve` returns verbatim
113/// and so ignores the paint walker's theme projection: accent chrome baked from
114/// `theme_signal` (a Filled button fill, an accent focus border) would stay
115/// vivid in a background window, and keep its normal colours under high
116/// contrast, while paint-resolving controls (Toggle, Checkbox, which read
117/// `colors.accent` in `paint()`) followed the projection. Resolving against
118/// this keeps them in step, including a theme's own
119/// [`PaintProjection`](teksilo_core::styles::PaintProjection).
120///
121/// Role-preserving paint paths (passing a `SurfaceRole` / `BorderRole` /
122/// `Signal<Role>` straight to a widget so it resolves against `ctx.theme` at
123/// paint) already follow the projection and need no change.
124pub(crate) fn window_resolution_colors(ctx: &BuildContext) -> Signal<ColorTokens> {
125    let wa = ctx.window_active_signal();
126    let hc = ctx.high_contrast_signal();
127    ctx.theme_signal()
128        .zip3(&wa, &hc)
129        .map(|(theme, window_active, high_contrast)| {
130            theme.paint_colors(PaintState {
131                window_active: *window_active,
132                high_contrast: *high_contrast,
133            })
134        })
135}