Skip to main content

fret_ui_kit/style/
slots.rs

1use super::{WidgetStateProperty, WidgetStates};
2
3/// ADR 0220 override slot shape.
4///
5/// - outer `Option`: whether a slot is overridden at all
6/// - inner `Option<T>`: per-state "no override" to fall back to defaults for that state
7pub type OverrideSlot<T> = Option<WidgetStateProperty<Option<T>>>;
8
9/// Resolves an ADR 0220-style override slot for a non-optional value.
10///
11/// - `overrides`: `None` means "slot not overridden".
12/// - `overrides.resolve(states) == None` means "no override for this state; fall back to defaults".
13pub fn resolve_override_slot<T: Clone>(
14    overrides: Option<&WidgetStateProperty<Option<T>>>,
15    defaults: &WidgetStateProperty<T>,
16    states: WidgetStates,
17) -> T {
18    match overrides {
19        Some(overrides) => overrides
20            .resolve(states)
21            .as_ref()
22            .cloned()
23            .unwrap_or_else(|| defaults.resolve(states).clone()),
24        None => defaults.resolve(states).clone(),
25    }
26}
27
28/// Resolves an ADR 0220-style override slot for a computed default.
29///
30/// Use this when defaults are already computed for the current `states`, rather than stored in a
31/// `WidgetStateProperty`.
32pub fn resolve_override_slot_with<T, U>(
33    overrides: Option<&WidgetStateProperty<Option<T>>>,
34    states: WidgetStates,
35    map: impl FnOnce(&T) -> U,
36    fallback: impl FnOnce() -> U,
37) -> U {
38    match overrides.and_then(|slot| slot.resolve(states).as_ref()) {
39        Some(value) => map(value),
40        None => fallback(),
41    }
42}
43
44/// Resolves an ADR 0220-style override slot for an optional value.
45///
46/// This variant is useful when the default style itself can be absent (e.g. "no background").
47pub fn resolve_override_slot_opt<T: Clone>(
48    overrides: Option<&WidgetStateProperty<Option<T>>>,
49    defaults: &WidgetStateProperty<Option<T>>,
50    states: WidgetStates,
51) -> Option<T> {
52    match overrides {
53        Some(overrides) => overrides
54            .resolve(states)
55            .as_ref()
56            .cloned()
57            .or_else(|| defaults.resolve(states).clone()),
58        None => defaults.resolve(states).clone(),
59    }
60}
61
62/// Resolves an ADR 0220-style override slot for a computed optional default.
63pub fn resolve_override_slot_opt_with<T, U>(
64    overrides: Option<&WidgetStateProperty<Option<T>>>,
65    states: WidgetStates,
66    map: impl FnOnce(&T) -> U,
67    fallback: impl FnOnce() -> Option<U>,
68) -> Option<U> {
69    match overrides.and_then(|slot| slot.resolve(states).as_ref()) {
70        Some(value) => Some(map(value)),
71        None => fallback(),
72    }
73}
74
75/// Right-biased merge for an optional override slot (ADR 0220).
76pub fn merge_override_slot<T>(base: Option<T>, other: Option<T>) -> Option<T> {
77    if other.is_some() { other } else { base }
78}