Closed rsaccon closed 5 years ago
Ups, somehow I confused things when I formulated out this initial issue, it turns out that it is much easier, all what is is needed is a small modification of ClassBuilder
to allow something like this:
lazy_static! {
static ref FOO_CLASS__HOVER: String = class! {
.pseudo("hover") // not implemented yet.
.style("background-color", "yellow")
};
}
That should generate this:
<style>
.__class_0__:hover {
background-color: yellow;
}
</style>
will try to implement it and provide a PR
Ok, I implemented it at my fork and so far it seems to work perfectly. For pseudo classes and elements, the class!
macro just has an additional first argument which defines the pseudo class name, see example below.
pub static ref FOO__HOVER: String = class! ("hover", {
.style("background-color", "yellow")
});
Unfortunately when I wanted to create a Pull Request, I realized that each file I modified got auto-formatted differently, that makes a PR full of noise, need to sort out that first.
Hey, sorry for the delay on this (I've spent the past few months moving to a new country). I'll look into this and your other issues soon!
No problem, no hurry, thanks anyway and happy country-moving!
I also run into one more issue when using StyleSheetBuilder
when trying to do a CSS Reset based on something like normalize.css
when the rule selector is browser specific, e.g.:
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
then we get a panic, because (I assume) when the currently used browser is not the targeted browser in the rule, a CSS parsing DOM exception gets thrown at insertRule:
I also built a minimalistic wasm-bindgen
version of a CssStyleRule injector, just to troubleshoot this issue. If the insertRule fails, I just ignore it, and all seems to be fine. But I am not sure whether this is the right approach, and how to handle this in StyleSheetBuilder
. I will further investigate, probably check how the JS libs such as style-mod handle this.
Is is currently possible to do something like that ?
That's a good question. Currently, it's not possible, but I can add it in.
However, from a philosophical standpoint, CSS was never intended to specify behavior, only appearance.
So the idiomatic way to handle things like hovering is to do this:
let is_hovering = Mutable::new(false);
html!("div", {
.class(&*FOO_CLASS)
.class_signal(&*FOO_CLASS_HOVER, is_hovering.signal())
.event(clone!(is_hovering => move |_: MouseEnterEvent| {
is_hovering.set_neq(true);
}))
.event(move |_: MouseLeaveEvent| {
is_hovering.set_neq(false);
})
})
It's easy to wrap that in a mixin:
fn class_on_hover<A>(name: &str) -> impl FnOnce(DomBuilder<A>) -> DomBuilder<A> where A: IEventTarget + IHtmlElement {
move |dom| {
let is_hovering = Mutable::new(false);
dom.class_signal(name, is_hovering.signal())
.event(clone!(is_hovering => move |_: MouseEnterEvent| {
is_hovering.set_neq(true);
}))
.event(move |_: MouseLeaveEvent| {
is_hovering.set_neq(false);
})
}
}
And now you can use it like this:
html!("div", {
.class(&*FOO_CLASS)
.apply(class_on_hover(&*FOO_CLASS_HOVER))
})
One thing I am not sure about: For the pseudo classes we need the base class name, but when the base class name gets first time accessed (inside the macro for the pseudo class), then maybe the compiler can not optimize it away anymore, in case the base class never gets used in the actual app code.
If you use the pseudo class, then it will include the base class as well (this is necessary because the base class generates a unique ID, and it needs to use that ID in the pseudo class).
But if you don't use the base class or the pseudo class, then it won't include either one.
I am aware that I could build pseudo classes with StylesheetBuilder and its macro, but then I won't have typed class names anymore, which was my main motivation to start with all this.
The class names will still be unique, because they're using the base class (which is unique):
lazy_static! {
static ref FOO_CLASS: String = class! {
.style("background-color", "green")
};
static ref FOO_CLASS_HOVER: String = {
let name = format!(".{}:hover", &*FOO_CLASS);
stylesheet!(&name, {
.style_hover("background-color", "yellow")
});
name
};
}
The above will generate this CSS:
.__class_0__ {
background-color: green;
}
.__class_0__:hover {
background-color: yellow;
}
then we get a panic, because (I assume) when the currently used browser is not the targeted browser in the rule, a CSS parsing DOM exception gets thrown at insertRule
Yeah, that seems like a really tricky situation. I'm not sure how to handle that.
Okay, so I changed the stylesheet
macro so it now can accept multiple selectors:
stylesheet!([
"button::-moz-focus-inner",
"button::-webkit-focus-inner",
"button::-ms-focus-inner",
"button::-o-focus-inner",
"button::focus-inner",
], {
.style("background-color", "green")
});
It will try each selector in order, and if a selector errors then it will try the next. As soon as a selector works then it uses it.
I also added in a pseudo!
method for class
, which lets you specify pseudo elements:
lazy_static! {
static ref FOO: String = class! {
.style("background-color", "green")
.pseudo!(":hover", {
.style("background-color", "red")
})
.pseudo!(":first", {
.style("background-color", "orange")
})
};
}
Similar to stylesheet
it also can accept multiple pseudos, which are tried in order until one succeeds:
.pseudo!([
"::-moz-progress-bar",
"::-ms-progress-bar",
"::-o-progress-bar",
"::-webkit-progress-bar",
"::progress-bar",
], {
.style("background-color", "red")
})
I am trying to implement a Design System and CSS framework partially based on TailwindCSS with the dominator
class!
(andstylesheet!
if necessary) macros.Main motivation is to have typed class names and only those CSS classes which are actually used, will end up in the compiled binary (and eventually in the
CSSRuleList
).However i got stuck at the following issue: I see no way how I could define pseudo classes with the current
ClassBuilder
and itsclass!
macro. I would like to do something like:That should generate this:
Is is currently possible to do something like that ?
Does the code above to implement pseudo classes make sense ? One thing I am not sure about: For the pseudo classes we need the base class name, but when the base class name gets first time accessed (inside the macro for the pseudo class), then maybe the compiler can not optimize it away anymore, in case the base class never gets used in the actual app code.
I am aware that I could build pseudo classes with
StylesheetBuilder
and its macro, but then I won't have typed class names anymore, which was my main motivation to start with all this.