Add input toolbar, button.
This commit is contained in:
parent
9d76d16d7e
commit
88e53935b4
7 changed files with 223 additions and 11 deletions
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "bootstrap-rs"
|
name = "bootstrap-rs"
|
||||||
version = "0.2.9"
|
version = "0.2.10"
|
||||||
authors = ["Thomas Gideon <cmdln@thecommandline.net>"]
|
authors = ["Thomas Gideon <cmdln@thecommandline.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
|
27
src/button/group.rs
Normal file
27
src/button/group.rs
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
|
@ -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::*;
|
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,
|
props: Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for ButtonGroup {
|
impl Component for Button {
|
||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
type Message = ();
|
type Message = ();
|
||||||
|
|
||||||
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
|
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||||
Self { props }
|
Self { link, props }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
||||||
|
self.props.on_click.emit(());
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +55,43 @@ impl Component for ButtonGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
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
81
src/button/props.rs
Normal 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
31
src/button/toolbar.rs
Normal 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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ mod render;
|
||||||
pub use self::{
|
pub use self::{
|
||||||
alert::Alert,
|
alert::Alert,
|
||||||
breadcrumb::{Breadcrumb, BreadcrumbItem},
|
breadcrumb::{Breadcrumb, BreadcrumbItem},
|
||||||
button::ButtonGroup,
|
button::{Button, ButtonGroup, ButtonToolbar},
|
||||||
card::{Card, CardBody, CardHeader, CardText},
|
card::{Card, CardBody, CardHeader, CardText},
|
||||||
container::Container,
|
container::Container,
|
||||||
form::FormGroup,
|
form::FormGroup,
|
||||||
|
|
|
@ -36,14 +36,17 @@ pub(crate) fn p(children: &Children) -> Html {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::props::Props;
|
use crate::{prelude::*, props::Props};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multiple_prefixes() {
|
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 comp = render_with_prefix(&props, vec!["first", "second"], html! { <div/> });
|
||||||
let expected = html! {
|
let expected = html! {
|
||||||
<div class="first second"/>
|
<div class="first second m-3"/>
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(expected, comp);
|
assert_eq!(expected, comp);
|
||||||
|
|
Loading…
Reference in a new issue