Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transform as an html attribute not parsed correctly #834

Open
noahbald opened this issue Oct 14, 2024 · 3 comments
Open

Transform as an html attribute not parsed correctly #834

noahbald opened this issue Oct 14, 2024 · 3 comments

Comments

@noahbald
Copy link

Because transform="..." tends to be unit-less and space-separated they aren't parsed correctly by lightning-css despite being a presentation attribute.
For example, the following is a valid transform in HTML, but not CSS

/* eg <g transform="translate(0 10)"></g> */
translate(0 10)

While the following is valid in both CSS and HTML

/* eg <g transform="translate(0, 10px)></g> */
/* eg transform: translate(0, 10px); */
translate(0, 10px);

Yet, they are functionally equivalent.

Since in a HTML context the expected syntax is slightly difference, it might be nice to specify in the parser options whether a property being parsed is a presentation attribute

let options = ParserOptions { flags: ParserFlags::HTML, ..ParserOptions::default() }
let transform = properties::Property::parse_string(PropertyId::Transform(VendorPrefix::None), "translate(0 10)", options);
@devongovett
Copy link
Member

Yeah the syntax for SVG transform attributes is completely different from CSS. For example rotate takes additional arguments for the center point instead of using transform-origin. I'd probably recommend using a different parser and value type for the presentation attributes vs CSS.

@noahbald
Copy link
Author

noahbald commented Oct 16, 2024

Yep, absolutely -- SVG transform seems to be a kind of superset of CSS transforms. Thought it'd be worth making this issue for awareness anyway.
For what it's worth, I do have a workaround using some (yucky) regex.

use lazy_static::lazy_static;

fn svg_transform_to_css_transform(css_string: String) -> Cow<'_, str> {
    // transform `rotate(r, x, y)` -> `matrix(a, b, c, d, e, f)`
    // see https://github.com/svg/svgo/blob/a8472bc45fe1d92d5f848a08cf4d5c8f4a531ad9/plugins/_transforms.js#L511
    let v = ROTATE_LONG.replace_all(&value, |caps: &regex::Captures| {
        let original = format!("rotate({} {} {})", &caps["r"], &caps["x"], &caps["y"]);
        let Ok(deg) = caps["r"].parse::<f64>() else {
            log::debug!("r failed: {}", &caps["r"]);
            return original;
        };
        let Ok(x) = caps["x"].parse::<f64>() else {
            log::debug!("x failed: {}", &caps["x"]);
            return original;
        };
        let Ok(y) = caps["y"].parse::<f64>() else {
            log::debug!("y failed: {}", &caps["y"]);
            return original;
        };
        let rad = deg.to_radians();
        let cos = rad.cos();
        let sin = rad.sin();
        format!(
            "matrix({cos} {sin} {} {cos} {} {})",
            -sin,
            (1.0 - cos) * x + sin * y,
            (1.0 - cos) * y - sin * x
        )
    });

    // transform `f(a b ...)` -> `f(a, b, ...)`
    let v = LIST_SEP_SPACE.replace_all(&v, "$a, ");

    // transform `rotate(r)` -> `rotate(rdeg)`
    value = ROTATE
        .replace_all(&v, |caps: &regex::Captures| {
            format!("{}({}deg", &caps["f"], &caps["v"])
        })
}

lazy_static! {
    static ref LIST_SEP_SPACE: regex::Regex = regex::Regex::new(r"(?<a>\d)\s+").unwrap();
    static ref ROTATE: regex::Regex =
        regex::Regex::new(r"(?<f>rotate|skewX|skewY)\((?<v>\s*[^\s\),]+)").unwrap();
    static ref ROTATE_LONG: regex::Regex = regex::Regex::new(
        r"rotate\((?<r>[\d\.e-]+)[^\d\)]+?(?<x>[\d\.e-]+)[^\d\)]+?(?<y>[\d\.e-]+)\)"
    )
    .unwrap();
}

In terms of lightningcss, having a separate parser makes sense to me.
Would a separate parser mean having something similar to Property but for HTML presentation attributes instead of CSS properties?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants
@devongovett @noahbald and others