Add input toolbar, button.

This commit is contained in:
Thomas Gideon 2020-06-24 17:16:43 -04:00
parent 9d76d16d7e
commit 88e53935b4
7 changed files with 223 additions and 11 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "bootstrap-rs"
version = "0.2.9"
version = "0.2.10"
authors = ["Thomas Gideon <cmdln@thecommandline.net>"]
edition = "2018"

27
src/button/group.rs Normal file
View File

@ -0,0 +1,27 @@
use crate::{prelude::render_on_change, props::Props, render};
use yew::prelude::*;
pub struct ButtonGroup {
props: Props,
}
impl Component for ButtonGroup {
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 {
render::render_with_prefix(&self.props, "btn-group", render::div(&self.props.children))
}
}

View File

@ -1,19 +1,52 @@
use crate::{prelude::render_on_change, props::Props, render};
mod group;
mod props;
mod toolbar;
use self::props::Props;
pub use self::{group::ButtonGroup, toolbar::ButtonToolbar};
use crate::{prelude::render_on_change, render};
use std::fmt::{Display, Formatter, Result};
use yew::prelude::*;
pub struct ButtonGroup {
#[derive(Clone, PartialEq)]
pub enum ButtonType {
Button,
Submit,
Reset,
}
impl Default for ButtonType {
fn default() -> Self {
ButtonType::Button
}
}
impl Display for ButtonType {
fn fmt(&self, f: &mut Formatter) -> Result {
use ButtonType::*;
match self {
Submit => write!(f, "submit"),
Reset => write!(f, "reset"),
_ => write!(f, "button"),
}
}
}
pub struct Button {
link: ComponentLink<Self>,
props: Props,
}
impl Component for ButtonGroup {
impl Component for Button {
type Properties = Props;
type Message = ();
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
Self { props }
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
Self { link, props }
}
fn update(&mut self, _: Self::Message) -> ShouldRender {
self.props.on_click.emit(());
false
}
@ -22,6 +55,43 @@ impl Component for ButtonGroup {
}
fn view(&self) -> Html {
render::render_with_prefix(&self.props, "btn-group", render::div(&self.props.children))
let html = html! {
<button
button=self.props.button_type
onclick=self.link.callback(|_| ())
disabled=self.props.disabled.unwrap_or_default()
>
{ self.props.children.render() }
</button>
};
render::render_with_prefix(&self.props, self.calculate_prefix(), html)
}
}
impl Button {
fn calculate_prefix(&self) -> Classes {
let mut prefix = Classes::from("btn");
if self.props.active.unwrap_or_default() {
prefix.push("active");
}
if let Some(ref color) = self.props.color {
prefix.push(&color.with_prefix("btn"));
}
if let Some(ref outline) = self.props.outline {
prefix.push(&outline.with_prefix("btn-outline"));
}
if self.props.text_nowrap.unwrap_or_default() {
prefix.push("text-nowrap");
}
if self.props.small.unwrap_or_default() {
prefix.push("btn-sm");
}
if self.props.large.unwrap_or_default() {
prefix.push("btn-lg");
}
if self.props.block.unwrap_or_default() {
prefix.push("btn-block");
}
prefix
}
}

81
src/button/props.rs Normal file
View File

@ -0,0 +1,81 @@
use super::ButtonType;
use crate::{
prelude::*,
props::{add_opt_attr, collect_props, BootstrapProps},
};
use std::collections::HashMap;
use yew::{html::Children, prelude::*};
#[derive(Properties, Clone, PartialEq, Default)]
pub struct Props {
// component specific
#[prop_or_default]
pub on_click: Callback<()>,
#[prop_or_default]
pub button_type: ButtonType,
#[prop_or_default]
pub active: Option<bool>,
#[prop_or_default]
pub disabled: Option<bool>,
#[prop_or_default]
pub text_nowrap: Option<bool>,
// bootstrap specific
#[prop_or_default]
pub color: Option<Color>,
#[prop_or_default]
pub outline: Option<Color>,
#[prop_or_default]
pub small: Option<bool>,
#[prop_or_default]
pub large: Option<bool>,
#[prop_or_default]
pub block: Option<bool>,
#[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>,
// html specific
#[prop_or_default]
pub id: Option<String>,
#[prop_or_default]
pub class: Classes,
#[prop_or_default]
pub style: Option<String>,
#[prop_or_default]
pub aria_label: Option<String>,
#[prop_or_default]
pub aria_describedby: Option<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_props(&props.border, &props.borders);
let margins = collect_props(&props.margin, &props.margins);
let paddings = collect_props(&props.padding, &props.paddings);
let mut attributes = HashMap::new();
add_opt_attr(&mut attributes, "id", &props.id);
add_opt_attr(&mut attributes, "style", &props.style);
add_opt_attr(&mut attributes, "aria-label", &props.aria_label);
add_opt_attr(&mut attributes, "aria-describedby", &props.aria_describedby);
BootstrapProps {
class,
borders,
margins,
paddings,
attributes,
}
}
}

31
src/button/toolbar.rs Normal file
View File

@ -0,0 +1,31 @@
use crate::{prelude::render_on_change, props::Props, render};
use yew::prelude::*;
pub struct ButtonToolbar {
props: Props,
}
impl Component for ButtonToolbar {
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 {
render::render_with_prefix(
&self.props,
"btn-toolbar",
render::div(&self.props.children),
)
}
}

View File

@ -13,7 +13,7 @@ mod render;
pub use self::{
alert::Alert,
breadcrumb::{Breadcrumb, BreadcrumbItem},
button::ButtonGroup,
button::{Button, ButtonGroup, ButtonToolbar},
card::{Card, CardBody, CardHeader, CardText},
container::Container,
form::FormGroup,

View File

@ -36,14 +36,17 @@ pub(crate) fn p(children: &Children) -> Html {
#[cfg(test)]
mod tests {
use super::*;
use crate::props::Props;
use crate::{prelude::*, props::Props};
#[test]
fn test_multiple_prefixes() {
let props = Props::default();
let props = Props {
margin: Some(Margin(Edge::All, 3)),
..Props::default()
};
let comp = render_with_prefix(&props, vec!["first", "second"], html! { <div/> });
let expected = html! {
<div class="first second"/>
<div class="first second m-3"/>
};
assert_eq!(expected, comp);