Re-factor props and attrs handling.

This commit is contained in:
Thomas Gideon 2020-06-21 11:57:50 -04:00
parent c6ba1f9b11
commit 6236cf6ae9
27 changed files with 604 additions and 500 deletions

View file

@ -1,8 +1,10 @@
use super::{Color, Edge};
use crate::props::IntoBsClass;
#[derive(Clone, PartialEq)]
pub struct Border(pub Edge, pub Color);
impl super::BootstrapClass for Border {
impl IntoBsClass for Border {
fn as_classname(&self) -> String {
let edge = match self.0 {
Edge::All => "border".to_owned(),

View file

@ -34,3 +34,13 @@ impl Color {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_with_prefix() {
assert_eq!(Color::Primary.with_prefix("alert"), "alert-primary");
}
}

54
src/prelude/edge.rs Normal file
View file

@ -0,0 +1,54 @@
use std::fmt::{Display, Formatter, Result};
#[derive(Debug, Clone, PartialEq)]
pub enum Edge {
All,
Top,
Right,
Bottom,
Left,
LeftAndRight,
TopAndBottom,
}
impl Display for Edge {
fn fmt(&self, fmt: &mut Formatter) -> Result {
match self {
Self::All => write!(fmt, ""),
Self::Top => write!(fmt, "t"),
Self::Bottom => write!(fmt, "b"),
Self::Right => write!(fmt, "r"),
Self::Left => write!(fmt, "l"),
Self::LeftAndRight => write!(fmt, "x"),
Self::TopAndBottom => write!(fmt, "y"),
}
}
}
impl Edge {
fn suffix(&self) -> &str {
match self {
Self::Top => "-top",
_ => "",
}
}
pub(crate) fn with_prefix<S: AsRef<str>>(&self, prefix: S) -> String {
match self {
Self::All => prefix.as_ref().to_owned(),
Self::LeftAndRight => format!(
"{0}{1} {0}{2}",
prefix.as_ref(),
Self::Left.suffix(),
Self::Right.suffix()
),
Self::TopAndBottom => format!(
"{0}{1} {0}{2}",
prefix.as_ref(),
Self::Top.suffix(),
Self::Bottom.suffix()
),
_ => format!("{}{}", prefix.as_ref(), self.suffix()),
}
}
}

View file

@ -1,7 +1,9 @@
use crate::props::IntoBsClass;
#[derive(Debug, Clone, PartialEq)]
pub struct Margin(pub super::Edge, pub usize);
impl super::BootstrapClass for Margin {
impl IntoBsClass for Margin {
fn as_classname(&self) -> String {
format!("m{}-{}", self.0, self.1)
}

View file

@ -1,117 +1,12 @@
mod border;
mod color;
mod edge;
mod margin;
mod padding;
pub use self::{border::Border, color::Color, margin::Margin, padding::Padding};
use std::fmt::{Display, Formatter, Result};
pub use self::{border::Border, color::Color, edge::Edge, margin::Margin, padding::Padding};
use yew::prelude::*;
#[derive(Properties, Clone, PartialEq, Default)]
pub struct Props {
#[prop_or_default]
pub aria_label: String,
#[prop_or_default]
pub role: String,
#[prop_or_default]
pub border: Option<Border>,
#[prop_or_default]
pub borders: Vec<Border>,
#[prop_or_default]
pub margin: Option<Margin>,
#[prop_or_default]
pub margins: Vec<Margin>,
#[prop_or_default]
pub padding: Option<Padding>,
#[prop_or_default]
pub paddings: Vec<Padding>,
#[prop_or_default]
pub class: String,
#[prop_or_default]
pub style: String,
#[prop_or_default]
pub children: Children,
}
impl<'a> From<&'a Props> for BootstrapProps<'a> {
fn from(props: &Props) -> BootstrapProps {
let class = &props.class;
let borders = collect_bs(&props.border, &props.borders);
let margins = collect_bs(&props.margin, &props.margins);
let paddings = collect_bs(&props.padding, &props.paddings);
BootstrapProps {
class,
borders,
margins,
paddings,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Edge {
All,
Top,
Right,
Bottom,
Left,
LeftAndRight,
TopAndBottom,
}
impl Display for Edge {
fn fmt(&self, fmt: &mut Formatter) -> Result {
match self {
Self::All => write!(fmt, ""),
Self::Top => write!(fmt, "t"),
Self::Bottom => write!(fmt, "b"),
Self::Right => write!(fmt, "r"),
Self::Left => write!(fmt, "l"),
Self::LeftAndRight => write!(fmt, "x"),
Self::TopAndBottom => write!(fmt, "y"),
}
}
}
impl Edge {
fn suffix(&self) -> &str {
match self {
Self::Top => "-top",
_ => "",
}
}
fn with_prefix<S: AsRef<str>>(&self, prefix: S) -> String {
match self {
Self::All => prefix.as_ref().to_owned(),
Self::LeftAndRight => format!(
"{0}{1} {0}{2}",
prefix.as_ref(),
Self::Left.suffix(),
Self::Right.suffix()
),
Self::TopAndBottom => format!(
"{0}{1} {0}{2}",
prefix.as_ref(),
Self::Top.suffix(),
Self::Bottom.suffix()
),
_ => format!("{}{}", prefix.as_ref(), self.suffix()),
}
}
}
trait BootstrapClass {
fn as_classname(&self) -> String;
}
pub struct BootstrapProps<'a> {
pub class: &'a str,
pub borders: Vec<&'a Border>,
pub margins: Vec<&'a Margin>,
pub paddings: Vec<&'a Padding>,
}
pub fn render_on_change<P: Properties + PartialEq>(
props_on_comp: &mut P,
props: P,
@ -131,38 +26,3 @@ pub fn valid_as_class(v: &Option<bool>) -> &'static str {
Some(false) => " is-invalid",
}
}
pub fn collect_bs<'a, T>(t: &'a Option<T>, ts: &'a [T]) -> Vec<&'a T> {
if let Some(t) = t.as_ref() {
let mut r = vec![t];
r.append(&mut ts.iter().collect());
r
} else {
ts.iter().collect()
}
}
pub fn calculate_classes<S: AsRef<str>>(prefix: S, props: BootstrapProps) -> String {
let BootstrapProps {
class,
borders,
margins,
paddings,
} = props;
let mut classes = Vec::new();
if !prefix.as_ref().is_empty() {
classes.push(prefix.as_ref().to_owned());
}
if !props.class.is_empty() {
classes.push(class.to_owned());
}
classes.append(&mut into_classnames(borders));
classes.append(&mut into_classnames(margins));
classes.append(&mut into_classnames(paddings));
classes.join(" ")
}
fn into_classnames<C: BootstrapClass>(c: Vec<&C>) -> Vec<String> {
c.into_iter().map(|c| c.as_classname()).collect()
}

View file

@ -1,7 +1,9 @@
use crate::props::IntoBsClass;
#[derive(Debug, Clone, PartialEq)]
pub struct Padding(pub super::Edge, pub usize);
impl super::BootstrapClass for Padding {
impl IntoBsClass for Padding {
fn as_classname(&self) -> String {
format!("p{}-{}", self.0, self.1)
}