#![warn(unused_must_use)]
use crate as css;
use css::css_properties::Property;
use css::{PrintErr, Printer, PropertyHandlerContext};
use css::css_values::ident::DashedIdent;
use bun_alloc::core_alloc::AllocVec as PlainVec;
use bun_alloc::core_alloc::Global as _G;
type PlainVec2<T> = PlainVec<T, _G>;
bitflags::bitflags! {
#[derive(Clone, Copy, PartialEq, Eq, Default)]
pub struct ColorScheme: u8 {
const LIGHT = 1 << 0;
const DARK = 1 << 1;
const ONLY = 1 << 2;
}
}
impl ColorScheme {
pub(crate) fn parse(input: &mut css::Parser) -> css::Result<ColorScheme> {
let mut res = ColorScheme::empty();
let ident = input.expect_ident_cloned()?;
if let Some(value) = color_scheme_map_get(ident) {
match value {
ColorSchemeKeyword::Normal => return Ok(res),
ColorSchemeKeyword::Only => res.insert(ColorScheme::ONLY),
ColorSchemeKeyword::Light => res.insert(ColorScheme::LIGHT),
ColorSchemeKeyword::Dark => res.insert(ColorScheme::DARK),
}
}
while let Ok(i) = input.try_parse(|p| p.expect_ident_cloned()) {
if let Some(value) = color_scheme_map_get(i) {
match value {
ColorSchemeKeyword::Normal => {
return Err(input.new_custom_error(css::ParserError::invalid_value));
}
ColorSchemeKeyword::Only => {
if res.contains(ColorScheme::ONLY) {
return Err(input.new_custom_error(css::ParserError::invalid_value));
}
res.insert(ColorScheme::ONLY);
return Ok(res);
}
ColorSchemeKeyword::Light => res.insert(ColorScheme::LIGHT),
ColorSchemeKeyword::Dark => res.insert(ColorScheme::DARK),
}
}
}
Ok(res)
}
pub(crate) fn to_css(self, dest: &mut Printer) -> Result<(), PrintErr> {
if self == ColorScheme::empty() {
return dest.write_str("normal");
}
if self.contains(ColorScheme::LIGHT) {
dest.write_str("light")?;
if self.contains(ColorScheme::DARK) {
dest.write_char(b' ')?;
}
}
if self.contains(ColorScheme::DARK) {
dest.write_str("dark")?;
}
if self.contains(ColorScheme::ONLY) {
dest.write_str(" only")?;
}
Ok(())
}
}
#[derive(Clone, Copy)]
enum ColorSchemeKeyword {
Normal,
Only,
Light,
Dark,
}
fn color_scheme_map_get(ident: &[u8]) -> Option<ColorSchemeKeyword> {
match ident {
b"normal" => Some(ColorSchemeKeyword::Normal),
b"only" => Some(ColorSchemeKeyword::Only),
b"light" => Some(ColorSchemeKeyword::Light),
b"dark" => Some(ColorSchemeKeyword::Dark),
_ => None,
}
}
pub struct Resize;
#[derive(Default)]
pub struct ColorSchemeHandler;
impl ColorSchemeHandler {
pub(crate) fn handle_property(
&mut self,
property: &Property,
dest: &mut css::DeclarationList,
context: &mut PropertyHandlerContext,
) -> bool {
match property {
Property::ColorScheme(color_scheme_) => {
let color_scheme: ColorScheme = *color_scheme_;
if !context
.targets
.is_compatible(css::compat::Feature::LightDark)
{
if color_scheme.contains(ColorScheme::LIGHT) {
dest.push(define_var(b"--buncss-light", css::Token::Ident(b"initial")));
dest.push(define_var(b"--buncss-dark", css::Token::Whitespace(b" ")));
if color_scheme.contains(ColorScheme::DARK) {
context.add_dark_rule(define_var(
b"--buncss-light",
css::Token::Whitespace(b" "),
));
context.add_dark_rule(define_var(
b"--buncss-dark",
css::Token::Ident(b"initial"),
));
}
} else if color_scheme.contains(ColorScheme::DARK) {
dest.push(define_var(b"--buncss-light", css::Token::Whitespace(b" ")));
dest.push(define_var(b"--buncss-dark", css::Token::Ident(b"initial")));
}
}
dest.push(Property::ColorScheme(color_scheme));
true
}
_ => false,
}
}
pub(crate) fn finalize(
&mut self,
_: &mut css::DeclarationList<'_>,
_: &mut PropertyHandlerContext<'_>,
) {
}
}
fn define_var(name: &'static [u8], value: css::Token) -> Property {
Property::Custom(css::css_properties::custom::CustomProperty {
name: css::css_properties::custom::CustomPropertyName::Custom(DashedIdent { v: name }),
value: css::TokenList {
v: PlainVec2::from_iter([css::css_properties::custom::TokenOrValue::Token(value)]),
},
})
}