use crate::calc::CalcExpr;
use crate::element::CursorStyle;
use blinc_core::{
BlendMode, Brush, ClipPath, Color, CornerRadius, CornerShape, OverflowFade, PointerEvents,
Shadow, Transform,
};
#[derive(Clone, Debug)]
pub enum DynamicProperty {
Opacity(CalcExpr),
RotateX(CalcExpr),
RotateY(CalcExpr),
Perspective(CalcExpr),
CornerRadius(CalcExpr),
TranslateZ(CalcExpr),
Depth(CalcExpr),
BorderWidth(CalcExpr),
SkewX(CalcExpr),
SkewY(CalcExpr),
Rotate(CalcExpr),
ScaleX(CalcExpr),
ScaleY(CalcExpr),
}
impl DynamicProperty {
pub fn apply(&self, props: &mut crate::element::RenderProps, ctx: &crate::calc::CalcContext) {
match self {
DynamicProperty::Opacity(expr) => {
let v = expr.eval(ctx).clamp(0.0, 1.0);
props.opacity = v;
}
DynamicProperty::RotateX(expr) => {
let v = expr.eval(ctx);
props.rotate_x = Some(v);
}
DynamicProperty::RotateY(expr) => {
let v = expr.eval(ctx);
props.rotate_y = Some(v);
}
DynamicProperty::Perspective(expr) => {
props.perspective = Some(expr.eval(ctx));
}
DynamicProperty::CornerRadius(expr) => {
let r = expr.eval(ctx).max(0.0);
props.border_radius = blinc_core::CornerRadius::uniform(r);
}
DynamicProperty::TranslateZ(expr) => {
props.translate_z = Some(expr.eval(ctx));
}
DynamicProperty::Depth(expr) => {
props.depth = Some(expr.eval(ctx));
}
DynamicProperty::BorderWidth(expr) => {
let v = expr.eval(ctx).max(0.0);
props.border_width = v;
}
DynamicProperty::SkewX(expr) => {
let deg = expr.eval(ctx);
let skew = blinc_core::Affine2D::skew_x(deg.to_radians());
compose_affine(props, skew);
}
DynamicProperty::SkewY(expr) => {
let deg = expr.eval(ctx);
let skew = blinc_core::Affine2D::skew_y(deg.to_radians());
compose_affine(props, skew);
}
DynamicProperty::Rotate(expr) => {
let deg = expr.eval(ctx);
let rot = blinc_core::Affine2D::rotation(deg.to_radians());
compose_affine(props, rot);
}
DynamicProperty::ScaleX(expr) => {
let sx = expr.eval(ctx);
let s = blinc_core::Affine2D::scale(sx, 1.0);
compose_affine(props, s);
}
DynamicProperty::ScaleY(expr) => {
let sy = expr.eval(ctx);
let s = blinc_core::Affine2D::scale(1.0, sy);
compose_affine(props, s);
}
}
}
pub fn is_transform(&self) -> bool {
matches!(
self,
DynamicProperty::SkewX(_)
| DynamicProperty::SkewY(_)
| DynamicProperty::Rotate(_)
| DynamicProperty::ScaleX(_)
| DynamicProperty::ScaleY(_)
)
}
pub fn expr(&self) -> &CalcExpr {
match self {
DynamicProperty::Opacity(e)
| DynamicProperty::RotateX(e)
| DynamicProperty::RotateY(e)
| DynamicProperty::Perspective(e)
| DynamicProperty::CornerRadius(e)
| DynamicProperty::TranslateZ(e)
| DynamicProperty::Depth(e)
| DynamicProperty::BorderWidth(e)
| DynamicProperty::SkewX(e)
| DynamicProperty::SkewY(e)
| DynamicProperty::Rotate(e)
| DynamicProperty::ScaleX(e)
| DynamicProperty::ScaleY(e) => e,
}
}
}
fn compose_affine(props: &mut crate::element::RenderProps, new_affine: blinc_core::Affine2D) {
use blinc_core::Transform;
let composed = match &props.transform {
Some(Transform::Affine2D(existing)) => existing.then(&new_affine),
_ => new_affine,
};
props.transform = Some(Transform::Affine2D(composed));
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct CssFilter {
pub grayscale: f32,
pub invert: f32,
pub sepia: f32,
pub hue_rotate: f32,
pub brightness: f32,
pub contrast: f32,
pub saturate: f32,
pub blur: f32,
pub drop_shadow: Option<Shadow>,
}
impl Default for CssFilter {
fn default() -> Self {
Self {
grayscale: 0.0,
invert: 0.0,
sepia: 0.0,
hue_rotate: 0.0,
brightness: 1.0,
contrast: 1.0,
saturate: 1.0,
blur: 0.0,
drop_shadow: None,
}
}
}
impl CssFilter {
pub fn is_identity(&self) -> bool {
self.grayscale == 0.0
&& self.invert == 0.0
&& self.sepia == 0.0
&& self.hue_rotate == 0.0
&& self.brightness == 1.0
&& self.contrast == 1.0
&& self.saturate == 1.0
&& self.blur == 0.0
&& self.drop_shadow.is_none()
}
}
use blinc_theme::ThemeState;
use crate::css_parser::{CssAnimation, CssTransitionSet};
use crate::element::{GlassMaterial, Material, MetallicMaterial, RenderLayer, WoodMaterial};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TextDecoration {
None,
Underline,
LineThrough,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TextOverflow {
Clip,
Ellipsis,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum WhiteSpace {
Normal,
Nowrap,
Pre,
PreWrap,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ScrollbarWidth {
Auto,
Thin,
None,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct SpacingRect {
pub top: f32,
pub right: f32,
pub bottom: f32,
pub left: f32,
}
impl SpacingRect {
pub fn uniform(px: f32) -> Self {
Self {
top: px,
right: px,
bottom: px,
left: px,
}
}
pub fn xy(x: f32, y: f32) -> Self {
Self {
top: y,
right: x,
bottom: y,
left: x,
}
}
pub fn new(top: f32, right: f32, bottom: f32, left: f32) -> Self {
Self {
top,
right,
bottom,
left,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StyleFlexDirection {
Row,
Column,
RowReverse,
ColumnReverse,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StyleDisplay {
Flex,
Block,
None,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StyleAlign {
Start,
Center,
End,
Stretch,
Baseline,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StyleJustify {
Start,
Center,
End,
SpaceBetween,
SpaceAround,
SpaceEvenly,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StyleOverflow {
Visible,
Clip,
Scroll,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StyleVisibility {
Visible,
Hidden,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StylePosition {
Static,
Relative,
Absolute,
Fixed,
Sticky,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StyleDimension {
Length(f32),
Percent(f32),
Auto,
}
#[derive(Clone, Default, Debug)]
pub struct ElementStyle {
pub background: Option<Brush>,
pub corner_radius: Option<CornerRadius>,
pub corner_shape: Option<CornerShape>,
pub shadow: Option<Shadow>,
pub transform: Option<Transform>,
pub material: Option<Material>,
pub render_layer: Option<RenderLayer>,
pub opacity: Option<f32>,
pub text_color: Option<blinc_core::Color>,
pub font_size: Option<f32>,
pub text_shadow: Option<Shadow>,
pub font_weight: Option<crate::div::FontWeight>,
pub text_decoration: Option<TextDecoration>,
pub line_height: Option<f32>,
pub text_align: Option<crate::div::TextAlign>,
pub letter_spacing: Option<f32>,
pub rotate: Option<f32>,
pub scale_x: Option<f32>,
pub scale_y: Option<f32>,
pub skew_x: Option<f32>,
pub skew_y: Option<f32>,
pub transform_origin: Option<[f32; 2]>,
pub animation: Option<CssAnimation>,
pub transition: Option<CssTransitionSet>,
pub rotate_x: Option<f32>,
pub rotate_y: Option<f32>,
pub perspective: Option<f32>,
pub shape_3d: Option<String>,
pub depth: Option<f32>,
pub light_direction: Option<[f32; 3]>,
pub light_intensity: Option<f32>,
pub ambient: Option<f32>,
pub specular: Option<f32>,
pub translate_z: Option<f32>,
pub op_3d: Option<String>,
pub blend_3d: Option<f32>,
pub clip_path: Option<ClipPath>,
pub filter: Option<CssFilter>,
pub width: Option<StyleDimension>,
pub height: Option<StyleDimension>,
pub min_width: Option<f32>,
pub min_height: Option<f32>,
pub max_width: Option<f32>,
pub max_height: Option<f32>,
pub display: Option<StyleDisplay>,
pub flex_direction: Option<StyleFlexDirection>,
pub flex_wrap: Option<bool>,
pub flex_grow: Option<f32>,
pub flex_shrink: Option<f32>,
pub align_items: Option<StyleAlign>,
pub justify_content: Option<StyleJustify>,
pub align_self: Option<StyleAlign>,
pub padding: Option<SpacingRect>,
pub margin: Option<SpacingRect>,
pub gap: Option<f32>,
pub overflow: Option<StyleOverflow>,
pub overflow_x: Option<StyleOverflow>,
pub overflow_y: Option<StyleOverflow>,
pub overflow_fade: Option<OverflowFade>,
pub border_width: Option<f32>,
pub border_color: Option<Color>,
pub outline_width: Option<f32>,
pub outline_color: Option<Color>,
pub outline_offset: Option<f32>,
pub caret_color: Option<Color>,
pub selection_color: Option<Color>,
pub placeholder_color: Option<Color>,
pub accent_color: Option<Color>,
pub scrollbar_color: Option<(Color, Color)>,
pub scrollbar_width: Option<ScrollbarWidth>,
pub fill: Option<Color>,
pub stroke: Option<Color>,
pub stroke_width: Option<f32>,
pub stroke_dasharray: Option<Vec<f32>>,
pub stroke_dashoffset: Option<f32>,
pub svg_path_data: Option<String>,
pub position: Option<StylePosition>,
pub top: Option<f32>,
pub right: Option<f32>,
pub bottom: Option<f32>,
pub left: Option<f32>,
pub z_index: Option<i32>,
pub visibility: Option<StyleVisibility>,
pub object_fit: Option<u8>,
pub object_position: Option<[f32; 2]>,
pub pointer_events: Option<PointerEvents>,
pub cursor: Option<CursorStyle>,
pub mix_blend_mode: Option<BlendMode>,
pub text_decoration_color: Option<Color>,
pub text_decoration_thickness: Option<f32>,
pub text_overflow: Option<TextOverflow>,
pub white_space: Option<WhiteSpace>,
pub mask_image: Option<blinc_core::MaskImage>,
pub mask_mode: Option<blinc_core::MaskMode>,
pub flow: Option<String>,
pub pointer_space: Option<crate::pointer_query::PointerSpaceConfig>,
pub dynamic_properties: Option<Vec<DynamicProperty>>,
}
impl ElementStyle {
pub fn new() -> Self {
Self::default()
}
pub fn bg(mut self, color: impl Into<Brush>) -> Self {
self.background = Some(color.into());
self
}
pub fn bg_color(mut self, color: Color) -> Self {
self.background = Some(Brush::Solid(color));
self
}
pub fn background(mut self, brush: Brush) -> Self {
self.background = Some(brush);
self
}
pub fn rounded(mut self, radius: f32) -> Self {
self.corner_radius = Some(CornerRadius::uniform(radius));
self
}
pub fn rounded_full(mut self) -> Self {
self.corner_radius = Some(CornerRadius::uniform(9999.0));
self
}
pub fn rounded_corners(mut self, tl: f32, tr: f32, br: f32, bl: f32) -> Self {
self.corner_radius = Some(CornerRadius::new(tl, tr, br, bl));
self
}
pub fn corner_radius(mut self, radius: CornerRadius) -> Self {
self.corner_radius = Some(radius);
self
}
pub fn corner_shape(mut self, n: f32) -> Self {
self.corner_shape = Some(CornerShape::uniform(n));
self
}
pub fn corner_shapes(mut self, tl: f32, tr: f32, br: f32, bl: f32) -> Self {
self.corner_shape = Some(CornerShape::new(tl, tr, br, bl));
self
}
pub fn corner_bevel(mut self) -> Self {
self.corner_shape = Some(CornerShape::BEVEL);
self
}
pub fn corner_squircle(mut self) -> Self {
self.corner_shape = Some(CornerShape::SQUIRCLE);
self
}
pub fn corner_scoop(mut self) -> Self {
self.corner_shape = Some(CornerShape::SCOOP);
self
}
pub fn rounded_sm(self) -> Self {
self.rounded(ThemeState::get().radii().radius_sm)
}
pub fn rounded_default(self) -> Self {
self.rounded(ThemeState::get().radii().radius_default)
}
pub fn rounded_md(self) -> Self {
self.rounded(ThemeState::get().radii().radius_md)
}
pub fn rounded_lg(self) -> Self {
self.rounded(ThemeState::get().radii().radius_lg)
}
pub fn rounded_xl(self) -> Self {
self.rounded(ThemeState::get().radii().radius_xl)
}
pub fn rounded_2xl(self) -> Self {
self.rounded(ThemeState::get().radii().radius_2xl)
}
pub fn rounded_none(self) -> Self {
self.rounded(0.0)
}
pub fn shadow(mut self, shadow: Shadow) -> Self {
self.shadow = Some(shadow);
self
}
pub fn shadow_params(self, offset_x: f32, offset_y: f32, blur: f32, color: Color) -> Self {
self.shadow(Shadow::new(offset_x, offset_y, blur, color))
}
pub fn shadow_sm(self) -> Self {
self.shadow(ThemeState::get().shadows().shadow_sm.into())
}
pub fn shadow_md(self) -> Self {
self.shadow(ThemeState::get().shadows().shadow_md.into())
}
pub fn shadow_lg(self) -> Self {
self.shadow(ThemeState::get().shadows().shadow_lg.into())
}
pub fn shadow_xl(self) -> Self {
self.shadow(ThemeState::get().shadows().shadow_xl.into())
}
pub fn shadow_none(mut self) -> Self {
self.shadow = Some(Shadow::new(0.0, 0.0, 0.0, Color::TRANSPARENT));
self
}
pub fn transform(mut self, transform: Transform) -> Self {
self.transform = Some(transform);
self
}
pub fn scale(self, factor: f32) -> Self {
self.transform(Transform::scale(factor, factor))
}
pub fn scale_xy(self, sx: f32, sy: f32) -> Self {
self.transform(Transform::scale(sx, sy))
}
pub fn translate(self, x: f32, y: f32) -> Self {
self.transform(Transform::translate(x, y))
}
pub fn rotate(self, angle: f32) -> Self {
self.transform(Transform::rotate(angle))
}
pub fn rotate_deg(self, degrees: f32) -> Self {
self.rotate(degrees * std::f32::consts::PI / 180.0)
}
pub fn rotate_x_deg(mut self, degrees: f32) -> Self {
self.rotate_x = Some(degrees);
self
}
pub fn rotate_y_deg(mut self, degrees: f32) -> Self {
self.rotate_y = Some(degrees);
self
}
pub fn perspective_px(mut self, px: f32) -> Self {
self.perspective = Some(px);
self
}
pub fn shape_3d(mut self, shape: impl Into<String>) -> Self {
self.shape_3d = Some(shape.into());
self
}
pub fn depth_px(mut self, px: f32) -> Self {
self.depth = Some(px);
self
}
pub fn light_direction(mut self, x: f32, y: f32, z: f32) -> Self {
self.light_direction = Some([x, y, z]);
self
}
pub fn light_intensity(mut self, intensity: f32) -> Self {
self.light_intensity = Some(intensity);
self
}
pub fn ambient_light(mut self, level: f32) -> Self {
self.ambient = Some(level);
self
}
pub fn specular_power(mut self, power: f32) -> Self {
self.specular = Some(power);
self
}
pub fn translate_z_px(mut self, px: f32) -> Self {
self.translate_z = Some(px);
self
}
pub fn op_3d_type(mut self, op: &str) -> Self {
self.op_3d = Some(op.to_string());
self
}
pub fn blend_3d_px(mut self, px: f32) -> Self {
self.blend_3d = Some(px);
self
}
pub fn clip_path(mut self, path: ClipPath) -> Self {
self.clip_path = Some(path);
self
}
pub fn material(mut self, material: Material) -> Self {
if matches!(material, Material::Glass(_)) {
self.render_layer = Some(RenderLayer::Glass);
}
self.material = Some(material);
self
}
pub fn effect(self, effect: impl Into<Material>) -> Self {
self.material(effect.into())
}
pub fn glass(self) -> Self {
self.material(Material::Glass(GlassMaterial::new()))
}
pub fn glass_custom(self, glass: GlassMaterial) -> Self {
self.material(Material::Glass(glass))
}
pub fn metallic(self) -> Self {
self.material(Material::Metallic(MetallicMaterial::new()))
}
pub fn chrome(self) -> Self {
self.material(Material::Metallic(MetallicMaterial::chrome()))
}
pub fn gold(self) -> Self {
self.material(Material::Metallic(MetallicMaterial::gold()))
}
pub fn wood(self) -> Self {
self.material(Material::Wood(WoodMaterial::new()))
}
pub fn layer(mut self, layer: RenderLayer) -> Self {
self.render_layer = Some(layer);
self
}
pub fn foreground(self) -> Self {
self.layer(RenderLayer::Foreground)
}
pub fn layer_background(self) -> Self {
self.layer(RenderLayer::Background)
}
pub fn opacity(mut self, opacity: f32) -> Self {
self.opacity = Some(opacity.clamp(0.0, 1.0));
self
}
pub fn opaque(self) -> Self {
self.opacity(1.0)
}
pub fn translucent(self) -> Self {
self.opacity(0.5)
}
pub fn transparent(self) -> Self {
self.opacity(0.0)
}
pub fn w(mut self, px: f32) -> Self {
self.width = Some(StyleDimension::Length(px));
self
}
pub fn h(mut self, px: f32) -> Self {
self.height = Some(StyleDimension::Length(px));
self
}
pub fn min_w(mut self, px: f32) -> Self {
self.min_width = Some(px);
self
}
pub fn min_h(mut self, px: f32) -> Self {
self.min_height = Some(px);
self
}
pub fn max_w(mut self, px: f32) -> Self {
self.max_width = Some(px);
self
}
pub fn max_h(mut self, px: f32) -> Self {
self.max_height = Some(px);
self
}
pub fn flex_row(mut self) -> Self {
self.display = Some(StyleDisplay::Flex);
self.flex_direction = Some(StyleFlexDirection::Row);
self
}
pub fn flex_col(mut self) -> Self {
self.display = Some(StyleDisplay::Flex);
self.flex_direction = Some(StyleFlexDirection::Column);
self
}
pub fn flex_row_reverse(mut self) -> Self {
self.display = Some(StyleDisplay::Flex);
self.flex_direction = Some(StyleFlexDirection::RowReverse);
self
}
pub fn flex_col_reverse(mut self) -> Self {
self.display = Some(StyleDisplay::Flex);
self.flex_direction = Some(StyleFlexDirection::ColumnReverse);
self
}
pub fn flex_wrap(mut self) -> Self {
self.flex_wrap = Some(true);
self
}
pub fn display_none(mut self) -> Self {
self.display = Some(StyleDisplay::None);
self
}
pub fn flex_grow(mut self) -> Self {
self.flex_grow = Some(1.0);
self
}
pub fn flex_grow_value(mut self, value: f32) -> Self {
self.flex_grow = Some(value);
self
}
pub fn flex_shrink_0(mut self) -> Self {
self.flex_shrink = Some(0.0);
self
}
pub fn items_center(mut self) -> Self {
self.align_items = Some(StyleAlign::Center);
self
}
pub fn items_start(mut self) -> Self {
self.align_items = Some(StyleAlign::Start);
self
}
pub fn items_end(mut self) -> Self {
self.align_items = Some(StyleAlign::End);
self
}
pub fn items_stretch(mut self) -> Self {
self.align_items = Some(StyleAlign::Stretch);
self
}
pub fn justify_center(mut self) -> Self {
self.justify_content = Some(StyleJustify::Center);
self
}
pub fn justify_start(mut self) -> Self {
self.justify_content = Some(StyleJustify::Start);
self
}
pub fn justify_end(mut self) -> Self {
self.justify_content = Some(StyleJustify::End);
self
}
pub fn justify_between(mut self) -> Self {
self.justify_content = Some(StyleJustify::SpaceBetween);
self
}
pub fn justify_around(mut self) -> Self {
self.justify_content = Some(StyleJustify::SpaceAround);
self
}
pub fn justify_evenly(mut self) -> Self {
self.justify_content = Some(StyleJustify::SpaceEvenly);
self
}
pub fn self_center(mut self) -> Self {
self.align_self = Some(StyleAlign::Center);
self
}
pub fn self_start(mut self) -> Self {
self.align_self = Some(StyleAlign::Start);
self
}
pub fn self_end(mut self) -> Self {
self.align_self = Some(StyleAlign::End);
self
}
pub fn p(mut self, px: f32) -> Self {
self.padding = Some(SpacingRect::uniform(px));
self
}
pub fn p_xy(mut self, x: f32, y: f32) -> Self {
self.padding = Some(SpacingRect::xy(x, y));
self
}
pub fn p_trbl(mut self, top: f32, right: f32, bottom: f32, left: f32) -> Self {
self.padding = Some(SpacingRect::new(top, right, bottom, left));
self
}
pub fn m(mut self, px: f32) -> Self {
self.margin = Some(SpacingRect::uniform(px));
self
}
pub fn m_xy(mut self, x: f32, y: f32) -> Self {
self.margin = Some(SpacingRect::xy(x, y));
self
}
pub fn m_trbl(mut self, top: f32, right: f32, bottom: f32, left: f32) -> Self {
self.margin = Some(SpacingRect::new(top, right, bottom, left));
self
}
pub fn gap(mut self, px: f32) -> Self {
self.gap = Some(px);
self
}
pub fn overflow_clip(mut self) -> Self {
self.overflow = Some(StyleOverflow::Clip);
self
}
pub fn overflow_visible(mut self) -> Self {
self.overflow = Some(StyleOverflow::Visible);
self
}
pub fn overflow_scroll(mut self) -> Self {
self.overflow = Some(StyleOverflow::Scroll);
self
}
pub fn overflow_fade(mut self, distance: f32) -> Self {
self.overflow_fade = Some(OverflowFade::uniform(distance));
self
}
pub fn overflow_fade_edges(mut self, top: f32, right: f32, bottom: f32, left: f32) -> Self {
self.overflow_fade = Some(OverflowFade::new(top, right, bottom, left));
self
}
pub fn overflow_fade_y(mut self, distance: f32) -> Self {
self.overflow_fade = Some(OverflowFade::vertical(distance));
self
}
pub fn overflow_fade_x(mut self, distance: f32) -> Self {
self.overflow_fade = Some(OverflowFade::horizontal(distance));
self
}
pub fn border(mut self, width: f32, color: Color) -> Self {
self.border_width = Some(width);
self.border_color = Some(color);
self
}
pub fn border_w(mut self, width: f32) -> Self {
self.border_width = Some(width);
self
}
pub fn outline(mut self, width: f32, color: Color) -> Self {
self.outline_width = Some(width);
self.outline_color = Some(color);
self
}
pub fn outline_w(mut self, width: f32) -> Self {
self.outline_width = Some(width);
self
}
pub fn outline_offset(mut self, offset: f32) -> Self {
self.outline_offset = Some(offset);
self
}
pub fn pointer_events(mut self, pe: PointerEvents) -> Self {
self.pointer_events = Some(pe);
self
}
pub fn pointer_events_none(mut self) -> Self {
self.pointer_events = Some(PointerEvents::None);
self
}
pub fn cursor(mut self, cursor: CursorStyle) -> Self {
self.cursor = Some(cursor);
self
}
pub fn mix_blend_mode(mut self, mode: BlendMode) -> Self {
self.mix_blend_mode = Some(mode);
self
}
pub fn text_decoration_color(mut self, color: Color) -> Self {
self.text_decoration_color = Some(color);
self
}
pub fn text_decoration_thickness(mut self, thickness: f32) -> Self {
self.text_decoration_thickness = Some(thickness);
self
}
pub fn text_overflow(mut self, overflow: TextOverflow) -> Self {
self.text_overflow = Some(overflow);
self
}
pub fn white_space(mut self, ws: WhiteSpace) -> Self {
self.white_space = Some(ws);
self
}
pub fn mask_image(mut self, url: impl Into<String>) -> Self {
self.mask_image = Some(blinc_core::MaskImage::Url(url.into()));
self
}
pub fn mask_gradient(mut self, gradient: blinc_core::Gradient) -> Self {
self.mask_image = Some(blinc_core::MaskImage::Gradient(gradient));
self
}
pub fn mask_mode(mut self, mode: blinc_core::MaskMode) -> Self {
self.mask_mode = Some(mode);
self
}
pub fn flow(mut self, name: impl Into<String>) -> Self {
self.flow = Some(name.into());
self
}
pub fn text_color(mut self, color: Color) -> Self {
self.text_color = Some(color);
self
}
pub fn font_size(mut self, size: f32) -> Self {
self.font_size = Some(size);
self
}
pub fn font_weight(mut self, weight: crate::div::FontWeight) -> Self {
self.font_weight = Some(weight);
self
}
pub fn text_decoration(mut self, decoration: TextDecoration) -> Self {
self.text_decoration = Some(decoration);
self
}
pub fn line_height(mut self, height: f32) -> Self {
self.line_height = Some(height);
self
}
pub fn text_align(mut self, align: crate::div::TextAlign) -> Self {
self.text_align = Some(align);
self
}
pub fn letter_spacing(mut self, spacing: f32) -> Self {
self.letter_spacing = Some(spacing);
self
}
pub fn text_shadow(mut self, shadow: Shadow) -> Self {
self.text_shadow = Some(shadow);
self
}
pub fn skew_x(mut self, deg: f32) -> Self {
self.skew_x = Some(deg);
self
}
pub fn skew_y(mut self, deg: f32) -> Self {
self.skew_y = Some(deg);
self
}
pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
self.transform_origin = Some([x, y]);
self
}
pub fn transition(mut self, t: CssTransitionSet) -> Self {
self.transition = Some(t);
self
}
pub fn filter(mut self, f: CssFilter) -> Self {
self.filter = Some(f);
self
}
pub fn overflow_x(mut self, o: StyleOverflow) -> Self {
self.overflow_x = Some(o);
self
}
pub fn overflow_y(mut self, o: StyleOverflow) -> Self {
self.overflow_y = Some(o);
self
}
pub fn position(mut self, pos: StylePosition) -> Self {
self.position = Some(pos);
self
}
pub fn top(mut self, px: f32) -> Self {
self.top = Some(px);
self
}
pub fn right(mut self, px: f32) -> Self {
self.right = Some(px);
self
}
pub fn bottom(mut self, px: f32) -> Self {
self.bottom = Some(px);
self
}
pub fn left(mut self, px: f32) -> Self {
self.left = Some(px);
self
}
pub fn inset(mut self, px: f32) -> Self {
self.top = Some(px);
self.right = Some(px);
self.bottom = Some(px);
self.left = Some(px);
self
}
pub fn z_index(mut self, z: i32) -> Self {
self.z_index = Some(z);
self
}
pub fn visibility(mut self, vis: StyleVisibility) -> Self {
self.visibility = Some(vis);
self
}
pub fn caret_color(mut self, color: Color) -> Self {
self.caret_color = Some(color);
self
}
pub fn selection_color(mut self, color: Color) -> Self {
self.selection_color = Some(color);
self
}
pub fn placeholder_color(mut self, color: Color) -> Self {
self.placeholder_color = Some(color);
self
}
pub fn accent_color(mut self, color: Color) -> Self {
self.accent_color = Some(color);
self
}
pub fn scrollbar_color(mut self, thumb: Color, track: Color) -> Self {
self.scrollbar_color = Some((thumb, track));
self
}
pub fn scrollbar_width(mut self, width: ScrollbarWidth) -> Self {
self.scrollbar_width = Some(width);
self
}
pub fn fill(mut self, color: Color) -> Self {
self.fill = Some(color);
self
}
pub fn stroke(mut self, color: Color) -> Self {
self.stroke = Some(color);
self
}
pub fn stroke_width(mut self, width: f32) -> Self {
self.stroke_width = Some(width);
self
}
pub fn stroke_dasharray(mut self, pattern: Vec<f32>) -> Self {
self.stroke_dasharray = Some(pattern);
self
}
pub fn stroke_dashoffset(mut self, offset: f32) -> Self {
self.stroke_dashoffset = Some(offset);
self
}
pub fn svg_path_data(mut self, data: impl Into<String>) -> Self {
self.svg_path_data = Some(data.into());
self
}
pub fn object_fit(mut self, fit: u8) -> Self {
self.object_fit = Some(fit);
self
}
pub fn object_position(mut self, x: f32, y: f32) -> Self {
self.object_position = Some([x, y]);
self
}
pub fn flex_shrink(mut self, value: f32) -> Self {
self.flex_shrink = Some(value);
self
}
pub fn merge(&self, other: &ElementStyle) -> ElementStyle {
ElementStyle {
background: other.background.clone().or_else(|| self.background.clone()),
corner_radius: other.corner_radius.or(self.corner_radius),
corner_shape: other.corner_shape.or(self.corner_shape),
shadow: other.shadow.or(self.shadow),
transform: other.transform.clone().or_else(|| self.transform.clone()),
material: other.material.clone().or_else(|| self.material.clone()),
render_layer: other.render_layer.or(self.render_layer),
opacity: other.opacity.or(self.opacity),
text_color: other.text_color.or(self.text_color),
font_size: other.font_size.or(self.font_size),
text_shadow: other.text_shadow.or(self.text_shadow),
font_weight: other.font_weight.or(self.font_weight),
text_decoration: other.text_decoration.or(self.text_decoration),
line_height: other.line_height.or(self.line_height),
text_align: other.text_align.or(self.text_align),
letter_spacing: other.letter_spacing.or(self.letter_spacing),
rotate: other.rotate.or(self.rotate),
scale_x: other.scale_x.or(self.scale_x),
scale_y: other.scale_y.or(self.scale_y),
skew_x: other.skew_x.or(self.skew_x),
skew_y: other.skew_y.or(self.skew_y),
transform_origin: other.transform_origin.or(self.transform_origin),
animation: other.animation.clone().or_else(|| self.animation.clone()),
transition: other.transition.clone().or_else(|| self.transition.clone()),
rotate_x: other.rotate_x.or(self.rotate_x),
rotate_y: other.rotate_y.or(self.rotate_y),
perspective: other.perspective.or(self.perspective),
shape_3d: other.shape_3d.clone().or_else(|| self.shape_3d.clone()),
depth: other.depth.or(self.depth),
light_direction: other.light_direction.or(self.light_direction),
light_intensity: other.light_intensity.or(self.light_intensity),
ambient: other.ambient.or(self.ambient),
specular: other.specular.or(self.specular),
translate_z: other.translate_z.or(self.translate_z),
op_3d: other.op_3d.clone().or_else(|| self.op_3d.clone()),
blend_3d: other.blend_3d.or(self.blend_3d),
clip_path: other.clip_path.clone().or_else(|| self.clip_path.clone()),
filter: other.filter.or(self.filter),
width: other.width.or(self.width),
height: other.height.or(self.height),
min_width: other.min_width.or(self.min_width),
min_height: other.min_height.or(self.min_height),
max_width: other.max_width.or(self.max_width),
max_height: other.max_height.or(self.max_height),
display: other.display.or(self.display),
flex_direction: other.flex_direction.or(self.flex_direction),
flex_wrap: other.flex_wrap.or(self.flex_wrap),
flex_grow: other.flex_grow.or(self.flex_grow),
flex_shrink: other.flex_shrink.or(self.flex_shrink),
align_items: other.align_items.or(self.align_items),
justify_content: other.justify_content.or(self.justify_content),
align_self: other.align_self.or(self.align_self),
padding: other.padding.or(self.padding),
margin: other.margin.or(self.margin),
gap: other.gap.or(self.gap),
overflow: other.overflow.or(self.overflow),
overflow_x: other.overflow_x.or(self.overflow_x),
overflow_y: other.overflow_y.or(self.overflow_y),
overflow_fade: other.overflow_fade.or(self.overflow_fade),
border_width: other.border_width.or(self.border_width),
border_color: other.border_color.or(self.border_color),
outline_width: other.outline_width.or(self.outline_width),
outline_color: other.outline_color.or(self.outline_color),
outline_offset: other.outline_offset.or(self.outline_offset),
caret_color: other.caret_color.or(self.caret_color),
selection_color: other.selection_color.or(self.selection_color),
placeholder_color: other.placeholder_color.or(self.placeholder_color),
accent_color: other.accent_color.or(self.accent_color),
scrollbar_color: other.scrollbar_color.or(self.scrollbar_color),
scrollbar_width: other.scrollbar_width.or(self.scrollbar_width),
fill: other.fill.or(self.fill),
stroke: other.stroke.or(self.stroke),
stroke_width: other.stroke_width.or(self.stroke_width),
stroke_dasharray: other
.stroke_dasharray
.clone()
.or(self.stroke_dasharray.clone()),
stroke_dashoffset: other.stroke_dashoffset.or(self.stroke_dashoffset),
svg_path_data: other.svg_path_data.clone().or(self.svg_path_data.clone()),
position: other.position.or(self.position),
top: other.top.or(self.top),
right: other.right.or(self.right),
bottom: other.bottom.or(self.bottom),
left: other.left.or(self.left),
z_index: other.z_index.or(self.z_index),
visibility: other.visibility.or(self.visibility),
object_fit: other.object_fit.or(self.object_fit),
object_position: other.object_position.or(self.object_position),
pointer_events: other.pointer_events.or(self.pointer_events),
cursor: other.cursor.or(self.cursor),
mix_blend_mode: other.mix_blend_mode.or(self.mix_blend_mode),
text_decoration_color: other.text_decoration_color.or(self.text_decoration_color),
text_decoration_thickness: other
.text_decoration_thickness
.or(self.text_decoration_thickness),
text_overflow: other.text_overflow.or(self.text_overflow),
white_space: other.white_space.or(self.white_space),
mask_image: other
.mask_image
.as_ref()
.or(self.mask_image.as_ref())
.cloned(),
mask_mode: other.mask_mode.clone().or(self.mask_mode.clone()),
flow: other.flow.clone().or_else(|| self.flow.clone()),
pointer_space: other
.pointer_space
.clone()
.or_else(|| self.pointer_space.clone()),
dynamic_properties: match (&self.dynamic_properties, &other.dynamic_properties) {
(None, None) => None,
(Some(a), None) => Some(a.clone()),
(None, Some(b)) => Some(b.clone()),
(Some(a), Some(b)) => {
let mut merged = a.clone();
merged.extend(b.iter().cloned());
Some(merged)
}
},
}
}
pub fn has_visual_props(&self) -> bool {
self.background.is_some()
|| self.corner_radius.is_some()
|| self.corner_shape.is_some()
|| self.shadow.is_some()
|| self.transform.is_some()
|| self.material.is_some()
|| self.render_layer.is_some()
|| self.opacity.is_some()
|| self.animation.is_some()
|| self.z_index.is_some()
|| self.visibility.is_some()
|| self.overflow_fade.is_some()
}
pub fn has_layout_props(&self) -> bool {
self.width.is_some()
|| self.height.is_some()
|| self.min_width.is_some()
|| self.min_height.is_some()
|| self.max_width.is_some()
|| self.max_height.is_some()
|| self.display.is_some()
|| self.flex_direction.is_some()
|| self.flex_wrap.is_some()
|| self.flex_grow.is_some()
|| self.flex_shrink.is_some()
|| self.align_items.is_some()
|| self.justify_content.is_some()
|| self.align_self.is_some()
|| self.padding.is_some()
|| self.margin.is_some()
|| self.gap.is_some()
|| self.overflow.is_some()
|| self.overflow_x.is_some()
|| self.overflow_y.is_some()
|| self.border_width.is_some()
|| self.border_color.is_some()
|| self.position.is_some()
|| self.top.is_some()
|| self.right.is_some()
|| self.bottom.is_some()
|| self.left.is_some()
|| self.visibility.is_some()
}
pub fn is_empty(&self) -> bool {
!self.has_visual_props() && !self.has_layout_props()
}
pub fn animation(mut self, animation: CssAnimation) -> Self {
self.animation = Some(animation);
self
}
pub fn animation_name(mut self, name: impl Into<String>) -> Self {
let mut anim = self.animation.take().unwrap_or_default();
anim.name = name.into();
self.animation = Some(anim);
self
}
pub fn animation_duration(mut self, duration_ms: u32) -> Self {
let mut anim = self.animation.take().unwrap_or_default();
anim.duration_ms = duration_ms;
self.animation = Some(anim);
self
}
}
pub fn style() -> ElementStyle {
ElementStyle::new()
}
#[macro_export]
macro_rules! css {
() => {
$crate::element_style::ElementStyle::new()
};
($($tokens:tt)*) => {{
let mut __style = $crate::element_style::ElementStyle::new();
$crate::css_impl!(__style; $($tokens)*);
__style
}};
}
#[macro_export]
#[doc(hidden)]
macro_rules! css_impl {
($style:ident;) => {};
($style:ident; background: $value:expr; $($rest:tt)*) => {
$style = $style.bg($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; background: $value:expr) => {
$style = $style.bg($value);
};
($style:ident; border-radius: $value:expr; $($rest:tt)*) => {
$style = $style.rounded($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; border-radius: $value:expr) => {
$style = $style.rounded($value);
};
($style:ident; corner-shape: round; $($rest:tt)*) => {
$style = $style.corner_shape(1.0);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; corner-shape: round) => {
$style = $style.corner_shape(1.0);
};
($style:ident; corner-shape: bevel; $($rest:tt)*) => {
$style = $style.corner_shape(0.0);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; corner-shape: bevel) => {
$style = $style.corner_shape(0.0);
};
($style:ident; corner-shape: squircle; $($rest:tt)*) => {
$style = $style.corner_shape(2.0);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; corner-shape: squircle) => {
$style = $style.corner_shape(2.0);
};
($style:ident; corner-shape: scoop; $($rest:tt)*) => {
$style = $style.corner_shape(-1.0);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; corner-shape: scoop) => {
$style = $style.corner_shape(-1.0);
};
($style:ident; corner-shape: notch; $($rest:tt)*) => {
$style = $style.corner_shape(-100.0);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; corner-shape: notch) => {
$style = $style.corner_shape(-100.0);
};
($style:ident; corner-shape: square; $($rest:tt)*) => {
$style = $style.corner_shape(100.0);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; corner-shape: square) => {
$style = $style.corner_shape(100.0);
};
($style:ident; corner-shape: $value:expr; $($rest:tt)*) => {
$style = $style.corner_shape($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; corner-shape: $value:expr) => {
$style = $style.corner_shape($value);
};
($style:ident; overflow-fade: $value:expr; $($rest:tt)*) => {
$style = $style.overflow_fade($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; overflow-fade: $value:expr) => {
$style = $style.overflow_fade($value);
};
($style:ident; box-shadow: sm; $($rest:tt)*) => {
$style = $style.shadow_sm();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; box-shadow: sm) => {
$style = $style.shadow_sm();
};
($style:ident; box-shadow: md; $($rest:tt)*) => {
$style = $style.shadow_md();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; box-shadow: md) => {
$style = $style.shadow_md();
};
($style:ident; box-shadow: lg; $($rest:tt)*) => {
$style = $style.shadow_lg();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; box-shadow: lg) => {
$style = $style.shadow_lg();
};
($style:ident; box-shadow: xl; $($rest:tt)*) => {
$style = $style.shadow_xl();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; box-shadow: xl) => {
$style = $style.shadow_xl();
};
($style:ident; box-shadow: none; $($rest:tt)*) => {
$style = $style.shadow_none();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; box-shadow: none) => {
$style = $style.shadow_none();
};
($style:ident; box-shadow: $value:expr; $($rest:tt)*) => {
$style = $style.shadow($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; box-shadow: $value:expr) => {
$style = $style.shadow($value);
};
($style:ident; opacity: $value:expr; $($rest:tt)*) => {
$style = $style.opacity($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; opacity: $value:expr) => {
$style = $style.opacity($value);
};
($style:ident; flow: $value:expr; $($rest:tt)*) => {
$style = $style.flow($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flow: $value:expr) => {
$style = $style.flow($value);
};
($style:ident; transform: $value:expr; $($rest:tt)*) => {
$style = $style.transform($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; transform: $value:expr) => {
$style = $style.transform($value);
};
($style:ident; transform: scale($value:expr); $($rest:tt)*) => {
$style = $style.scale($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; transform: scale($sx:expr, $sy:expr); $($rest:tt)*) => {
$style = $style.scale_xy($sx, $sy);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; transform: translate($x:expr, $y:expr); $($rest:tt)*) => {
$style = $style.translate($x, $y);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; transform: rotate($deg:expr); $($rest:tt)*) => {
$style = $style.rotate_deg($deg);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; rotate-x: $value:expr; $($rest:tt)*) => {
$style = $style.rotate_x_deg($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; rotate-x: $value:expr) => {
$style = $style.rotate_x_deg($value);
};
($style:ident; rotate-y: $value:expr; $($rest:tt)*) => {
$style = $style.rotate_y_deg($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; rotate-y: $value:expr) => {
$style = $style.rotate_y_deg($value);
};
($style:ident; perspective: $value:expr; $($rest:tt)*) => {
$style = $style.perspective_px($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; perspective: $value:expr) => {
$style = $style.perspective_px($value);
};
($style:ident; translate-z: $value:expr; $($rest:tt)*) => {
$style = $style.translate_z_px($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; translate-z: $value:expr) => {
$style = $style.translate_z_px($value);
};
($style:ident; shape-3d: $value:expr; $($rest:tt)*) => {
$style = $style.shape_3d($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; shape-3d: $value:expr) => {
$style = $style.shape_3d($value);
};
($style:ident; depth: $value:expr; $($rest:tt)*) => {
$style = $style.depth_px($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; depth: $value:expr) => {
$style = $style.depth_px($value);
};
($style:ident; light-direction: ($x:expr, $y:expr, $z:expr); $($rest:tt)*) => {
$style = $style.light_direction($x, $y, $z);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; light-direction: ($x:expr, $y:expr, $z:expr)) => {
$style = $style.light_direction($x, $y, $z);
};
($style:ident; light-intensity: $value:expr; $($rest:tt)*) => {
$style = $style.light_intensity($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; light-intensity: $value:expr) => {
$style = $style.light_intensity($value);
};
($style:ident; ambient: $value:expr; $($rest:tt)*) => {
$style = $style.ambient_light($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; ambient: $value:expr) => {
$style = $style.ambient_light($value);
};
($style:ident; specular: $value:expr; $($rest:tt)*) => {
$style = $style.specular_power($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; specular: $value:expr) => {
$style = $style.specular_power($value);
};
($style:ident; 3d-op: $value:expr; $($rest:tt)*) => {
$style = $style.op_3d_type($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; 3d-op: $value:expr) => {
$style = $style.op_3d_type($value);
};
($style:ident; 3d-blend: $value:expr; $($rest:tt)*) => {
$style = $style.blend_3d_px($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; 3d-blend: $value:expr) => {
$style = $style.blend_3d_px($value);
};
($style:ident; clip-path: $value:expr; $($rest:tt)*) => {
$style = $style.clip_path($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; clip-path: $value:expr) => {
$style = $style.clip_path($value);
};
($style:ident; backdrop-filter: glass; $($rest:tt)*) => {
$style = $style.glass();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; backdrop-filter: glass) => {
$style = $style.glass();
};
($style:ident; backdrop-filter: metallic; $($rest:tt)*) => {
$style = $style.metallic();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; backdrop-filter: chrome; $($rest:tt)*) => {
$style = $style.chrome();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; backdrop-filter: gold; $($rest:tt)*) => {
$style = $style.gold();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; backdrop-filter: wood; $($rest:tt)*) => {
$style = $style.wood();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; backdrop-filter: $value:expr; $($rest:tt)*) => {
$style = $style.material($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; render-layer: foreground; $($rest:tt)*) => {
$style = $style.foreground();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; render-layer: background; $($rest:tt)*) => {
$style = $style.layer_background();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; render-layer: $value:expr; $($rest:tt)*) => {
$style = $style.layer($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; animation: $value:expr; $($rest:tt)*) => {
$style = $style.animation($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; animation: $value:expr) => {
$style = $style.animation($value);
};
($style:ident; animation-name: $value:expr; $($rest:tt)*) => {
$style = $style.animation_name($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; animation-name: $value:expr) => {
$style = $style.animation_name($value);
};
($style:ident; animation-duration: $value:expr; $($rest:tt)*) => {
$style = $style.animation_duration($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; animation-duration: $value:expr) => {
$style = $style.animation_duration($value);
};
($style:ident; width: $value:expr; $($rest:tt)*) => {
$style = $style.w($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; width: $value:expr) => {
$style = $style.w($value);
};
($style:ident; height: $value:expr; $($rest:tt)*) => {
$style = $style.h($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; height: $value:expr) => {
$style = $style.h($value);
};
($style:ident; min-width: $value:expr; $($rest:tt)*) => {
$style = $style.min_w($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; min-width: $value:expr) => {
$style = $style.min_w($value);
};
($style:ident; min-height: $value:expr; $($rest:tt)*) => {
$style = $style.min_h($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; min-height: $value:expr) => {
$style = $style.min_h($value);
};
($style:ident; max-width: $value:expr; $($rest:tt)*) => {
$style = $style.max_w($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; max-width: $value:expr) => {
$style = $style.max_w($value);
};
($style:ident; max-height: $value:expr; $($rest:tt)*) => {
$style = $style.max_h($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; max-height: $value:expr) => {
$style = $style.max_h($value);
};
($style:ident; display: flex; $($rest:tt)*) => {
$style.display = Some($crate::element_style::StyleDisplay::Flex);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; display: none; $($rest:tt)*) => {
$style = $style.display_none();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flex-direction: row; $($rest:tt)*) => {
$style = $style.flex_row();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flex-direction: column; $($rest:tt)*) => {
$style = $style.flex_col();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flex-direction: row-reverse; $($rest:tt)*) => {
$style = $style.flex_row_reverse();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flex-direction: column-reverse; $($rest:tt)*) => {
$style = $style.flex_col_reverse();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flex-wrap: wrap; $($rest:tt)*) => {
$style = $style.flex_wrap();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flex-grow: $value:expr; $($rest:tt)*) => {
$style = $style.flex_grow_value($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flex-grow: $value:expr) => {
$style = $style.flex_grow_value($value);
};
($style:ident; flex-shrink: $value:expr; $($rest:tt)*) => {
$style.flex_shrink = Some($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flex-shrink: $value:expr) => {
$style.flex_shrink = Some($value);
};
($style:ident; align-items: center; $($rest:tt)*) => {
$style = $style.items_center();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; align-items: start; $($rest:tt)*) => {
$style = $style.items_start();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; align-items: end; $($rest:tt)*) => {
$style = $style.items_end();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; align-items: stretch; $($rest:tt)*) => {
$style = $style.items_stretch();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; justify-content: center; $($rest:tt)*) => {
$style = $style.justify_center();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; justify-content: start; $($rest:tt)*) => {
$style = $style.justify_start();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; justify-content: end; $($rest:tt)*) => {
$style = $style.justify_end();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; justify-content: space-between; $($rest:tt)*) => {
$style = $style.justify_between();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; justify-content: space-around; $($rest:tt)*) => {
$style = $style.justify_around();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; justify-content: space-evenly; $($rest:tt)*) => {
$style = $style.justify_evenly();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; align-self: center; $($rest:tt)*) => {
$style = $style.self_center();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; align-self: start; $($rest:tt)*) => {
$style = $style.self_start();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; align-self: end; $($rest:tt)*) => {
$style = $style.self_end();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; padding: $value:expr; $($rest:tt)*) => {
$style = $style.p($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; padding: $value:expr) => {
$style = $style.p($value);
};
($style:ident; margin: $value:expr; $($rest:tt)*) => {
$style = $style.m($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; margin: $value:expr) => {
$style = $style.m($value);
};
($style:ident; gap: $value:expr; $($rest:tt)*) => {
$style = $style.gap($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; gap: $value:expr) => {
$style = $style.gap($value);
};
($style:ident; overflow: clip; $($rest:tt)*) => {
$style = $style.overflow_clip();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; overflow: visible; $($rest:tt)*) => {
$style = $style.overflow_visible();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; overflow: scroll; $($rest:tt)*) => {
$style = $style.overflow_scroll();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; overflow: hidden; $($rest:tt)*) => {
$style = $style.overflow_clip();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; border-width: $value:expr; $($rest:tt)*) => {
$style = $style.border_w($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; border-width: $value:expr) => {
$style = $style.border_w($value);
};
($style:ident; border-color: $value:expr; $($rest:tt)*) => {
$style.border_color = Some($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; border-color: $value:expr) => {
$style.border_color = Some($value);
};
($style:ident; color: $value:expr; $($rest:tt)*) => {
$style = $style.text_color($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; color: $value:expr) => {
$style = $style.text_color($value);
};
($style:ident; font-size: $value:expr; $($rest:tt)*) => {
$style = $style.font_size($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; font-size: $value:expr) => {
$style = $style.font_size($value);
};
($style:ident; font-weight: $value:expr; $($rest:tt)*) => {
$style = $style.font_weight($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; font-weight: $value:expr) => {
$style = $style.font_weight($value);
};
($style:ident; text-decoration: $value:expr; $($rest:tt)*) => {
$style = $style.text_decoration($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; text-decoration: $value:expr) => {
$style = $style.text_decoration($value);
};
($style:ident; text-decoration-color: $value:expr; $($rest:tt)*) => {
$style = $style.text_decoration_color($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; text-decoration-color: $value:expr) => {
$style = $style.text_decoration_color($value);
};
($style:ident; text-decoration-thickness: $value:expr; $($rest:tt)*) => {
$style = $style.text_decoration_thickness($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; text-decoration-thickness: $value:expr) => {
$style = $style.text_decoration_thickness($value);
};
($style:ident; line-height: $value:expr; $($rest:tt)*) => {
$style = $style.line_height($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; line-height: $value:expr) => {
$style = $style.line_height($value);
};
($style:ident; text-align: center; $($rest:tt)*) => {
$style = $style.text_align($crate::div::TextAlign::Center);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; text-align: right; $($rest:tt)*) => {
$style = $style.text_align($crate::div::TextAlign::Right);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; text-align: left; $($rest:tt)*) => {
$style = $style.text_align($crate::div::TextAlign::Left);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; text-align: $value:expr; $($rest:tt)*) => {
$style = $style.text_align($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; text-align: $value:expr) => {
$style = $style.text_align($value);
};
($style:ident; letter-spacing: $value:expr; $($rest:tt)*) => {
$style = $style.letter_spacing($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; letter-spacing: $value:expr) => {
$style = $style.letter_spacing($value);
};
($style:ident; text-shadow: $value:expr; $($rest:tt)*) => {
$style = $style.text_shadow($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; text-shadow: $value:expr) => {
$style = $style.text_shadow($value);
};
($style:ident; text-overflow: clip; $($rest:tt)*) => {
$style = $style.text_overflow($crate::element_style::TextOverflow::Clip);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; text-overflow: ellipsis; $($rest:tt)*) => {
$style = $style.text_overflow($crate::element_style::TextOverflow::Ellipsis);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; text-overflow: $value:expr; $($rest:tt)*) => {
$style = $style.text_overflow($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; text-overflow: $value:expr) => {
$style = $style.text_overflow($value);
};
($style:ident; white-space: normal; $($rest:tt)*) => {
$style = $style.white_space($crate::element_style::WhiteSpace::Normal);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; white-space: nowrap; $($rest:tt)*) => {
$style = $style.white_space($crate::element_style::WhiteSpace::Nowrap);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; white-space: pre; $($rest:tt)*) => {
$style = $style.white_space($crate::element_style::WhiteSpace::Pre);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; white-space: $value:expr; $($rest:tt)*) => {
$style = $style.white_space($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; white-space: $value:expr) => {
$style = $style.white_space($value);
};
($style:ident; transform-origin: ($x:expr, $y:expr); $($rest:tt)*) => {
$style = $style.transform_origin($x, $y);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; transform-origin: ($x:expr, $y:expr)) => {
$style = $style.transform_origin($x, $y);
};
($style:ident; transform: skewX($deg:expr); $($rest:tt)*) => {
$style = $style.skew_x($deg);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; transform: skewY($deg:expr); $($rest:tt)*) => {
$style = $style.skew_y($deg);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; transition: $value:expr; $($rest:tt)*) => {
$style = $style.transition($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; transition: $value:expr) => {
$style = $style.transition($value);
};
($style:ident; filter: $value:expr; $($rest:tt)*) => {
$style = $style.filter($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; filter: $value:expr) => {
$style = $style.filter($value);
};
($style:ident; mask-image: $value:expr; $($rest:tt)*) => {
$style.mask_image = Some($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; mask-image: $value:expr) => {
$style.mask_image = Some($value);
};
($style:ident; mask-mode: $value:expr; $($rest:tt)*) => {
$style = $style.mask_mode($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; mask-mode: $value:expr) => {
$style = $style.mask_mode($value);
};
($style:ident; mix-blend-mode: $value:expr; $($rest:tt)*) => {
$style = $style.mix_blend_mode($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; mix-blend-mode: $value:expr) => {
$style = $style.mix_blend_mode($value);
};
($style:ident; outline: ($width:expr, $color:expr); $($rest:tt)*) => {
$style = $style.outline($width, $color);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; outline: ($width:expr, $color:expr)) => {
$style = $style.outline($width, $color);
};
($style:ident; outline-width: $value:expr; $($rest:tt)*) => {
$style = $style.outline_w($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; outline-width: $value:expr) => {
$style = $style.outline_w($value);
};
($style:ident; outline-color: $value:expr; $($rest:tt)*) => {
$style.outline_color = Some($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; outline-color: $value:expr) => {
$style.outline_color = Some($value);
};
($style:ident; outline-offset: $value:expr; $($rest:tt)*) => {
$style = $style.outline_offset($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; outline-offset: $value:expr) => {
$style = $style.outline_offset($value);
};
($style:ident; border: ($width:expr, $color:expr); $($rest:tt)*) => {
$style = $style.border($width, $color);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; border: ($width:expr, $color:expr)) => {
$style = $style.border($width, $color);
};
($style:ident; overflow-x: clip; $($rest:tt)*) => {
$style = $style.overflow_x($crate::element_style::StyleOverflow::Clip);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; overflow-x: hidden; $($rest:tt)*) => {
$style = $style.overflow_x($crate::element_style::StyleOverflow::Clip);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; overflow-x: visible; $($rest:tt)*) => {
$style = $style.overflow_x($crate::element_style::StyleOverflow::Visible);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; overflow-x: scroll; $($rest:tt)*) => {
$style = $style.overflow_x($crate::element_style::StyleOverflow::Scroll);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; overflow-y: clip; $($rest:tt)*) => {
$style = $style.overflow_y($crate::element_style::StyleOverflow::Clip);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; overflow-y: hidden; $($rest:tt)*) => {
$style = $style.overflow_y($crate::element_style::StyleOverflow::Clip);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; overflow-y: visible; $($rest:tt)*) => {
$style = $style.overflow_y($crate::element_style::StyleOverflow::Visible);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; overflow-y: scroll; $($rest:tt)*) => {
$style = $style.overflow_y($crate::element_style::StyleOverflow::Scroll);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; position: static; $($rest:tt)*) => {
$style = $style.position($crate::element_style::StylePosition::Static);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; position: relative; $($rest:tt)*) => {
$style = $style.position($crate::element_style::StylePosition::Relative);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; position: absolute; $($rest:tt)*) => {
$style = $style.position($crate::element_style::StylePosition::Absolute);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; position: fixed; $($rest:tt)*) => {
$style = $style.position($crate::element_style::StylePosition::Fixed);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; position: sticky; $($rest:tt)*) => {
$style = $style.position($crate::element_style::StylePosition::Sticky);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; position: $value:expr; $($rest:tt)*) => {
$style = $style.position($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; position: $value:expr) => {
$style = $style.position($value);
};
($style:ident; top: $value:expr; $($rest:tt)*) => {
$style = $style.top($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; top: $value:expr) => {
$style = $style.top($value);
};
($style:ident; right: $value:expr; $($rest:tt)*) => {
$style = $style.right($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; right: $value:expr) => {
$style = $style.right($value);
};
($style:ident; bottom: $value:expr; $($rest:tt)*) => {
$style = $style.bottom($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; bottom: $value:expr) => {
$style = $style.bottom($value);
};
($style:ident; left: $value:expr; $($rest:tt)*) => {
$style = $style.left($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; left: $value:expr) => {
$style = $style.left($value);
};
($style:ident; inset: $value:expr; $($rest:tt)*) => {
$style = $style.inset($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; inset: $value:expr) => {
$style = $style.inset($value);
};
($style:ident; z-index: $value:expr; $($rest:tt)*) => {
$style = $style.z_index($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; z-index: $value:expr) => {
$style = $style.z_index($value);
};
($style:ident; visibility: visible; $($rest:tt)*) => {
$style = $style.visibility($crate::element_style::StyleVisibility::Visible);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; visibility: hidden; $($rest:tt)*) => {
$style = $style.visibility($crate::element_style::StyleVisibility::Hidden);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; visibility: $value:expr; $($rest:tt)*) => {
$style = $style.visibility($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; visibility: $value:expr) => {
$style = $style.visibility($value);
};
($style:ident; caret-color: $value:expr; $($rest:tt)*) => {
$style = $style.caret_color($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; caret-color: $value:expr) => {
$style = $style.caret_color($value);
};
($style:ident; selection-color: $value:expr; $($rest:tt)*) => {
$style = $style.selection_color($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; selection-color: $value:expr) => {
$style = $style.selection_color($value);
};
($style:ident; placeholder-color: $value:expr; $($rest:tt)*) => {
$style = $style.placeholder_color($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; placeholder-color: $value:expr) => {
$style = $style.placeholder_color($value);
};
($style:ident; accent-color: $value:expr; $($rest:tt)*) => {
$style = $style.accent_color($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; accent-color: $value:expr) => {
$style = $style.accent_color($value);
};
($style:ident; scrollbar-color: ($thumb:expr, $track:expr); $($rest:tt)*) => {
$style = $style.scrollbar_color($thumb, $track);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; scrollbar-color: ($thumb:expr, $track:expr)) => {
$style = $style.scrollbar_color($thumb, $track);
};
($style:ident; scrollbar-width: auto; $($rest:tt)*) => {
$style = $style.scrollbar_width($crate::element_style::ScrollbarWidth::Auto);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; scrollbar-width: thin; $($rest:tt)*) => {
$style = $style.scrollbar_width($crate::element_style::ScrollbarWidth::Thin);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; scrollbar-width: none; $($rest:tt)*) => {
$style = $style.scrollbar_width($crate::element_style::ScrollbarWidth::None);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; scrollbar-width: $value:expr; $($rest:tt)*) => {
$style = $style.scrollbar_width($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; scrollbar-width: $value:expr) => {
$style = $style.scrollbar_width($value);
};
($style:ident; fill: $value:expr; $($rest:tt)*) => {
$style = $style.fill($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; fill: $value:expr) => {
$style = $style.fill($value);
};
($style:ident; stroke: $value:expr; $($rest:tt)*) => {
$style = $style.stroke($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; stroke: $value:expr) => {
$style = $style.stroke($value);
};
($style:ident; stroke-width: $value:expr; $($rest:tt)*) => {
$style = $style.stroke_width($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; stroke-width: $value:expr) => {
$style = $style.stroke_width($value);
};
($style:ident; stroke-dasharray: $value:expr; $($rest:tt)*) => {
$style = $style.stroke_dasharray($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; stroke-dasharray: $value:expr) => {
$style = $style.stroke_dasharray($value);
};
($style:ident; stroke-dashoffset: $value:expr; $($rest:tt)*) => {
$style = $style.stroke_dashoffset($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; stroke-dashoffset: $value:expr) => {
$style = $style.stroke_dashoffset($value);
};
($style:ident; object-fit: $value:expr; $($rest:tt)*) => {
$style = $style.object_fit($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; object-fit: $value:expr) => {
$style = $style.object_fit($value);
};
($style:ident; object-position: ($x:expr, $y:expr); $($rest:tt)*) => {
$style = $style.object_position($x, $y);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; object-position: ($x:expr, $y:expr)) => {
$style = $style.object_position($x, $y);
};
($style:ident; pointer-events: none; $($rest:tt)*) => {
$style = $style.pointer_events_none();
$crate::css_impl!($style; $($rest)*);
};
($style:ident; pointer-events: auto; $($rest:tt)*) => {
$style = $style.pointer_events(blinc_core::PointerEvents::Auto);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; pointer-events: $value:expr; $($rest:tt)*) => {
$style = $style.pointer_events($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; pointer-events: $value:expr) => {
$style = $style.pointer_events($value);
};
($style:ident; cursor: $value:expr; $($rest:tt)*) => {
$style = $style.cursor($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; cursor: $value:expr) => {
$style = $style.cursor($value);
};
($style:ident; animation-delay: $value:expr; $($rest:tt)*) => {
{
let mut anim = $style.animation.clone().unwrap_or_default();
anim.delay_ms = $value;
$style.animation = Some(anim);
}
$crate::css_impl!($style; $($rest)*);
};
($style:ident; animation-delay: $value:expr) => {
{
let mut anim = $style.animation.clone().unwrap_or_default();
anim.delay_ms = $value;
$style.animation = Some(anim);
}
};
($style:ident; animation-timing-function: $value:expr; $($rest:tt)*) => {
{
let mut anim = $style.animation.clone().unwrap_or_default();
anim.timing = $value;
$style.animation = Some(anim);
}
$crate::css_impl!($style; $($rest)*);
};
($style:ident; animation-timing-function: $value:expr) => {
{
let mut anim = $style.animation.clone().unwrap_or_default();
anim.timing = $value;
$style.animation = Some(anim);
}
};
($style:ident; animation-iteration-count: $value:expr; $($rest:tt)*) => {
{
let mut anim = $style.animation.clone().unwrap_or_default();
anim.iteration_count = $value;
$style.animation = Some(anim);
}
$crate::css_impl!($style; $($rest)*);
};
($style:ident; animation-iteration-count: $value:expr) => {
{
let mut anim = $style.animation.clone().unwrap_or_default();
anim.iteration_count = $value;
$style.animation = Some(anim);
}
};
($style:ident; animation-direction: $value:expr; $($rest:tt)*) => {
{
let mut anim = $style.animation.clone().unwrap_or_default();
anim.direction = $value;
$style.animation = Some(anim);
}
$crate::css_impl!($style; $($rest)*);
};
($style:ident; animation-direction: $value:expr) => {
{
let mut anim = $style.animation.clone().unwrap_or_default();
anim.direction = $value;
$style.animation = Some(anim);
}
};
($style:ident; animation-fill-mode: $value:expr; $($rest:tt)*) => {
{
let mut anim = $style.animation.clone().unwrap_or_default();
anim.fill_mode = $value;
$style.animation = Some(anim);
}
$crate::css_impl!($style; $($rest)*);
};
($style:ident; animation-fill-mode: $value:expr) => {
{
let mut anim = $style.animation.clone().unwrap_or_default();
anim.fill_mode = $value;
$style.animation = Some(anim);
}
};
($style:ident; display: block; $($rest:tt)*) => {
$style.display = Some($crate::element_style::StyleDisplay::Block);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flex-wrap: nowrap; $($rest:tt)*) => {
$style.flex_wrap = Some(false);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flex-shrink: $value:expr; $($rest:tt)*) => {
$style = $style.flex_shrink($value);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; flex-shrink: $value:expr) => {
$style = $style.flex_shrink($value);
};
($style:ident; align-items: baseline; $($rest:tt)*) => {
$style.align_items = Some($crate::element_style::StyleAlign::Baseline);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; align-self: stretch; $($rest:tt)*) => {
$style.align_self = Some($crate::element_style::StyleAlign::Stretch);
$crate::css_impl!($style; $($rest)*);
};
($style:ident; align-self: baseline; $($rest:tt)*) => {
$style.align_self = Some($crate::element_style::StyleAlign::Baseline);
$crate::css_impl!($style; $($rest)*);
};
}
#[macro_export]
macro_rules! style {
() => {
$crate::element_style::ElementStyle::new()
};
($($tokens:tt)*) => {{
let mut __style = $crate::element_style::ElementStyle::new();
$crate::style_impl!(__style; $($tokens)*);
__style
}};
}
#[macro_export]
#[doc(hidden)]
macro_rules! style_impl {
($style:ident;) => {};
($style:ident; bg: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.bg($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; background: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.background($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rounded: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.rounded($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rounded_corners: ($tl:expr, $tr:expr, $br:expr, $bl:expr) $(, $($rest:tt)*)?) => {
$style = $style.rounded_corners($tl, $tr, $br, $bl);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rounded_sm $(, $($rest:tt)*)?) => {
$style = $style.rounded_sm();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rounded_md $(, $($rest:tt)*)?) => {
$style = $style.rounded_md();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rounded_lg $(, $($rest:tt)*)?) => {
$style = $style.rounded_lg();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rounded_xl $(, $($rest:tt)*)?) => {
$style = $style.rounded_xl();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rounded_2xl $(, $($rest:tt)*)?) => {
$style = $style.rounded_2xl();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rounded_none $(, $($rest:tt)*)?) => {
$style = $style.rounded_none();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rounded_full $(, $($rest:tt)*)?) => {
$style = $style.rounded_full();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; corner_shape: round $(, $($rest:tt)*)?) => {
$style = $style.corner_shape(1.0);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; corner_shape: bevel $(, $($rest:tt)*)?) => {
$style = $style.corner_shape(0.0);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; corner_shape: squircle $(, $($rest:tt)*)?) => {
$style = $style.corner_shape(2.0);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; corner_shape: scoop $(, $($rest:tt)*)?) => {
$style = $style.corner_shape(-1.0);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; corner_shape: notch $(, $($rest:tt)*)?) => {
$style = $style.corner_shape(-100.0);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; corner_shape: square $(, $($rest:tt)*)?) => {
$style = $style.corner_shape(100.0);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; corner_shape: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.corner_shape($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; overflow_fade: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.overflow_fade($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; shadow: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.shadow($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; shadow_sm $(, $($rest:tt)*)?) => {
$style = $style.shadow_sm();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; shadow_md $(, $($rest:tt)*)?) => {
$style = $style.shadow_md();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; shadow_lg $(, $($rest:tt)*)?) => {
$style = $style.shadow_lg();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; shadow_xl $(, $($rest:tt)*)?) => {
$style = $style.shadow_xl();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; shadow_none $(, $($rest:tt)*)?) => {
$style = $style.shadow_none();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; transform: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.transform($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; scale: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.scale($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; scale_xy: ($sx:expr, $sy:expr) $(, $($rest:tt)*)?) => {
$style = $style.scale_xy($sx, $sy);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; translate: ($x:expr, $y:expr) $(, $($rest:tt)*)?) => {
$style = $style.translate($x, $y);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rotate: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.rotate($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rotate_deg: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.rotate_deg($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rotate_x: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.rotate_x_deg($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; rotate_y: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.rotate_y_deg($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; perspective: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.perspective_px($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; translate_z: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.translate_z_px($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; shape_3d: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.shape_3d($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; depth: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.depth_px($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; light_direction: ($x:expr, $y:expr, $z:expr) $(, $($rest:tt)*)?) => {
$style = $style.light_direction($x, $y, $z);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; light_intensity: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.light_intensity($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; ambient: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.ambient_light($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; specular: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.specular_power($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; op_3d: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.op_3d_type($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; blend_3d: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.blend_3d_px($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; clip_path: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.clip_path($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; opacity: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.opacity($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; flow: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.flow($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; opaque $(, $($rest:tt)*)?) => {
$style = $style.opaque();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; translucent $(, $($rest:tt)*)?) => {
$style = $style.translucent();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; transparent $(, $($rest:tt)*)?) => {
$style = $style.transparent();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; material: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.material($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; glass $(, $($rest:tt)*)?) => {
$style = $style.glass();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; metallic $(, $($rest:tt)*)?) => {
$style = $style.metallic();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; chrome $(, $($rest:tt)*)?) => {
$style = $style.chrome();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; gold $(, $($rest:tt)*)?) => {
$style = $style.gold();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; wood $(, $($rest:tt)*)?) => {
$style = $style.wood();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; layer: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.layer($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; foreground $(, $($rest:tt)*)?) => {
$style = $style.foreground();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; layer_background $(, $($rest:tt)*)?) => {
$style = $style.layer_background();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; animation: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.animation($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; animation_name: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.animation_name($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; animation_duration: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.animation_duration($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; w: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.w($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; h: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.h($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; min_w: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.min_w($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; min_h: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.min_h($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; max_w: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.max_w($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; max_h: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.max_h($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; flex_row $(, $($rest:tt)*)?) => {
$style = $style.flex_row();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; flex_col $(, $($rest:tt)*)?) => {
$style = $style.flex_col();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; flex_row_reverse $(, $($rest:tt)*)?) => {
$style = $style.flex_row_reverse();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; flex_col_reverse $(, $($rest:tt)*)?) => {
$style = $style.flex_col_reverse();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; flex_wrap $(, $($rest:tt)*)?) => {
$style = $style.flex_wrap();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; display_none $(, $($rest:tt)*)?) => {
$style = $style.display_none();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; flex_grow $(, $($rest:tt)*)?) => {
$style = $style.flex_grow();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; flex_grow_value: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.flex_grow_value($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; flex_shrink_0 $(, $($rest:tt)*)?) => {
$style = $style.flex_shrink_0();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; items_center $(, $($rest:tt)*)?) => {
$style = $style.items_center();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; items_start $(, $($rest:tt)*)?) => {
$style = $style.items_start();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; items_end $(, $($rest:tt)*)?) => {
$style = $style.items_end();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; items_stretch $(, $($rest:tt)*)?) => {
$style = $style.items_stretch();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; justify_center $(, $($rest:tt)*)?) => {
$style = $style.justify_center();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; justify_start $(, $($rest:tt)*)?) => {
$style = $style.justify_start();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; justify_end $(, $($rest:tt)*)?) => {
$style = $style.justify_end();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; justify_between $(, $($rest:tt)*)?) => {
$style = $style.justify_between();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; justify_around $(, $($rest:tt)*)?) => {
$style = $style.justify_around();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; justify_evenly $(, $($rest:tt)*)?) => {
$style = $style.justify_evenly();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; self_center $(, $($rest:tt)*)?) => {
$style = $style.self_center();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; self_start $(, $($rest:tt)*)?) => {
$style = $style.self_start();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; self_end $(, $($rest:tt)*)?) => {
$style = $style.self_end();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; p: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.p($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; p_xy: ($x:expr, $y:expr) $(, $($rest:tt)*)?) => {
$style = $style.p_xy($x, $y);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; m: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.m($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; m_xy: ($x:expr, $y:expr) $(, $($rest:tt)*)?) => {
$style = $style.m_xy($x, $y);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; gap: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.gap($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; overflow_clip $(, $($rest:tt)*)?) => {
$style = $style.overflow_clip();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; overflow_visible $(, $($rest:tt)*)?) => {
$style = $style.overflow_visible();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; overflow_scroll $(, $($rest:tt)*)?) => {
$style = $style.overflow_scroll();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; border: ($width:expr, $color:expr) $(, $($rest:tt)*)?) => {
$style = $style.border($width, $color);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; border_width: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.border_w($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; border_color: $value:expr $(, $($rest:tt)*)?) => {
$style.border_color = Some($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; text_color: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.text_color($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; color: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.text_color($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; font_size: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.font_size($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; font_weight: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.font_weight($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; text_decoration: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.text_decoration($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; text_decoration_color: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.text_decoration_color($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; text_decoration_thickness: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.text_decoration_thickness($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; line_height: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.line_height($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; text_align: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.text_align($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; letter_spacing: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.letter_spacing($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; text_shadow: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.text_shadow($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; text_overflow: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.text_overflow($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; white_space: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.white_space($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; skew_x: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.skew_x($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; skew_y: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.skew_y($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; transform_origin: ($x:expr, $y:expr) $(, $($rest:tt)*)?) => {
$style = $style.transform_origin($x, $y);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; transition: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.transition($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; filter: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.filter($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; mask_image: $value:expr $(, $($rest:tt)*)?) => {
$style.mask_image = Some($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; mask_gradient: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.mask_gradient($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; mask_mode: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.mask_mode($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; mix_blend_mode: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.mix_blend_mode($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; outline: ($width:expr, $color:expr) $(, $($rest:tt)*)?) => {
$style = $style.outline($width, $color);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; outline_width: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.outline_w($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; outline_color: $value:expr $(, $($rest:tt)*)?) => {
$style.outline_color = Some($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; outline_offset: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.outline_offset($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; overflow_x: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.overflow_x($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; overflow_y: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.overflow_y($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; position: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.position($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; top: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.top($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; right: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.right($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; bottom: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.bottom($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; left: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.left($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; inset: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.inset($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; z_index: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.z_index($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; visibility: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.visibility($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; caret_color: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.caret_color($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; selection_color: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.selection_color($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; placeholder_color: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.placeholder_color($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; accent_color: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.accent_color($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; scrollbar_color: ($thumb:expr, $track:expr) $(, $($rest:tt)*)?) => {
$style = $style.scrollbar_color($thumb, $track);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; scrollbar_width: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.scrollbar_width($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; fill: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.fill($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; stroke: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.stroke($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; stroke_width: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.stroke_width($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; stroke_dasharray: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.stroke_dasharray($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; stroke_dashoffset: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.stroke_dashoffset($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; svg_path_data: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.svg_path_data($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; object_fit: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.object_fit($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; object_position: ($x:expr, $y:expr) $(, $($rest:tt)*)?) => {
$style = $style.object_position($x, $y);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; pointer_events: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.pointer_events($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; pointer_events_none $(, $($rest:tt)*)?) => {
$style = $style.pointer_events_none();
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; cursor: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.cursor($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; flex_shrink: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.flex_shrink($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; display_block $(, $($rest:tt)*)?) => {
$style.display = Some($crate::element_style::StyleDisplay::Block);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; width: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.w($value);
$crate::style_impl!($style; $($($rest)*)?);
};
($style:ident; height: $value:expr $(, $($rest:tt)*)?) => {
$style = $style.h($value);
$crate::style_impl!($style; $($($rest)*)?);
};
}
#[macro_export]
macro_rules! flow {
($name:ident, $target:ident, { $($body:tt)* }) => {{
$crate::css_parser::parse_flow_string(concat!(
"@flow ", stringify!($name), " {\n target: ", stringify!($target), ";\n ",
stringify!($($body)*),
"\n}"
)).expect(concat!("flow!: failed to parse flow '", stringify!($name), "'"))
}};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_style_builder() {
ThemeState::init_default();
let s = style().bg(Color::BLUE).rounded(8.0).shadow_md().scale(1.05);
assert!(s.background.is_some());
assert!(s.corner_radius.is_some());
assert!(s.shadow.is_some());
assert!(s.transform.is_some());
}
#[test]
fn test_style_merge() {
ThemeState::init_default();
let base = style().bg(Color::BLUE).rounded(8.0).shadow_sm();
let hover = style().bg(Color::GREEN).scale(1.02);
let merged = base.merge(&hover);
assert!(matches!(merged.background, Some(Brush::Solid(c)) if c == Color::GREEN));
assert!(merged.corner_radius.is_some());
assert!(merged.shadow.is_some());
assert!(merged.transform.is_some());
}
#[test]
fn test_style_empty() {
let empty = ElementStyle::new();
assert!(empty.is_empty());
let non_empty = style().bg(Color::RED);
assert!(!non_empty.is_empty());
}
#[test]
fn test_style_macro_empty() {
let s = style!();
assert!(s.is_empty());
}
#[test]
fn test_style_macro_basic() {
ThemeState::init_default();
let s = style! {
bg: Color::BLUE,
rounded: 8.0,
opacity: 0.9,
};
assert!(matches!(s.background, Some(Brush::Solid(c)) if c == Color::BLUE));
assert!(s.corner_radius.is_some());
assert_eq!(s.opacity, Some(0.9));
}
#[test]
fn test_style_macro_presets() {
ThemeState::init_default();
let s = style! {
bg: Color::WHITE,
rounded_lg,
shadow_md,
};
assert!(s.background.is_some());
assert!(s.corner_radius.is_some());
assert!(s.shadow.is_some());
}
#[test]
fn test_style_macro_transforms() {
let s = style! {
scale: 1.05,
};
assert!(s.transform.is_some());
let s2 = style! {
translate: (10.0, 20.0),
};
assert!(s2.transform.is_some());
let s3 = style! {
rotate_deg: 45.0,
};
assert!(s3.transform.is_some());
let s4 = style! {
scale_xy: (1.1, 0.9),
};
assert!(s4.transform.is_some());
}
#[test]
fn test_style_macro_materials() {
let s = style! {
glass,
rounded: 16.0,
};
assert!(s.material.is_some());
assert!(s.corner_radius.is_some());
assert!(s.render_layer.is_some());
}
#[test]
fn test_style_macro_opacity_presets() {
let s1 = style! { opaque };
assert_eq!(s1.opacity, Some(1.0));
let s2 = style! { translucent };
assert_eq!(s2.opacity, Some(0.5));
let s3 = style! { transparent };
assert_eq!(s3.opacity, Some(0.0));
}
#[test]
fn test_style_macro_combined() {
ThemeState::init_default();
let card_style = style! {
bg: Color::WHITE,
rounded_lg,
shadow_md,
opacity: 0.95,
scale: 1.0,
};
assert!(card_style.background.is_some());
assert!(card_style.corner_radius.is_some());
assert!(card_style.shadow.is_some());
assert_eq!(card_style.opacity, Some(0.95));
assert!(card_style.transform.is_some());
}
#[test]
fn test_style_macro_rounded_variants() {
ThemeState::init_default();
let s1 = style! { rounded_sm };
assert!(s1.corner_radius.is_some());
let s2 = style! { rounded_md };
assert!(s2.corner_radius.is_some());
let s3 = style! { rounded_xl };
assert!(s3.corner_radius.is_some());
let s4 = style! { rounded_full };
assert!(s4.corner_radius.is_some());
let s5 = style! { rounded_none };
assert!(s5.corner_radius.is_some());
}
#[test]
fn test_style_macro_shadow_variants() {
ThemeState::init_default();
let s1 = style! { shadow_sm };
assert!(s1.shadow.is_some());
let s2 = style! { shadow_lg };
assert!(s2.shadow.is_some());
let s3 = style! { shadow_xl };
assert!(s3.shadow.is_some());
let s4 = style! { shadow_none };
assert!(s4.shadow.is_some()); }
#[test]
fn test_style_macro_material_variants() {
let s1 = style! { metallic };
assert!(s1.material.is_some());
let s2 = style! { chrome };
assert!(s2.material.is_some());
let s3 = style! { gold };
assert!(s3.material.is_some());
let s4 = style! { wood };
assert!(s4.material.is_some());
}
#[test]
fn test_style_macro_layer() {
let s1 = style! { foreground };
assert!(s1.render_layer.is_some());
let s2 = style! { layer_background };
assert!(s2.render_layer.is_some());
}
#[test]
fn test_style_macro_rounded_corners() {
let s = style! {
rounded_corners: (8.0, 8.0, 0.0, 0.0),
};
assert!(s.corner_radius.is_some());
let cr = s.corner_radius.unwrap();
assert_eq!(cr.top_left, 8.0);
assert_eq!(cr.top_right, 8.0);
assert_eq!(cr.bottom_right, 0.0);
assert_eq!(cr.bottom_left, 0.0);
}
#[test]
fn test_css_macro_empty() {
let s = css!();
assert!(s.is_empty());
}
#[test]
fn test_css_macro_basic() {
let s = css! {
background: Color::BLUE;
border-radius: 8.0;
opacity: 0.9;
};
assert!(matches!(s.background, Some(Brush::Solid(c)) if c == Color::BLUE));
assert!(s.corner_radius.is_some());
assert_eq!(s.opacity, Some(0.9));
}
#[test]
fn test_css_macro_shadow() {
ThemeState::init_default();
let s = css! {
box-shadow: md;
};
assert!(s.shadow.is_some());
let s2 = css! {
box-shadow: Shadow::new(0.0, 4.0, 8.0, Color::BLACK);
};
assert!(s2.shadow.is_some());
}
#[test]
fn test_css_macro_transform() {
let s = css! {
transform: Transform::scale(1.05, 1.05);
};
assert!(s.transform.is_some());
}
#[test]
fn test_css_macro_backdrop_filter() {
let s = css! {
backdrop-filter: glass;
};
assert!(s.material.is_some());
assert!(s.render_layer.is_some()); }
#[test]
fn test_css_macro_combined() {
ThemeState::init_default();
let card = css! {
background: Color::WHITE;
border-radius: 12.0;
box-shadow: lg;
opacity: 0.95;
};
assert!(card.background.is_some());
assert!(card.corner_radius.is_some());
assert!(card.shadow.is_some());
assert_eq!(card.opacity, Some(0.95));
}
#[test]
fn test_css_macro_animation() {
let s = css! {
animation-name: "fade-in";
animation-duration: 300;
};
assert!(s.animation.is_some());
let anim = s.animation.unwrap();
assert_eq!(anim.name, "fade-in");
assert_eq!(anim.duration_ms, 300);
}
#[test]
fn test_css_and_style_macros_produce_same_result() {
let from_css = css! {
background: Color::RED;
border-radius: 10.0;
opacity: 0.8;
};
let from_style = style! {
bg: Color::RED,
rounded: 10.0,
opacity: 0.8,
};
assert!(matches!(from_css.background, Some(Brush::Solid(c)) if c == Color::RED));
assert!(matches!(from_style.background, Some(Brush::Solid(c)) if c == Color::RED));
assert_eq!(from_css.corner_radius, from_style.corner_radius);
assert_eq!(from_css.opacity, from_style.opacity);
}
#[test]
fn test_css_macro_text_properties() {
let s = css! {
color: Color::RED;
font-size: 16.0;
line-height: 1.5;
letter-spacing: 0.5;
};
assert_eq!(s.text_color, Some(Color::RED));
assert_eq!(s.font_size, Some(16.0));
assert_eq!(s.line_height, Some(1.5));
assert_eq!(s.letter_spacing, Some(0.5));
}
#[test]
fn test_style_macro_text_properties() {
let s = style! {
text_color: Color::BLUE,
font_size: 14.0,
line_height: 1.2,
letter_spacing: 1.0,
};
assert_eq!(s.text_color, Some(Color::BLUE));
assert_eq!(s.font_size, Some(14.0));
assert_eq!(s.line_height, Some(1.2));
assert_eq!(s.letter_spacing, Some(1.0));
}
#[test]
fn test_css_macro_text_decoration() {
let s = css! {
text-decoration: TextDecoration::Underline;
text-decoration-color: Color::RED;
text-decoration-thickness: 2.0;
};
assert_eq!(s.text_decoration, Some(TextDecoration::Underline));
assert_eq!(s.text_decoration_color, Some(Color::RED));
assert_eq!(s.text_decoration_thickness, Some(2.0));
}
#[test]
fn test_css_macro_text_overflow() {
let s = css! {
text-overflow: ellipsis;
white-space: nowrap;
};
assert_eq!(s.text_overflow, Some(TextOverflow::Ellipsis));
assert_eq!(s.white_space, Some(WhiteSpace::Nowrap));
}
#[test]
fn test_css_macro_position_inset() {
let s = css! {
position: absolute;
top: 10.0;
right: 20.0;
bottom: 30.0;
left: 40.0;
z-index: 5;
};
assert_eq!(s.position, Some(StylePosition::Absolute));
assert_eq!(s.top, Some(10.0));
assert_eq!(s.right, Some(20.0));
assert_eq!(s.bottom, Some(30.0));
assert_eq!(s.left, Some(40.0));
assert_eq!(s.z_index, Some(5));
}
#[test]
fn test_style_macro_position_inset() {
let s = style! {
position: StylePosition::Relative,
top: 5.0,
inset: 0.0,
z_index: 10,
};
assert_eq!(s.position, Some(StylePosition::Relative));
assert_eq!(s.top, Some(0.0));
assert_eq!(s.right, Some(0.0));
assert_eq!(s.bottom, Some(0.0));
assert_eq!(s.left, Some(0.0));
assert_eq!(s.z_index, Some(10));
}
#[test]
fn test_css_macro_visibility() {
let s = css! {
visibility: hidden;
};
assert_eq!(s.visibility, Some(StyleVisibility::Hidden));
}
#[test]
fn test_css_macro_overflow_axes() {
let s = css! {
overflow-x: scroll;
overflow-y: hidden;
};
assert_eq!(s.overflow_x, Some(StyleOverflow::Scroll));
assert_eq!(s.overflow_y, Some(StyleOverflow::Clip));
}
#[test]
fn test_css_macro_outline() {
let s = css! {
outline: (2.0, Color::RED);
outline-offset: 4.0;
};
assert_eq!(s.outline_width, Some(2.0));
assert_eq!(s.outline_color, Some(Color::RED));
assert_eq!(s.outline_offset, Some(4.0));
}
#[test]
fn test_style_macro_outline() {
let s = style! {
outline: (3.0, Color::BLUE),
outline_offset: 2.0,
};
assert_eq!(s.outline_width, Some(3.0));
assert_eq!(s.outline_color, Some(Color::BLUE));
assert_eq!(s.outline_offset, Some(2.0));
}
#[test]
fn test_css_macro_form_colors() {
let s = css! {
caret-color: Color::RED;
selection-color: Color::BLUE;
placeholder-color: Color::rgba(0.5, 0.5, 0.5, 1.0);
accent-color: Color::GREEN;
};
assert_eq!(s.caret_color, Some(Color::RED));
assert_eq!(s.selection_color, Some(Color::BLUE));
assert!(s.placeholder_color.is_some());
assert_eq!(s.accent_color, Some(Color::GREEN));
}
#[test]
fn test_style_macro_form_colors() {
let s = style! {
caret_color: Color::RED,
accent_color: Color::GREEN,
};
assert_eq!(s.caret_color, Some(Color::RED));
assert_eq!(s.accent_color, Some(Color::GREEN));
}
#[test]
fn test_css_macro_svg_properties() {
let s = css! {
fill: Color::RED;
stroke: Color::BLUE;
stroke-width: 2.0;
stroke-dashoffset: 10.0;
};
assert_eq!(s.fill, Some(Color::RED));
assert_eq!(s.stroke, Some(Color::BLUE));
assert_eq!(s.stroke_width, Some(2.0));
assert_eq!(s.stroke_dashoffset, Some(10.0));
}
#[test]
fn test_style_macro_svg_properties() {
let s = style! {
fill: Color::RED,
stroke: Color::BLUE,
stroke_width: 3.0,
stroke_dasharray: vec![5.0, 3.0],
stroke_dashoffset: 0.0,
};
assert_eq!(s.fill, Some(Color::RED));
assert_eq!(s.stroke, Some(Color::BLUE));
assert_eq!(s.stroke_width, Some(3.0));
assert_eq!(s.stroke_dasharray, Some(vec![5.0, 3.0]));
assert_eq!(s.stroke_dashoffset, Some(0.0));
}
#[test]
fn test_css_macro_transform_extras() {
let s = css! {
transform-origin: (0.0, 100.0);
};
assert_eq!(s.transform_origin, Some([0.0, 100.0]));
}
#[test]
fn test_style_macro_transform_extras() {
let s = style! {
skew_x: 15.0,
skew_y: 10.0,
transform_origin: (50.0, 50.0),
};
assert_eq!(s.skew_x, Some(15.0));
assert_eq!(s.skew_y, Some(10.0));
assert_eq!(s.transform_origin, Some([50.0, 50.0]));
}
#[test]
fn test_css_macro_scrollbar() {
let s = css! {
scrollbar-color: (Color::RED, Color::WHITE);
scrollbar-width: thin;
};
assert_eq!(s.scrollbar_color, Some((Color::RED, Color::WHITE)));
assert_eq!(s.scrollbar_width, Some(ScrollbarWidth::Thin));
}
#[test]
fn test_css_macro_image_properties() {
let s = css! {
object-fit: 1;
object-position: (0.5, 0.0);
};
assert_eq!(s.object_fit, Some(1));
assert_eq!(s.object_position, Some([0.5, 0.0]));
}
#[test]
fn test_style_macro_image_properties() {
let s = style! {
object_fit: 0,
object_position: (0.0, 1.0),
};
assert_eq!(s.object_fit, Some(0));
assert_eq!(s.object_position, Some([0.0, 1.0]));
}
#[test]
fn test_css_macro_filter() {
let f = CssFilter {
grayscale: 1.0,
..Default::default()
};
let s = css! {
filter: f;
};
assert!(s.filter.is_some());
assert_eq!(s.filter.unwrap().grayscale, 1.0);
}
#[test]
fn test_style_macro_filter() {
let f = CssFilter {
brightness: 1.5,
..Default::default()
};
let s = style! {
filter: f,
};
assert!(s.filter.is_some());
assert_eq!(s.filter.unwrap().brightness, 1.5);
}
#[test]
fn test_css_macro_border_shorthand() {
let s = css! {
border: (2.0, Color::RED);
};
assert_eq!(s.border_width, Some(2.0));
assert_eq!(s.border_color, Some(Color::RED));
}
#[test]
fn test_css_macro_display_block() {
let s = css! {
display: block;
};
assert_eq!(s.display, Some(StyleDisplay::Block));
}
#[test]
fn test_css_macro_pointer_events() {
let s = css! {
pointer-events: none;
};
assert_eq!(s.pointer_events, Some(PointerEvents::None));
}
#[test]
fn test_style_macro_pointer_events() {
let s = style! {
pointer_events_none,
};
assert_eq!(s.pointer_events, Some(PointerEvents::None));
}
#[test]
fn test_css_macro_inset() {
let s = css! {
inset: 10.0;
};
assert_eq!(s.top, Some(10.0));
assert_eq!(s.right, Some(10.0));
assert_eq!(s.bottom, Some(10.0));
assert_eq!(s.left, Some(10.0));
}
#[test]
fn test_css_macro_flex_extras() {
let s = css! {
flex-wrap: nowrap;
align-items: baseline;
align-self: stretch;
};
assert_eq!(s.flex_wrap, Some(false));
assert_eq!(s.align_items, Some(StyleAlign::Baseline));
assert_eq!(s.align_self, Some(StyleAlign::Stretch));
}
#[test]
fn test_css_style_parity_text() {
let from_css = css! {
color: Color::RED;
font-size: 16.0;
letter-spacing: 2.0;
};
let from_style = style! {
text_color: Color::RED,
font_size: 16.0,
letter_spacing: 2.0,
};
assert_eq!(from_css.text_color, from_style.text_color);
assert_eq!(from_css.font_size, from_style.font_size);
assert_eq!(from_css.letter_spacing, from_style.letter_spacing);
}
#[test]
fn test_css_style_parity_position() {
let from_css = css! {
position: absolute;
top: 10.0;
z-index: 5;
};
let from_style = style! {
position: StylePosition::Absolute,
top: 10.0,
z_index: 5,
};
assert_eq!(from_css.position, from_style.position);
assert_eq!(from_css.top, from_style.top);
assert_eq!(from_css.z_index, from_style.z_index);
}
}