Progressbar (#27)

This commit is contained in:
nbrr 2020-09-29 16:57:31 +02:00 committed by GitHub
parent 20a39e8107
commit e433e11db7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 261 additions and 3 deletions

View file

@ -79,7 +79,7 @@ Roadmap
- [ ] [Navbar](https://blueprintjs.com/docs/#core/components/navbar) - [ ] [Navbar](https://blueprintjs.com/docs/#core/components/navbar)
- [ ] [OverflowList](https://blueprintjs.com/docs/#core/components/overflow-list) - [ ] [OverflowList](https://blueprintjs.com/docs/#core/components/overflow-list)
- [ ] [PanelStack](https://blueprintjs.com/docs/#core/components/panel-stack) - [ ] [PanelStack](https://blueprintjs.com/docs/#core/components/panel-stack)
- [ ] [ProgressBar](https://blueprintjs.com/docs/#core/components/progress-bar) - [x] [ProgressBar](https://blueprintjs.com/docs/#core/components/progress-bar)
- [ ] [ResizeSensor](https://blueprintjs.com/docs/#core/components/resize-sensor) - [ ] [ResizeSensor](https://blueprintjs.com/docs/#core/components/resize-sensor)
- [ ] [Skeleton](https://blueprintjs.com/docs/#core/components/skeleton) - [ ] [Skeleton](https://blueprintjs.com/docs/#core/components/skeleton)
- [ ] [Spinner](https://blueprintjs.com/docs/#core/components/spinner) - [ ] [Spinner](https://blueprintjs.com/docs/#core/components/spinner)
@ -131,5 +131,5 @@ Roadmap
- [ ] [MultiSelect](https://blueprintjs.com/docs/#select/multi-select) - [ ] [MultiSelect](https://blueprintjs.com/docs/#select/multi-select)
- [ ] [Omnibar](https://blueprintjs.com/docs/#select/omnibar) - [ ] [Omnibar](https://blueprintjs.com/docs/#select/omnibar)
- [ ] [QueryList](https://blueprintjs.com/docs/#select/query-list) - [ ] [QueryList](https://blueprintjs.com/docs/#select/query-list)
- [ ] [Table](https://blueprintjs.com/docs/#select/query-list) - [ ] [Table](https://blueprintjs.com/docs/#table)
- [ ] [TimezonePicker](https://blueprintjs.com/docs/#timezone) - [ ] [TimezonePicker](https://blueprintjs.com/docs/#timezone)

View file

@ -4,6 +4,8 @@ use crate::collapse::*;
use crate::icon::*; use crate::icon::*;
use crate::switch::*; use crate::switch::*;
use crate::tree::*; use crate::tree::*;
use crate::progressbar::*;
use yew::prelude::*; use yew::prelude::*;
use yewprint::{ConditionalClass, IconName, Menu, MenuItem}; use yewprint::{ConditionalClass, IconName, Menu, MenuItem};
@ -123,6 +125,10 @@ impl Component for App {
text={html!("Tree")} text={html!("Tree")}
onclick=self.link.callback(|_| Msg::GoToMenu(DocMenu::Tree)) onclick=self.link.callback(|_| Msg::GoToMenu(DocMenu::Tree))
/> />
<MenuItem
text={html!("ProgressBar")}
onclick=self.link.callback(|_| Msg::GoToMenu(DocMenu::ProgressBar))
/>
</Menu> </Menu>
<div class="docs-nav-sponsors"> <div class="docs-nav-sponsors">
<a href="https://www.netlify.com"> <a href="https://www.netlify.com">
@ -147,6 +153,7 @@ impl Component for App {
DocMenu::Collapse => html!(<CollapseDoc />), DocMenu::Collapse => html!(<CollapseDoc />),
DocMenu::Tree => html!(<TreeDoc />), DocMenu::Tree => html!(<TreeDoc />),
DocMenu::Icon => html!(<IconDoc />), DocMenu::Icon => html!(<IconDoc />),
DocMenu::ProgressBar => html!(<ProgressBarDoc />),
DocMenu::Menu => html!(), DocMenu::Menu => html!(),
} }
} }
@ -167,4 +174,5 @@ pub enum DocMenu {
Menu, Menu,
Switch, Switch,
Tree, Tree,
ProgressBar,
} }

View file

@ -6,6 +6,7 @@ mod example;
mod icon; mod icon;
mod switch; mod switch;
mod tree; mod tree;
mod progressbar;
pub use app::*; pub use app::*;
pub use example::*; pub use example::*;

View file

@ -0,0 +1,43 @@
use yew::prelude::*;
use yewprint::{ProgressBar, Intent};
pub struct Example {
props: ExampleProps,
}
#[derive(Clone, PartialEq, Properties)]
pub struct ExampleProps {
pub intent: Option<Intent>,
pub animate: bool,
pub stripes: bool,
}
impl Component for Example {
type Message = ();
type Properties = ExampleProps;
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
Example { props }
}
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
true
}
fn change(&mut self, props: Self::Properties) -> ShouldRender {
if self.props != props {
self.props = props;
true
} else {
false
}
}
fn view(&self) -> Html {
html! {
<ProgressBar
animate=self.props.animate
stripes=self.props.stripes
intent=self.props.intent
value=0.3
/>
}
}
}

View file

@ -0,0 +1,133 @@
mod example;
use crate::ExampleContainer;
use example::*;
use yew::prelude::*;
use yewprint::{Intent, Menu, MenuItem, Switch, H1, H5};
pub struct ProgressBarDoc {
callback: Callback<ExampleProps>,
state: ExampleProps,
}
impl Component for ProgressBarDoc {
type Message = ExampleProps;
type Properties = ();
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
ProgressBarDoc {
callback: link.callback(|x| x),
state: ExampleProps {
intent: None,
animate: false,
stripes: false
},
}
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
self.state = msg;
true
}
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
true
}
fn view(&self) -> Html {
let example_props = self.state.clone();
let source = crate::include_raw_html!(
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
"bp3-code-block"
);
html! {
<div>
<H1 class="docs-title">{"ProgressBar"}</H1>
<ExampleContainer
source=source
props=Some(html! {
<ProgressBarProps
callback={self.callback.clone()}
props=example_props.clone()
/>
})
>
<Example with example_props />
</ExampleContainer>
</div>
}
}
}
crate::build_example_prop_component! {
ProgressBarProps for ExampleProps =>
fn view(&self) -> Html {
html! {
<div>
<H5>{"Props"}</H5>
<div>
<Switch
onclick=self.update_props(|props| ExampleProps {
stripes: !props.stripes,
..props
})
checked=self.props.stripes
label="Stripes"
/>
<Switch
onclick=self.update_props(|props| ExampleProps {
animate: !props.animate,
..props
})
checked=self.props.animate
label="animate"
/>
<p>{"Select intent:"}</p>
<Menu>
<MenuItem
onclick=self.update_props(|props| ExampleProps {
intent: None,
..props
})
text=html!{"None"}
/>
<MenuItem
onclick=self.update_props(|props| ExampleProps {
intent: Some(Intent::Primary),
..props
})
text=html!{"Primary"}
intent=Intent::Primary
/>
<MenuItem
onclick=self.update_props(|props| ExampleProps {
intent: Some(Intent::Success),
..props
})
text=html!{"Success"}
intent=Intent::Success
/>
<MenuItem
onclick=self.update_props(|props| ExampleProps {
intent: Some(Intent::Warning),
..props
})
text=html!{"Warning"}
intent=Intent::Warning
/>
<MenuItem
onclick=self.update_props(|props| ExampleProps {
intent: Some(Intent::Danger),
..props
})
text=html!{"Danger"}
intent=Intent::Danger
/>
</Menu>
</div>
</div>
}
}
}

View file

@ -4,6 +4,7 @@ mod collapse;
mod html_elements; mod html_elements;
mod icon; mod icon;
mod menu; mod menu;
mod progressbar;
mod switch; mod switch;
mod tree; mod tree;
@ -14,10 +15,11 @@ pub use html_elements::*;
pub use icon::*; pub use icon::*;
pub use id_tree; pub use id_tree;
pub use menu::*; pub use menu::*;
pub use progressbar::*;
pub use switch::*; pub use switch::*;
pub use tree::*; pub use tree::*;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut, Not};
use yew::virtual_dom::{Classes, Transformer, VComp}; use yew::virtual_dom::{Classes, Transformer, VComp};
// NOTE: this class needs to become deprecated when the feature bool_to_option lands in stable // NOTE: this class needs to become deprecated when the feature bool_to_option lands in stable
@ -68,6 +70,14 @@ impl DerefMut for ConditionalClass {
} }
} }
impl Not for ConditionalClass {
type Output = ConditionalClass;
fn not(self) -> Self::Output {
ConditionalClass(!self.0)
}
}
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub enum Intent { pub enum Intent {
Primary, Primary,

View file

@ -0,0 +1,63 @@
use crate::{ConditionalClass, Intent};
use yew::prelude::*;
pub struct ProgressBar {
props: Props,
}
#[derive(Clone, PartialEq, Properties)]
pub struct Props {
#[prop_or_default]
pub animate: ConditionalClass,
#[prop_or_default]
pub stripes: ConditionalClass,
#[prop_or_default]
pub value: Option<f32>,
#[prop_or_default]
pub intent: Option<Intent>,
}
impl Component for ProgressBar {
type Message = ();
type Properties = Props;
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
Self { props }
}
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
true
}
fn change(&mut self, props: Self::Properties) -> ShouldRender {
if self.props != props {
self.props = props;
true
} else {
false
}
}
fn view(&self) -> Html {
let width = if let Some(value) = self.props.value {
// NOTE: nightly, issue #44095 for f32::clamp
// let percent = ((1000. * value).ceil() / 10.).clamp(0.,100.);
let percent = ((1000. * value).ceil() / 10.).max(0.).min(100.);
format!("width: {}%;", percent)
} else {
"".into()
};
html! {
<div
class=(
"bp3-progress-bar",
self.props.intent,
(!self.props.animate).map_some("bp3-no-animation"),
(!self.props.stripes).map_some("bp3-no-stripes")
)
>
<div class="bp3-progress-meter" style={{width}}/>
</div>
}
}
}