Standardize props
This commit is contained in:
parent
96b6152d7b
commit
c833bb1957
17 changed files with 358 additions and 252 deletions
19
examples/Cargo.toml
Normal file
19
examples/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "examples"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Thomas Gideon <cmdln@thecommandline.net>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bootstrap-rs = { path = "../" }
|
||||||
|
yew = "~0.16.2"
|
||||||
|
log = "~0.4.8"
|
||||||
|
anyhow = "^1.0.28"
|
||||||
|
wasm-bindgen = "~0.2.61"
|
||||||
|
web-sys = "~0.3.38"
|
||||||
|
wasm-logger = "~0.2.0"
|
||||||
|
yew-router = "~0.13.0"
|
||||||
|
yew-components = "~0.1.2"
|
52
examples/src/lib.rs
Normal file
52
examples/src/lib.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
use bootstrap_rs::{prelude::*, Breadcrumb, BreadcrumbItem, Container, Jumbotron};
|
||||||
|
use yew::{html::Children, prelude::*};
|
||||||
|
|
||||||
|
pub struct Example {
|
||||||
|
props: Props,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Properties, Clone, PartialEq)]
|
||||||
|
pub struct Props {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub children: Children,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Example {
|
||||||
|
type Properties = Props;
|
||||||
|
type Message = ();
|
||||||
|
|
||||||
|
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||||
|
Self { props }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||||
|
render_on_change(&mut self.props, props)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self) -> Html {
|
||||||
|
html! {
|
||||||
|
<Container>
|
||||||
|
<Jumbotron>
|
||||||
|
<h1>{ "Example!" }</h1>
|
||||||
|
</Jumbotron>
|
||||||
|
<Breadcrumb
|
||||||
|
margin=Margin(Edge::Bottom, 3)
|
||||||
|
>
|
||||||
|
<BreadcrumbItem active=false>
|
||||||
|
{ "Grandparent" }
|
||||||
|
</BreadcrumbItem>
|
||||||
|
<BreadcrumbItem active=false>
|
||||||
|
{ "Parent" }
|
||||||
|
</BreadcrumbItem>
|
||||||
|
<BreadcrumbItem active=true>
|
||||||
|
{ "Active" }
|
||||||
|
</BreadcrumbItem>
|
||||||
|
</Breadcrumb>
|
||||||
|
</Container>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,22 @@ pub struct BreadcrumbItem {
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
pub active: bool,
|
pub active: bool,
|
||||||
#[prop_or_default]
|
#[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,
|
pub children: Children,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,16 +47,41 @@ impl Component for BreadcrumbItem {
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
if self.props.active {
|
if self.props.active {
|
||||||
html! {
|
html! {
|
||||||
<li class="breadcrumb-item active" aria-current="page">
|
<li class=self.classes() aria-current="page">
|
||||||
{ self.props.children.render() }
|
{ self.props.children.render() }
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
html! {
|
html! {
|
||||||
<li class="breadcrumb-item">
|
<li class=self.classes()>
|
||||||
{ self.props.children.render() }
|
{ self.props.children.render() }
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BreadcrumbItem {
|
||||||
|
fn classes(&self) -> String {
|
||||||
|
if self.props.active {
|
||||||
|
calculate_classes("breadcrumb-item active", (&self.props).into())
|
||||||
|
} else {
|
||||||
|
calculate_classes("breadcrumb-item", (&self.props).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,34 +2,12 @@ mod item;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
pub use item::BreadcrumbItem;
|
pub use item::BreadcrumbItem;
|
||||||
use yew::{html::Children, prelude::*};
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Breadcrumb {
|
pub struct Breadcrumb {
|
||||||
props: Props,
|
props: Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, Clone, PartialEq)]
|
|
||||||
pub struct Props {
|
|
||||||
#[prop_or_default]
|
|
||||||
pub border: Option<Border>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub borders: Vec<Border>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub border_color: Option<BorderColor>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub border_colors: Vec<BorderColor>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub margin: Option<Margin>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub margins: Vec<Margin>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub class: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub style: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub children: Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for Breadcrumb {
|
impl Component for Breadcrumb {
|
||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
type Message = ();
|
type Message = ();
|
||||||
|
@ -47,9 +25,10 @@ impl Component for Breadcrumb {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
|
let class = calculate_classes("breadcrumb", (&self.props).into());
|
||||||
html! {
|
html! {
|
||||||
<nav
|
<nav
|
||||||
class=self.props.class.clone()
|
class=class
|
||||||
aria-label="breadcrumb"
|
aria-label="breadcrumb"
|
||||||
style=self.props.style.clone()
|
style=self.props.style.clone()
|
||||||
>
|
>
|
||||||
|
@ -62,16 +41,3 @@ impl Component for Breadcrumb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a Props> for BootstrapProps<'a> {
|
|
||||||
fn from(props: &Props) -> BootstrapProps {
|
|
||||||
let borders = collect_bs(&props.border, &props.borders);
|
|
||||||
let border_colors = collect_bs(&props.border_color, &props.border_colors);
|
|
||||||
let margins = collect_bs(&props.margin, &props.margins);
|
|
||||||
BootstrapProps {
|
|
||||||
borders,
|
|
||||||
border_colors,
|
|
||||||
margins,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,24 +1,10 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use yew::{html::Children, prelude::*};
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct ButtonGroup {
|
pub struct ButtonGroup {
|
||||||
props: Props,
|
props: Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, Clone, PartialEq)]
|
|
||||||
pub struct Props {
|
|
||||||
#[prop_or_default]
|
|
||||||
pub class: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub style: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub role: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub aria_label: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub children: Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for ButtonGroup {
|
impl Component for ButtonGroup {
|
||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
type Message = ();
|
type Message = ();
|
||||||
|
@ -38,7 +24,7 @@ impl Component for ButtonGroup {
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div class=self.class()
|
<div class=self.class()
|
||||||
style=self.style()
|
style=self.props.style.clone()
|
||||||
role=self.props.role.clone()
|
role=self.props.role.clone()
|
||||||
aria-label=self.props.aria_label.clone()
|
aria-label=self.props.aria_label.clone()
|
||||||
>
|
>
|
||||||
|
@ -56,12 +42,4 @@ impl ButtonGroup {
|
||||||
format!("btn-group {}", self.props.class)
|
format!("btn-group {}", self.props.class)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> &str {
|
|
||||||
if self.props.style.is_empty() {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
&self.props.style
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,10 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use yew::{html::Children, prelude::*};
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct CardBody {
|
pub struct CardBody {
|
||||||
props: Props,
|
props: Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, Clone, PartialEq)]
|
|
||||||
pub struct Props {
|
|
||||||
#[prop_or_default]
|
|
||||||
pub class: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub style: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub children: Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for CardBody {
|
impl Component for CardBody {
|
||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
type Message = ();
|
type Message = ();
|
||||||
|
@ -32,28 +22,11 @@ impl Component for CardBody {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
|
let class = calculate_classes("card-body", (&self.props).into());
|
||||||
html! {
|
html! {
|
||||||
<div class=self.class() style=self.style()>
|
<div class=class style=self.props.style.clone()>
|
||||||
{ self.props.children.render() }
|
{ self.props.children.render() }
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CardBody {
|
|
||||||
fn class(&self) -> String {
|
|
||||||
if self.props.class.is_empty() {
|
|
||||||
"card-body".into()
|
|
||||||
} else {
|
|
||||||
format!("card-body {}", self.props.class)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn style(&self) -> &str {
|
|
||||||
if self.props.style.is_empty() {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
&self.props.style
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,34 +4,12 @@ mod text;
|
||||||
|
|
||||||
pub use self::{body::CardBody, header::CardHeader, text::CardText};
|
pub use self::{body::CardBody, header::CardHeader, text::CardText};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use yew::{html::Children, prelude::*};
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Card {
|
pub struct Card {
|
||||||
props: Props,
|
props: Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, Clone, PartialEq)]
|
|
||||||
pub struct Props {
|
|
||||||
#[prop_or_default]
|
|
||||||
pub margin: Option<Margin>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub margins: Vec<Margin>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub border: Option<Border>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub borders: Vec<Border>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub border_color: Option<BorderColor>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub border_colors: Vec<BorderColor>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub class: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub style: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub children: Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for Card {
|
impl Component for Card {
|
||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
type Message = ();
|
type Message = ();
|
||||||
|
@ -49,45 +27,11 @@ impl Component for Card {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
|
let class = calculate_classes("card", (&self.props).into());
|
||||||
html! {
|
html! {
|
||||||
<div class=self.class() style=self.style()>
|
<div class=class style=self.props.style.clone()>
|
||||||
{ self.props.children.render() }
|
{ self.props.children.render() }
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Card {
|
|
||||||
fn class(&self) -> String {
|
|
||||||
if self.props.class.is_empty() {
|
|
||||||
format!("card {}", calculate_classes((&self.props).into()))
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"card {} {}",
|
|
||||||
self.props.class,
|
|
||||||
calculate_classes((&self.props).into())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn style(&self) -> &str {
|
|
||||||
if self.props.style.is_empty() {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
&self.props.style
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a Props> for BootstrapProps<'a> {
|
|
||||||
fn from(props: &'a Props) -> Self {
|
|
||||||
let borders = collect_bs(&props.border, &props.borders);
|
|
||||||
let border_colors = collect_bs(&props.border_color, &props.border_colors);
|
|
||||||
let margins = collect_bs(&props.margin, &props.margins);
|
|
||||||
Self {
|
|
||||||
borders,
|
|
||||||
border_colors,
|
|
||||||
margins,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use yew::{html::Children, prelude::*};
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Container {
|
pub struct Container {
|
||||||
props: Props,
|
props: Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, Clone, PartialEq)]
|
|
||||||
pub struct Props {
|
|
||||||
#[prop_or_default]
|
|
||||||
pub children: Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for Container {
|
impl Component for Container {
|
||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
type Message = ();
|
type Message = ();
|
||||||
|
@ -29,9 +23,31 @@ impl Component for Container {
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div class="container">
|
<div class=calculate_classes("container", (&self.props).into())>
|
||||||
{ self.props.children.render() }
|
{ self.props.children.render() }
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let container = Container {
|
||||||
|
props: Props {
|
||||||
|
margin: Some(Margin(Edge::All, 3)),
|
||||||
|
padding: Some(Padding(Edge::Top, 3)),
|
||||||
|
..Props::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let expected = html! {
|
||||||
|
<div class="container m-3 pt-3">
|
||||||
|
<></>
|
||||||
|
</div>
|
||||||
|
};
|
||||||
|
assert_eq!(expected, container.view());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,35 +1,10 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use yew::{html::Children, prelude::*};
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct InputGroup {
|
pub struct InputGroup {
|
||||||
props: Props,
|
props: Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, Clone, PartialEq)]
|
|
||||||
pub struct Props {
|
|
||||||
#[prop_or_default]
|
|
||||||
pub margin: Option<Margin>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub margins: Vec<Margin>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub class: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub children: Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a Props> for BootstrapProps<'a> {
|
|
||||||
fn from(props: &'a Props) -> BootstrapProps<'a> {
|
|
||||||
let borders = Vec::new();
|
|
||||||
let border_colors = Vec::new();
|
|
||||||
let margins = collect_bs(&props.margin, &props.margins);
|
|
||||||
Self {
|
|
||||||
borders,
|
|
||||||
border_colors,
|
|
||||||
margins,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for InputGroup {
|
impl Component for InputGroup {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
|
@ -47,9 +22,9 @@ impl Component for InputGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
let classes = calculate_classes((&self.props).into());
|
let class = calculate_classes("input-group", (&self.props).into());
|
||||||
html! {
|
html! {
|
||||||
<div class=format!("input-group {} {}", classes, self.props.class)>
|
<div class=class>
|
||||||
{ self.props.children.render() }
|
{ self.props.children.render() }
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,12 +33,28 @@ pub struct Props {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub on_signal: Callback<String>,
|
pub on_change: Callback<String>,
|
||||||
pub input_type: InputType,
|
pub input_type: InputType,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub readonly: bool,
|
pub readonly: bool,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub value: String,
|
pub value: 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Input {
|
impl Component for Input {
|
||||||
|
@ -53,7 +69,7 @@ impl Component for Input {
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
if let InputChange(ChangeData::Value(value)) = msg {
|
if let InputChange(ChangeData::Value(value)) = msg {
|
||||||
self.state = value.clone();
|
self.state = value.clone();
|
||||||
self.props.on_signal.emit(value);
|
self.props.on_change.emit(value);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -69,9 +85,9 @@ impl Component for Input {
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
let class = if self.props.readonly {
|
let class = if self.props.readonly {
|
||||||
"form-control-plaintext pl-3"
|
calculate_classes("form-control-plaintext", (&self.props).into())
|
||||||
} else {
|
} else {
|
||||||
"form-control"
|
calculate_classes("form-control", (&self.props).into())
|
||||||
};
|
};
|
||||||
html! {
|
html! {
|
||||||
<input
|
<input
|
||||||
|
@ -86,3 +102,18 @@ impl Component for Input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,23 @@ pub struct Props {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub on_signal: Callback<String>,
|
pub on_change: Callback<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,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for TextArea {
|
impl Component for TextArea {
|
||||||
|
@ -31,7 +47,7 @@ impl Component for TextArea {
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
if let InputChange(ChangeData::Value(value)) = msg {
|
if let InputChange(ChangeData::Value(value)) = msg {
|
||||||
self.state = value.clone();
|
self.state = value.clone();
|
||||||
self.props.on_signal.emit(value);
|
self.props.on_change.emit(value);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -47,7 +63,7 @@ impl Component for TextArea {
|
||||||
<textarea
|
<textarea
|
||||||
name=&self.props.name
|
name=&self.props.name
|
||||||
id=&self.props.id
|
id=&self.props.id
|
||||||
class="form-control"
|
class=calculate_classes("form-control", (&self.props).into())
|
||||||
onchange=self.link.callback(|evt| InputChange(evt))
|
onchange=self.link.callback(|evt| InputChange(evt))
|
||||||
>
|
>
|
||||||
{ &self.state }
|
{ &self.state }
|
||||||
|
@ -55,3 +71,18 @@ impl Component for TextArea {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,22 +1,10 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use yew::{html::Children, prelude::*};
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Jumbotron {
|
pub struct Jumbotron {
|
||||||
props: Props,
|
props: Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, Clone)]
|
|
||||||
pub struct Props {
|
|
||||||
#[prop_or_default]
|
|
||||||
pub margin: Option<Margin>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub margins: Vec<Margin>,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub class: String,
|
|
||||||
#[prop_or_default]
|
|
||||||
pub children: Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for Jumbotron {
|
impl Component for Jumbotron {
|
||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
type Message = ();
|
type Message = ();
|
||||||
|
@ -34,8 +22,9 @@ impl Component for Jumbotron {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
|
let class = calculate_classes("jumbotron", (&self.props).into());
|
||||||
html! {
|
html! {
|
||||||
<div class=format!("jumbotron {}", self.props.class)>
|
<div class=class>
|
||||||
{ self.props.children.render() }
|
{ self.props.children.render() }
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,13 @@
|
||||||
|
use super::{Color, Edge};
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum Border {
|
pub struct Border(pub Edge, pub Color);
|
||||||
All,
|
|
||||||
Top,
|
|
||||||
Right,
|
|
||||||
Bottom,
|
|
||||||
Left,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl super::BootstrapClass for Border {
|
impl super::BootstrapClass for Border {
|
||||||
fn as_classname(&self) -> String {
|
fn as_classname(&self) -> String {
|
||||||
match self {
|
let edge = match self.0 {
|
||||||
Self::All => "border".into(),
|
Edge::All => "border".to_owned(),
|
||||||
Self::Top => "border-top".into(),
|
_ => self.0.with_prefix("border"),
|
||||||
Self::Right => "border-right".into(),
|
};
|
||||||
Self::Bottom => "border-bottom".into(),
|
format!("{} {}", edge, self.1.with_prefix("border"))
|
||||||
Self::Left => "border-left".into(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
pub enum BorderColor {
|
|
||||||
Primary,
|
|
||||||
Secondary,
|
|
||||||
Unset,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for BorderColor {
|
|
||||||
fn default() -> Self {
|
|
||||||
BorderColor::Unset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl super::BootstrapClass for BorderColor {
|
|
||||||
fn as_classname(&self) -> String {
|
|
||||||
match self {
|
|
||||||
Self::Primary => "border-primary".into(),
|
|
||||||
Self::Secondary => "border-secondary".into(),
|
|
||||||
Self::Unset => "".into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
36
src/prelude/color.rs
Normal file
36
src/prelude/color.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub enum Color {
|
||||||
|
Primary,
|
||||||
|
Secondary,
|
||||||
|
Success,
|
||||||
|
Danger,
|
||||||
|
Warning,
|
||||||
|
Info,
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
White,
|
||||||
|
Unset,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Color {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Unset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
pub fn with_prefix<S: AsRef<str>>(&self, prefix: S) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Primary => format!("{}-primary", prefix.as_ref()),
|
||||||
|
Self::Secondary => format!("{}-secondary", prefix.as_ref()),
|
||||||
|
Self::Success => format!("{}-success", prefix.as_ref()),
|
||||||
|
Self::Danger => format!("{}-danger", prefix.as_ref()),
|
||||||
|
Self::Warning => format!("{}-warning", prefix.as_ref()),
|
||||||
|
Self::Info => format!("{}-info", prefix.as_ref()),
|
||||||
|
Self::Light => format!("{}-light", prefix.as_ref()),
|
||||||
|
Self::Dark => format!("{}-dark", prefix.as_ref()),
|
||||||
|
Self::White => format!("{}-white", prefix.as_ref()),
|
||||||
|
Self::Unset => "".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +1,102 @@
|
||||||
mod border;
|
mod border;
|
||||||
mod border_color;
|
mod color;
|
||||||
mod margin;
|
mod margin;
|
||||||
|
mod padding;
|
||||||
|
|
||||||
pub use self::{border::Border, border_color::BorderColor, margin::Margin};
|
pub use self::{border::Border, color::Color, margin::Margin, padding::Padding};
|
||||||
use std::fmt::{Display, Formatter, Result};
|
use std::fmt::{Display, Formatter, Result};
|
||||||
use yew::prelude::*;
|
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)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Edge {
|
pub enum Edge {
|
||||||
|
All,
|
||||||
Top,
|
Top,
|
||||||
Right,
|
Right,
|
||||||
Bottom,
|
Bottom,
|
||||||
Left,
|
Left,
|
||||||
|
LeftAndRight,
|
||||||
|
TopAndBottom,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Edge {
|
impl Display for Edge {
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
||||||
match self {
|
match self {
|
||||||
|
Self::All => write!(fmt, ""),
|
||||||
Self::Top => write!(fmt, "t"),
|
Self::Top => write!(fmt, "t"),
|
||||||
Self::Bottom => write!(fmt, "b"),
|
Self::Bottom => write!(fmt, "b"),
|
||||||
Self::Right => write!(fmt, "r"),
|
Self::Right => write!(fmt, "r"),
|
||||||
Self::Left => write!(fmt, "l"),
|
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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,9 +106,10 @@ trait BootstrapClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BootstrapProps<'a> {
|
pub struct BootstrapProps<'a> {
|
||||||
|
pub class: &'a str,
|
||||||
pub borders: Vec<&'a Border>,
|
pub borders: Vec<&'a Border>,
|
||||||
pub border_colors: Vec<&'a BorderColor>,
|
|
||||||
pub margins: Vec<&'a Margin>,
|
pub margins: Vec<&'a Margin>,
|
||||||
|
pub paddings: Vec<&'a Padding>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_on_change<P: Properties + PartialEq>(
|
pub fn render_on_change<P: Properties + PartialEq>(
|
||||||
|
@ -57,16 +134,23 @@ pub fn collect_bs<'a, T>(t: &'a Option<T>, ts: &'a [T]) -> Vec<&'a T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_classes(props: BootstrapProps) -> String {
|
pub fn calculate_classes<S: AsRef<str>>(prefix: S, props: BootstrapProps) -> String {
|
||||||
let BootstrapProps {
|
let BootstrapProps {
|
||||||
|
class,
|
||||||
borders,
|
borders,
|
||||||
border_colors,
|
|
||||||
margins,
|
margins,
|
||||||
|
paddings,
|
||||||
} = props;
|
} = props;
|
||||||
let mut classes = Vec::new();
|
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(borders));
|
||||||
classes.append(&mut into_classnames(border_colors));
|
|
||||||
classes.append(&mut into_classnames(margins));
|
classes.append(&mut into_classnames(margins));
|
||||||
|
classes.append(&mut into_classnames(paddings));
|
||||||
|
|
||||||
classes.join(" ")
|
classes.join(" ")
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,6 @@ pub struct Padding(pub super::Edge, pub usize);
|
||||||
|
|
||||||
impl super::BootstrapClass for Padding {
|
impl super::BootstrapClass for Padding {
|
||||||
fn as_classname(&self) -> String {
|
fn as_classname(&self) -> String {
|
||||||
format!("m{}-{}", self.0, self.1)
|
format!("p{}-{}", self.0, self.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue