Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/polished-css-macros/src/utils/color_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use super::DATA_TYPE_TRAIT_SUFFIX;
)]
#[strum(serialize_all = "PascalCase")]
pub enum ColorFunction {
Hsl,
Oklch,
Rgb,
}

impl ColorFunction {
Expand Down
19 changes: 15 additions & 4 deletions crates/polished-css-macros/src/utils/data_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,14 @@ pub enum DataType {
Ratio,
RelativeLength,
Resolution,
Saturation,
String,
SystemColor,
Time,
ViewportLength,
Blue,
Green,
Red,
}

impl DataType {
Expand Down Expand Up @@ -96,9 +100,14 @@ impl DataType {
Self::NamedColor,
]
}
Self::Alpha | Self::Chroma | Self::Lightness | Self::NumberPercentage => {
&[Self::Number, Self::Percentage]
}
Self::Alpha
| Self::Chroma
| Self::Lightness
| Self::NumberPercentage
| Self::Blue
| Self::Green
| Self::Red
| Self::Saturation => &[Self::Number, Self::Percentage],
Self::Color => &[Self::AbsoluteColor, Self::SystemColor],
Self::Dimension => &[Self::Frequency, Self::Length, Self::Resolution, Self::Time],
Self::FrequencyPercentage => &[Self::Frequency, Self::Percentage],
Expand All @@ -118,7 +127,9 @@ impl DataType {

pub const fn get_dependant_color_functions(&self) -> &[ColorFunction] {
match self {
Self::AbsoluteColorFunction => &[ColorFunction::Oklch],
Self::AbsoluteColorFunction => {
&[ColorFunction::Hsl, ColorFunction::Oklch, ColorFunction::Rgb]
}
_ => &[],
}
}
Expand Down
6 changes: 6 additions & 0 deletions crates/polished-css/src/data_type/alpha.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
//! Alpha channel or transparency of a color.

use crate::data_type::{Number, NumberStorage, Percentage};

/// Alpha channel or transparency of a color.
///
/// ### Resources
///
/// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/alpha_value)
#[derive(
Clone,
Expand Down
66 changes: 66 additions & 0 deletions crates/polished-css/src/data_type/blue.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//! Blue channel from the [RGB](https://en.wikipedia.org/wiki/RGB_color_model) color model.

use crate::data_type::{Number, NumberStorage, Percentage};

/// Blue channel from the [RGB](https://en.wikipedia.org/wiki/RGB_color_model) color model.
/// It can be a float `f64` number between `0` and `255`,
/// or a percentage is respective to those min and max values.
///
/// ### Resources
///
/// - [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/rgb)
/// - [CSSWG specification](https://www.w3.org/TR/css-color-3/#rgb-color)
#[derive(
Clone,
Debug,
PartialEq,
strum_macros::EnumIs,
polished_css_macros::Display,
polished_css_macros::DataTypeFromDataTypes,
)]
#[display(on_enum = true)]
pub enum Blue {
// NOTE: We need to override to add bounds - min - 0 max 255
// TODO: #[custom_constraint(fn_name)]
Number(Number),
// NOTE: We need to override to add bounds
Percentage(Percentage),
}

impl From<f64> for Blue {
fn from(value: f64) -> Self {
Self::number(value)
}
}

#[polished_css_macros::create_trait_from_enum_impl()]
impl Blue {
/// Use minimum value from the channel - `0`.
#[must_use]
pub const fn min() -> Self {
Self::Number(Number(0.0))
}

/// Use maximum value from the channel - `255`.
#[must_use]
pub const fn max() -> Self {
Self::Number(Number(255.0))
}

// TODO: Add conversion methods?
}

#[cfg(test)]
mod test {
#[test]
fn display() {
use crate::data_type::*;
assert_eq!(super::Blue::number(0.1).to_string(), String::from("0.1"));
assert_eq!(
super::Blue::percentage(10.0).to_string(),
String::from("10%")
);
assert_eq!(super::Blue::min().to_string(), String::from("0"));
assert_eq!(super::Blue::max().to_string(), String::from("255"));
}
}
138 changes: 138 additions & 0 deletions crates/polished-css/src/data_type/color/absolute/function/hsl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//! [HSL](https://en.wikipedia.org/wiki/HSL_and_HSV) color model.

use std::fmt;

use crate::data_type::{Alpha, Hue, Lightness, Saturation};

/// `hsl()` and its `hsla()` alias - specifies sRGB colors by hue,
/// saturation, and lightness using the HSL cylindrical coordinate
/// model.
///
/// ### Resources
///
/// - [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/hsl)
/// - [CSSWG specification](https://www.w3.org/TR/css-color-3/#hsl-color)
#[derive(Clone, Debug, PartialEq)]
pub struct Hsl {
/// Dominant wavelength of a color
pub hue: Hue,
/// Determines how much of the pure hue is present in the color
pub saturation: Saturation,
/// Overall brightness of the color without affecting its hue (type of
/// color) or saturation (color intensity)
pub lightness: Lightness,
/// Optional alpha channel - by default is `1`
pub alpha: Option<Alpha>,
}

impl fmt::Display for Hsl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"hsl({} {} {} / {})",
self.hue,
self.saturation,
self.lightness,
self.alpha
.clone()
.map_or_else(Alpha::visible, |alpha| alpha)
)
}
}

impl<H, S, L, A> From<(H, S, L, A)> for Hsl
where
H: Into<Hue>,
S: Into<Saturation>,
L: Into<Lightness>,
A: Into<Option<Alpha>>,
{
fn from(value: (H, S, L, A)) -> Self {
let (r, g, b, a) = value;
Self {
hue: r.into(),
saturation: g.into(),
lightness: b.into(),
alpha: a.into(),
}
}
}

impl<H, S, L> From<(H, S, L)> for Hsl
where
H: Into<Hue>,
S: Into<Saturation>,
L: Into<Lightness>,
{
fn from(value: (H, S, L)) -> Self {
let (r, g, b) = value;
Self {
hue: r.into(),
saturation: g.into(),
lightness: b.into(),
alpha: Some(Alpha::default()),
}
}
}

pub trait HslStorage: From<Hsl> {
#[must_use]
fn hsl(value: Hsl) -> Self
where
Self: Sized,
{
Self::from(value)
}
}

#[cfg(test)]
mod test {
#[test]
fn display() {
use crate::data_type::*;

assert_eq!(
super::Hsl {
hue: Hue::rad(255.0),
saturation: Saturation::number(0.77),
lightness: Lightness::reset(),
alpha: Some(Alpha::visible())
}
.to_string(),
String::from("hsl(255rad 0.77 0% / 1)")
);

assert_eq!(
super::Hsl {
hue: Hue::turn(1.0),
saturation: Saturation::unsaturated(),
lightness: Lightness::full(),
alpha: Some(Alpha::visible())
}
.to_string(),
String::from("hsl(1turn 0 100% / 1)")
);

assert_eq!(
super::Hsl::from((
Hue::deg(33.0),
Saturation::percentage(66.7),
Lightness::percentage(100.0),
Some(Alpha::invisible())
))
.to_string(),
String::from("hsl(33deg 66.7% 100% / 0)")
);

assert_eq!(
super::Hsl::from((
Hue::grad(45.0),
Saturation::number(0.22),
Lightness::percentage(70.0),
Some(Alpha::number(0.43))
))
.to_string(),
String::from("hsl(45grad 0.22 70% / 0.43)")
);
}
}
70 changes: 57 additions & 13 deletions crates/polished-css/src/data_type/color/absolute/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
//! - [CSSWG specification](https://www.w3.org/TR/css-color-4/#color-functions)
//! - [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value)

pub mod hsl;
pub mod oklch;
pub mod rgb;

pub use hsl::*;
pub use oklch::*;
pub use rgb::*;

/// [CSSWG specification](https://drafts.csswg.org/css-color/#typedef-absolute-color-function)
#[derive(
Expand All @@ -23,13 +27,15 @@ pub use oklch::*;
// TODO: Implement missing color functions - feel free to contribute.
#[non_exhaustive]
pub enum AbsoluteColorFunction {
// /// `rgb()` and its `rgba()` alias - which (like the hex color notation)
// /// specify sRGB colors directly by their red/green/blue/alpha channels.
// Rgb,
// /// `hsl()` and its `hsla()` alias - specifies sRGB colors by hue,
// /// saturation, and lightness using the HSL cylindrical coordinate
// /// model.
// Hsl,
/// `hsl()` and its `hsla()` alias - specifies sRGB colors by hue,
/// saturation, and lightness using the HSL cylindrical coordinate
/// model.
Hsl(Hsl),

/// `rgb()` and its `rgba()` alias - which _(like the hex color notation)_
/// specify sRGB colors directly by their red/green/blue/alpha channels.
Rgb(Rgb),

// /// `hwb()` - specifies an sRGB color by hue, whiteness, and blackness
// /// using the HWB cylindrical coordinate model.
// Hwb,
Expand Down Expand Up @@ -61,24 +67,47 @@ pub enum AbsoluteColorFunction {
// }
// }

pub trait AbsoluteColorFunctionStorage: From<AbsoluteColorFunction> + OklchStorage {
// fn oklch(value: Oklch) -> Self {
// Self::from(value)
// }
pub trait AbsoluteColorFunctionStorage: From<AbsoluteColorFunction> {}

impl From<Hsl> for AbsoluteColorFunction {
fn from(value: Hsl) -> Self {
Self::Hsl(value)
}
}
impl HslStorage for AbsoluteColorFunction {}

// TODO: Macro'ify it
impl From<Oklch> for AbsoluteColorFunction {
fn from(value: Oklch) -> Self {
Self::Oklch(value)
}
}
impl OklchStorage for AbsoluteColorFunction {}

impl From<Rgb> for AbsoluteColorFunction {
fn from(value: Rgb) -> Self {
Self::Rgb(value)
}
}
impl RgbStorage for AbsoluteColorFunction {}

mod test {
#[test]
fn display_hsl() {
use crate::prelude::*;
assert_eq!(
super::AbsoluteColorFunction::hsl(Hsl {
hue: Hue::deg(75.0),
saturation: Saturation::number(1.0),
lightness: Lightness::number(0.5),
alpha: Some(Alpha::invisible())
})
.to_string(),
String::from("hsl(75deg 1 0.5 / 0)")
);
}

#[test]
fn display() {
fn display_oklch() {
use crate::prelude::*;
assert_eq!(
super::AbsoluteColorFunction::oklch(Oklch {
Expand All @@ -91,4 +120,19 @@ mod test {
String::from("oklch(50% 0.4 225deg / 1)")
);
}

#[test]
fn display_rgb() {
use crate::prelude::*;
assert_eq!(
super::AbsoluteColorFunction::rgb(Rgb {
red: Red::percentage(75.0),
green: Green::number(150.0),
blue: Blue::number(225.0),
alpha: Some(Alpha::invisible())
})
.to_string(),
String::from("rgb(75% 150 225 / 0)")
);
}
}
Loading