use std::ops::Neg;
use cssparser::{Parser, match_ignore_ascii_case};
use crate::layout::style::{
CssToken,
Length::{self, *},
tw::TailwindPropertyParser,
*,
};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TwFontSize {
pub(crate) font_size: FontSize,
pub(crate) line_height: Option<LineHeight>,
}
impl<'i> FromCss<'i> for TwFontSize {
fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
Ok(Self::new(FontSize::from_css(input)?, None))
}
const VALID_TOKENS: &'static [CssToken] = FontSize::VALID_TOKENS;
}
impl TailwindPropertyParser for TwFontSize {
fn parse_tw(token: &str) -> Option<Self> {
if let Some((font_size, line_height)) = token.split_once('/') {
return Some(Self::new(
TwFontSize::parse_tw(font_size)?.font_size,
Some(LineHeight::parse_tw_with_arbitrary(line_height)?),
));
}
match_ignore_ascii_case! {token,
"xs" => Some(
Self::new(Rem(0.75).into(), Some(Em(1.0 / 0.75).into())),
),
"sm" => Some(
Self::new(Rem(0.875).into(), Some(Em(1.25 / 0.875).into())),
),
"base" => Some(
Self::new(Rem(1.0).into(), Some(Em(1.5 / 1.0).into())),
),
"lg" => Some(
Self::new(Rem(1.125).into(), Some(Em(1.75 / 1.125).into())),
),
"xl" => Some(
Self::new(Rem(1.25).into(), Some(Em(1.75 / 1.25).into())),
),
"2xl" => Some(
Self::new(Rem(1.5).into(), Some(Em(2.0 / 1.5).into())),
),
"3xl" => Some(
Self::new(Rem(1.875).into(), Some(Em(2.25 / 1.875).into())),
),
"4xl" => Some(
Self::new(Rem(2.25).into(), Some(Em(2.5 / 2.25).into())),
),
"5xl" => Some(
Self::new(Rem(3.0).into(), Some(LineHeight::Unitless(1.0))),
),
"6xl" => Some(
Self::new(Rem(3.75).into(), Some(LineHeight::Unitless(1.0))),
),
"7xl" => Some(
Self::new(Rem(4.5).into(), Some(LineHeight::Unitless(1.0))),
),
"8xl" => Some(
Self::new(Rem(6.0).into(), Some(LineHeight::Unitless(1.0))),
),
"9xl" => Some(
Self::new(Rem(8.0).into(), Some(LineHeight::Unitless(1.0))),
),
_ => None,
}
}
}
impl TwFontSize {
pub const fn new(font_size: FontSize, line_height: Option<LineHeight>) -> Self {
Self {
font_size,
line_height,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TwGridTemplate(pub GridTemplateComponents);
impl<'i> FromCss<'i> for TwGridTemplate {
fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
Ok(Self(GridTemplateComponents::from_css(input)?))
}
const VALID_TOKENS: &'static [CssToken] = GridTemplateComponents::VALID_TOKENS;
}
impl TailwindPropertyParser for TwGridTemplate {
fn parse_tw(token: &str) -> Option<Self> {
if token.eq_ignore_ascii_case("none") {
return Some(TwGridTemplate(GridTemplateComponents::default()));
}
let count = token.parse::<u32>().ok()?;
if count == 0 {
return None;
}
let track_sizes = vec![
GridTrackSize::MinMax(GridMinMaxSize {
min: GridLength::Unit(Length::Px(0.0)),
max: GridLength::Fr(1.0),
});
count as usize
];
let template_components = track_sizes
.into_iter()
.map(GridTemplateComponent::Single)
.collect();
Some(TwGridTemplate(template_components))
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TwLetterSpacing(pub Length);
impl<'i> FromCss<'i> for TwLetterSpacing {
fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
Ok(Self(Length::from_css(input)?))
}
const VALID_TOKENS: &'static [CssToken] = Length::<true>::VALID_TOKENS;
}
impl Neg for TwLetterSpacing {
type Output = Self;
fn neg(self) -> Self::Output {
TwLetterSpacing(-self.0)
}
}
impl TailwindPropertyParser for TwLetterSpacing {
fn parse_tw(token: &str) -> Option<Self> {
match_ignore_ascii_case! {token,
"tighter" => Some(TwLetterSpacing(Length::Em(-0.05))),
"tight" => Some(TwLetterSpacing(Length::Em(-0.025))),
"normal" => Some(TwLetterSpacing(Length::Em(0.0))),
"wide" => Some(TwLetterSpacing(Length::Em(0.025))),
"wider" => Some(TwLetterSpacing(Length::Em(0.05))),
"widest" => Some(TwLetterSpacing(Length::Em(0.1))),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TwBorderWidth(pub Length);
impl<'i> FromCss<'i> for TwBorderWidth {
fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
Ok(Self(Length::from_css(input)?))
}
const VALID_TOKENS: &'static [CssToken] = Length::<true>::VALID_TOKENS;
}
impl TailwindPropertyParser for TwBorderWidth {
fn parse_tw(token: &str) -> Option<Self> {
let value = token.parse::<f32>().ok()?;
Some(TwBorderWidth(Length::Px(value)))
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TwRounded(pub(crate) LengthDefaultsToZero);
impl<'i> FromCss<'i> for TwRounded {
fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
Ok(TwRounded(Length::from_css(input)?))
}
const VALID_TOKENS: &'static [CssToken] = Length::<false>::VALID_TOKENS;
}
impl TailwindPropertyParser for TwRounded {
fn parse_tw(token: &str) -> Option<Self> {
match_ignore_ascii_case! {token,
"full" => Some(TwRounded(Length::Px(9999.0))),
"none" => Some(TwRounded(Length::Px(0.0))),
"xs" => Some(TwRounded(Length::Rem(0.125))),
"sm" => Some(TwRounded(Length::Rem(0.25))),
"md" => Some(TwRounded(Length::Rem(0.375))),
"lg" => Some(TwRounded(Length::Rem(0.5))),
"xl" => Some(TwRounded(Length::Rem(0.75))),
"2xl" => Some(TwRounded(Length::Rem(1.0))),
"3xl" => Some(TwRounded(Length::Rem(1.5))),
"4xl" => Some(TwRounded(Length::Rem(2.0))),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TwGradientPosition(pub Length);
impl<'i> FromCss<'i> for TwGradientPosition {
fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
let location = input.current_source_location();
let length = Length::from_css(input)?;
if matches!(length, Length::Auto) {
return Err(
location
.new_basic_unexpected_token_error(cssparser::Token::Ident("auto".into()))
.into(),
);
}
Ok(TwGradientPosition(length))
}
const VALID_TOKENS: &'static [CssToken] = Length::<true>::VALID_TOKENS;
}
impl TailwindPropertyParser for TwGradientPosition {
fn parse_tw(token: &str) -> Option<Self> {
let stripped = token.strip_suffix('%')?;
let value = stripped.parse::<f32>().ok()?;
Some(TwGradientPosition(Length::Percentage(value)))
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TwBlur(pub(crate) Length);
impl<'i> FromCss<'i> for TwBlur {
fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
Ok(TwBlur(Length::from_css(input)?))
}
const VALID_TOKENS: &'static [CssToken] = Length::<true>::VALID_TOKENS;
}
impl TailwindPropertyParser for TwBlur {
fn parse_tw(token: &str) -> Option<Self> {
match_ignore_ascii_case! {token,
"none" => Some(TwBlur(Length::Px(0.0))),
"xs" => Some(TwBlur(Length::Px(4.0))),
"sm" => Some(TwBlur(Length::Px(8.0))),
"md" => Some(TwBlur(Length::Px(12.0))),
"lg" => Some(TwBlur(Length::Px(16.0))),
"xl" => Some(TwBlur(Length::Px(24.0))),
"2xl" => Some(TwBlur(Length::Px(40.0))),
"3xl" => Some(TwBlur(Length::Px(64.0))),
_ => None,
}
}
}