dioxus/packages/core-macro/styles/mod.rs
2021-07-21 22:55:04 -04:00

2044 lines
57 KiB
Rust

//! A module to type styles.
// TODO most stuff here is on the stack, but there are a few heap-allocs here and there. It would
// be good if we could just to allocate them in the bump arena when using bumpalo.
mod calc;
mod codegen;
mod color;
pub mod string;
mod syn_parse;
use std::{
fmt,
ops::{Deref, DerefMut},
};
pub use calc::*;
pub use color::{Color, DynamicColor};
// pub use crate::{
// calc::*,
// color::{Color, DynamicColor},
// };
pub struct DynamicStyles {
pub rules: Vec<DynamicStyle>,
}
impl From<Vec<DynamicStyle>> for DynamicStyles {
fn from(v: Vec<DynamicStyle>) -> Self {
Self { rules: v }
}
}
impl fmt::Display for DynamicStyles {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for style in self
.rules
.iter()
.filter(|style| !(style.is_dynamic() || style.is_dummy()))
{
write!(f, "{};", style)?;
}
Ok(())
}
}
// TODO make container generic over heap (e.g. support bumpalo)
#[derive(Debug, Clone, PartialEq)]
pub struct Styles {
pub rules: Vec<Style>,
}
impl Styles {
pub fn new() -> Self {
Styles { rules: Vec::new() }
}
pub fn add(&mut self, style: Style) {
self.rules.push(style);
}
pub fn merge(&mut self, other: Styles) {
self.rules.extend(other.rules.into_iter())
}
}
impl From<DynamicStyles> for Styles {
fn from(dy: DynamicStyles) -> Self {
Styles {
rules: dy
.rules
.into_iter()
.filter_map(|dy_sty| match dy_sty {
DynamicStyle::Dynamic(_) => None,
DynamicStyle::Literal(l) => Some(l),
})
.collect(),
}
}
}
impl Deref for Styles {
type Target = Vec<Style>;
fn deref(&self) -> &Self::Target {
&self.rules
}
}
impl DerefMut for Styles {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.rules
}
}
impl From<Vec<Style>> for Styles {
fn from(v: Vec<Style>) -> Self {
Self { rules: v }
}
}
impl From<Styles> for Vec<Style> {
fn from(v: Styles) -> Self {
v.rules
}
}
impl fmt::Display for Styles {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for style in self.rules.iter().filter(|style| !style.is_dummy()) {
write!(f, "{};", style)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum DynamicStyle {
/// A literal style.
Literal(Style),
/// Tokens to pass through directly to codegen.
Dynamic(syn::Block),
}
impl DynamicStyle {
pub fn is_dynamic(&self) -> bool {
match self {
DynamicStyle::Literal(style) => style.is_dynamic(),
DynamicStyle::Dynamic(_) => true,
}
}
pub fn is_dummy(&self) -> bool {
match self {
DynamicStyle::Literal(style) => style.is_dummy(),
DynamicStyle::Dynamic(_) => false,
}
}
}
impl From<Style> for DynamicStyle {
fn from(style: Style) -> Self {
DynamicStyle::Literal(style)
}
}
impl fmt::Display for DynamicStyle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DynamicStyle::Literal(style) => style.fmt(f),
DynamicStyle::Dynamic(_) => Ok(()),
}
}
}
/// a `Style` is one of the css key/value pairs, also sometimes known as rules.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum Style {
/// For when you don't want to include any style at all (useful in expressions like `if`)
Dummy,
/// For when you want to use some unimplemented css. This is not type checked!
Unchecked(String),
// *From w3 spec:*
/// align-content
AlignContent(AlignContent),
/// align-items
AlignItems(AlignItems),
/// align-self
AlignSelf(AlignSelf),
// all - todo when doing global values
// background
/// background-attachment
BackgroundAttachment(BackgroundAttachment),
/// background-blend-mode
BackgroundBlendMode(NonemptyCommaList<BlendMode>),
/// background-clip
BackgroundClip(BackgroundBox),
/// background-color
BackgroundColor(DynamicColor),
/// background-image
BackgroundImage(NonemptyCommaList<BackgroundImage>),
/// background-origin
BackgroundOrigin(BackgroundBox),
/// background-position
BackgroundPosition(BackgroundPosition),
/// background-repeat
BackgroundRepeat(NonemptyCommaList<BackgroundRepeat>),
/// background-size
BackgroundSize(BackgroundSize),
/// border
Border(Border),
/// border-bottom
BorderBottom(Border),
/// border-bottom-color
BorderBottomColor(Color),
/// border-bottom-left-radius
BorderBottomLeftRadius(SingleOrDouble<LengthPercentage>),
/// border-bottom-right-radius
BorderBottomRightRadius(SingleOrDouble<LengthPercentage>),
/// border-bottom-style
BorderBottomStyle(LineStyle),
/// border-bottom-width
BorderBottomWidth(LineWidth),
/// border-collapse
BorderCollapse(BorderCollapse),
/// border-color
BorderColor(Rect<Color>),
// border-image
// border-image-outset
// border-image-repeat
// border-image-slice
// border-image-source
// border-image-width
/// border-left
BorderLeft(Border),
/// border-left-color
BorderLeftColor(Color),
/// border-left-style
BorderLeftStyle(LineStyle),
/// border-left-width
BorderLeftWidth(LineWidth),
/// border-radius
BorderRadius(BorderRadius),
/// border-right
BorderRight(Border),
/// border-right-color
BorderRightColor(Color),
/// border-right-style
BorderRightStyle(LineStyle),
/// border-right-width
BorderRightWidth(LineWidth),
// border-spacing
/// border-style
BorderStyle(BorderStyle),
/// border-top
BorderTop(Border),
/// border-top-color
BorderTopColor(Color),
/// border-top-left-radius
BorderTopLeftRadius(SingleOrDouble<LengthPercentage>),
/// border-top-right-radius
BorderTopRightRadius(SingleOrDouble<LengthPercentage>),
/// border-top-style
BorderTopStyle(LineStyle),
/// border-top-width
BorderTopWidth(LineWidth),
/// border-width
BorderWidth(BorderWidth),
/// bottom
Bottom(AutoLengthPercentage),
// box-decoration-break
/// box-shadow
BoxShadow(BoxShadow),
/// box-sizing
BoxSizing(BoxSizing),
// break-after
// break-before
// break-inside
// caption-side
// caret-color
/// clear
Clear(Clear),
// clip
// clip-path
// clip-rule
/// color
Color(DynamicColor),
/// column-count (manually added)
ColumnCount(ColumnCount),
// contain
// content
// counter-increment
// counter-reset
// cue
// cue-after
// cue-before
/// cursor
Cursor(Cursor),
// direction
/// display https://www.w3.org/TR/css-display-3/#typedef-display-outside
Display(Display),
// elevation
// empty-cells
// flex
/// flex-basis
FlexBasis(FlexBasis),
/// flex-direction
FlexDirection(FlexDirection),
// flex-flow
/// flex-grow
FlexGrow(f64),
/// flex-shrink
FlexShrink(f64),
/// flex-wrap
FlexWrap(FlexWrap),
/// float
Float(Float),
// font
/// font-family
FontFamily(FontFamily),
// font-feature-settings
// font-kerning
/// font-size
FontSize(FontSize),
// font-size-adjust
// font-stretch
/// font-style
FontStyle(FontStyle),
// font-synthesis
// font-variant
// font-variant-caps
// font-variant-east-asian
// font-variant-ligatures
// font-variant-numeric
// font-variant-position
/// font-weight
FontWeight(FontWeight),
// glyph-orientation-vertical
// grid
// grid-area
// grid-auto-columns
// grid-auto-flow
// grid-auto-rows
// grid-column
// grid-column-end
// grid-column-start
// grid-row
// grid-row-end
// grid-row-start
// grid-template
// grid-template-areas
// grid-template-columns
// grid-template-rows
/// height
Height(WidthHeight),
// image-orientation
// image-rendering
// isolation
/// justify-content
JustifyContent(JustifyContent),
/// left
Left(AutoLengthPercentage),
// letter-spacing
/// line-height
LineHeight(LineHeight),
// list-style
// list-style-image
// list-style-position
/// list-style-type
ListStyleType(ListStyleType),
/// margin
Margin(Margin),
/// margin-bottom
MarginBottom(MarginWidth),
/// margin-left
MarginLeft(MarginWidth),
/// margin-right
MarginRight(MarginWidth),
/// margin-top
MarginTop(MarginWidth),
// mask
// mask-border
// mask-border-mode
// mask-border-outset
// mask-border-repeat
// mask-border-slice
// mask-border-source
// mask-border-width
// mask-clip
// mask-composite
// mask-image
// mask-mode
// mask-origin
// mask-position
// mask-repeat
// mask-size
// mask-type
/// max-height
MaxHeight(MaxWidthHeight),
/// max-width
MaxWidth(MaxWidthHeight),
/// min-height - current implementing CSS2 spec
MinHeight(Calc),
/// min-width - current implementing CSS2 spec
MinWidth(Calc),
// mix-blend-mode
/// object-fit - https://drafts.csswg.org/css-images-4/#the-object-fit
ObjectFit(ObjectFit),
// object-position
// opacity
// order
// orphans
// outline
// outline-color
// outline-offset
// outline-style
// outline-width
/// overflow - https://drafts.csswg.org/css-overflow-3/#propdef-overflow
Overflow(Overflow),
/// overflow-x manually added
OverflowX(OverflowXY),
/// overflow-y manually added
OverflowY(OverflowXY),
/// padding
Padding(Padding),
/// padding-bottom
PaddingBottom(PaddingWidth),
/// padding-left
PaddingLeft(PaddingWidth),
/// padding-right
PaddingRight(PaddingWidth),
/// padding-top
PaddingTop(PaddingWidth),
// page-break-after
// page-break-before
// page-break-inside
// pause
// pause-after
// pause-before
// pitch
// pitch-range
// play-during
/// position
Position(Position),
// quotes
/// resize
Resize(Resize),
// richness
/// right
Right(AutoLengthPercentage),
// scroll-margin
// scroll-margin-block
// scroll-margin-block-end
// scroll-margin-block-start
// scroll-margin-bottom
// scroll-margin-inline
// scroll-margin-inline-end
// scroll-margin-inline-start
// scroll-margin-left
// scroll-margin-right
// scroll-margin-top
// scroll-padding
// scroll-padding-block
// scroll-padding-block-end
// scroll-padding-block-start
// scroll-padding-bottom
// scroll-padding-inline
// scroll-padding-inline-end
// scroll-padding-inline-start
// scroll-padding-left
// scroll-padding-right
// scroll-padding-top
// scroll-snap-align
// scroll-snap-stop
// scroll-snap-type
// shape-image-threshold
// shape-margin
// shape-outside
// speak
// speak-header
// speak-numeral
// speak-punctuation
// speech-rate
// stress
// table-layout
/// text-align
TextAlign(TextAlign),
// text-combine-upright
// text-decoration
// text-decoration-color
// text-decoration-line
// text-decoration-style
// text-emphasis
// text-emphasis-color
// text-emphasis-position
// text-emphasis-style
// text-indent
// text-orientation
// text-overflow
// text-shadow
// text-transform
// text-underline-position
/// top
Top(AutoLengthPercentage),
// transform
// transform-box
// transform-origin
// unicode-bidi
// vertical-align
// visibility
// voice-family
// volume
/// white-space
WhiteSpace(WhiteSpace),
/// widows
Widows(u32),
/// width
Width(WidthHeight),
// will-change
// word-spacing
// writing-mode
// z-index
}
impl Style {
fn is_dummy(&self) -> bool {
match self {
Style::Dummy => true,
_ => false,
}
}
fn is_dynamic(&self) -> bool {
match self {
Style::BackgroundColor(value) => value.is_dynamic(),
Style::Color(value) => value.is_dynamic(),
_ => false,
}
}
}
impl fmt::Display for Style {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Style::Dummy => Ok(()),
Style::Unchecked(v) => write!(f, "{}", v),
Style::AlignContent(v) => write!(f, "align-content:{}", v),
Style::AlignItems(v) => write!(f, "align-items:{}", v),
Style::AlignSelf(v) => write!(f, "align-self:{}", v),
// all - deferred
// background
Style::BackgroundAttachment(v) => write!(f, "background-attachment:{}", v),
Style::BackgroundBlendMode(v) => write!(f, "background-blend-mode:{}", v),
Style::BackgroundClip(v) => write!(f, "background-clip:{}", v),
Style::BackgroundColor(v) => write!(f, "background-color:{}", v),
Style::BackgroundImage(v) => write!(f, "background-image:{}", v),
Style::BackgroundOrigin(v) => write!(f, "background-origin:{}", v),
Style::BackgroundPosition(v) => write!(f, "background-position:{}", v),
Style::BackgroundRepeat(v) => write!(f, "background-repeat:{}", v),
Style::BackgroundSize(v) => write!(f, "background-size:{}", v),
Style::Border(v) => write!(f, "border:{}", v),
Style::BorderBottom(v) => write!(f, "border-bottom:{}", v),
Style::BorderBottomColor(v) => write!(f, "border-bottom-color:{}", v),
Style::BorderBottomLeftRadius(v) => write!(f, "border-bottom-left-radius:{}", v),
Style::BorderBottomRightRadius(v) => write!(f, "border-bottom-right-radius:{}", v),
Style::BorderBottomStyle(v) => write!(f, "border-bottom-style:{}", v),
Style::BorderBottomWidth(v) => write!(f, "border-bottom-width:{}", v),
Style::BorderCollapse(v) => write!(f, "border-collapse:{}", v),
Style::BorderColor(v) => write!(f, "border-color:{}", v),
// border-image
// border-image-outset
// border-image-repeat
// border-image-slice
// border-image-source
// border-image-width
Style::BorderLeft(v) => write!(f, "border-left:{}", v),
Style::BorderLeftColor(v) => write!(f, "border-left-color:{}", v),
Style::BorderLeftStyle(v) => write!(f, "border-left-style:{}", v),
Style::BorderLeftWidth(v) => write!(f, "border-left-width:{}", v),
Style::BorderRadius(v) => write!(f, "border-radius:{}", v),
Style::BorderRight(v) => write!(f, "border-right:{}", v),
Style::BorderRightColor(v) => write!(f, "border-right-color:{}", v),
Style::BorderRightStyle(v) => write!(f, "border-right-style:{}", v),
Style::BorderRightWidth(v) => write!(f, "border-right-width:{}", v),
// border-spacing
Style::BorderStyle(v) => write!(f, "border-style:{}", v),
Style::BorderTop(v) => write!(f, "border-top:{}", v),
Style::BorderTopColor(v) => write!(f, "border-top-color:{}", v),
Style::BorderTopLeftRadius(v) => write!(f, "border-top-left-radius:{}", v),
Style::BorderTopRightRadius(v) => write!(f, "border-top-right-radius:{}", v),
Style::BorderTopStyle(v) => write!(f, "border-top-style:{}", v),
Style::BorderTopWidth(v) => write!(f, "border-top-width:{}", v),
Style::BorderWidth(v) => write!(f, "border-width:{}", v),
Style::Bottom(v) => write!(f, "bottom:{}", v),
// box-decoration-break
Style::BoxShadow(v) => write!(f, "box-shadow:{}", v),
Style::BoxSizing(v) => write!(f, "box-sizing:{}", v),
// break-after
// break-before
// break-inside
// caption-side
// caret-color
Style::Clear(v) => write!(f, "clear:{}", v),
// clip
// clip-path
// clip-rule
Style::Color(v) => write!(f, "color:{}", v),
Style::ColumnCount(v) => write!(f, "column-count:{}", v),
// contain
// content
// counter-increment
// counter-reset
// cue
// cue-after
// cue-before
Style::Cursor(v) => write!(f, "cursor:{}", v),
// direction
Style::Display(v) => write!(f, "display:{}", v),
// elevation
// empty-cells
// flex
Style::FlexBasis(v) => write!(f, "flex-basis:{}", v),
Style::FlexDirection(v) => write!(f, "flex-direction:{}", v),
// flex-flow
Style::FlexGrow(v) => write!(f, "flex-grow:{}", v),
Style::FlexShrink(v) => write!(f, "flex-shrink:{}", v),
Style::FlexWrap(v) => write!(f, "flex-wrap:{}", v),
Style::Float(v) => write!(f, "float:{}", v),
// font
Style::FontFamily(v) => write!(f, "font-family:{}", v),
// font-feature-settings
// font-kerning
Style::FontSize(v) => write!(f, "font-size:{}", v),
// font-size-adjust
// font-stretch
Style::FontStyle(v) => write!(f, "font-style:{}", v),
// font-synthesis
// font-variant
// font-variant-caps
// font-variant-east-asian
// font-variant-ligatures
// font-variant-numeric
// font-variant-position
Style::FontWeight(v) => write!(f, "font-weight:{}", v),
// glyph-orientation-vertical
// grid
// grid-area
// grid-auto-columns
// grid-auto-flow
// grid-auto-rows
// grid-column
// grid-column-end
// grid-column-start
// grid-row
// grid-row-end
// grid-row-start
// grid-template
// grid-template-areas
// grid-template-columns
// grid-template-rows
Style::Height(v) => write!(f, "height:{}", v),
// image-orientation
// image-rendering
// isolation
Style::JustifyContent(v) => write!(f, "justify-content:{}", v),
// left
Style::Left(v) => write!(f, "left:{}", v),
// letter-spacing
// line-height
Style::LineHeight(v) => write!(f, "line-height:{}", v),
// list-style
// list-style-image
// list-style-position
Style::ListStyleType(v) => write!(f, "list-style-type:{}", v),
Style::Margin(v) => write!(f, "margin:{}", v),
Style::MarginBottom(v) => write!(f, "margin-bottom:{}", v),
Style::MarginLeft(v) => write!(f, "margin-left:{}", v),
Style::MarginRight(v) => write!(f, "margin-right:{}", v),
Style::MarginTop(v) => write!(f, "margin-top:{}", v),
// mask
// mask-border
// mask-border-mode
// mask-border-outset
// mask-border-repeat
// mask-border-slice
// mask-border-source
// mask-border-width
// mask-clip
// mask-composite
// mask-image
// mask-mode
// mask-origin
// mask-position
// mask-repeat
// mask-size
// mask-type
Style::MaxHeight(v) => write!(f, "max-height:{}", v),
Style::MaxWidth(v) => write!(f, "max-width:{}", v),
Style::MinHeight(v) => write!(f, "min-height:{}", v),
Style::MinWidth(v) => write!(f, "min-width:{}", v),
// mix-blend-mode
Style::ObjectFit(v) => write!(f, "object-fit:{}", v),
// object-position
// opacity
// order
// orphans
// outline
// outline-color
// outline-offset
// outline-style
// outline-width
Style::Overflow(v) => write!(f, "overflow:{}", v),
Style::OverflowX(v) => write!(f, "overflow-x:{}", v),
Style::OverflowY(v) => write!(f, "overflow-y:{}", v),
Style::Padding(v) => write!(f, "padding:{}", v),
Style::PaddingBottom(v) => write!(f, "padding-bottom:{}", v),
Style::PaddingLeft(v) => write!(f, "padding-left:{}", v),
Style::PaddingRight(v) => write!(f, "padding-right:{}", v),
Style::PaddingTop(v) => write!(f, "padding-top:{}", v),
// padding-bottom
// padding-left
// padding-right
// padding-top
// page-break-after
// page-break-before
// page-break-inside
// pause
// pause-after
// pause-before
// pitch
// pitch-range
// play-during
Style::Position(v) => write!(f, "position:{}", v),
// uotes
Style::Resize(v) => write!(f, "resize:{}", v),
// richness
Style::Right(v) => write!(f, "right:{}", v),
// scroll-margin
// scroll-margin-block
// scroll-margin-block-end
// scroll-margin-block-start
// scroll-margin-bottom
// scroll-margin-inline
// scroll-margin-inline-end
// scroll-margin-inline-start
// scroll-margin-left
// scroll-margin-right
// scroll-margin-top
// scroll-padding
// scroll-padding-block
// scroll-padding-block-end
// scroll-padding-block-start
// scroll-padding-bottom
// scroll-padding-inline
// scroll-padding-inline-end
// scroll-padding-inline-start
// scroll-padding-left
// scroll-padding-right
// scroll-padding-top
// scroll-snap-align
// scroll-snap-stop
// scroll-snap-type
// shape-image-threshold
// shape-margin
// shape-outside
// speak
// speak-header
// speak-numeral
// speak-punctuation
// speech-rate
// stress
// table-layout
Style::TextAlign(v) => write!(f, "text-align:{}", v),
// text-combine-upright
// text-decoration
// text-decoration-color
// text-decoration-line
// text-decoration-style
// text-emphasis
// text-emphasis-color
// text-emphasis-position
// text-emphasis-style
// text-indent
// text-orientation
// text-overflow
// text-shadow
// text-transform
// text-underline-position
// top
Style::Top(v) => write!(f, "top:{}", v),
// transform
// transform-box
// transform-origin
// unicode-bidi
// vertical-align
// visibility
// voice-family
// volume
Style::WhiteSpace(v) => write!(f, "white-space:{}", v),
Style::Widows(v) => write!(f, "widows:{}", v),
Style::Width(v) => write!(f, "width:{}", v),
// will-change
// word-spacing
// writing-mode
// z-index
}
}
}
/// https://www.w3.org/TR/css-flexbox-1/#propdef-justify-content
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AlignContent {
FlexStart,
Center,
FlexEnd,
SpaceBetween,
SpaceAround,
Stretch,
}
impl Default for AlignContent {
fn default() -> Self {
AlignContent::Stretch
}
}
impl fmt::Display for AlignContent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AlignContent::FlexStart => write!(f, "flex-start"),
AlignContent::Center => write!(f, "center"),
AlignContent::FlexEnd => write!(f, "flex-end"),
AlignContent::SpaceAround => write!(f, "space-around"),
AlignContent::SpaceBetween => write!(f, "space-between"),
AlignContent::Stretch => write!(f, "stretch"),
}
}
}
/// https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AlignItems {
Normal,
Stretch,
Center,
Start,
End,
FlexStart,
FlexEnd,
Baseline,
FirstBaseline,
LastBaseline,
SafeCenter,
UnsafeCenter,
}
impl fmt::Display for AlignItems {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AlignItems::Normal => write!(f, "normal"),
AlignItems::Stretch => write!(f, "stretch"),
AlignItems::Center => write!(f, "center"),
AlignItems::Start => write!(f, "start"),
AlignItems::End => write!(f, "end"),
AlignItems::FlexStart => write!(f, "flex-start"),
AlignItems::FlexEnd => write!(f, "flex-end"),
AlignItems::Baseline => write!(f, "baseline"),
AlignItems::FirstBaseline => write!(f, "first baseline"),
AlignItems::LastBaseline => write!(f, "last baseline"),
AlignItems::SafeCenter => write!(f, "safe center"),
AlignItems::UnsafeCenter => write!(f, "unsafe center"),
}
}
}
/// https://developer.mozilla.org/en-US/docs/Web/CSS/align-self
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AlignSelf {
Auto,
Normal,
Center,
Start,
End,
SelfStart,
SelfEnd,
FlexStart,
FlexEnd,
Baseline,
FirstBaseline,
LastBaseline,
Stretch,
SafeCenter,
UnsafeCenter,
}
impl fmt::Display for AlignSelf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AlignSelf::Auto => write!(f, "auto"),
AlignSelf::Normal => write!(f, "normal"),
AlignSelf::Center => write!(f, "center"),
AlignSelf::Start => write!(f, "start"),
AlignSelf::End => write!(f, "end"),
AlignSelf::SelfStart => write!(f, "self-start"),
AlignSelf::SelfEnd => write!(f, "self-end"),
AlignSelf::FlexStart => write!(f, "flex-start"),
AlignSelf::FlexEnd => write!(f, "flex-end"),
AlignSelf::Baseline => write!(f, "baseline"),
AlignSelf::FirstBaseline => write!(f, "first baseline"),
AlignSelf::LastBaseline => write!(f, "last baseline"),
AlignSelf::Stretch => write!(f, "stretch"),
AlignSelf::SafeCenter => write!(f, "safe center"),
AlignSelf::UnsafeCenter => write!(f, "unsafe center"),
}
}
}
/// https://developer.mozilla.org/en-US/docs/Web/CSS/background-attachment
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BackgroundAttachment {
Scroll,
Fixed,
Local,
}
impl fmt::Display for BackgroundAttachment {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BackgroundAttachment::Scroll => write!(f, "scroll"),
BackgroundAttachment::Fixed => write!(f, "fixed"),
BackgroundAttachment::Local => write!(f, "local"),
}
}
}
/// https://developer.mozilla.org/en-US/docs/Web/CSS/background-blend-mode
#[derive(Debug, Clone, PartialEq)]
pub enum BlendMode {
Normal,
Multiply,
Screen,
Overlay,
Darken,
Lighten,
ColorDodge,
ColorBurn,
HardLight,
SoftLight,
Difference,
Exclusion,
Hue,
Saturation,
Color,
Luminosity,
}
impl fmt::Display for BlendMode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BlendMode::Normal => write!(f, "normal"),
BlendMode::Multiply => write!(f, "multiply"),
BlendMode::Screen => write!(f, "screen"),
BlendMode::Overlay => write!(f, "overlay"),
BlendMode::Darken => write!(f, "darken"),
BlendMode::Lighten => write!(f, "lighten"),
BlendMode::ColorDodge => write!(f, "color-dodge"),
BlendMode::ColorBurn => write!(f, "color-burn"),
BlendMode::HardLight => write!(f, "hard-light"),
BlendMode::SoftLight => write!(f, "soft-light"),
BlendMode::Difference => write!(f, "difference"),
BlendMode::Exclusion => write!(f, "exclusion"),
BlendMode::Hue => write!(f, "hue"),
BlendMode::Saturation => write!(f, "saturation"),
BlendMode::Color => write!(f, "color"),
BlendMode::Luminosity => write!(f, "luminosity"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BackgroundBox {
BorderBox,
PaddingBox,
ContentBox,
}
impl fmt::Display for BackgroundBox {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BackgroundBox::BorderBox => write!(f, "border-box"),
BackgroundBox::PaddingBox => write!(f, "padding-box"),
BackgroundBox::ContentBox => write!(f, "content-box"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BackgroundImage {
None,
Url(String),
// TODO other variants
}
impl fmt::Display for BackgroundImage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BackgroundImage::None => write!(f, "none"),
BackgroundImage::Url(url) => write!(f, "url({})", url),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BackgroundPosition {
Top,
Bottom,
Left,
Right,
Center,
// TODO other variants
}
impl fmt::Display for BackgroundPosition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BackgroundPosition::Top => write!(f, "top"),
BackgroundPosition::Left => write!(f, "left"),
BackgroundPosition::Bottom => write!(f, "bottom"),
BackgroundPosition::Right => write!(f, "right"),
BackgroundPosition::Center => write!(f, "center"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BackgroundRepeat {
RepeatX,
RepeatY,
SingleOrDouble(SingleOrDouble<BgRepeatPart>),
}
impl fmt::Display for BackgroundRepeat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BackgroundRepeat::RepeatX => write!(f, "repeat-x"),
BackgroundRepeat::RepeatY => write!(f, "repeat-y"),
BackgroundRepeat::SingleOrDouble(v) => v.fmt(f),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BgRepeatPart {
Repeat,
Space,
Round,
NoRepeat,
}
impl fmt::Display for BgRepeatPart {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BgRepeatPart::Repeat => write!(f, "repeat"),
BgRepeatPart::Space => write!(f, "space"),
BgRepeatPart::Round => write!(f, "round"),
BgRepeatPart::NoRepeat => write!(f, "no-repeat"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BackgroundSize {
Cover,
Contain,
SingleOrDouble(SingleOrDouble<AutoLengthPercentage>),
}
impl fmt::Display for BackgroundSize {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BackgroundSize::Cover => write!(f, "cover"),
BackgroundSize::Contain => write!(f, "contain"),
BackgroundSize::SingleOrDouble(v) => v.fmt(f),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Border {
pub line_width: Option<LineWidth>,
pub line_style: Option<LineStyle>,
pub color: Option<Color>,
}
impl Border {
fn new() -> Self {
Border {
line_width: None,
line_style: None,
color: None,
}
}
fn is_full(&self) -> bool {
match (&self.line_width, &self.line_style, &self.color) {
(Some(_), Some(_), Some(_)) => true,
_ => false,
}
}
fn has_line_width(&self) -> bool {
self.line_width.is_some()
}
fn has_line_style(&self) -> bool {
self.line_style.is_some()
}
fn has_color(&self) -> bool {
self.color.is_some()
}
}
impl fmt::Display for Border {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn space(yes: bool) -> &'static str {
if yes {
" "
} else {
""
}
}
let mut cont = false;
if let Some(line_width) = self.line_width {
write!(f, "{}", line_width)?;
cont = true;
}
if let Some(line_style) = self.line_style {
write!(f, "{}{}", space(cont), line_style)?;
cont = true;
}
if let Some(color) = self.color {
write!(f, "{}{}", space(cont), color)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BorderCollapse {
Collapse,
Separate,
}
impl fmt::Display for BorderCollapse {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BorderCollapse::Collapse => write!(f, "collapse"),
BorderCollapse::Separate => write!(f, "separate"),
}
}
}
pub type BorderRadius = Calc;
pub type BorderStyle = Rect<LineStyle>;
pub type BorderWidth = Rect<LineWidth>;
#[derive(Debug, Clone, PartialEq)]
pub enum BoxShadow {
None,
Shadows(NonemptyCommaList<Shadow>),
}
impl fmt::Display for BoxShadow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BoxShadow::None => f.write_str("none"),
BoxShadow::Shadows(list) => write!(f, "{}", list),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BoxSizing {
BorderBox,
ContentBox,
}
impl fmt::Display for BoxSizing {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BoxSizing::BorderBox => f.write_str("border-box"),
BoxSizing::ContentBox => f.write_str("content-box"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Clear {
None,
Left,
Right,
Both,
InlineStart,
InlineEnd,
}
impl fmt::Display for Clear {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Clear::None => f.write_str("none"),
Clear::Left => f.write_str("left"),
Clear::Right => f.write_str("right"),
Clear::Both => f.write_str("both"),
Clear::InlineStart => f.write_str("inline-start"),
Clear::InlineEnd => f.write_str("inline-end"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ColumnCount {
Auto,
Fixed(u32),
}
impl fmt::Display for ColumnCount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ColumnCount::Auto => f.write_str("auto"),
ColumnCount::Fixed(inner) => write!(f, "{}", inner),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Cursor {
// todo url
Auto,
Default,
None,
ContextMenu,
Help,
Pointer,
Progress,
Wait,
Cell,
Crosshair,
Text,
VerticalText,
Alias,
Copy,
Move,
NoDrop,
NotAllowed,
Grab,
Grabbing,
EResize,
NResize,
NEResize,
NWResize,
SResize,
SEResize,
SWResize,
WResize,
EWResize,
NSResize,
NESWResize,
NWSEResize,
ColResize,
RowResize,
AllScroll,
ZoomIn,
ZoomOut,
}
impl fmt::Display for Cursor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Cursor::Auto => f.write_str("auto"),
Cursor::Default => f.write_str("default"),
Cursor::None => f.write_str("none"),
Cursor::ContextMenu => f.write_str("context-menu"),
Cursor::Help => f.write_str("help"),
Cursor::Pointer => f.write_str("pointer"),
Cursor::Progress => f.write_str("progress"),
Cursor::Wait => f.write_str("wait"),
Cursor::Cell => f.write_str("cell"),
Cursor::Crosshair => f.write_str("crosshair"),
Cursor::Text => f.write_str("text"),
Cursor::VerticalText => f.write_str("vertical-text"),
Cursor::Alias => f.write_str("alias"),
Cursor::Copy => f.write_str("copy"),
Cursor::Move => f.write_str("move"),
Cursor::NoDrop => f.write_str("no-drop"),
Cursor::NotAllowed => f.write_str("not-allowed"),
Cursor::Grab => f.write_str("grab"),
Cursor::Grabbing => f.write_str("grabbing"),
Cursor::EResize => f.write_str("e-resize"),
Cursor::NResize => f.write_str("n-resize"),
Cursor::NEResize => f.write_str("ne-resize"),
Cursor::NWResize => f.write_str("nw-resize"),
Cursor::SResize => f.write_str("s-resize"),
Cursor::SEResize => f.write_str("se-resize"),
Cursor::SWResize => f.write_str("sw-resize"),
Cursor::WResize => f.write_str("w-resize"),
Cursor::EWResize => f.write_str("ew-resize"),
Cursor::NSResize => f.write_str("ns-resize"),
Cursor::NESWResize => f.write_str("nesw-resize"),
Cursor::NWSEResize => f.write_str("nwse-resize"),
Cursor::ColResize => f.write_str("col-resize"),
Cursor::RowResize => f.write_str("row-resize"),
Cursor::AllScroll => f.write_str("all-scroll"),
Cursor::ZoomIn => f.write_str("zoom-in"),
Cursor::ZoomOut => f.write_str("zoom-out"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Display {
Block,
Flex,
Inline,
// todo incomplete
}
impl fmt::Display for Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Display::Block => f.write_str("block"),
Display::Flex => f.write_str("flex"),
Display::Inline => f.write_str("inline"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum FlexBasis {
Width(Width21),
Content,
}
impl fmt::Display for FlexBasis {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FlexBasis::Width(v) => fmt::Display::fmt(v, f),
FlexBasis::Content => f.write_str("content"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FlexDirection {
Row,
Column,
}
impl fmt::Display for FlexDirection {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FlexDirection::Row => f.write_str("row"),
FlexDirection::Column => f.write_str("column"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FlexWrap {
Wrap,
Nowrap,
}
impl fmt::Display for FlexWrap {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FlexWrap::Wrap => write!(f, "wrap"),
FlexWrap::Nowrap => write!(f, "nowrap"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Float {
None,
Left,
Right,
InlineStart,
InlineEnd,
}
impl fmt::Display for Float {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Float::None => f.write_str("inline-end"),
Float::Left => f.write_str("left"),
Float::Right => f.write_str("right"),
Float::InlineStart => f.write_str("inline-start"),
Float::InlineEnd => f.write_str("inline-end"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Font {
// todo escape when `Display`ing
Named(String),
Serif,
SansSerif,
Cursive,
Fantasy,
Monospace,
}
impl fmt::Display for Font {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Font::Named(inner) => write!(f, "\"{}\"", inner),
Font::Serif => write!(f, "serif"),
Font::SansSerif => write!(f, "sans-serif"),
Font::Cursive => write!(f, "cursive"),
Font::Fantasy => write!(f, "fantasy"),
Font::Monospace => write!(f, "monospace"),
}
}
}
pub type FontFamily = NonemptyCommaList<Font>;
#[derive(Debug, Clone, PartialEq)]
pub enum FontSize {
XXSmall,
XSmall,
Small,
Medium,
Large,
XLarge,
XXLarge,
XXXLarge,
Larger,
Smaller,
LengthPercentage(Calc),
}
impl fmt::Display for FontSize {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FontSize::XXSmall => f.write_str("xx-small"),
FontSize::XSmall => f.write_str("x-small"),
FontSize::Small => f.write_str("small"),
FontSize::Medium => f.write_str("medium"),
FontSize::Large => f.write_str("large"),
FontSize::XLarge => f.write_str("x-large"),
FontSize::XXLarge => f.write_str("xx-large"),
FontSize::XXXLarge => f.write_str("xxx-large"),
FontSize::Larger => f.write_str("larger"),
FontSize::Smaller => f.write_str("smaller"),
FontSize::LengthPercentage(v) => fmt::Display::fmt(v, f),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FontStyle {
Normal,
Italic,
Oblique,
}
impl fmt::Display for FontStyle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FontStyle::Normal => f.write_str("normal"),
FontStyle::Italic => f.write_str("italic"),
FontStyle::Oblique => f.write_str("oblique"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FontWeight {
Normal,
Bold,
Lighter,
Bolder,
/// Between 1 and 1000
Number(f64),
}
impl fmt::Display for FontWeight {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FontWeight::Normal => f.write_str("normal"),
FontWeight::Bold => f.write_str("bold"),
FontWeight::Lighter => f.write_str("lighter"),
FontWeight::Bolder => f.write_str("bolder"),
FontWeight::Number(v) => fmt::Display::fmt(v, f),
}
}
}
/// https://www.w3.org/TR/css-flexbox-1/#propdef-justify-content
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum JustifyContent {
FlexStart,
Center,
FlexEnd,
SpaceBetween,
SpaceAround,
}
impl fmt::Display for JustifyContent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
JustifyContent::FlexStart => write!(f, "flex-start"),
JustifyContent::Center => write!(f, "center"),
JustifyContent::FlexEnd => write!(f, "flex-end"),
JustifyContent::SpaceAround => write!(f, "space-around"),
JustifyContent::SpaceBetween => write!(f, "space-between"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Length {
Em(f64),
Ex(f64),
In(f64),
Cm(f64),
Mm(f64),
Pt(f64),
Pc(f64),
Px(f64),
Zero,
}
impl fmt::Display for Length {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Length::Em(val) => write!(f, "{}em", val),
Length::Ex(val) => write!(f, "{}ex", val),
Length::In(val) => write!(f, "{}in", val),
Length::Cm(val) => write!(f, "{}cm", val),
Length::Mm(val) => write!(f, "{}mm", val),
Length::Pt(val) => write!(f, "{}pt", val),
Length::Pc(val) => write!(f, "{}pc", val),
Length::Px(val) => write!(f, "{}px", val),
Length::Zero => write!(f, "0"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LengthPercentage {
Length(Length),
Percentage(Percentage),
}
impl fmt::Display for LengthPercentage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LengthPercentage::Length(v) => fmt::Display::fmt(v, f),
LengthPercentage::Percentage(v) => fmt::Display::fmt(v, f),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineStyle {
None,
Hidden,
Dotted,
Dashed,
Solid,
Double,
Groove,
Ridge,
Inset,
Outset,
}
impl fmt::Display for LineStyle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LineStyle::None => write!(f, "none"),
LineStyle::Hidden => write!(f, "hidden"),
LineStyle::Dotted => write!(f, "dotted"),
LineStyle::Dashed => write!(f, "dashed"),
LineStyle::Solid => write!(f, "solid"),
LineStyle::Double => write!(f, "double"),
LineStyle::Groove => write!(f, "groove"),
LineStyle::Ridge => write!(f, "ridge"),
LineStyle::Inset => write!(f, "inset"),
LineStyle::Outset => write!(f, "outset"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineWidth {
Length(Length),
Thin,
Medium,
Thick,
}
impl fmt::Display for LineWidth {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LineWidth::Length(v) => fmt::Display::fmt(v, f),
LineWidth::Thin => write!(f, "thin"),
LineWidth::Medium => write!(f, "medium"),
LineWidth::Thick => write!(f, "thick"),
}
}
}
// TODO this isn't the full spec for lineheight
// (https://www.w3.org/TR/CSS2/visudet.html#propdef-line-height)
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LineHeight(f64);
impl fmt::Display for LineHeight {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ListStyleType {
Disc,
Circle,
Square,
Decimal,
DecimalLeadingZero,
LowerRoman,
UpperRoman,
LowerGreek,
UpperGreek,
LowerLatin,
UpperLatin,
Armenian,
Georgian,
LowerAlpha,
UpperAlpha,
None,
}
impl fmt::Display for ListStyleType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ListStyleType::Disc => write!(f, "disc"),
ListStyleType::Circle => write!(f, "circle"),
ListStyleType::Square => write!(f, "square"),
ListStyleType::Decimal => write!(f, "decimal"),
ListStyleType::DecimalLeadingZero => write!(f, "decimal-leading-zero"),
ListStyleType::LowerRoman => write!(f, "lower-roman"),
ListStyleType::UpperRoman => write!(f, "upper-roman"),
ListStyleType::LowerGreek => write!(f, "lower-greek"),
ListStyleType::UpperGreek => write!(f, "upper-greek"),
ListStyleType::LowerLatin => write!(f, "lower-latin"),
ListStyleType::UpperLatin => write!(f, "upper-latin"),
ListStyleType::Armenian => write!(f, "armenian"),
ListStyleType::Georgian => write!(f, "georgian"),
ListStyleType::LowerAlpha => write!(f, "lower-alpha"),
ListStyleType::UpperAlpha => write!(f, "upper-alpha"),
ListStyleType::None => write!(f, "none"),
}
}
}
pub type Margin = Rect<MarginWidth>;
#[derive(Debug, Clone, PartialEq)]
pub enum AutoLengthPercentage {
LengthPercentage(Calc),
Auto,
}
impl fmt::Display for AutoLengthPercentage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AutoLengthPercentage::LengthPercentage(v) => fmt::Display::fmt(v, f),
AutoLengthPercentage::Auto => write!(f, "auto"),
}
}
}
pub type MarginWidth = AutoLengthPercentage;
/// for max-width and max-height
#[derive(Debug, Clone, PartialEq)]
pub enum MaxWidthHeight {
None,
LengthPercentage(Calc),
MinContent,
MaxContent,
FitContent(Calc),
}
impl fmt::Display for MaxWidthHeight {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MaxWidthHeight::None => write!(f, "none"),
MaxWidthHeight::LengthPercentage(v) => write!(f, "{}", v),
MaxWidthHeight::MinContent => write!(f, "min-content"),
MaxWidthHeight::MaxContent => write!(f, "max-content"),
MaxWidthHeight::FitContent(v) => write!(f, "fit-content({})", v),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ObjectFit {
Fill,
None,
Contain { scale_down: bool },
Cover { scale_down: bool },
}
impl fmt::Display for ObjectFit {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ObjectFit::Fill => write!(f, "fill"),
ObjectFit::None => write!(f, "none"),
ObjectFit::Contain { scale_down } => {
if *scale_down {
write!(f, "contain scale-down")
} else {
write!(f, "contain")
}
}
ObjectFit::Cover { scale_down } => {
if *scale_down {
write!(f, "cover scale-down")
} else {
write!(f, "cover")
}
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Overflow {
Both(OverflowXY),
XY(OverflowXY, OverflowXY),
}
impl fmt::Display for Overflow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Overflow::Both(v) => write!(f, "{}", v),
Overflow::XY(x, y) => write!(f, "{} {}", x, y),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OverflowXY {
Visible,
Hidden,
Clip,
Scroll,
Auto,
}
impl fmt::Display for OverflowXY {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
OverflowXY::Visible => write!(f, "visible"),
OverflowXY::Hidden => write!(f, "hidden"),
OverflowXY::Clip => write!(f, "clip"),
OverflowXY::Scroll => write!(f, "scroll"),
OverflowXY::Auto => write!(f, "auto"),
}
}
}
pub type Padding = Rect<Calc>;
/// for e.g. `padding-top`
pub type PaddingWidth = Calc;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Percentage(pub f64);
impl fmt::Display for Percentage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}%", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Position {
Static,
Relative,
Absolute,
Fixed,
}
impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Position::Static => write!(f, "static"),
Position::Relative => write!(f, "relative"),
Position::Absolute => write!(f, "absolute"),
Position::Fixed => write!(f, "fixed"),
}
}
}
/// For parsing things in groups of 1, 2, 3 or 4 for specifying the sides of a rectangle.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Rect<T> {
All(T),
VerticalHorizontal(T, T),
TopHorizontalBottom(T, T, T),
TopRightBottomLeft(T, T, T, T),
}
impl<T> fmt::Display for Rect<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Rect::All(a) => write!(f, "{}", a),
Rect::VerticalHorizontal(v, h) => write!(f, "{} {}", v, h),
Rect::TopHorizontalBottom(t, h, b) => write!(f, "{} {} {}", t, h, b),
Rect::TopRightBottomLeft(t, r, b, l) => write!(f, "{} {} {} {}", t, r, b, l),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Resize {
None,
Both,
Horizontal,
Vertical,
}
impl fmt::Display for Resize {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Resize::None => write!(f, "none"),
Resize::Both => write!(f, "both"),
Resize::Horizontal => write!(f, "horizontal"),
Resize::Vertical => write!(f, "vertical"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Shadow {
pub color: Option<Color>,
pub length: ShadowLength,
pub inset: bool,
}
impl fmt::Display for Shadow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// we do it in this order because it makes spacing easier.
write!(f, "{}", self.length)?;
if let Some(color) = self.color {
write!(f, " {}", color)?;
}
if self.inset {
write!(f, " inset")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ShadowLength {
Offsets {
horizontal: Length,
vertical: Length,
},
OffsetsBlur {
horizontal: Length,
vertical: Length,
blur: Length,
},
OffsetsBlurSpread {
horizontal: Length,
vertical: Length,
blur: Length,
spread: Length,
},
}
impl fmt::Display for ShadowLength {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ShadowLength::Offsets {
horizontal,
vertical,
} => write!(f, "{} {}", horizontal, vertical),
ShadowLength::OffsetsBlur {
horizontal,
vertical,
blur,
} => write!(f, "{} {} {}", horizontal, vertical, blur),
ShadowLength::OffsetsBlurSpread {
horizontal,
vertical,
blur,
spread,
} => write!(f, "{} {} {} {}", horizontal, vertical, blur, spread),
}
}
}
#[test]
fn test_shadow_length() {
for (input, output) in vec![
(
"0 10px",
ShadowLength::Offsets {
horizontal: Length::Zero,
vertical: Length::Px(10.0),
},
),
(
"0 10px -10px",
ShadowLength::OffsetsBlur {
horizontal: Length::Zero,
vertical: Length::Px(10.0),
blur: Length::Px(-10.0),
},
),
] {
assert_eq!(syn::parse_str::<ShadowLength>(input).unwrap(), output)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum TextAlign {
Left,
Right,
Center,
Justify,
}
impl fmt::Display for TextAlign {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TextAlign::Left => write!(f, "left"),
TextAlign::Right => write!(f, "right"),
TextAlign::Center => write!(f, "center"),
TextAlign::Justify => write!(f, "justify"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Url {
// todo modifiers
url: String,
}
impl fmt::Display for Url {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "url(\"{}\")", self.url)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum WhiteSpace {
Normal,
Pre,
Nowrap,
PreWrap,
PreLine,
}
impl fmt::Display for WhiteSpace {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
WhiteSpace::Normal => write!(f, "normal"),
WhiteSpace::Pre => write!(f, "pre"),
WhiteSpace::Nowrap => write!(f, "nowrap"),
WhiteSpace::PreWrap => write!(f, "pre-wrap"),
WhiteSpace::PreLine => write!(f, "pre-line"),
}
}
}
/// values of `width` and `height`, `min-width`, `min-height`.
#[derive(Debug, Clone, PartialEq)]
pub enum WidthHeight {
Auto,
LengthPercentage(Calc),
MinContent,
MaxContent,
FitContent(Calc),
}
impl fmt::Display for WidthHeight {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
WidthHeight::Auto => write!(f, "auto"),
WidthHeight::LengthPercentage(v) => write!(f, "{}", v),
WidthHeight::MinContent => write!(f, "min-content"),
WidthHeight::MaxContent => write!(f, "max-content"),
WidthHeight::FitContent(v) => write!(f, "fit-content({})", v),
}
}
}
/// CSS2.1 width, for use with flexbox.
#[derive(Debug, Clone, PartialEq)]
pub enum Width21 {
Auto,
LengthPercentage(Calc),
}
impl fmt::Display for Width21 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Width21::Auto => write!(f, "auto"),
Width21::LengthPercentage(v) => fmt::Display::fmt(v, f),
}
}
}
/// A generic container for a non-empty comma-separated list of values
#[derive(Debug, Clone, PartialEq)]
pub struct NonemptyCommaList<T> {
first: T,
rest: Vec<T>,
}
impl<T> fmt::Display for NonemptyCommaList<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.first)?;
for t in &self.rest {
write!(f, ",{}", t)?;
}
Ok(())
}
}
/// Matches one or two variables.
#[derive(Debug, Clone, PartialEq)]
pub enum SingleOrDouble<T> {
Single(T),
Double { horiz: T, vert: T },
}
impl<T> fmt::Display for SingleOrDouble<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SingleOrDouble::Single(t) => t.fmt(f),
SingleOrDouble::Double { vert, horiz } => write!(f, "{} {}", vert, horiz),
}
}
}