Crates.io | class_list |
lib.rs | class_list |
version | 0.1.7 |
source | src |
created_at | 2023-08-21 17:14:02.075746 |
updated_at | 2023-08-23 07:08:15.680911 |
description | A reactive helper that ensures normalized class list strings in frontend frameworks like Leptos. |
homepage | |
repository | https://github.com/Kyza/class_list |
max_upload_size | |
id | 950215 |
size | 14,639 |
A reactive helper that ensures normalized class list strings in frontend frameworks like Leptos.
Examples provided will be for the Leptos framework post-{context removal}, but it will work pre-{context removal} and might work in other similar frameworks.
This library is meant to be agnostic and has no runtime dependencies, but it has only been tested with Leptos.
cargo add class_list
class_list![]
by default wraps itself in a move closure, meaning it will be reactive by default.
let (count, set_count) = create_signal(0);
set_interval(
move || {
set_count.update(|count| *count += 1);
},
Duration::from_millis(100),
);
let count_class = move || format!("count-{}", count());
let count_is_even = move || count() % 2 == 0;
view! {
<div class=class_list![
"default-class-names",
// Closures get called automatically.
count_class,
// Closures can be written directly into the macro.
move || format!("count-{}", count()),
// Both Option and Result can be used as values.
// None and Err result in no class name.
Some("option"),
None::<String>,
// More conveniently, class names can be bound to reactive toggles.
// "even" will only be applied when `count_is_even()` is true.
// You also don't need to call closures here.
"even" <=> count_is_even
] />
}
Each option must be followed by a ;
.
To generate a non-reactive String, add the raw
option to the beginning.
class_list![
raw;
"default-class-names",
]
Rarely, you may need to clone something before passing it in.
The macro makes this easy with the clone
option which clones the variable before it gets moved into the closure.
If possible try to avoid needing this option in the first place.
class_list![
clone[count_class];
"default-class-names",
]
This should never be needed because it's automatically supplied by a wrapper macro_rules!
.
In a case where the trait imports cannot be resolved--such as when used inside of another library--, the path can be redefined.
The path should lead to the root of this library.
__class_list![
crate = ::your_lib::class_list;
"default-class-names",
]
If you'd like to simply pass a type to the macro instead of converting it every time, you can implement the ClassList
and ClassToggle
types.
Check out traits.rs to see the default implementations which are good examples of implementing them.
// If you're using a type you don't own,
// you must wrap it in a new struct.
struct Bool(bool);
impl ClassList for Bool {
fn to_class_list(&self, normalize: bool) -> String {
// If the string could contain multiple class names
// you should use `normalize` to determine whether
// or not to call `.to_class_list()` on it before
// returning.
// If you're lazy you could always normalize, but
// then the string will be normalized multiple
// times for every update in the macro.
if self.0 {
"true".into()
} else {
"false".into()
}
}
}
impl ClassToggle for Bool {
fn to_class_toggle(&self) -> bool {
self.0
}
}
// Option, Result, and Fn are implemented in a way which
// allows any new type you implement to be automatically
// passed through.
assert_eq!(
class_list![
// ClassList
move || Bool(false),
Bool(true),
"class",
// ClassToggle
"hidden" <=> move || Bool(false),
"list",
](),
"false true class list".to_string()
);