//! Dynamic CSS selectors for runtime evaluation based on OS, media queries, container queries, etc.
/// Note: This is a CSS-only version. See `azul_core::styled_dom::StyledNodeState` for the main type.
impl_vec!(DynamicSelector, DynamicSelectorVec, DynamicSelectorVecDestructor, DynamicSelectorVecDestructorType, DynamicSelectorVecSlice, OptionDynamicSelector);
/// Used by `OsVersionCondition::DesktopEnv{Min,Max,Exact}` for `@os(linux:gnome > 40)` style selectors.
#[must_use] pub const fn from_system_desktop_env(de: &crate::system::DesktopEnvironment) -> Self {
#[allow(variant_size_differences)] // repr(C,u8) FFI enum: boxing the large variant would change the C ABI (api.json bindings); size disparity accepted
#[must_use] pub fn with_container(&self, width: f32, height: f32, name: Option<AzString>) -> Self {
#[must_use] pub fn viewport_breakpoint_changed(&self, other: &Self, breakpoints: &[f32]) -> bool {
Self::OsVersion(ver) => Self::match_os_version(ver, ctx.os_version, ctx.desktop_env, ctx.de_version),
const fn match_pseudo_state(state: PseudoStateType, ctx: &DynamicSelectorContext) -> bool {
/// - `(linux:gnome > 40)` → `[Os(Linux), OsVersion(DesktopEnvMin{ env: Gnome, version_id: 40 })]`
#[must_use] pub fn parse_os_at_rule_content(content: &str) -> Option<Vec<DynamicSelector>> {
// Earliest match wins; on a tie, the longer operator wins (so ">=" beats "=" at the same position).
/// If `apply_if` contains conditions, ALL conditions must be satisfied for the property to apply.
#[must_use] pub fn with_condition(property: CssProperty, condition: DynamicSelector) -> Self {
#[must_use] pub const fn with_conditions(property: CssProperty, conditions: DynamicSelectorVec) -> Self {
impl_vec!(CssPropertyWithConditions, CssPropertyWithConditionsVec, CssPropertyWithConditionsVecDestructor, CssPropertyWithConditionsVecDestructorType, CssPropertyWithConditionsVecSlice, OptionCssPropertyWithConditions);
/// CssPropertyWithConditionsVec::parse("@os linux { font-size: 14px; :hover { color: red; }}")
if let Some(parsed) = Self::parse_property_segment(&segment, inherited_conditions, &key_map) {
if let Some(parsed) = Self::parse_property_segment(remaining, inherited_conditions, &key_map) {
"focus-within" => return Some(vec![DynamicSelector::PseudoState(PseudoStateType::FocusWithin)]),
"min-width" => { if let Some(px) = px_value { conds.push(DynamicSelector::ContainerWidth(MinMaxRange::with_min(px))); } }
"max-width" => { if let Some(px) = px_value { conds.push(DynamicSelector::ContainerWidth(MinMaxRange::with_max(px))); } }
"min-height" => { if let Some(px) = px_value { conds.push(DynamicSelector::ContainerHeight(MinMaxRange::with_min(px))); } }
"max-height" => { if let Some(px) = px_value { conds.push(DynamicSelector::ContainerHeight(MinMaxRange::with_max(px))); } }
if value.eq_ignore_ascii_case("more") || value.eq_ignore_ascii_case("high") || value.eq_ignore_ascii_case("active") {
} else if value.eq_ignore_ascii_case("no-preference") || value.eq_ignore_ascii_case("none") {
let style = "padding: 20px; background-color: #f0f0f0; font-size: 14px; color: #222;overflow: scroll;";
let style = "display: grid; grid-template-columns: repeat(4, 160px); gap: 16px; padding: 10px;";