mirror of
https://github.com/yewprint/yewprint
synced 2025-02-16 12:08:25 +00:00
Yewprint upgrade 0.19 (#131)
Co-authored-by: Cecile Tonglet <cecile.tonglet@cecton.com> Co-authored-by: Francois Stephany <francois@tamere.eu>
This commit is contained in:
parent
9407209aa2
commit
3f96db6a7e
81 changed files with 2726 additions and 3824 deletions
766
Cargo.lock
generated
766
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -18,11 +18,13 @@ default = ["tree"]
|
||||||
tree = ["id_tree"]
|
tree = ["id_tree"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
web-sys = { version = "0.3", features = ["DomRect", "Element"] }
|
web-sys = { version = "0.3", features = ["DomRect", "Element", "Event", "HtmlSelectElement"] }
|
||||||
yew = "0.18"
|
# yew = { git = "https://github.com/yewstack/yew", branch = "master" }
|
||||||
|
yew = "0.19"
|
||||||
id_tree = { version = "1.7", optional = true }
|
id_tree = { version = "1.7", optional = true }
|
||||||
yewtil = { version = "0.4", features = ["pure"] }
|
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
|
gloo = "0.6"
|
||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
regex = { version = "1", default-features = false, features = ["std", "unicode-perl"] }
|
regex = { version = "1", default-features = false, features = ["std", "unicode-perl"] }
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct ButtonGroup {
|
|
||||||
props: ButtonGroupProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ButtonGroupProps {
|
pub struct ButtonGroupProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -16,49 +11,28 @@ pub struct ButtonGroupProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub large: bool,
|
pub large: bool,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub style: Option<Cow<'static, str>>,
|
pub style: Option<String>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub children: html::Children,
|
pub children: html::Children,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub class: Classes,
|
pub class: Classes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for ButtonGroup {
|
#[function_component(ButtonGroup)]
|
||||||
type Message = ();
|
pub fn button_group(props: &ButtonGroupProps) -> Html {
|
||||||
type Properties = ButtonGroupProps;
|
html! {
|
||||||
|
<div
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
class={classes!(
|
||||||
Self { props }
|
"bp3-button-group",
|
||||||
}
|
props.minimal.then(|| "bp3-minimal"),
|
||||||
|
props.fill.then(|| "bp3-fill"),
|
||||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
props.large.then(|| "bp3-large"),
|
||||||
true
|
props.vertical.then(|| "bp3-vertical"),
|
||||||
}
|
props.class.clone(),
|
||||||
|
)}
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
style={props.style.clone()}
|
||||||
if self.props != props {
|
>
|
||||||
self.props = props;
|
{props.children.clone()}
|
||||||
true
|
</div>
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<div
|
|
||||||
class=classes!(
|
|
||||||
"bp3-button-group",
|
|
||||||
self.props.minimal.then(|| "bp3-minimal"),
|
|
||||||
self.props.fill.then(|| "bp3-fill"),
|
|
||||||
self.props.large.then(|| "bp3-large"),
|
|
||||||
self.props.vertical.then(|| "bp3-vertical"),
|
|
||||||
self.props.class.clone(),
|
|
||||||
)
|
|
||||||
style=self.props.style.clone()
|
|
||||||
>
|
|
||||||
{self.props.children.clone()}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
127
src/buttons.rs
127
src/buttons.rs
|
@ -1,11 +1,6 @@
|
||||||
use crate::{Icon, IconName, Intent, Spinner, ICON_SIZE_LARGE};
|
use crate::{Icon, IconName, Intent, Spinner, ICON_SIZE_LARGE};
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Button {
|
|
||||||
props: ButtonProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ButtonProps {
|
pub struct ButtonProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -35,84 +30,62 @@ pub struct ButtonProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub class: Classes,
|
pub class: Classes,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub style: Option<Cow<'static, str>>,
|
pub style: Option<String>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub children: html::Children,
|
pub children: html::Children,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Button {
|
#[function_component(Button)]
|
||||||
type Message = ();
|
pub fn button(props: &ButtonProps) -> Html {
|
||||||
type Properties = ButtonProps;
|
html! {
|
||||||
|
<button
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
class={classes!(
|
||||||
Button { props }
|
"bp3-button",
|
||||||
}
|
props.fill.then(|| "bp3-fill"),
|
||||||
|
props.minimal.then(|| "bp3-minimal"),
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
props.small.then(|| "bp3-small"),
|
||||||
true
|
props.outlined.then(|| "bp3-outlined"),
|
||||||
}
|
props.loading.then(|| "bp3-loading"),
|
||||||
|
props.large.then(|| "bp3-large"),
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
(props.active && !props.disabled).then(|| "bp3-active"),
|
||||||
if self.props != props {
|
props.disabled.then(|| "bp3-disabled"),
|
||||||
self.props = props;
|
props.intent,
|
||||||
true
|
props.class.clone(),
|
||||||
} else {
|
)}
|
||||||
false
|
style={props.style.clone()}
|
||||||
}
|
onclick={(!props.disabled).then(|| props.onclick.clone())}
|
||||||
}
|
>
|
||||||
|
{
|
||||||
fn view(&self) -> Html {
|
props
|
||||||
html! {
|
.loading
|
||||||
<button
|
.then(|| html! {
|
||||||
class=classes!(
|
<Spinner
|
||||||
"bp3-button",
|
class={classes!("bp3-button-spinner")}
|
||||||
self.props.fill.then(|| "bp3-fill"),
|
size={ICON_SIZE_LARGE as f32}
|
||||||
self.props.minimal.then(|| "bp3-minimal"),
|
/>
|
||||||
self.props.small.then(|| "bp3-small"),
|
})
|
||||||
self.props.outlined.then(|| "bp3-outlined"),
|
.unwrap_or_default()
|
||||||
self.props.loading.then(|| "bp3-loading"),
|
}
|
||||||
self.props.large.then(|| "bp3-large"),
|
{
|
||||||
(self.props.active && !self.props.disabled).then(|| "bp3-active"),
|
if let Some(icon) = props.icon {
|
||||||
self.props.disabled.then(|| "bp3-disabled"),
|
html! {
|
||||||
self.props.intent,
|
<Icon icon={icon} />
|
||||||
self.props.class.clone(),
|
}
|
||||||
)
|
} else {
|
||||||
style=self.props.style.clone()
|
html!()
|
||||||
onclick=(!self.props.disabled).then(|| self.props.onclick.clone())
|
|
||||||
>
|
|
||||||
{
|
|
||||||
self
|
|
||||||
.props
|
|
||||||
.loading
|
|
||||||
.then(|| html! {
|
|
||||||
<Spinner
|
|
||||||
class=classes!("bp3-button-spinner")
|
|
||||||
size=ICON_SIZE_LARGE as f32
|
|
||||||
/>
|
|
||||||
})
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
}
|
||||||
{
|
}
|
||||||
if let Some(icon) = self.props.icon {
|
{
|
||||||
html! {
|
if props.children.is_empty() {
|
||||||
<Icon icon=icon />
|
html! ()
|
||||||
}
|
} else {
|
||||||
} else {
|
html! {
|
||||||
html!()
|
<span class="bp3-button-text">
|
||||||
|
{for props.children.iter()}
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
}
|
||||||
if self.props.children.is_empty() {
|
</button>
|
||||||
html! ()
|
|
||||||
} else {
|
|
||||||
html! {
|
|
||||||
<span class="bp3-button-text">
|
|
||||||
{for self.props.children.iter()}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
use crate::icon::ICON_SIZE_LARGE;
|
use crate::icon::ICON_SIZE_LARGE;
|
||||||
use crate::{Icon, IconName, Intent};
|
use crate::{Icon, IconName, Intent};
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Callout {
|
|
||||||
props: CalloutProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct CalloutProps {
|
pub struct CalloutProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -18,63 +13,43 @@ pub struct CalloutProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub intent: Option<Intent>,
|
pub intent: Option<Intent>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub title: Option<Cow<'static, str>>,
|
pub title: Option<String>,
|
||||||
pub children: html::Children,
|
pub children: html::Children,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Callout {
|
#[function_component(Callout)]
|
||||||
type Message = ();
|
pub fn callout(props: &CalloutProps) -> Html {
|
||||||
type Properties = CalloutProps;
|
let icon = if props.without_icon {
|
||||||
|
None
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
} else {
|
||||||
Self { props }
|
props.icon.or_else(|| {
|
||||||
}
|
props.intent.map(|intent| match intent {
|
||||||
|
Intent::Primary => IconName::InfoSign,
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
Intent::Success => IconName::Tick,
|
||||||
true
|
Intent::Warning => IconName::WarningSign,
|
||||||
}
|
Intent::Danger => IconName::Error,
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
|
||||||
if self.props == props {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let icon = if self.props.without_icon {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
self.props.icon.or_else(|| {
|
|
||||||
self.props.intent.map(|intent| match intent {
|
|
||||||
Intent::Primary => IconName::InfoSign,
|
|
||||||
Intent::Success => IconName::Tick,
|
|
||||||
Intent::Warning => IconName::WarningSign,
|
|
||||||
Intent::Danger => IconName::Error,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
};
|
})
|
||||||
let classes = classes!(
|
};
|
||||||
self.props.class.clone(),
|
let classes = classes!(
|
||||||
"bp3-callout",
|
props.class.clone(),
|
||||||
icon.map(|_| "bp3-callout-icon"),
|
"bp3-callout",
|
||||||
self.props.intent,
|
icon.map(|_| "bp3-callout-icon"),
|
||||||
);
|
props.intent,
|
||||||
html! {
|
);
|
||||||
<div class=classes>
|
html! {
|
||||||
{
|
<div class={classes}>
|
||||||
icon.iter()
|
{
|
||||||
.map(|name| html!{<Icon icon=*name icon_size=ICON_SIZE_LARGE/>})
|
icon.iter()
|
||||||
.collect::<Html>()
|
.map(|name| html!{<Icon icon={*name} icon_size={ICON_SIZE_LARGE}/>})
|
||||||
}
|
.collect::<Html>()
|
||||||
{
|
}
|
||||||
self.props.title.iter()
|
{
|
||||||
.map(|title| html!{<h4 class={"bp3-heading"}>{title}</h4>})
|
props.title.iter()
|
||||||
.collect::<Html>()
|
.map(|title| html!{<h4 class={"bp3-heading"}>{title}</h4>})
|
||||||
}
|
.collect::<Html>()
|
||||||
{ self.props.children.clone() }
|
}
|
||||||
</div>
|
{ props.children.clone() }
|
||||||
}
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
49
src/card.rs
49
src/card.rs
|
@ -14,42 +14,17 @@ pub struct CardProps {
|
||||||
pub children: html::Children,
|
pub children: html::Children,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Card {
|
#[function_component(Card)]
|
||||||
props: CardProps,
|
pub fn card(props: &CardProps) -> Html {
|
||||||
}
|
html! {
|
||||||
|
<div class={classes!(
|
||||||
impl Component for Card {
|
"bp3-card",
|
||||||
type Message = ();
|
props.class.clone(),
|
||||||
type Properties = CardProps;
|
props.elevation,
|
||||||
|
props.interactive.then(|| "bp3-interactive"),
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
)}
|
||||||
Self { props }
|
onclick={props.onclick.clone()}>
|
||||||
}
|
{props.children.clone()}
|
||||||
|
</div>
|
||||||
fn update(&mut self, _msg: Self::Message) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> bool {
|
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<div class=classes!(
|
|
||||||
"bp3-card",
|
|
||||||
self.props.class.clone(),
|
|
||||||
self.props.elevation,
|
|
||||||
self.props.interactive.then(|| "bp3-interactive"),
|
|
||||||
)
|
|
||||||
onclick={self.props.onclick.clone()}>
|
|
||||||
{self.props.children.clone()}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Checkbox {
|
|
||||||
props: Props,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct Props {
|
pub struct CheckboxProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -15,56 +11,35 @@ pub struct Props {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub checked: bool,
|
pub checked: bool,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub onchange: Callback<ChangeData>,
|
pub onchange: Callback<Event>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub label: yew::virtual_dom::VNode,
|
pub label: yew::virtual_dom::VNode,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub indeterminate_state: bool,
|
pub indeterminate_state: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Checkbox {
|
#[function_component(Checkbox)]
|
||||||
type Message = ();
|
pub fn checkbox(props: &CheckboxProps) -> Html {
|
||||||
type Properties = Props;
|
html! {
|
||||||
|
<label
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
class={classes!(
|
||||||
Self { props }
|
"bp3-control", "bp3-checkbox",
|
||||||
}
|
props.disabled.then(|| "bp3-disabled"),
|
||||||
|
props.inline.then(|| "bp3-inline"),
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
props.large.then(|| "bp3-large")
|
||||||
true
|
)}
|
||||||
}
|
>
|
||||||
|
<input
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
type="checkbox"
|
||||||
if self.props != props {
|
checked={props.checked}
|
||||||
self.props = props;
|
onchange={props.onchange.clone()}
|
||||||
true
|
disabled={props.disabled}
|
||||||
} else {
|
/>
|
||||||
false
|
<span
|
||||||
}
|
class="bp3-control-indicator"
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<label
|
|
||||||
class=classes!(
|
|
||||||
"bp3-control", "bp3-checkbox",
|
|
||||||
self.props.disabled.then(|| "bp3-disabled"),
|
|
||||||
self.props.inline.then(|| "bp3-inline"),
|
|
||||||
self.props.large.then(|| "bp3-large")
|
|
||||||
)
|
|
||||||
>
|
>
|
||||||
<input
|
</span>
|
||||||
type="checkbox"
|
{props.label.clone()}
|
||||||
checked={self.props.checked}
|
</label>
|
||||||
onchange={self.props.onchange.clone()}
|
|
||||||
disabled=self.props.disabled
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class="bp3-control-indicator"
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
{self.props.label.clone()}
|
|
||||||
</label>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
111
src/collapse.rs
111
src/collapse.rs
|
@ -1,7 +1,7 @@
|
||||||
use std::time::Duration;
|
use gloo::timers::callback::Timeout;
|
||||||
|
use std::{convert::TryInto, time::Duration};
|
||||||
use web_sys::Element;
|
use web_sys::Element;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew::services::*;
|
|
||||||
|
|
||||||
pub struct Collapse {
|
pub struct Collapse {
|
||||||
height: Height,
|
height: Height,
|
||||||
|
@ -11,10 +11,7 @@ pub struct Collapse {
|
||||||
height_when_open: Option<String>,
|
height_when_open: Option<String>,
|
||||||
animation_state: AnimationState,
|
animation_state: AnimationState,
|
||||||
contents_ref: NodeRef,
|
contents_ref: NodeRef,
|
||||||
callback_delayed_state_change: Callback<()>,
|
handle_delayed_state_change: Option<Timeout>,
|
||||||
handle_delayed_state_change: Option<Box<dyn Task>>,
|
|
||||||
props: CollapseProps,
|
|
||||||
link: ComponentLink<Self>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
@ -52,77 +49,83 @@ impl Component for Collapse {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
type Properties = CollapseProps;
|
type Properties = CollapseProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
Collapse {
|
Collapse {
|
||||||
height: if props.is_open {
|
height: if ctx.props().is_open {
|
||||||
Height::Auto
|
Height::Auto
|
||||||
} else {
|
} else {
|
||||||
Height::Zero
|
Height::Zero
|
||||||
},
|
},
|
||||||
overflow_visible: false,
|
overflow_visible: false,
|
||||||
translated: false,
|
translated: false,
|
||||||
render_children: props.is_open || props.keep_children_mounted,
|
render_children: ctx.props().is_open || ctx.props().keep_children_mounted,
|
||||||
height_when_open: None,
|
height_when_open: None,
|
||||||
animation_state: if props.is_open {
|
animation_state: if ctx.props().is_open {
|
||||||
AnimationState::Open
|
AnimationState::Open
|
||||||
} else {
|
} else {
|
||||||
AnimationState::Closed
|
AnimationState::Closed
|
||||||
},
|
},
|
||||||
contents_ref: NodeRef::default(),
|
contents_ref: NodeRef::default(),
|
||||||
callback_delayed_state_change: link.callback(|_| ()),
|
|
||||||
handle_delayed_state_change: None,
|
handle_delayed_state_change: None,
|
||||||
props,
|
|
||||||
link,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn changed(&mut self, ctx: &Context<Self>) -> bool {
|
||||||
if self.props != props {
|
if ctx.props().is_open {
|
||||||
if props.is_open {
|
match self.animation_state {
|
||||||
match self.animation_state {
|
AnimationState::Open | AnimationState::Opening => {}
|
||||||
AnimationState::Open | AnimationState::Opening => {}
|
_ => {
|
||||||
_ => {
|
self.animation_state = AnimationState::OpenStart;
|
||||||
self.animation_state = AnimationState::OpenStart;
|
self.render_children = true;
|
||||||
self.render_children = true;
|
self.translated = false;
|
||||||
self.translated = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match self.animation_state {
|
|
||||||
AnimationState::Closed | AnimationState::Closing => {}
|
|
||||||
_ => {
|
|
||||||
self.animation_state = AnimationState::ClosingStart;
|
|
||||||
self.height = Height::Full;
|
|
||||||
self.translated = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
} else {
|
||||||
false
|
match self.animation_state {
|
||||||
|
AnimationState::Closed | AnimationState::Closing => {}
|
||||||
|
_ => {
|
||||||
|
self.animation_state = AnimationState::ClosingStart;
|
||||||
|
self.height = Height::Full;
|
||||||
|
self.translated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||||
match self.animation_state {
|
match self.animation_state {
|
||||||
AnimationState::OpenStart => {
|
AnimationState::OpenStart => {
|
||||||
|
let link = ctx.link().clone();
|
||||||
self.animation_state = AnimationState::Opening;
|
self.animation_state = AnimationState::Opening;
|
||||||
self.height = Height::Full;
|
self.height = Height::Full;
|
||||||
self.handle_delayed_state_change = Some(Box::new(TimeoutService::spawn(
|
self.handle_delayed_state_change = Some(Timeout::new(
|
||||||
self.props.transition_duration,
|
ctx.props()
|
||||||
self.callback_delayed_state_change.clone(),
|
.transition_duration
|
||||||
)));
|
.as_millis()
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
move || {
|
||||||
|
link.send_message(());
|
||||||
|
},
|
||||||
|
));
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
AnimationState::ClosingStart => {
|
AnimationState::ClosingStart => {
|
||||||
|
let link = ctx.link().clone();
|
||||||
self.animation_state = AnimationState::Closing;
|
self.animation_state = AnimationState::Closing;
|
||||||
self.height = Height::Zero;
|
self.height = Height::Zero;
|
||||||
self.handle_delayed_state_change = Some(Box::new(TimeoutService::spawn(
|
self.handle_delayed_state_change = Some(Timeout::new(
|
||||||
self.props.transition_duration,
|
ctx.props()
|
||||||
self.callback_delayed_state_change.clone(),
|
.transition_duration
|
||||||
)));
|
.as_millis()
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
move || {
|
||||||
|
link.send_message(());
|
||||||
|
},
|
||||||
|
));
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
AnimationState::Opening => {
|
AnimationState::Opening => {
|
||||||
|
@ -132,7 +135,7 @@ impl Component for Collapse {
|
||||||
}
|
}
|
||||||
AnimationState::Closing => {
|
AnimationState::Closing => {
|
||||||
self.animation_state = AnimationState::Closed;
|
self.animation_state = AnimationState::Closed;
|
||||||
if !self.props.keep_children_mounted {
|
if !ctx.props().keep_children_mounted {
|
||||||
self.render_children = false;
|
self.render_children = false;
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -141,19 +144,19 @@ impl Component for Collapse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rendered(&mut self, _first_render: bool) {
|
fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
|
||||||
if self.render_children {
|
if self.render_children {
|
||||||
let client_height = self.contents_ref.cast::<Element>().unwrap().client_height();
|
let client_height = self.contents_ref.cast::<Element>().unwrap().client_height();
|
||||||
self.height_when_open = Some(format!("{}px", client_height));
|
self.height_when_open = Some(format!("{}px", client_height));
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.animation_state {
|
match self.animation_state {
|
||||||
AnimationState::OpenStart | AnimationState::ClosingStart => self.link.send_message(()),
|
AnimationState::OpenStart | AnimationState::ClosingStart => ctx.link().send_message(()),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
let mut container_style = String::with_capacity(30);
|
let mut container_style = String::with_capacity(30);
|
||||||
match (self.height, self.height_when_open.as_ref()) {
|
match (self.height, self.height_when_open.as_ref()) {
|
||||||
(Height::Zero, _) => container_style.push_str("height: 0px; "),
|
(Height::Zero, _) => container_style.push_str("height: 0px; "),
|
||||||
|
@ -179,19 +182,19 @@ impl Component for Collapse {
|
||||||
}
|
}
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class=classes!("bp3-collapse") style={container_style}>
|
<div class={classes!("bp3-collapse")} style={container_style}>
|
||||||
<div
|
<div
|
||||||
class=classes!(
|
class={classes!(
|
||||||
"bp3-collapse-body",
|
"bp3-collapse-body",
|
||||||
self.props.class.clone(),
|
ctx.props().class.clone(),
|
||||||
)
|
)}
|
||||||
style={content_style}
|
style={content_style}
|
||||||
aria-hidden={(!self.render_children).then(|| "true")}
|
aria-hidden={(!self.render_children).then(|| "true")}
|
||||||
ref={self.contents_ref.clone()}
|
ref={self.contents_ref.clone()}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
if self.render_children {
|
if self.render_children {
|
||||||
self.props.children.clone()
|
ctx.props().children.clone()
|
||||||
} else {
|
} else {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct ControlGroup {
|
|
||||||
props: ControlGroupProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ControlGroupProps {
|
pub struct ControlGroupProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -18,39 +14,18 @@ pub struct ControlGroupProps {
|
||||||
pub class: Classes,
|
pub class: Classes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for ControlGroup {
|
#[function_component(ControlGroup)]
|
||||||
type Message = ();
|
pub fn control_group(props: &ControlGroupProps) -> Html {
|
||||||
type Properties = ControlGroupProps;
|
html! {
|
||||||
|
<div
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
class={classes!(
|
||||||
Self { props }
|
"bp3-control-group",
|
||||||
}
|
props.fill.then(|| "bp3-fill"),
|
||||||
|
props.vertical.then(|| "bp3-vertical"),
|
||||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
props.class.clone(),
|
||||||
true
|
)}
|
||||||
}
|
>
|
||||||
|
{props.children.clone()}
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
</div>
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<div
|
|
||||||
class=classes!(
|
|
||||||
"bp3-control-group",
|
|
||||||
self.props.fill.then(|| "bp3-fill"),
|
|
||||||
self.props.vertical.then(|| "bp3-vertical"),
|
|
||||||
self.props.class.clone(),
|
|
||||||
)
|
|
||||||
>
|
|
||||||
{self.props.children.clone()}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Divider {
|
|
||||||
props: DividerProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct DividerProps {
|
pub struct DividerProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -14,36 +10,15 @@ pub struct DividerProps {
|
||||||
pub class: Classes,
|
pub class: Classes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Divider {
|
#[function_component(Divider)]
|
||||||
type Message = ();
|
pub fn view(props: &DividerProps) -> Html {
|
||||||
type Properties = DividerProps;
|
html! {
|
||||||
|
<span
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
class={classes!(
|
||||||
Self { props }
|
"bp3-divider",
|
||||||
}
|
props.vertical.then(|| "bp3-vertical"),
|
||||||
|
props.class.clone(),
|
||||||
fn update(&mut self, _: 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! {
|
|
||||||
<span
|
|
||||||
class=classes!(
|
|
||||||
"bp3-divider",
|
|
||||||
self.props.vertical.then(|| "bp3-vertical"),
|
|
||||||
self.props.class.clone(),
|
|
||||||
)
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,36 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewtil::{Pure, PureComponent};
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct ChildrenOnlyProps {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub class: Classes,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub children: html::Children,
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! build_component {
|
macro_rules! build_component {
|
||||||
($name:ident, $props_name:ident, $tag:tt, $class:literal) => {
|
($name:ident, $tag:tt, $class:literal) => {
|
||||||
pub type $name = Pure<$props_name>;
|
#[function_component($name)]
|
||||||
|
pub fn $tag(props: &ChildrenOnlyProps) -> Html {
|
||||||
#[derive(Debug, Clone, PartialEq, Properties)]
|
html! {
|
||||||
pub struct $props_name {
|
<$tag class={classes!($class, props.class.clone())}>
|
||||||
#[prop_or_default]
|
{ props.children.clone() }
|
||||||
pub class: Classes,
|
</$tag>
|
||||||
#[prop_or_default]
|
|
||||||
pub children: html::Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PureComponent for $props_name {
|
|
||||||
fn render(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<$tag class=classes!($class, self.class.clone())>
|
|
||||||
{self.children.clone()}
|
|
||||||
</$tag>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
build_component!(H1, H1Props, h1, "bp3-heading");
|
build_component!(H1, h1, "bp3-heading");
|
||||||
build_component!(H2, H2Props, h2, "bp3-heading");
|
build_component!(H2, h2, "bp3-heading");
|
||||||
build_component!(H3, H3Props, h3, "bp3-heading");
|
build_component!(H3, h3, "bp3-heading");
|
||||||
build_component!(H4, H4Props, h4, "bp3-heading");
|
build_component!(H4, h4, "bp3-heading");
|
||||||
build_component!(H5, H5Props, h5, "bp3-heading");
|
build_component!(H5, h5, "bp3-heading");
|
||||||
build_component!(H6, H6Props, h6, "bp3-heading");
|
build_component!(H6, h6, "bp3-heading");
|
||||||
|
|
||||||
build_component!(Blockquote, BlockquoteProps, blockquote, "bp3-blockquote");
|
build_component!(Blockquote, blockquote, "bp3-blockquote");
|
||||||
build_component!(Code, CodeProps, code, "bp3-code");
|
build_component!(Code, code, "bp3-code");
|
||||||
build_component!(Label, LabelProps, label, "bp3-label");
|
build_component!(Label, label, "bp3-label");
|
||||||
build_component!(Pre, PreProps, pre, "bp3-pre");
|
build_component!(Pre, pre, "bp3-pre");
|
||||||
build_component!(Ol, OlProps, ol, "bp3-ol");
|
build_component!(Ol, ol, "bp3-ol");
|
||||||
build_component!(Ul, UlProps, ul, "bp3-ul");
|
build_component!(Ul, ul, "bp3-ul");
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{Icon, IconName};
|
use crate::{Icon, IconName};
|
||||||
|
use web_sys::HtmlSelectElement;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct HtmlSelect<T: Clone + PartialEq + 'static> {
|
pub struct HtmlSelect<T: Clone + PartialEq + 'static> {
|
||||||
props: HtmlSelectProps<T>,
|
phantom: PhantomData<T>,
|
||||||
link: ComponentLink<Self>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
@ -30,51 +32,44 @@ pub struct HtmlSelectProps<T: Clone + PartialEq + 'static> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone + PartialEq + 'static> Component for HtmlSelect<T> {
|
impl<T: Clone + PartialEq + 'static> Component for HtmlSelect<T> {
|
||||||
type Message = ChangeData;
|
type Message = Event;
|
||||||
type Properties = HtmlSelectProps<T>;
|
type Properties = HtmlSelectProps<T>;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Self { props, link }
|
Self {
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
let i = if let ChangeData::Select(select) = msg {
|
let i = if let Some(select) = msg.target_dyn_into::<HtmlSelectElement>() {
|
||||||
select.selected_index()
|
select.selected_index()
|
||||||
} else {
|
} else {
|
||||||
unreachable!("unexpected ChangeData variant: {:?}", msg);
|
unreachable!("unexpected Event: {:?}", msg);
|
||||||
};
|
};
|
||||||
if i >= 0 {
|
if i >= 0 {
|
||||||
let i = i as usize;
|
let i = i as usize;
|
||||||
let variant = self.props.options[i].0.clone();
|
let variant = ctx.props().options[i].0.clone();
|
||||||
self.props.onchange.emit(variant);
|
ctx.props().onchange.emit(variant);
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
let option_children = ctx
|
||||||
self.props = props;
|
.props()
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let option_children = self
|
|
||||||
.props
|
|
||||||
.options
|
.options
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(value, label)| {
|
.map(|(value, label)| {
|
||||||
let selected = self
|
let selected = ctx
|
||||||
.props
|
.props()
|
||||||
.value
|
.value
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|x| value == x)
|
.map(|x| value == x)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<option selected=selected>
|
<option selected={selected}>
|
||||||
{label}
|
{label}
|
||||||
</option>
|
</option>
|
||||||
}
|
}
|
||||||
|
@ -83,24 +78,24 @@ impl<T: Clone + PartialEq + 'static> Component for HtmlSelect<T> {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div
|
<div
|
||||||
class=classes!(
|
class={classes!(
|
||||||
"bp3-html-select",
|
"bp3-html-select",
|
||||||
self.props.minimal.then(|| "bp3-minimal"),
|
ctx.props().minimal.then(|| "bp3-minimal"),
|
||||||
self.props.large.then(|| "bp3-large"),
|
ctx.props().large.then(|| "bp3-large"),
|
||||||
self.props.fill.then(|| "bp3-fill"),
|
ctx.props().fill.then(|| "bp3-fill"),
|
||||||
self.props.disabled.then(|| "bp3-disabled"),
|
ctx.props().disabled.then(|| "bp3-disabled"),
|
||||||
self.props.class.clone(),
|
ctx.props().class.clone(),
|
||||||
)
|
)}
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
onchange={self.link.callback(|x| x)}
|
onchange={ctx.link().callback(|x| x)}
|
||||||
title={self.props.title.clone()}
|
title={ctx.props().title.clone()}
|
||||||
value={"".to_string()}
|
value={"".to_string()}
|
||||||
>
|
>
|
||||||
{option_children}
|
{option_children}
|
||||||
</select>
|
</select>
|
||||||
<Icon icon=IconName::DoubleCaretVertical/>
|
<Icon icon={IconName::DoubleCaretVertical}/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
93
src/icon.rs
93
src/icon.rs
|
@ -12,10 +12,6 @@ impl Default for IconName {
|
||||||
pub const ICON_SIZE_STANDARD: i32 = 16;
|
pub const ICON_SIZE_STANDARD: i32 = 16;
|
||||||
pub const ICON_SIZE_LARGE: i32 = 20;
|
pub const ICON_SIZE_LARGE: i32 = 20;
|
||||||
|
|
||||||
pub struct Icon {
|
|
||||||
props: IconProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct IconProps {
|
pub struct IconProps {
|
||||||
pub icon: IconName,
|
pub icon: IconName,
|
||||||
|
@ -33,62 +29,41 @@ pub struct IconProps {
|
||||||
pub onclick: Callback<MouseEvent>,
|
pub onclick: Callback<MouseEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Icon {
|
#[function_component(Icon)]
|
||||||
type Message = ();
|
pub fn icon(props: &IconProps) -> Html {
|
||||||
type Properties = IconProps;
|
let paths = if props.icon_size == ICON_SIZE_STANDARD {
|
||||||
|
icon_svg_paths_16(props.icon)
|
||||||
|
} else {
|
||||||
|
icon_svg_paths_20(props.icon)
|
||||||
|
};
|
||||||
|
let pixel_grid_size = if props.icon_size >= ICON_SIZE_LARGE {
|
||||||
|
ICON_SIZE_LARGE
|
||||||
|
} else {
|
||||||
|
ICON_SIZE_STANDARD
|
||||||
|
};
|
||||||
|
let icon_string = format!("{:?}", props.icon);
|
||||||
|
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
html! {
|
||||||
Icon { props }
|
<span
|
||||||
}
|
class={classes!("bp3-icon", props.class.clone(), props.intent)}
|
||||||
|
onclick={props.onclick.clone()}
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
>
|
||||||
true
|
<svg
|
||||||
}
|
fill={props.color.clone()}
|
||||||
|
data-icon={icon_string.clone()}
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
width={props.icon_size.to_string()}
|
||||||
if self.props != props {
|
height={props.icon_size.to_string()}
|
||||||
self.props = props;
|
viewBox={format!("0 0 {x} {x}", x=pixel_grid_size)}
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let paths = if self.props.icon_size == ICON_SIZE_STANDARD {
|
|
||||||
icon_svg_paths_16(self.props.icon)
|
|
||||||
} else {
|
|
||||||
icon_svg_paths_20(self.props.icon)
|
|
||||||
};
|
|
||||||
let pixel_grid_size = if self.props.icon_size >= ICON_SIZE_LARGE {
|
|
||||||
ICON_SIZE_LARGE
|
|
||||||
} else {
|
|
||||||
ICON_SIZE_STANDARD
|
|
||||||
};
|
|
||||||
let icon_string = format!("{:?}", self.props.icon);
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<span
|
|
||||||
class=classes!("bp3-icon", self.props.class.clone(), self.props.intent)
|
|
||||||
onclick=self.props.onclick.clone()
|
|
||||||
>
|
>
|
||||||
<svg
|
<desc>{props.title.clone().unwrap_or(icon_string)}</desc>
|
||||||
fill={self.props.color.clone()}
|
{
|
||||||
data-icon={icon_string.clone()}
|
paths.iter()
|
||||||
width={self.props.icon_size.to_string()}
|
.map(|x| html! {
|
||||||
height={self.props.icon_size.to_string()}
|
<path d={*x} fillRule="evenodd" />
|
||||||
viewBox={format!("0 0 {x} {x}", x=pixel_grid_size)}
|
})
|
||||||
>
|
.collect::<Html>()
|
||||||
<desc>{self.props.title.clone().unwrap_or(icon_string)}</desc>
|
}
|
||||||
{
|
</svg>
|
||||||
paths.iter()
|
</span>
|
||||||
.map(|x| html! {
|
|
||||||
<path d=*x fillRule="evenodd" />
|
|
||||||
})
|
|
||||||
.collect::<Html>()
|
|
||||||
}
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ use yew::prelude::*;
|
||||||
const MIN_HORIZONTAL_PADDING: i32 = 10;
|
const MIN_HORIZONTAL_PADDING: i32 = 10;
|
||||||
|
|
||||||
pub struct InputGroup {
|
pub struct InputGroup {
|
||||||
props: InputGroupProps,
|
|
||||||
link: ComponentLink<Self>,
|
|
||||||
left_element_ref: NodeRef,
|
left_element_ref: NodeRef,
|
||||||
left_element_width: Option<i32>,
|
left_element_width: Option<i32>,
|
||||||
right_element_ref: NodeRef,
|
right_element_ref: NodeRef,
|
||||||
|
@ -74,7 +72,7 @@ pub struct InputGroupProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub input_type: TextInputType,
|
pub input_type: TextInputType,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub oninput: Callback<InputData>,
|
pub oninput: Callback<InputEvent>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub onkeyup: Callback<KeyboardEvent>,
|
pub onkeyup: Callback<KeyboardEvent>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -91,10 +89,8 @@ impl Component for InputGroup {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
type Properties = InputGroupProps;
|
type Properties = InputGroupProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
props,
|
|
||||||
link,
|
|
||||||
left_element_ref: Default::default(),
|
left_element_ref: Default::default(),
|
||||||
left_element_width: Default::default(),
|
left_element_width: Default::default(),
|
||||||
right_element_ref: Default::default(),
|
right_element_ref: Default::default(),
|
||||||
|
@ -102,20 +98,11 @@ impl Component for InputGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, _: Self::Message) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let input_style = match (self.left_element_width, self.right_element_width) {
|
let input_style = match (self.left_element_width, self.right_element_width) {
|
||||||
(Some(left), None) => format!("padding-left:{}px", left.max(MIN_HORIZONTAL_PADDING)),
|
(Some(left), None) => format!("padding-left:{}px", left.max(MIN_HORIZONTAL_PADDING)),
|
||||||
(None, Some(right)) => format!("padding-right:{}px", right.max(MIN_HORIZONTAL_PADDING)),
|
(None, Some(right)) => format!("padding-right:{}px", right.max(MIN_HORIZONTAL_PADDING)),
|
||||||
|
@ -129,53 +116,53 @@ impl Component for InputGroup {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div
|
<div
|
||||||
class=classes!(
|
class={classes!(
|
||||||
"bp3-input-group",
|
"bp3-input-group",
|
||||||
self.props.disabled.then(|| "bp3-disabled"),
|
ctx.props().disabled.then(|| "bp3-disabled"),
|
||||||
self.props.fill.then(|| "bp3-fill"),
|
ctx.props().fill.then(|| "bp3-fill"),
|
||||||
self.props.large.then(|| "bp3-large"),
|
ctx.props().large.then(|| "bp3-large"),
|
||||||
self.props.small.then(|| "bp3-small"),
|
ctx.props().small.then(|| "bp3-small"),
|
||||||
self.props.round.then(|| "bp3-round"),
|
ctx.props().round.then(|| "bp3-round"),
|
||||||
self.props.placeholder.clone(),
|
ctx.props().placeholder.clone(),
|
||||||
self.props.class.clone(),
|
ctx.props().class.clone(),
|
||||||
)
|
)}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
if let Some(left_element) = self.props.left_element.clone() {
|
if let Some(left_element) = ctx.props().left_element.clone() {
|
||||||
html! {
|
html! {
|
||||||
<span
|
<span
|
||||||
class="bp3-input-left-container"
|
class="bp3-input-left-container"
|
||||||
ref=self.left_element_ref.clone()
|
ref={self.left_element_ref.clone()}
|
||||||
>
|
>
|
||||||
{left_element}
|
{left_element}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
} else if let Some(icon) = self.props.left_icon {
|
} else if let Some(icon) = ctx.props().left_icon {
|
||||||
html! {
|
html! {
|
||||||
<Icon icon=icon />
|
<Icon icon={icon} />
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
html!()
|
html!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<input
|
<input
|
||||||
ref=self.props.input_ref.clone()
|
ref={ctx.props().input_ref.clone()}
|
||||||
class="bp3-input"
|
class="bp3-input"
|
||||||
type=self.props.input_type.as_str()
|
type={ctx.props().input_type.as_str()}
|
||||||
placeholder=self.props.placeholder.clone()
|
placeholder={ctx.props().placeholder.clone()}
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
oninput={self.props.oninput.clone()}
|
oninput={ctx.props().oninput.clone()}
|
||||||
onkeyup={self.props.onkeyup.clone()}
|
onkeyup={ctx.props().onkeyup.clone()}
|
||||||
onkeydown={self.props.onkeydown.clone()}
|
onkeydown={ctx.props().onkeydown.clone()}
|
||||||
value=self.props.value.clone()
|
value={ctx.props().value.clone()}
|
||||||
style=input_style
|
style={input_style}
|
||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
if let Some(right_element) = self.props.right_element.clone() {
|
if let Some(right_element) = ctx.props().right_element.clone() {
|
||||||
html! {
|
html! {
|
||||||
<span
|
<span
|
||||||
class="bp3-input-action"
|
class="bp3-input-action"
|
||||||
ref=self.right_element_ref.clone()
|
ref={self.right_element_ref.clone()}
|
||||||
>
|
>
|
||||||
{right_element}
|
{right_element}
|
||||||
</span>
|
</span>
|
||||||
|
@ -188,7 +175,7 @@ impl Component for InputGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rendered(&mut self, _first_render: bool) {
|
fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
|
||||||
let left_old_value = self.left_element_width.take();
|
let left_old_value = self.left_element_width.take();
|
||||||
self.left_element_width = self
|
self.left_element_width = self
|
||||||
.left_element_ref
|
.left_element_ref
|
||||||
|
@ -203,7 +190,7 @@ impl Component for InputGroup {
|
||||||
|
|
||||||
if left_old_value != self.left_element_width || right_old_value != self.right_element_width
|
if left_old_value != self.left_element_width || right_old_value != self.right_element_width
|
||||||
{
|
{
|
||||||
self.link.send_message(());
|
ctx.link().send_message(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
226
src/menu.rs
226
src/menu.rs
|
@ -1,11 +1,6 @@
|
||||||
use crate::{Icon, IconName, Intent, H6};
|
use crate::{Icon, IconName, Intent, H6};
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Menu {
|
|
||||||
props: MenuProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct MenuProps {
|
pub struct MenuProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -17,45 +12,20 @@ pub struct MenuProps {
|
||||||
pub children: html::Children,
|
pub children: html::Children,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Menu {
|
#[function_component(Menu)]
|
||||||
type Message = ();
|
pub fn menu(props: &MenuProps) -> Html {
|
||||||
type Properties = MenuProps;
|
html! {
|
||||||
|
<ul
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
class={classes!(
|
||||||
Menu { props }
|
"bp3-menu",
|
||||||
|
props.large.then(|| "bp3-large"),
|
||||||
|
props.class.clone(),
|
||||||
|
)}
|
||||||
|
ref={props.r#ref.clone()}
|
||||||
|
>
|
||||||
|
{props.children.clone()}
|
||||||
|
</ul>
|
||||||
}
|
}
|
||||||
|
|
||||||
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! {
|
|
||||||
<ul
|
|
||||||
class=classes!(
|
|
||||||
"bp3-menu",
|
|
||||||
self.props.large.then(|| "bp3-large"),
|
|
||||||
self.props.class.clone(),
|
|
||||||
)
|
|
||||||
ref={self.props.r#ref.clone()}
|
|
||||||
>
|
|
||||||
{self.props.children.clone()}
|
|
||||||
</ul>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MenuItem {
|
|
||||||
props: MenuItemProps,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
@ -71,7 +41,7 @@ pub struct MenuItemProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub href: Option<Cow<'static, str>>,
|
pub href: Option<String>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub label: Option<yew::virtual_dom::VNode>,
|
pub label: Option<yew::virtual_dom::VNode>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -89,127 +59,81 @@ pub struct MenuItemProps {
|
||||||
// TODO: pub children: html::Children,
|
// TODO: pub children: html::Children,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for MenuItem {
|
#[function_component(MenuItem)]
|
||||||
type Message = ();
|
pub fn menu_item(props: &MenuItemProps) -> Html {
|
||||||
type Properties = MenuItemProps;
|
html! {
|
||||||
|
<li>
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
<a
|
||||||
MenuItem { props }
|
class={classes!(
|
||||||
}
|
"bp3-menu-item",
|
||||||
|
props.active.then(|| "bp3-active"),
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
props.disabled.then(|| "bp3-disabled"),
|
||||||
true
|
props.intent
|
||||||
}
|
.or_else(|| props.active.then(|| Intent::Primary)),
|
||||||
|
props.class.clone(),
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
)}
|
||||||
if self.props != props {
|
href={(!props.disabled).then(|| props.href.clone()).flatten()}
|
||||||
self.props = props;
|
tabIndex={(!props.disabled).then(|| "0")}
|
||||||
true
|
onclick={(!props.disabled).then(|| props.onclick.clone())}
|
||||||
} else {
|
>
|
||||||
false
|
{
|
||||||
}
|
if let Some(icon_name) = props.icon {
|
||||||
}
|
html! {
|
||||||
|
<Icon icon={icon_name} />
|
||||||
fn view(&self) -> Html {
|
}
|
||||||
html! {
|
} else if let Some(html) = props.icon_html.clone() {
|
||||||
<li>
|
html
|
||||||
<a
|
} else {
|
||||||
class=classes!(
|
html! {
|
||||||
"bp3-menu-item",
|
<Icon icon={IconName::Blank} />
|
||||||
self.props.active.then(|| "bp3-active"),
|
|
||||||
self.props.disabled.then(|| "bp3-disabled"),
|
|
||||||
self.props.intent
|
|
||||||
.or_else(|| self.props.active.then(|| Intent::Primary)),
|
|
||||||
self.props.class.clone(),
|
|
||||||
)
|
|
||||||
href={(!self.props.disabled).then(|| self.props.href.clone())}.flatten()
|
|
||||||
tabIndex={(!self.props.disabled).then(|| "0")}
|
|
||||||
onclick={(!self.props.disabled).then(|| self.props.onclick.clone())}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
if let Some(icon_name) = self.props.icon {
|
|
||||||
html! {
|
|
||||||
<Icon icon={icon_name} />
|
|
||||||
}
|
|
||||||
} else if let Some(html) = self.props.icon_html.clone() {
|
|
||||||
html
|
|
||||||
} else {
|
|
||||||
html! {
|
|
||||||
<Icon icon=IconName::Blank />
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<div class=classes!("bp3-text", "bp3-fill", self.props.text_class.clone())>
|
}
|
||||||
{self.props.text.clone()}
|
<div class={classes!("bp3-text", "bp3-fill", props.text_class.clone())}>
|
||||||
</div>
|
{props.text.clone()}
|
||||||
{
|
</div>
|
||||||
if let Some(label) = self.props.label.clone() {
|
{
|
||||||
html! {
|
if let Some(label) = props.label.clone() {
|
||||||
<span
|
html! {
|
||||||
class=classes!(
|
<span
|
||||||
"bp3-menu-item-label",
|
class={classes!(
|
||||||
self.props.label_class.clone())
|
"bp3-menu-item-label",
|
||||||
>
|
props.label_class.clone())}
|
||||||
{label}
|
>
|
||||||
</span>
|
{label}
|
||||||
}
|
</span>
|
||||||
} else {
|
|
||||||
html!()
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
html!()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MenuDivider {
|
|
||||||
props: MenuDividerProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct MenuDividerProps {
|
pub struct MenuDividerProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub title: Option<yew::virtual_dom::VNode>,
|
pub title: Option<yew::virtual_dom::VNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for MenuDivider {
|
#[function_component(MenuDivider)]
|
||||||
type Message = ();
|
pub fn menu_divider(props: &MenuDividerProps) -> Html {
|
||||||
type Properties = MenuDividerProps;
|
html! {
|
||||||
|
{if let Some(title) = props.title.clone() {
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
html! {
|
||||||
Self { props }
|
<li
|
||||||
}
|
class={classes!("bp3-menu-header")}
|
||||||
|
>
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
<H6>{title}</H6>
|
||||||
true
|
</li>
|
||||||
}
|
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
if let Some(title) = self.props.title.clone() {
|
|
||||||
html! {
|
|
||||||
<li
|
|
||||||
class=classes!("bp3-menu-header")
|
|
||||||
>
|
|
||||||
<H6>{title}</H6>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
html! {
|
|
||||||
<li class=classes!("bp3-menu-divider") />
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
html! {
|
||||||
|
<li class={classes!("bp3-menu-divider")} />
|
||||||
|
}
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use crate::{Button, ButtonGroup, ControlGroup, IconName, InputGroup, Intent};
|
use crate::{Button, ButtonGroup, ControlGroup, IconName, InputGroup, Intent};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::ops::{Add, Bound, RangeBounds, Sub};
|
use std::ops::{Add, Bound, RangeBounds, Sub};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use web_sys::HtmlInputElement;
|
||||||
use yew::html::IntoPropValue;
|
use yew::html::IntoPropValue;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
@ -16,9 +18,8 @@ where
|
||||||
+ PartialOrd
|
+ PartialOrd
|
||||||
+ 'static,
|
+ 'static,
|
||||||
{
|
{
|
||||||
props: NumericInputProps<T>,
|
|
||||||
link: ComponentLink<Self>,
|
|
||||||
input: String,
|
input: String,
|
||||||
|
phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
@ -84,42 +85,46 @@ where
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = NumericInputProps<T>;
|
type Properties = NumericInputProps<T>;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
props,
|
|
||||||
link,
|
|
||||||
input: Default::default(),
|
input: Default::default(),
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
|
let mut update_value = |new_value| {
|
||||||
|
let new_value = ctx.props().bounds.clamp(new_value, ctx.props().increment);
|
||||||
|
|
||||||
|
if new_value != ctx.props().value {
|
||||||
|
self.input = new_value.to_string();
|
||||||
|
ctx.props().onchange.emit(new_value);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
Msg::InputUpdate(new_value) => {
|
Msg::InputUpdate(new_value) => {
|
||||||
if let Ok(new_value) = new_value.trim().parse::<T>() {
|
if let Ok(new_value) = new_value.trim().parse::<T>() {
|
||||||
self.update_value(new_value)
|
update_value(new_value)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::Up => self.update_value(self.props.value + self.props.increment),
|
Msg::Up => update_value(ctx.props().value + ctx.props().increment),
|
||||||
Msg::Down => self.update_value(self.props.value - self.props.increment),
|
Msg::Down => update_value(ctx.props().value - ctx.props().increment),
|
||||||
Msg::Noop => false,
|
Msg::Noop => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn changed(&mut self, ctx: &Context<Self>) -> bool {
|
||||||
if self.props != props {
|
self.input = ctx.props().value.to_string();
|
||||||
if self.props.value != props.value {
|
true
|
||||||
self.input = props.value.to_string();
|
|
||||||
}
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
let NumericInputProps {
|
let NumericInputProps {
|
||||||
value,
|
value,
|
||||||
increment,
|
increment,
|
||||||
|
@ -127,8 +132,9 @@ where
|
||||||
disable_buttons,
|
disable_buttons,
|
||||||
buttons_on_the_left,
|
buttons_on_the_left,
|
||||||
..
|
..
|
||||||
} = self.props;
|
} = *ctx.props();
|
||||||
let bounds = &self.props.bounds;
|
|
||||||
|
let bounds = &ctx.props().bounds;
|
||||||
let button_up_disabled = disabled || bounds.clamp(value + increment, increment) == value;
|
let button_up_disabled = disabled || bounds.clamp(value + increment, increment) == value;
|
||||||
let button_down_disabled = disabled || bounds.clamp(value - increment, increment) == value;
|
let button_down_disabled = disabled || bounds.clamp(value - increment, increment) == value;
|
||||||
|
|
||||||
|
@ -136,16 +142,16 @@ where
|
||||||
html!()
|
html!()
|
||||||
} else {
|
} else {
|
||||||
html! {
|
html! {
|
||||||
<ButtonGroup vertical=true class=classes!("bp3-fixed")>
|
<ButtonGroup vertical=true class={classes!("bp3-fixed")}>
|
||||||
<Button
|
<Button
|
||||||
icon=IconName::ChevronUp
|
icon={IconName::ChevronUp}
|
||||||
disabled=button_up_disabled
|
disabled={button_up_disabled}
|
||||||
onclick=self.link.callback(|_| Msg::Up)
|
onclick={ctx.link().callback(|_| Msg::Up)}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
icon=IconName::ChevronDown
|
icon={IconName::ChevronDown}
|
||||||
disabled=button_down_disabled
|
disabled={button_down_disabled}
|
||||||
onclick=self.link.callback(|_| Msg::Down)
|
onclick={ctx.link().callback(|_| Msg::Down)}
|
||||||
/>
|
/>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
}
|
}
|
||||||
|
@ -153,15 +159,18 @@ where
|
||||||
|
|
||||||
let input_group = html! {
|
let input_group = html! {
|
||||||
<InputGroup
|
<InputGroup
|
||||||
placeholder=self.props.placeholder.clone()
|
placeholder={ctx.props().placeholder.clone()}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
left_icon=self.props.left_icon
|
left_icon={ctx.props().left_icon}
|
||||||
left_element=self.props.left_element.clone()
|
left_element={ctx.props().left_element.clone()}
|
||||||
right_element=self.props.right_element.clone()
|
right_element={ctx.props().right_element.clone()}
|
||||||
value=self.input.clone()
|
value={self.input.clone()}
|
||||||
oninput=self.link.callback(|e: InputData| Msg::InputUpdate(e.value))
|
oninput={ctx.link().callback(|e: InputEvent| {
|
||||||
onkeydown=self.link.callback(|e: KeyboardEvent| {
|
let value = e.target_unchecked_into::<HtmlInputElement>().value();
|
||||||
|
Msg::InputUpdate(value)
|
||||||
|
})}
|
||||||
|
onkeydown={ctx.link().callback(|e: KeyboardEvent| {
|
||||||
if e.key() == "ArrowUp" {
|
if e.key() == "ArrowUp" {
|
||||||
Msg::Up
|
Msg::Up
|
||||||
} else if e.key() == "ArrowDown" {
|
} else if e.key() == "ArrowDown" {
|
||||||
|
@ -169,16 +178,16 @@ where
|
||||||
} else {
|
} else {
|
||||||
Msg::Noop
|
Msg::Noop
|
||||||
}
|
}
|
||||||
})
|
})}
|
||||||
/>
|
/>
|
||||||
};
|
};
|
||||||
|
|
||||||
if buttons_on_the_left {
|
if buttons_on_the_left {
|
||||||
html! {
|
html! {
|
||||||
<ControlGroup
|
<ControlGroup
|
||||||
class=classes!("bp3-numeric-input")
|
class={classes!("bp3-numeric-input")}
|
||||||
fill=self.props.fill
|
fill={ctx.props().fill}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
>
|
>
|
||||||
{buttons}
|
{buttons}
|
||||||
{input_group}
|
{input_group}
|
||||||
|
@ -187,9 +196,9 @@ where
|
||||||
} else {
|
} else {
|
||||||
html! {
|
html! {
|
||||||
<ControlGroup
|
<ControlGroup
|
||||||
class=classes!("bp3-numeric-input")
|
class={classes!("bp3-numeric-input")}
|
||||||
fill=self.props.fill
|
fill={ctx.props().fill}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
>
|
>
|
||||||
{input_group}
|
{input_group}
|
||||||
{buttons}
|
{buttons}
|
||||||
|
@ -199,30 +208,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> NumericInput<T>
|
|
||||||
where
|
|
||||||
T: Add<Output = T>
|
|
||||||
+ Sub<Output = T>
|
|
||||||
+ Copy
|
|
||||||
+ Display
|
|
||||||
+ FromStr
|
|
||||||
+ PartialEq
|
|
||||||
+ PartialOrd
|
|
||||||
+ 'static,
|
|
||||||
{
|
|
||||||
fn update_value(&mut self, new_value: T) -> ShouldRender {
|
|
||||||
let new_value = self.props.bounds.clamp(new_value, self.props.increment);
|
|
||||||
|
|
||||||
if new_value != self.props.value {
|
|
||||||
self.input = new_value.to_string();
|
|
||||||
self.props.onchange.emit(new_value);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct NumericInputRangeBounds<T> {
|
pub struct NumericInputRangeBounds<T> {
|
||||||
pub start: Bound<T>,
|
pub start: Bound<T>,
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
use crate::{Button, IconName};
|
use crate::{Button, IconName};
|
||||||
use std::borrow::Cow;
|
use gloo::timers::callback::Timeout;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew::services::timeout::{TimeoutService, TimeoutTask};
|
|
||||||
|
|
||||||
pub struct PanelBuilder<F: Fn(Option<Html>, I) -> O, I, O> {
|
pub struct PanelBuilder<F: Fn(Option<Html>, I) -> O, I, O> {
|
||||||
title: Option<Html>,
|
title: Option<Html>,
|
||||||
|
@ -119,9 +117,11 @@ impl From<StateAction> for Classes {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PanelStack {
|
pub struct PanelStack {
|
||||||
timeout_task: Option<TimeoutTask>,
|
timeout_task: Option<Timeout>,
|
||||||
props: PanelStackProps,
|
|
||||||
link: ComponentLink<Self>,
|
// We keep track of the latest action to perform from the PanelStackState
|
||||||
|
// because we need a mutable access to the action.
|
||||||
|
action_to_perform: Option<StateAction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Properties)]
|
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||||
|
@ -141,47 +141,36 @@ impl Component for PanelStack {
|
||||||
type Message = PanelStackMessage;
|
type Message = PanelStackMessage;
|
||||||
type Properties = PanelStackProps;
|
type Properties = PanelStackProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
timeout_task: None,
|
timeout_task: None,
|
||||||
props,
|
action_to_perform: None,
|
||||||
link,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
PanelStackMessage::PopPanel => {
|
PanelStackMessage::PopPanel => {
|
||||||
self.props.state.opened_panels.borrow_mut().pop();
|
ctx.props().state.opened_panels.borrow_mut().pop();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
let opened_panels = ctx.props().state.opened_panels.borrow();
|
||||||
self.props = props;
|
let last = match self.action_to_perform {
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let opened_panels = self.props.state.opened_panels.borrow();
|
|
||||||
let action = self.props.state.action;
|
|
||||||
let last = match action {
|
|
||||||
Some(StateAction::Pop) => opened_panels.len() - 2,
|
Some(StateAction::Pop) => opened_panels.len() - 2,
|
||||||
_ => opened_panels.len() - 1,
|
_ => opened_panels.len() - 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div
|
<div
|
||||||
class=classes!(
|
class={classes!(
|
||||||
"bp3-panel-stack2",
|
"bp3-panel-stack2",
|
||||||
action,
|
self.action_to_perform,
|
||||||
self.props.class.clone(),
|
ctx.props().class.clone(),
|
||||||
)
|
)}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
opened_panels
|
opened_panels
|
||||||
|
@ -190,9 +179,9 @@ impl Component for PanelStack {
|
||||||
.rev()
|
.rev()
|
||||||
.map(|(i, (title, content))| html! {
|
.map(|(i, (title, content))| html! {
|
||||||
<Panel
|
<Panel
|
||||||
title=title.clone()
|
title={title.clone()}
|
||||||
animation={
|
animation={
|
||||||
match action {
|
match self.action_to_perform {
|
||||||
_ if i == last => Animation::EnterStart,
|
_ if i == last => Animation::EnterStart,
|
||||||
Some(StateAction::Push) if i == last - 1 =>
|
Some(StateAction::Push) if i == last - 1 =>
|
||||||
Animation::ExitStart,
|
Animation::ExitStart,
|
||||||
|
@ -201,8 +190,8 @@ impl Component for PanelStack {
|
||||||
_ => Animation::Exited,
|
_ => Animation::Exited,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onclose=(i > 0).then(|| self.props.onclose.clone()).flatten()
|
onclose={(i > 0).then(|| ctx.props().onclose.clone()).flatten()}
|
||||||
key=i
|
key={i}
|
||||||
>
|
>
|
||||||
// TODO the state of content doesn't seem to be kept when re-opening
|
// TODO the state of content doesn't seem to be kept when re-opening
|
||||||
// a panel using the same components
|
// a panel using the same components
|
||||||
|
@ -215,21 +204,24 @@ impl Component for PanelStack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rendered(&mut self, _first_render: bool) {
|
fn changed(&mut self, ctx: &Context<Self>) -> bool {
|
||||||
if self.props.state.action.take() == Some(StateAction::Pop) {
|
self.action_to_perform = ctx.props().state.action;
|
||||||
self.timeout_task.replace(TimeoutService::spawn(
|
true
|
||||||
Duration::from_millis(400),
|
}
|
||||||
self.link.callback(|_| PanelStackMessage::PopPanel),
|
|
||||||
));
|
fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
|
||||||
|
if self.action_to_perform.take() == Some(StateAction::Pop) {
|
||||||
|
let link = ctx.link().clone();
|
||||||
|
self.timeout_task.replace(Timeout::new(400, move || {
|
||||||
|
link.send_message(PanelStackMessage::PopPanel)
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Panel {
|
struct Panel {
|
||||||
animation: Animation,
|
animation: Animation,
|
||||||
timeout_task: Option<TimeoutTask>,
|
timeout_task: Option<Timeout>,
|
||||||
props: PanelProps,
|
|
||||||
link: ComponentLink<Self>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Properties)]
|
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||||
|
@ -249,16 +241,14 @@ impl Component for Panel {
|
||||||
type Message = PanelMessage;
|
type Message = PanelMessage;
|
||||||
type Properties = PanelProps;
|
type Properties = PanelProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
animation: props.animation,
|
animation: ctx.props().animation,
|
||||||
timeout_task: None,
|
timeout_task: None,
|
||||||
props,
|
|
||||||
link,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
PanelMessage::UpdateAnimation(animation) => {
|
PanelMessage::UpdateAnimation(animation) => {
|
||||||
self.animation = animation;
|
self.animation = animation;
|
||||||
|
@ -267,17 +257,7 @@ impl Component for Panel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
|
||||||
self.animation = props.animation;
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let style = if self.animation == Animation::Exited {
|
let style = if self.animation == Animation::Exited {
|
||||||
"display:none"
|
"display:none"
|
||||||
} else {
|
} else {
|
||||||
|
@ -294,15 +274,15 @@ impl Component for Panel {
|
||||||
Animation::Exited => None,
|
Animation::Exited => None,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
let back_button = self.props.onclose.clone().map(|onclose| {
|
let back_button = ctx.props().onclose.clone().map(|onclose| {
|
||||||
html! {
|
html! {
|
||||||
<Button
|
<Button
|
||||||
class=classes!("bp3-panel-stack-header-back")
|
class={classes!("bp3-panel-stack-header-back")}
|
||||||
style=Cow::Borrowed("padding-right:0")
|
style={"padding-right:0"}
|
||||||
icon=IconName::ChevronLeft
|
icon={IconName::ChevronLeft}
|
||||||
minimal=true
|
minimal={true}
|
||||||
small=true
|
small={true}
|
||||||
onclick=onclose.reform(|_| ())
|
onclick={onclose.reform(|_| ())}
|
||||||
>
|
>
|
||||||
// TODO: I get a lot of "VComp is not mounted" if I try to use the title
|
// TODO: I get a lot of "VComp is not mounted" if I try to use the title
|
||||||
// of the previous panel
|
// of the previous panel
|
||||||
|
@ -311,47 +291,48 @@ impl Component for Panel {
|
||||||
});
|
});
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class=classes style=style>
|
<div class={classes} style={style}>
|
||||||
<div class="bp3-panel-stack-header">
|
<div class="bp3-panel-stack-header">
|
||||||
<span>{back_button.unwrap_or_default()}</span>
|
<span>{back_button.unwrap_or_default()}</span>
|
||||||
{self.props.title.clone().unwrap_or_default()}
|
{ctx.props().title.clone().unwrap_or_default()}
|
||||||
<span/>
|
<span/>
|
||||||
</div>
|
</div>
|
||||||
{for self.props.children.iter()}
|
{for ctx.props().children.iter()}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rendered(&mut self, _first_render: bool) {
|
fn changed(&mut self, ctx: &Context<Self>) -> bool {
|
||||||
|
self.animation = ctx.props().animation;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
|
||||||
match self.animation {
|
match self.animation {
|
||||||
Animation::EnterStart => {
|
Animation::EnterStart => {
|
||||||
self.timeout_task.replace(TimeoutService::spawn(
|
let link = ctx.link().clone();
|
||||||
Duration::from_millis(0),
|
self.timeout_task.replace(Timeout::new(0, move || {
|
||||||
self.link
|
link.send_message(PanelMessage::UpdateAnimation(Animation::Entering));
|
||||||
.callback(|_| PanelMessage::UpdateAnimation(Animation::Entering)),
|
}));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Animation::Entering => {
|
Animation::Entering => {
|
||||||
self.timeout_task.replace(TimeoutService::spawn(
|
let link = ctx.link().clone();
|
||||||
Duration::from_millis(400),
|
self.timeout_task.replace(Timeout::new(400, move || {
|
||||||
self.link
|
link.send_message(PanelMessage::UpdateAnimation(Animation::Entered));
|
||||||
.callback(|_| PanelMessage::UpdateAnimation(Animation::Entered)),
|
}));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Animation::Entered => {}
|
Animation::Entered => {}
|
||||||
Animation::ExitStart => {
|
Animation::ExitStart => {
|
||||||
self.timeout_task.replace(TimeoutService::spawn(
|
let link = ctx.link().clone();
|
||||||
Duration::from_millis(0),
|
self.timeout_task.replace(Timeout::new(0, move || {
|
||||||
self.link
|
link.send_message(PanelMessage::UpdateAnimation(Animation::Exiting));
|
||||||
.callback(|_| PanelMessage::UpdateAnimation(Animation::Exiting)),
|
}));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Animation::Exiting => {
|
Animation::Exiting => {
|
||||||
self.timeout_task.replace(TimeoutService::spawn(
|
let link = ctx.link().clone();
|
||||||
Duration::from_millis(400),
|
self.timeout_task.replace(Timeout::new(400, move || {
|
||||||
self.link
|
link.send_message(PanelMessage::UpdateAnimation(Animation::Exited));
|
||||||
.callback(|_| PanelMessage::UpdateAnimation(Animation::Exited)),
|
}));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Animation::Exited => {}
|
Animation::Exited => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
use crate::Intent;
|
use crate::Intent;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct ProgressBar {
|
|
||||||
props: ProgressBarProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ProgressBarProps {
|
pub struct ProgressBarProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -19,48 +15,27 @@ pub struct ProgressBarProps {
|
||||||
pub class: Classes,
|
pub class: Classes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for ProgressBar {
|
#[function_component(ProgressBar)]
|
||||||
type Message = ();
|
pub fn progress_bar(props: &ProgressBarProps) -> Html {
|
||||||
type Properties = ProgressBarProps;
|
let width = if let Some(value) = props.value {
|
||||||
|
// NOTE: nightly, issue #44095 for f32::clamp
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
// let percent = ((1000. * value).ceil() / 10.).clamp(0.,100.);
|
||||||
Self { props }
|
let percent = ((1000. * value).ceil() / 10.).max(0.).min(100.);
|
||||||
}
|
format!("width: {}%;", percent)
|
||||||
|
} else {
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
"".into()
|
||||||
true
|
};
|
||||||
}
|
html! {
|
||||||
|
<div
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
class={classes!(
|
||||||
if self.props != props {
|
"bp3-progress-bar",
|
||||||
self.props = props;
|
props.intent,
|
||||||
true
|
(!props.animate).then(|| "bp3-no-animation"),
|
||||||
} else {
|
(!props.stripes).then(|| "bp3-no-stripes"),
|
||||||
false
|
props.class.clone(),
|
||||||
}
|
)}
|
||||||
}
|
>
|
||||||
|
<div class={classes!("bp3-progress-meter")} style={{width}}/>
|
||||||
fn view(&self) -> Html {
|
</div>
|
||||||
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=classes!(
|
|
||||||
"bp3-progress-bar",
|
|
||||||
self.props.intent,
|
|
||||||
(!self.props.animate).then(|| "bp3-no-animation"),
|
|
||||||
(!self.props.stripes).then(|| "bp3-no-stripes"),
|
|
||||||
self.props.class.clone(),
|
|
||||||
)
|
|
||||||
>
|
|
||||||
<div class=classes!("bp3-progress-meter") style={{width}}/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
77
src/radio.rs
77
src/radio.rs
|
@ -1,9 +1,5 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Radio {
|
|
||||||
props: RadioProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct RadioProps {
|
pub struct RadioProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -17,59 +13,38 @@ pub struct RadioProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub onchange: Option<Callback<ChangeData>>,
|
pub onchange: Option<Callback<Event>>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub label: yew::virtual_dom::VNode,
|
pub label: yew::virtual_dom::VNode,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub value: Option<String>,
|
pub value: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Radio {
|
#[function_component(Radio)]
|
||||||
type Message = ();
|
pub fn radio(props: &RadioProps) -> Html {
|
||||||
type Properties = RadioProps;
|
html! {
|
||||||
|
<label
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
class={classes!(
|
||||||
Self { props }
|
"bp3-control",
|
||||||
}
|
"bp3-radio",
|
||||||
|
props.disabled.then(|| "bp3-disabled"),
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
props.inline.then(|| "bp3-inline"),
|
||||||
true
|
props.large.then(|| "bp3-large"),
|
||||||
}
|
)}
|
||||||
|
>
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
<input
|
||||||
if self.props != props {
|
type="radio"
|
||||||
self.props = props;
|
onchange={props.onchange.clone().unwrap_or_default()}
|
||||||
true
|
disabled={props.disabled}
|
||||||
} else {
|
value={props.value.clone().unwrap_or_default()}
|
||||||
false
|
checked={props.checked.unwrap_or(false)}
|
||||||
}
|
name={props.name.clone().unwrap_or_default()}
|
||||||
}
|
/>
|
||||||
|
<span
|
||||||
fn view(&self) -> Html {
|
class={classes!("bp3-control-indicator")}
|
||||||
html! {
|
|
||||||
<label
|
|
||||||
class=classes!(
|
|
||||||
"bp3-control",
|
|
||||||
"bp3-radio",
|
|
||||||
self.props.disabled.then(|| "bp3-disabled"),
|
|
||||||
self.props.inline.then(|| "bp3-inline"),
|
|
||||||
self.props.large.then(|| "bp3-large"),
|
|
||||||
)
|
|
||||||
>
|
>
|
||||||
<input
|
</span>
|
||||||
type="radio"
|
{props.label.clone()}
|
||||||
onchange={self.props.onchange.clone().unwrap_or_default()}
|
</label>
|
||||||
disabled=self.props.disabled
|
|
||||||
value={self.props.value.clone().unwrap_or_default()}
|
|
||||||
checked=self.props.checked.unwrap_or(false)
|
|
||||||
name={self.props.name.clone().unwrap_or_default()}
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class=classes!("bp3-control-indicator")
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
{self.props.label.clone()}
|
|
||||||
</label>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
use crate::Radio;
|
use crate::Radio;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct RadioGroup<T: Clone + PartialEq + 'static> {
|
|
||||||
props: RadioGroupProps<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct RadioGroupProps<T: Clone + PartialEq + 'static> {
|
pub struct RadioGroupProps<T: Clone + PartialEq + 'static> {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -24,71 +20,46 @@ pub struct RadioGroupProps<T: Clone + PartialEq + 'static> {
|
||||||
pub class: Classes,
|
pub class: Classes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone + PartialEq + 'static> Component for RadioGroup<T> {
|
// impl<T: Clone + PartialEq + 'static> Component for RadioGroup<T> {
|
||||||
type Message = ();
|
|
||||||
type Properties = RadioGroupProps<T>;
|
|
||||||
|
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
#[function_component(RadioGroup)]
|
||||||
Self { props }
|
pub fn radio_group<T: Clone + PartialEq + 'static>(props: &RadioGroupProps<T>) -> Html {
|
||||||
}
|
let option_children = props
|
||||||
|
.options
|
||||||
|
.iter()
|
||||||
|
.map(|(value, label)| {
|
||||||
|
let checked = props.value.as_ref().map(|x| value == x).unwrap_or_default();
|
||||||
|
let value = value.clone();
|
||||||
|
|
||||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
html! {
|
||||||
true
|
<Radio
|
||||||
}
|
value={"".to_string()}
|
||||||
|
label={html!(label)}
|
||||||
|
checked={checked}
|
||||||
|
onchange={props.onchange.reform(move |_| value.clone())}
|
||||||
|
inline={props.inline}
|
||||||
|
disabled={props.disabled}
|
||||||
|
large={props.large}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Html>();
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
html! {
|
||||||
if self.props != props {
|
<div
|
||||||
self.props = props;
|
class={classes!(
|
||||||
true
|
"bp3-radio-group",
|
||||||
} else {
|
props.class.clone(),
|
||||||
false
|
)}
|
||||||
}
|
>
|
||||||
}
|
{
|
||||||
|
if let Some(label) = props.label.clone() {
|
||||||
fn view(&self) -> Html {
|
label
|
||||||
let option_children = self
|
} else {
|
||||||
.props
|
html!()
|
||||||
.options
|
|
||||||
.iter()
|
|
||||||
.map(|(value, label)| {
|
|
||||||
let checked = self
|
|
||||||
.props
|
|
||||||
.value
|
|
||||||
.as_ref()
|
|
||||||
.map(|x| value == x)
|
|
||||||
.unwrap_or_default();
|
|
||||||
let value = value.clone();
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<Radio
|
|
||||||
value="".to_string()
|
|
||||||
label=html!(label)
|
|
||||||
checked=checked
|
|
||||||
onchange=self.props.onchange.reform(move |_| value.clone())
|
|
||||||
inline=self.props.inline
|
|
||||||
disabled=self.props.disabled
|
|
||||||
large=self.props.large
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.collect::<Html>();
|
{option_children}
|
||||||
|
</div>
|
||||||
html! {
|
|
||||||
<div
|
|
||||||
class=classes!(
|
|
||||||
"bp3-radio-group",
|
|
||||||
self.props.class.clone(),
|
|
||||||
)
|
|
||||||
>
|
|
||||||
{
|
|
||||||
if let Some(label) = self.props.label.clone() {
|
|
||||||
label
|
|
||||||
} else {
|
|
||||||
html!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{option_children}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
160
src/slider.rs
160
src/slider.rs
|
@ -1,19 +1,19 @@
|
||||||
use crate::Intent;
|
use crate::Intent;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use wasm_bindgen::closure::Closure;
|
use wasm_bindgen::closure::Closure;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use web_sys::Element;
|
use web_sys::Element;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Slider<T: Clone + PartialEq + 'static> {
|
pub struct Slider<T: Clone + PartialEq + 'static> {
|
||||||
props: SliderProps<T>,
|
|
||||||
mouse_move: Closure<dyn FnMut(MouseEvent)>,
|
mouse_move: Closure<dyn FnMut(MouseEvent)>,
|
||||||
mouse_up: Closure<dyn FnMut(MouseEvent)>,
|
mouse_up: Closure<dyn FnMut(MouseEvent)>,
|
||||||
link: ComponentLink<Self>,
|
|
||||||
handle_ref: NodeRef,
|
handle_ref: NodeRef,
|
||||||
track_ref: NodeRef,
|
track_ref: NodeRef,
|
||||||
is_moving: bool,
|
is_moving: bool,
|
||||||
focus_handle: bool,
|
focus_handle: bool,
|
||||||
|
phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
@ -42,35 +42,34 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = SliderProps<T>;
|
type Properties = SliderProps<T>;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
let mouse_move = {
|
let mouse_move = {
|
||||||
let link = link.clone();
|
let link = ctx.link().clone();
|
||||||
Closure::wrap(Box::new(move |event: web_sys::MouseEvent| {
|
Closure::wrap(Box::new(move |event: web_sys::MouseEvent| {
|
||||||
link.send_message(Msg::Mouse(event));
|
link.send_message(Msg::Mouse(event));
|
||||||
}) as Box<dyn FnMut(_)>)
|
}) as Box<dyn FnMut(_)>)
|
||||||
};
|
};
|
||||||
let mouse_up = {
|
let mouse_up = {
|
||||||
let link = link.clone();
|
let link = ctx.link().clone();
|
||||||
Closure::wrap(Box::new(move |_event: web_sys::MouseEvent| {
|
Closure::wrap(Box::new(move |_event: web_sys::MouseEvent| {
|
||||||
link.send_message(Msg::StopChange);
|
link.send_message(Msg::StopChange);
|
||||||
}) as Box<dyn FnMut(_)>)
|
}) as Box<dyn FnMut(_)>)
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
props,
|
|
||||||
mouse_move,
|
mouse_move,
|
||||||
mouse_up,
|
mouse_up,
|
||||||
link,
|
|
||||||
handle_ref: NodeRef::default(),
|
handle_ref: NodeRef::default(),
|
||||||
track_ref: NodeRef::default(),
|
track_ref: NodeRef::default(),
|
||||||
is_moving: false,
|
is_moving: false,
|
||||||
focus_handle: false,
|
focus_handle: false,
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::StartChange if self.props.values.len() > 1 => {
|
Msg::StartChange if ctx.props().values.len() > 1 => {
|
||||||
let document = yew::utils::document();
|
let document = gloo::utils::document();
|
||||||
let event_target: &web_sys::EventTarget = document.as_ref();
|
let event_target: &web_sys::EventTarget = document.as_ref();
|
||||||
self.is_moving = true;
|
self.is_moving = true;
|
||||||
event_target
|
event_target
|
||||||
|
@ -89,23 +88,23 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Msg::StartChange => false,
|
Msg::StartChange => false,
|
||||||
Msg::Mouse(event) if self.props.values.len() > 1 => {
|
Msg::Mouse(event) if ctx.props().values.len() > 1 => {
|
||||||
if event.buttons() == crate::MOUSE_EVENT_BUTTONS_PRIMARY {
|
if event.buttons() == crate::MOUSE_EVENT_BUTTONS_PRIMARY {
|
||||||
let track_rect = self.track_ref.cast::<Element>().expect("no track ref");
|
let track_rect = self.track_ref.cast::<Element>().expect("no track ref");
|
||||||
let tick_size = (track_rect.client_width() as f64)
|
let tick_size = (track_rect.client_width() as f64)
|
||||||
/ self.props.values.len().saturating_sub(1) as f64;
|
/ ctx.props().values.len().saturating_sub(1) as f64;
|
||||||
let pixel_delta =
|
let pixel_delta =
|
||||||
(event.client_x() as f64) - track_rect.get_bounding_client_rect().left();
|
(event.client_x() as f64) - track_rect.get_bounding_client_rect().left();
|
||||||
|
|
||||||
let position = (pixel_delta / tick_size).round() as usize;
|
let position = (pixel_delta / tick_size).round() as usize;
|
||||||
|
|
||||||
let (value, _) =
|
let (value, _) =
|
||||||
self.props.values.get(position).unwrap_or_else(|| {
|
ctx.props().values.get(position).unwrap_or_else(|| {
|
||||||
self.props.values.last().expect("No value in the vec")
|
ctx.props().values.last().expect("No value in the vec")
|
||||||
});
|
});
|
||||||
|
|
||||||
if Some(value) != self.props.selected.as_ref() {
|
if Some(value) != ctx.props().selected.as_ref() {
|
||||||
self.props.onchange.emit(value.clone());
|
ctx.props().onchange.emit(value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -115,7 +114,7 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
}
|
}
|
||||||
Msg::Mouse(_) => false,
|
Msg::Mouse(_) => false,
|
||||||
Msg::StopChange => {
|
Msg::StopChange => {
|
||||||
let document = yew::utils::document();
|
let document = gloo::utils::document();
|
||||||
let event_target: &web_sys::EventTarget = document.as_ref();
|
let event_target: &web_sys::EventTarget = document.as_ref();
|
||||||
self.is_moving = false;
|
self.is_moving = false;
|
||||||
event_target
|
event_target
|
||||||
|
@ -132,43 +131,43 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
.expect("No event listener to remove");
|
.expect("No event listener to remove");
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Msg::Keyboard(event) if self.props.values.len() > 1 => match event.key().as_str() {
|
Msg::Keyboard(event) if ctx.props().values.len() > 1 => match event.key().as_str() {
|
||||||
"ArrowDown" | "ArrowLeft" => {
|
"ArrowDown" | "ArrowLeft" => {
|
||||||
self.focus_handle = true;
|
self.focus_handle = true;
|
||||||
event.prevent_default();
|
event.prevent_default();
|
||||||
let index = self
|
let index = ctx
|
||||||
.props
|
.props()
|
||||||
.values
|
.values
|
||||||
.iter()
|
.iter()
|
||||||
.position(|(value, _)| Some(value) == self.props.selected.as_ref())
|
.position(|(value, _)| Some(value) == ctx.props().selected.as_ref())
|
||||||
.map(|i| i.saturating_sub(1))
|
.map(|i| i.saturating_sub(1))
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let (value, _) = self.props.values[index].clone();
|
let (value, _) = ctx.props().values[index].clone();
|
||||||
self.props.onchange.emit(value);
|
ctx.props().onchange.emit(value);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
"ArrowUp" | "ArrowRight" => {
|
"ArrowUp" | "ArrowRight" => {
|
||||||
self.focus_handle = true;
|
self.focus_handle = true;
|
||||||
event.prevent_default();
|
event.prevent_default();
|
||||||
let index = self
|
let index = ctx
|
||||||
.props
|
.props()
|
||||||
.values
|
.values
|
||||||
.iter()
|
.iter()
|
||||||
.position(|(value, _)| Some(value) == self.props.selected.as_ref())
|
.position(|(value, _)| Some(value) == ctx.props().selected.as_ref())
|
||||||
.map(|i| i.saturating_add(1))
|
.map(|i| i.saturating_add(1))
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let (value, _) = self
|
let (value, _) = ctx
|
||||||
.props
|
.props()
|
||||||
.values
|
.values
|
||||||
.get(index)
|
.get(index)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
self.props.values.last().expect(
|
ctx.props().values.last().expect(
|
||||||
"Already check, \
|
"Already check, \
|
||||||
there are at least 2 values in self.props.options; qed",
|
there are at least 2 values in ctx.props().options; qed",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.clone();
|
.clone();
|
||||||
self.props.onchange.emit(value);
|
ctx.props().onchange.emit(value);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -177,23 +176,14 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
let value_index = ctx
|
||||||
self.props = props;
|
.props()
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let value_index = self
|
|
||||||
.props
|
|
||||||
.values
|
.values
|
||||||
.iter()
|
.iter()
|
||||||
.position(|(value, _)| Some(value) == self.props.selected.as_ref());
|
.position(|(value, _)| Some(value) == ctx.props().selected.as_ref());
|
||||||
let labels = if self.props.values.len() > 1 {
|
let labels = if ctx.props().values.len() > 1 {
|
||||||
self.props
|
ctx.props()
|
||||||
.values
|
.values
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -201,11 +191,11 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
label.clone().map(|x| {
|
label.clone().map(|x| {
|
||||||
html! {
|
html! {
|
||||||
<div
|
<div
|
||||||
class=classes!("bp3-slider-label")
|
class={classes!("bp3-slider-label")}
|
||||||
style=format!(
|
style={format!(
|
||||||
"left: {}%;", (i as f64) * 100.0
|
"left: {}%;", (i as f64) * 100.0
|
||||||
/ ((self.props.values.len() as f64) - 1.0)
|
/ ((ctx.props().values.len() as f64) - 1.0)
|
||||||
)
|
)}
|
||||||
>
|
>
|
||||||
{x}
|
{x}
|
||||||
</div>
|
</div>
|
||||||
|
@ -213,11 +203,11 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Html>()
|
.collect::<Html>()
|
||||||
} else if let Some((_, Some(label))) = self.props.values.first() {
|
} else if let Some((_, Some(label))) = ctx.props().values.first() {
|
||||||
html! {
|
html! {
|
||||||
<div
|
<div
|
||||||
class=classes!("bp3-slider-label")
|
class={classes!("bp3-slider-label")}
|
||||||
style="left: 50%;"
|
style={"left: 50%;"}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</div>
|
</div>
|
||||||
|
@ -225,9 +215,9 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
} else {
|
} else {
|
||||||
html!()
|
html!()
|
||||||
};
|
};
|
||||||
let value_label = self.props.value_label.clone().map(|x| {
|
let value_label = ctx.props().value_label.clone().map(|x| {
|
||||||
html! {
|
html! {
|
||||||
<span class=classes!("bp3-slider-label")>
|
<span class={classes!("bp3-slider-label")}>
|
||||||
{x}
|
{x}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
@ -235,12 +225,12 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div
|
<div
|
||||||
class=classes!(
|
class={classes!(
|
||||||
"bp3-slider",
|
"bp3-slider",
|
||||||
self.props.vertical.then(|| "bp3-vertical"),
|
ctx.props().vertical.then(|| "bp3-vertical"),
|
||||||
)
|
)}
|
||||||
onmousedown=(self.props.values.len() > 1).then(
|
onmousedown={(ctx.props().values.len() > 1).then(
|
||||||
|| self.link.batch_callback(
|
|| ctx.link().batch_callback(
|
||||||
|event: MouseEvent| {
|
|event: MouseEvent| {
|
||||||
if event.buttons() ==
|
if event.buttons() ==
|
||||||
crate::MOUSE_EVENT_BUTTONS_PRIMARY
|
crate::MOUSE_EVENT_BUTTONS_PRIMARY
|
||||||
|
@ -251,19 +241,19 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class=classes!("bp3-slider-track")
|
class={classes!("bp3-slider-track")}
|
||||||
ref={self.track_ref.clone()}
|
ref={self.track_ref.clone()}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
if value_index.is_none() && !self.props.values.is_empty() {
|
if value_index.is_none() && !ctx.props().values.is_empty() {
|
||||||
html! {
|
html! {
|
||||||
<div
|
<div
|
||||||
class=classes!("bp3-slider-progress")
|
class={classes!("bp3-slider-progress")}
|
||||||
style="top: 0px;"
|
style="top: 0px;"
|
||||||
onkeydown=self.link.callback(|event| Msg::Keyboard(event))
|
onkeydown={ctx.link().callback(|event| Msg::Keyboard(event))}
|
||||||
tabindex=0
|
tabindex=0
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
@ -271,7 +261,7 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
} else {
|
} else {
|
||||||
html! {
|
html! {
|
||||||
<div
|
<div
|
||||||
class=classes!("bp3-slider-progress")
|
class={classes!("bp3-slider-progress")}
|
||||||
style="top: 0px;"
|
style="top: 0px;"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
@ -280,18 +270,18 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
match value_index {
|
match value_index {
|
||||||
Some(index) if self.props.values.len() > 1
|
Some(index) if ctx.props().values.len() > 1
|
||||||
&& self.props.intent.is_some() => {
|
&& ctx.props().intent.is_some() => {
|
||||||
html! {
|
html! {
|
||||||
<div
|
<div
|
||||||
class=classes!("bp3-slider-progress", self.props.intent)
|
class={classes!("bp3-slider-progress", ctx.props().intent)}
|
||||||
style=format!(
|
style={format!(
|
||||||
"left: 0%; right: {}%; top: 0px;",
|
"left: 0%; right: {}%; top: 0px;",
|
||||||
100.0 - (
|
100.0 - (
|
||||||
100.0 * (index as f64)
|
100.0 * (index as f64)
|
||||||
/ (self.props.values.len() as f64 - 1.0)
|
/ (ctx.props().values.len() as f64 - 1.0)
|
||||||
)
|
)
|
||||||
)
|
)}
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -300,34 +290,34 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class=classes!("bp3-slider-axis")>
|
<div class={classes!("bp3-slider-axis")}>
|
||||||
{labels}
|
{labels}
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
match value_index {
|
match value_index {
|
||||||
Some(index) if self.props.values.len() > 1 =>
|
Some(index) if ctx.props().values.len() > 1 =>
|
||||||
{
|
{
|
||||||
html! {
|
html! {
|
||||||
<span
|
<span
|
||||||
class=classes!(
|
class={classes!(
|
||||||
"bp3-slider-handle",
|
"bp3-slider-handle",
|
||||||
self.is_moving.then(|| "bp3-active"),
|
self.is_moving.then(|| "bp3-active"),
|
||||||
)
|
)}
|
||||||
ref={self.handle_ref.clone()}
|
ref={self.handle_ref.clone()}
|
||||||
style=format!(
|
style={format!(
|
||||||
"left: calc({}% - 8px);",
|
"left: calc({}% - 8px);",
|
||||||
100.0 * (index as f64)
|
100.0 * (index as f64)
|
||||||
/ (self.props.values.len() as f64 - 1.0),
|
/ (ctx.props().values.len() as f64 - 1.0),
|
||||||
)
|
)}
|
||||||
onmousedown=self.link.batch_callback(
|
onmousedown={ctx.link().batch_callback(
|
||||||
|event: MouseEvent| {
|
|event: MouseEvent| {
|
||||||
if event.buttons() == crate::MOUSE_EVENT_BUTTONS_PRIMARY {
|
if event.buttons() == crate::MOUSE_EVENT_BUTTONS_PRIMARY {
|
||||||
vec![Msg::StartChange]
|
vec![Msg::StartChange]
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
})
|
})}
|
||||||
onkeydown=self.link.callback(|event| Msg::Keyboard(event))
|
onkeydown={ctx.link().callback(|event| Msg::Keyboard(event))}
|
||||||
tabindex=0
|
tabindex=0
|
||||||
>
|
>
|
||||||
{value_label.clone().unwrap_or_default()}
|
{value_label.clone().unwrap_or_default()}
|
||||||
|
@ -337,10 +327,10 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
html! {
|
html! {
|
||||||
<span
|
<span
|
||||||
class=classes!(
|
class={classes!(
|
||||||
"bp3-slider-handle",
|
"bp3-slider-handle",
|
||||||
self.is_moving.then(|| "bp3-active"),
|
self.is_moving.then(|| "bp3-active"),
|
||||||
)
|
)}
|
||||||
ref={self.handle_ref.clone()}
|
ref={self.handle_ref.clone()}
|
||||||
style="left: calc(50% - 8px);"
|
style="left: calc(50% - 8px);"
|
||||||
>
|
>
|
||||||
|
@ -355,7 +345,7 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rendered(&mut self, _: bool) {
|
fn rendered(&mut self, _ctx: &Context<Self>, _: bool) {
|
||||||
if self.focus_handle {
|
if self.focus_handle {
|
||||||
if let Some(element) = self.handle_ref.cast::<web_sys::HtmlElement>() {
|
if let Some(element) = self.handle_ref.cast::<web_sys::HtmlElement>() {
|
||||||
let _ = element.focus();
|
let _ = element.focus();
|
||||||
|
|
117
src/spinner.rs
117
src/spinner.rs
|
@ -10,10 +10,6 @@ pub const SPINNER_SIZE_SMALL: f32 = 20.0;
|
||||||
pub const SPINNER_SIZE_STANDARD: f32 = 50.0;
|
pub const SPINNER_SIZE_STANDARD: f32 = 50.0;
|
||||||
pub const SPINNER_SIZE_LARGE: f32 = 100.0;
|
pub const SPINNER_SIZE_LARGE: f32 = 100.0;
|
||||||
|
|
||||||
pub struct Spinner {
|
|
||||||
props: SpinnerProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct SpinnerProps {
|
pub struct SpinnerProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -26,77 +22,56 @@ pub struct SpinnerProps {
|
||||||
pub value: f32,
|
pub value: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Spinner {
|
#[function_component(Spinner)]
|
||||||
type Message = ();
|
pub fn spinner(props: &SpinnerProps) -> Html {
|
||||||
type Properties = SpinnerProps;
|
let size = f32::max(SPINNER_MIN_SIZE, props.size);
|
||||||
|
let stroke_width = f32::min(MIN_STROKE_WIDTH, (STROKE_WIDTH * SPINNER_SIZE_LARGE) / size);
|
||||||
|
let view_box = {
|
||||||
|
let radius = R + stroke_width / 2.00;
|
||||||
|
let view_box_x = 50.00 - radius;
|
||||||
|
let view_box_width = radius * 2.00;
|
||||||
|
format!(
|
||||||
|
"{:.2} {:.2} {:.2} {:.2}",
|
||||||
|
view_box_x, view_box_x, view_box_width, view_box_width,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let spinner_track = format!(
|
||||||
|
"M 50,50 m 0,-{R:.0} a {R:.0},{R:.0} 0 1 1 0,{R2:.0} a {R:.0},{R:.0} 0 1 1 0,-{R2:.0}",
|
||||||
|
R = R,
|
||||||
|
R2 = R * 2.0,
|
||||||
|
);
|
||||||
|
let stroke_offset = PATH_LENGTH - PATH_LENGTH * props.value.clamp(0.0, 1.0);
|
||||||
|
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
html! {
|
||||||
Spinner { props }
|
<div
|
||||||
}
|
class={classes!(
|
||||||
|
"bp3-spinner",
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
props.intent,
|
||||||
true
|
props.class.clone(),
|
||||||
}
|
)}
|
||||||
|
>
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let size = f32::max(SPINNER_MIN_SIZE, self.props.size);
|
|
||||||
let stroke_width = f32::min(MIN_STROKE_WIDTH, (STROKE_WIDTH * SPINNER_SIZE_LARGE) / size);
|
|
||||||
let view_box = {
|
|
||||||
let radius = R + stroke_width / 2.00;
|
|
||||||
let view_box_x = 50.00 - radius;
|
|
||||||
let view_box_width = radius * 2.00;
|
|
||||||
format!(
|
|
||||||
"{:.2} {:.2} {:.2} {:.2}",
|
|
||||||
view_box_x, view_box_x, view_box_width, view_box_width,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let spinner_track = format!(
|
|
||||||
"M 50,50 m 0,-{R:.0} a {R:.0},{R:.0} 0 1 1 0,{R2:.0} a {R:.0},{R:.0} 0 1 1 0,-{R2:.0}",
|
|
||||||
R = R,
|
|
||||||
R2 = R * 2.0,
|
|
||||||
);
|
|
||||||
let stroke_offset = PATH_LENGTH - PATH_LENGTH * self.props.value.clamp(0.0, 1.0);
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<div
|
<div
|
||||||
class=classes!(
|
class={classes!("bp3-spinner-animation")}
|
||||||
"bp3-spinner",
|
|
||||||
self.props.intent,
|
|
||||||
self.props.class.clone(),
|
|
||||||
)
|
|
||||||
>
|
>
|
||||||
<div
|
<svg
|
||||||
class=classes!("bp3-spinner-animation")
|
width={size.to_string()}
|
||||||
|
height={size.to_string()}
|
||||||
|
stroke-width={stroke_width.to_string()}
|
||||||
|
viewBox={view_box}
|
||||||
>
|
>
|
||||||
<svg
|
<path
|
||||||
width=size.to_string()
|
class={classes!("bp3-spinner-track")}
|
||||||
height=size.to_string()
|
d={spinner_track.clone()}
|
||||||
stroke-width=stroke_width.to_string()
|
/>
|
||||||
viewBox=view_box
|
<path
|
||||||
>
|
class={classes!("bp3-spinner-head")}
|
||||||
<path
|
d={spinner_track}
|
||||||
class=classes!("bp3-spinner-track")
|
pathLength={PATH_LENGTH.to_string()}
|
||||||
d=spinner_track.clone()
|
stroke-dasharray={format!("{} {}", PATH_LENGTH, PATH_LENGTH)}
|
||||||
/>
|
stroke-dashoffset={stroke_offset.to_string()}
|
||||||
<path
|
/>
|
||||||
class=classes!("bp3-spinner-head")
|
</svg>
|
||||||
d=spinner_track
|
|
||||||
pathLength=PATH_LENGTH.to_string()
|
|
||||||
stroke-dasharray=format!("{} {}", PATH_LENGTH, PATH_LENGTH)
|
|
||||||
stroke-dashoffset=stroke_offset.to_string()
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
133
src/switch.rs
133
src/switch.rs
|
@ -1,9 +1,5 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Switch {
|
|
||||||
props: SwitchProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct SwitchProps {
|
pub struct SwitchProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -28,85 +24,64 @@ pub struct SwitchProps {
|
||||||
pub align_right: bool,
|
pub align_right: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Switch {
|
#[function_component(Switch)]
|
||||||
type Message = ();
|
pub fn switch(props: &SwitchProps) -> Html {
|
||||||
type Properties = SwitchProps;
|
let display_label = {
|
||||||
|
if props.inner_label.is_some() || props.inner_label_checked.is_some() {
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
let inner_label = props.inner_label.as_deref().unwrap_or_default();
|
||||||
Self { props }
|
let inner_label_checked = props.inner_label_checked.as_ref();
|
||||||
}
|
html! {
|
||||||
|
<>
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
<div class={classes!("bp3-control-indicator-child")}>
|
||||||
true
|
<div class={classes!("bp3-switch-inner-text")}>
|
||||||
}
|
{
|
||||||
|
if let Some(label_checked) = inner_label_checked {
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
label_checked.clone()
|
||||||
if self.props != props {
|
} else {
|
||||||
self.props = props;
|
inner_label.to_string()
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let display_label = {
|
|
||||||
if self.props.inner_label.is_some() || self.props.inner_label_checked.is_some() {
|
|
||||||
let inner_label = self.props.inner_label.as_deref().unwrap_or_default();
|
|
||||||
let inner_label_checked = self.props.inner_label_checked.as_ref();
|
|
||||||
html! {
|
|
||||||
<>
|
|
||||||
<div class=classes!("bp3-control-indicator-child")>
|
|
||||||
<div class=classes!("bp3-switch-inner-text")>
|
|
||||||
{
|
|
||||||
if let Some(label_checked) = inner_label_checked {
|
|
||||||
label_checked.clone()
|
|
||||||
} else {
|
|
||||||
inner_label.to_string()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</div>
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class=classes!("bp3-control-indicator-child")>
|
</div>
|
||||||
<div class=classes!("bp3-switch-inner-text")>
|
<div class={classes!("bp3-control-indicator-child")}>
|
||||||
{inner_label.to_string()}
|
<div class={classes!("bp3-switch-inner-text")}>
|
||||||
</div>
|
{inner_label.to_string()}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
}
|
</>
|
||||||
} else {
|
|
||||||
Html::default()
|
|
||||||
}
|
}
|
||||||
};
|
} else {
|
||||||
html! {
|
Html::default()
|
||||||
<label
|
|
||||||
class=classes!(
|
|
||||||
"bp3-control",
|
|
||||||
"bp3-switch",
|
|
||||||
self.props.disabled.then(|| "bp3-disabled"),
|
|
||||||
self.props.inline.then(|| "bp3-inline"),
|
|
||||||
self.props.large.then(|| "bp3-large"),
|
|
||||||
self.props.class.clone(),
|
|
||||||
if self.props.align_right {
|
|
||||||
"bp3-align-right"
|
|
||||||
} else {
|
|
||||||
"bp3-align-left"
|
|
||||||
},
|
|
||||||
)
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={self.props.checked}
|
|
||||||
onclick={self.props.onclick.clone()}
|
|
||||||
disabled=self.props.disabled
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class=classes!("bp3-control-indicator")
|
|
||||||
>
|
|
||||||
{display_label}
|
|
||||||
</span>
|
|
||||||
{self.props.label.clone()}
|
|
||||||
</label>
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
html! {
|
||||||
|
<label
|
||||||
|
class={classes!(
|
||||||
|
"bp3-control",
|
||||||
|
"bp3-switch",
|
||||||
|
props.disabled.then(|| "bp3-disabled"),
|
||||||
|
props.inline.then(|| "bp3-inline"),
|
||||||
|
props.large.then(|| "bp3-large"),
|
||||||
|
props.class.clone(),
|
||||||
|
if props.align_right {
|
||||||
|
"bp3-align-right"
|
||||||
|
} else {
|
||||||
|
"bp3-align-left"
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={props.checked}
|
||||||
|
onclick={props.onclick.clone()}
|
||||||
|
disabled={props.disabled}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class={classes!("bp3-control-indicator")}
|
||||||
|
>
|
||||||
|
{display_label}
|
||||||
|
</span>
|
||||||
|
{props.label.clone()}
|
||||||
|
</label>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
97
src/tabs.rs
97
src/tabs.rs
|
@ -1,12 +1,13 @@
|
||||||
use std::collections::{hash_map::DefaultHasher, HashMap};
|
use std::collections::{hash_map::DefaultHasher, HashMap};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::marker::PhantomData;
|
||||||
use web_sys::HtmlElement;
|
use web_sys::HtmlElement;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Tabs<T: Clone + PartialEq + Hash + 'static> {
|
pub struct Tabs<T: Clone + PartialEq + Hash + 'static> {
|
||||||
props: TabsProps<T>,
|
|
||||||
tab_refs: HashMap<u64, NodeRef>,
|
tab_refs: HashMap<u64, NodeRef>,
|
||||||
indicator_ref: NodeRef,
|
indicator_ref: NodeRef,
|
||||||
|
phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
@ -34,8 +35,9 @@ impl<T: Clone + PartialEq + Hash + 'static> Component for Tabs<T> {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
type Properties = TabsProps<T>;
|
type Properties = TabsProps<T>;
|
||||||
|
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
let tab_refs = props
|
let tab_refs = ctx
|
||||||
|
.props()
|
||||||
.tabs
|
.tabs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
|
@ -46,62 +48,53 @@ impl<T: Clone + PartialEq + Hash + 'static> Component for Tabs<T> {
|
||||||
})
|
})
|
||||||
.collect::<HashMap<_, _>>();
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
Tabs {
|
Self {
|
||||||
props,
|
|
||||||
tab_refs,
|
tab_refs,
|
||||||
indicator_ref: Default::default(),
|
indicator_ref: Default::default(),
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
let tabs = ctx
|
||||||
self.props = props;
|
.props()
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let tabs = self
|
|
||||||
.props
|
|
||||||
.tabs
|
.tabs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
x.id.hash(&mut hasher);
|
x.id.hash(&mut hasher);
|
||||||
let id = hasher.finish();
|
let id = hasher.finish();
|
||||||
let title_id = format!("bp3-tab-title_{}_{}", self.props.id, id);
|
let title_id = format!("bp3-tab-title_{}_{}", ctx.props().id, id);
|
||||||
let panel_id = format!("bp3-tab-panel_{}_{}", self.props.id, id);
|
let panel_id = format!("bp3-tab-panel_{}_{}", ctx.props().id, id);
|
||||||
let selected = self.props.selected_tab_id == x.id;
|
let selected = ctx.props().selected_tab_id == x.id;
|
||||||
(x, id, title_id, panel_id, selected)
|
(x, id, title_id, panel_id, selected)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div
|
<div
|
||||||
class=classes!(
|
class={classes!(
|
||||||
"bp3-tabs",
|
"bp3-tabs",
|
||||||
self.props.vertical.then(|| "bp3-vertical"),
|
ctx.props().vertical.then(|| "bp3-vertical"),
|
||||||
self.props.class.clone(),
|
ctx.props().class.clone(),
|
||||||
)
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class=classes!(
|
class={classes!(
|
||||||
"bp3-tab-list",
|
"bp3-tab-list",
|
||||||
self.props.large.then(|| "bp3-large"),
|
ctx.props().large.then(|| "bp3-large"),
|
||||||
)
|
)}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
if self.props.animate {
|
if ctx.props().animate {
|
||||||
html! {
|
html! {
|
||||||
<div
|
<div
|
||||||
class="bp3-tab-indicator-wrapper"
|
class="bp3-tab-indicator-wrapper"
|
||||||
ref=self.indicator_ref.clone()
|
ref={self.indicator_ref.clone()}
|
||||||
>
|
>
|
||||||
<div class="bp3-tab-indicator" />
|
<div class="bp3-tab-indicator" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -115,27 +108,27 @@ impl<T: Clone + PartialEq + Hash + 'static> Component for Tabs<T> {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(props, id, title_id, panel_id, selected)| html! {
|
.map(|(props, id, title_id, panel_id, selected)| html! {
|
||||||
<div
|
<div
|
||||||
class=classes!(
|
class={classes!(
|
||||||
"bp3-tab",
|
"bp3-tab",
|
||||||
props.title_class.clone(),
|
props.title_class.clone(),
|
||||||
)
|
)}
|
||||||
aria-disabled=props.disabled.then(|| "true")
|
aria-disabled={props.disabled.then(|| "true")}
|
||||||
aria-expanded=selected.to_string()
|
aria-expanded={selected.to_string()}
|
||||||
aria-selected=selected.to_string()
|
aria-selected={selected.to_string()}
|
||||||
role="tab"
|
role="tab"
|
||||||
tabIndex={(!props.disabled).then(|| "0")}
|
tabIndex={(!props.disabled).then(|| "0")}
|
||||||
id=title_id.to_string()
|
id={title_id.to_string()}
|
||||||
aria-controls=panel_id.to_string()
|
aria-controls={panel_id.to_string()}
|
||||||
data-tab-id=id.to_string()
|
data-tab-id={id.to_string()}
|
||||||
onclick={(!props.disabled).then(|| {
|
onclick={(!props.disabled).then(|| {
|
||||||
let tab_id = props.id.clone();
|
let tab_id = props.id.clone();
|
||||||
self
|
ctx
|
||||||
.props
|
.props()
|
||||||
.onchange
|
.onchange
|
||||||
.reform(move |_| tab_id.clone())
|
.reform(move |_| tab_id.clone())
|
||||||
})}
|
})}
|
||||||
key=*id
|
key={*id}
|
||||||
ref=self.tab_refs[id].clone()
|
ref={self.tab_refs[id].clone()}
|
||||||
>
|
>
|
||||||
{ props.title.clone() }
|
{ props.title.clone() }
|
||||||
</div>
|
</div>
|
||||||
|
@ -147,19 +140,19 @@ impl<T: Clone + PartialEq + Hash + 'static> Component for Tabs<T> {
|
||||||
tabs
|
tabs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, _, _, _, selected)| {
|
.filter(|(_, _, _, _, selected)| {
|
||||||
!self.props.render_active_panel_only || *selected
|
!ctx.props().render_active_panel_only || *selected
|
||||||
})
|
})
|
||||||
.map(|(props, id, title_id, panel_id, selected)| html! {
|
.map(|(props, id, title_id, panel_id, selected)| html! {
|
||||||
<div
|
<div
|
||||||
class=classes!(
|
class={classes!(
|
||||||
"bp3-tab-panel",
|
"bp3-tab-panel",
|
||||||
selected.then(|| props.panel_class.clone()),
|
selected.then(|| props.panel_class.clone()),
|
||||||
)
|
)}
|
||||||
aria-labelledby=title_id.to_string()
|
aria-labelledby={title_id.to_string()}
|
||||||
aria-hidden=(!selected).then(|| "true")
|
aria-hidden={(!selected).then(|| "true")}
|
||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
id=panel_id.to_string()
|
id={panel_id.to_string()}
|
||||||
key=*id
|
key={*id}
|
||||||
>
|
>
|
||||||
{ props.panel.clone() }
|
{ props.panel.clone() }
|
||||||
</div>
|
</div>
|
||||||
|
@ -170,10 +163,10 @@ impl<T: Clone + PartialEq + Hash + 'static> Component for Tabs<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rendered(&mut self, _first_render: bool) {
|
fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
|
||||||
if self.props.animate {
|
if ctx.props().animate {
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
self.props.selected_tab_id.hash(&mut hasher);
|
ctx.props().selected_tab_id.hash(&mut hasher);
|
||||||
let id = hasher.finish();
|
let id = hasher.finish();
|
||||||
let indicator = self.indicator_ref.cast::<HtmlElement>().unwrap();
|
let indicator = self.indicator_ref.cast::<HtmlElement>().unwrap();
|
||||||
|
|
||||||
|
|
120
src/tag.rs
120
src/tag.rs
|
@ -1,11 +1,6 @@
|
||||||
use crate::{if_html, Icon, IconName, Intent, Text};
|
use crate::{if_html, Icon, IconName, Intent, Text};
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Tag {
|
|
||||||
props: TagProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct TagProps {
|
pub struct TagProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -36,81 +31,60 @@ pub struct TagProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub round: bool,
|
pub round: bool,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub title: Option<Cow<'static, str>>,
|
pub title: Option<String>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub class: Classes,
|
pub class: Classes,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub style: Option<Cow<'static, str>>,
|
pub style: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Tag {
|
#[function_component(Tag)]
|
||||||
type Message = ();
|
pub fn tag(props: &TagProps) -> Html {
|
||||||
type Properties = TagProps;
|
let icon = if_html!(let Some(icon) = props.icon => <Icon icon={icon} />);
|
||||||
|
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
let right_icon =
|
||||||
Tag { props }
|
if_html!(let Some(right_icon) = props.right_icon => <Icon icon={right_icon} />);
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
let remove_button = if_html! {
|
||||||
true
|
let Some(callback) = props.onremove.clone() =>
|
||||||
}
|
html!(
|
||||||
|
<button
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
class={classes!("bp3-tag-remove")}
|
||||||
if self.props != props {
|
onclick={callback}
|
||||||
self.props = props;
|
tabindex={props.interactive.then(|| "0")}
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let icon = if_html!(let Some(icon) = self.props.icon => <Icon icon=icon />);
|
|
||||||
|
|
||||||
let right_icon =
|
|
||||||
if_html!(let Some(right_icon) = self.props.right_icon => <Icon icon=right_icon />);
|
|
||||||
|
|
||||||
let remove_button = if_html! {
|
|
||||||
let Some(callback) = self.props.onremove.clone() =>
|
|
||||||
html!(
|
|
||||||
<button
|
|
||||||
class=classes!("bp3-tag-remove")
|
|
||||||
onclick={callback}
|
|
||||||
tabindex={self.props.interactive.then(|| "0")}
|
|
||||||
>
|
|
||||||
<Icon icon=IconName::SmallCross />
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<span
|
|
||||||
class=classes!(
|
|
||||||
"bp3-tag",
|
|
||||||
self.props.intent,
|
|
||||||
self.props.active.then(|| "bp3-active"),
|
|
||||||
self.props.fill.then(|| "bp3-fill"),
|
|
||||||
self.props.interactive.then(|| "bp3-interactive"),
|
|
||||||
self.props.large.then(|| "bp3-large"),
|
|
||||||
self.props.minimal.then(|| "bp3-minimal"),
|
|
||||||
self.props.round.then(|| "bp3-round"),
|
|
||||||
self.props.class.clone(),
|
|
||||||
)
|
|
||||||
style=self.props.style.clone()
|
|
||||||
onclick={self.props.onclick.clone()}
|
|
||||||
>
|
>
|
||||||
{icon}
|
<Icon icon={IconName::SmallCross} />
|
||||||
<Text
|
</button>
|
||||||
class=classes!("bp3-fill")
|
)
|
||||||
ellipsize={!self.props.multiline}
|
};
|
||||||
title=self.props.title.clone()
|
|
||||||
inline=true
|
html! {
|
||||||
>
|
<span
|
||||||
{self.props.children.clone()}
|
class={classes!(
|
||||||
</Text>
|
"bp3-tag",
|
||||||
{right_icon}
|
props.intent,
|
||||||
{remove_button}
|
props.active.then(|| "bp3-active"),
|
||||||
</span>
|
props.fill.then(|| "bp3-fill"),
|
||||||
}
|
props.interactive.then(|| "bp3-interactive"),
|
||||||
|
props.large.then(|| "bp3-large"),
|
||||||
|
props.minimal.then(|| "bp3-minimal"),
|
||||||
|
props.round.then(|| "bp3-round"),
|
||||||
|
props.class.clone(),
|
||||||
|
)}
|
||||||
|
style={props.style.clone()}
|
||||||
|
onclick={props.onclick.clone()}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
<Text
|
||||||
|
class={classes!("bp3-fill")}
|
||||||
|
ellipsize={!props.multiline}
|
||||||
|
title={props.title.clone()}
|
||||||
|
inline=true
|
||||||
|
>
|
||||||
|
{props.children.clone()}
|
||||||
|
</Text>
|
||||||
|
{right_icon}
|
||||||
|
{remove_button}
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
56
src/text.rs
56
src/text.rs
|
@ -1,10 +1,5 @@
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Text {
|
|
||||||
props: TextProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct TextProps {
|
pub struct TextProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -17,44 +12,23 @@ pub struct TextProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub inline: bool,
|
pub inline: bool,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub title: Option<Cow<'static, str>>,
|
pub title: Option<String>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub style: Option<Cow<'static, str>>,
|
pub style: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Text {
|
#[function_component(Text)]
|
||||||
type Message = ();
|
pub fn text(props: &TextProps) -> Html {
|
||||||
type Properties = TextProps;
|
html! {
|
||||||
|
<@{if props.inline { "span" } else { "div"}}
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
class={classes!(
|
||||||
Text { props }
|
props.class.clone(),
|
||||||
}
|
props.ellipsize.then (|| "bp3-text-overflow-ellipsis"),
|
||||||
|
)}
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
style={props.style.clone()}
|
||||||
true
|
title={props.title.clone()}
|
||||||
}
|
>
|
||||||
|
{props.children.clone()}
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
</@>
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<@{if self.props.inline { "span" } else { "div"}}
|
|
||||||
class=classes!(
|
|
||||||
self.props.class.clone(),
|
|
||||||
self.props.ellipsize.then (|| "bp3-text-overflow-ellipsis"),
|
|
||||||
)
|
|
||||||
style=self.props.style.clone()
|
|
||||||
title=self.props.title.clone()
|
|
||||||
>
|
|
||||||
{self.props.children.clone()}
|
|
||||||
</@>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
use crate::Intent;
|
use crate::Intent;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct TextArea {
|
|
||||||
props: TextAreaProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct TextAreaProps {
|
pub struct TextAreaProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -22,44 +18,23 @@ pub struct TextAreaProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub small: bool,
|
pub small: bool,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub onchange: Option<Callback<ChangeData>>,
|
pub onchange: Option<Callback<Event>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for TextArea {
|
#[function_component(TextArea)]
|
||||||
type Message = ();
|
pub fn text_area(props: &TextAreaProps) -> Html {
|
||||||
type Properties = TextAreaProps;
|
let classes = classes!(
|
||||||
|
"bp3-input",
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
props.intent,
|
||||||
TextArea { props }
|
props.class.clone(),
|
||||||
}
|
props.fill.then(|| "bp3-fill"),
|
||||||
|
props.small.then(|| "bp3-small"),
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
props.large.then(|| "bp3-large"),
|
||||||
true
|
);
|
||||||
}
|
html! {
|
||||||
|
<textarea
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
class={classes}
|
||||||
if self.props != props {
|
onchange={props.onchange.clone()}
|
||||||
self.props = props;
|
/>
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let classes = classes!(
|
|
||||||
"bp3-input",
|
|
||||||
self.props.intent,
|
|
||||||
self.props.class.clone(),
|
|
||||||
self.props.fill.then(|| "bp3-fill"),
|
|
||||||
self.props.small.then(|| "bp3-small"),
|
|
||||||
self.props.large.then(|| "bp3-large"),
|
|
||||||
);
|
|
||||||
html! {
|
|
||||||
<textarea
|
|
||||||
class=classes
|
|
||||||
onchange=self.props.onchange.clone()
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
167
src/tree.rs
167
src/tree.rs
|
@ -6,6 +6,7 @@ use std::cell::{Ref, RefCell, RefMut};
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
@ -41,13 +42,13 @@ impl<T> From<id_tree::Tree<NodeData<T>>> for TreeData<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Tree<T: Clone> {
|
pub struct Tree<T: Clone + PartialEq> {
|
||||||
props: TreeProps<T>,
|
|
||||||
previous_expanded_state: RefCell<HashMap<u64, bool>>,
|
previous_expanded_state: RefCell<HashMap<u64, bool>>,
|
||||||
|
phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct TreeProps<T: Clone> {
|
pub struct TreeProps<T: Clone + PartialEq> {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub is_expanded: bool,
|
pub is_expanded: bool,
|
||||||
pub tree: TreeData<T>,
|
pub tree: TreeData<T>,
|
||||||
|
@ -112,41 +113,32 @@ impl<T: Clone + PartialEq + 'static> Component for Tree<T> {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
type Properties = TreeProps<T>;
|
type Properties = TreeProps<T>;
|
||||||
|
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Tree {
|
Self {
|
||||||
props,
|
|
||||||
previous_expanded_state: Default::default(),
|
previous_expanded_state: Default::default(),
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
let tree = ctx.props().tree.borrow();
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let tree = self.props.tree.borrow();
|
|
||||||
|
|
||||||
let nodes = if let Some(root_id) = tree.root_node_id() {
|
let nodes = if let Some(root_id) = tree.root_node_id() {
|
||||||
self.render_children(root_id, 0)
|
self.render_children(ctx, root_id, 0)
|
||||||
} else {
|
} else {
|
||||||
html!()
|
html!()
|
||||||
};
|
};
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class=classes!(
|
<div class={classes!(
|
||||||
"bp3-tree",
|
"bp3-tree",
|
||||||
self.props.class.clone(),
|
ctx.props().class.clone(),
|
||||||
)>
|
)}>
|
||||||
<ul class=classes!("bp3-tree-node-list")>
|
<ul class={classes!("bp3-tree-node-list")}>
|
||||||
{nodes}
|
{nodes}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -154,9 +146,15 @@ impl<T: Clone + PartialEq + 'static> Component for Tree<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> Tree<T> {
|
// FIXME: The 'static bound here is probably wrong. Fix this at the end of PR.
|
||||||
fn render_children(&self, node_id: &NodeId, depth: u32) -> yew::virtual_dom::VNode {
|
impl<T: 'static + Clone + PartialEq> Tree<T> {
|
||||||
let tree = self.props.tree.borrow();
|
fn render_children(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<Self>,
|
||||||
|
node_id: &NodeId,
|
||||||
|
depth: u32,
|
||||||
|
) -> yew::virtual_dom::VNode {
|
||||||
|
let tree = ctx.props().tree.borrow();
|
||||||
let node = tree.get(node_id).unwrap();
|
let node = tree.get(node_id).unwrap();
|
||||||
let children = node.children();
|
let children = node.children();
|
||||||
|
|
||||||
|
@ -177,26 +175,26 @@ impl<T: Clone> Tree<T> {
|
||||||
let inner_nodes = if !data.is_expanded && !previous_is_expanded.unwrap_or(true) {
|
let inner_nodes = if !data.is_expanded && !previous_is_expanded.unwrap_or(true) {
|
||||||
Default::default()
|
Default::default()
|
||||||
} else {
|
} else {
|
||||||
self.render_children(node_id, depth + 1)
|
self.render_children(ctx, node_id, depth + 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<TreeNode
|
<TreeNode
|
||||||
disabled=data.disabled
|
disabled={data.disabled}
|
||||||
has_caret=data.has_caret
|
has_caret={data.has_caret}
|
||||||
icon=data.icon
|
icon={data.icon}
|
||||||
icon_color=data.icon_color.clone()
|
icon_color={data.icon_color.clone()}
|
||||||
icon_intent=data.icon_intent
|
icon_intent={data.icon_intent}
|
||||||
is_expanded=data.is_expanded
|
is_expanded={data.is_expanded}
|
||||||
is_selected=data.is_selected
|
is_selected={data.is_selected}
|
||||||
label=data.label.clone()
|
label={data.label.clone()}
|
||||||
secondary_label=data.secondary_label.clone()
|
secondary_label={data.secondary_label.clone()}
|
||||||
on_collapse=self.props.on_collapse.clone()
|
on_collapse={ctx.props().on_collapse.clone()}
|
||||||
on_expand=self.props.on_expand.clone()
|
on_expand={ctx.props().on_expand.clone()}
|
||||||
onclick=self.props.onclick.clone()
|
onclick={ctx.props().onclick.clone()}
|
||||||
depth=depth
|
depth={depth}
|
||||||
node_id=node_id.clone()
|
node_id={node_id.clone()}
|
||||||
key=key
|
key={key}
|
||||||
>
|
>
|
||||||
{inner_nodes}
|
{inner_nodes}
|
||||||
</TreeNode>
|
</TreeNode>
|
||||||
|
@ -207,7 +205,6 @@ impl<T: Clone> Tree<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TreeNode {
|
struct TreeNode {
|
||||||
props: TreeNodeProps,
|
|
||||||
handler_caret_click: Callback<MouseEvent>,
|
handler_caret_click: Callback<MouseEvent>,
|
||||||
handler_click: Callback<MouseEvent>,
|
handler_click: Callback<MouseEvent>,
|
||||||
}
|
}
|
||||||
|
@ -260,34 +257,33 @@ impl Component for TreeNode {
|
||||||
type Message = TreeNodeMessage;
|
type Message = TreeNodeMessage;
|
||||||
type Properties = TreeNodeProps;
|
type Properties = TreeNodeProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
TreeNode {
|
TreeNode {
|
||||||
handler_caret_click: link.callback(TreeNodeMessage::CaretClick),
|
handler_caret_click: ctx.link().callback(TreeNodeMessage::CaretClick),
|
||||||
handler_click: link.callback(TreeNodeMessage::Click),
|
handler_click: ctx.link().callback(TreeNodeMessage::Click),
|
||||||
props,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
if self.props.disabled {
|
if ctx.props().disabled {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
TreeNodeMessage::CaretClick(event) => {
|
TreeNodeMessage::CaretClick(event) => {
|
||||||
if self.props.is_expanded {
|
if ctx.props().is_expanded {
|
||||||
if let Some(on_collapse) = self.props.on_collapse.as_ref() {
|
if let Some(on_collapse) = ctx.props().on_collapse.as_ref() {
|
||||||
event.stop_propagation();
|
event.stop_propagation();
|
||||||
on_collapse.emit((self.props.node_id.clone(), event));
|
on_collapse.emit((ctx.props().node_id.clone(), event));
|
||||||
}
|
}
|
||||||
} else if let Some(on_expand) = self.props.on_expand.as_ref() {
|
} else if let Some(on_expand) = ctx.props().on_expand.as_ref() {
|
||||||
event.stop_propagation();
|
event.stop_propagation();
|
||||||
on_expand.emit((self.props.node_id.clone(), event));
|
on_expand.emit((ctx.props().node_id.clone(), event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TreeNodeMessage::Click(event) => {
|
TreeNodeMessage::Click(event) => {
|
||||||
if let Some(onclick) = self.props.onclick.as_ref() {
|
if let Some(onclick) = ctx.props().onclick.as_ref() {
|
||||||
onclick.emit((self.props.node_id.clone(), event));
|
onclick.emit((ctx.props().node_id.clone(), event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -295,38 +291,23 @@ impl Component for TreeNode {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
let content_style = format!("padding-left: {}px;", 23 * ctx.props().depth);
|
||||||
// crate::log!(
|
|
||||||
// "rerender {:?} {} {:?}",
|
|
||||||
// self.props.node_id,
|
|
||||||
// self.props.children == props.children,
|
|
||||||
// self.props.icon,
|
|
||||||
// );
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let content_style = format!("padding-left: {}px;", 23 * self.props.depth);
|
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<li class=classes!(
|
<li class={classes!(
|
||||||
"bp3-tree-node",
|
"bp3-tree-node",
|
||||||
self.props.is_selected.then(|| "bp3-tree-node-selected")
|
ctx.props().is_selected.then(|| "bp3-tree-node-selected")
|
||||||
)>
|
)}>
|
||||||
<div
|
<div
|
||||||
class="bp3-tree-node-content"
|
class="bp3-tree-node-content"
|
||||||
style=content_style
|
style={content_style}
|
||||||
onclick=self.handler_click.clone()
|
onclick={self.handler_click.clone()}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
if self.props.has_caret {
|
if ctx.props().has_caret {
|
||||||
let mut class = Classes::from("bp3-tree-node-caret");
|
let mut class = Classes::from("bp3-tree-node-caret");
|
||||||
class.push(if self.props.is_expanded {
|
class.push(if ctx.props().is_expanded {
|
||||||
"bp3-tree-node-caret-open"
|
"bp3-tree-node-caret-open"
|
||||||
} else {
|
} else {
|
||||||
"bp3-tree-node-caret-closed"
|
"bp3-tree-node-caret-closed"
|
||||||
|
@ -334,9 +315,9 @@ impl Component for TreeNode {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<Icon
|
<Icon
|
||||||
class=classes!(class.to_string())
|
class={classes!(class.to_string())}
|
||||||
icon=IconName::ChevronRight
|
icon={IconName::ChevronRight}
|
||||||
onclick=self.handler_caret_click.clone()
|
onclick={self.handler_caret_click.clone()}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -346,16 +327,16 @@ impl Component for TreeNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<Icon
|
<Icon
|
||||||
class=classes!("bp3-tree-node-icon")
|
class={classes!("bp3-tree-node-icon")}
|
||||||
icon=self.props.icon.unwrap_or_default()
|
icon={ctx.props().icon.unwrap_or_default()}
|
||||||
color=self.props.icon_color.clone()
|
color={ctx.props().icon_color.clone()}
|
||||||
intent=self.props.icon_intent
|
intent={ctx.props().icon_intent}
|
||||||
/>
|
/>
|
||||||
<span class=classes!("bp3-tree-node-label")>{self.props.label.clone()}</span>
|
<span class={classes!("bp3-tree-node-label")}>{ctx.props().label.clone()}</span>
|
||||||
{
|
{
|
||||||
if let Some(label) = self.props.secondary_label.clone() {
|
if let Some(label) = ctx.props().secondary_label.clone() {
|
||||||
html!(
|
html!(
|
||||||
<span class=classes!("bp3-tree-node-secondary-label")>
|
<span class={classes!("bp3-tree-node-secondary-label")}>
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
@ -364,9 +345,9 @@ impl Component for TreeNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<Collapse is_open=self.props.is_expanded>
|
<Collapse is_open={ctx.props().is_expanded}>
|
||||||
<ul class=classes!("bp3-tree-node-list")>
|
<ul class={classes!("bp3-tree-node-list")}>
|
||||||
{self.props.children.clone()}
|
{ctx.props().children.clone()}
|
||||||
</ul>
|
</ul>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
name = "yewprint-doc"
|
name = "yewprint-doc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Cecile Tonglet <cecile.tonglet@cecton.com>"]
|
authors = ["Cecile Tonglet <cecile.tonglet@cecton.com>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
@ -10,11 +10,14 @@ edition = "2018"
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasm-bindgen = "=0.2"
|
wasm-bindgen = "0.2"
|
||||||
yew = "0.18"
|
web-sys = { version = "0.3", features = ["Window", "MediaQueryList", "Event", "HtmlInputElement"] }
|
||||||
web-sys = { version = "0.3", features = ["Window", "MediaQueryList"] }
|
gloo = "0.6"
|
||||||
|
yew = "0.19"
|
||||||
|
yew-router = "0.16"
|
||||||
|
# yew = { git = "https://github.com/yewstack/yew", branch = "master" }
|
||||||
|
# yew-router = { git = "https://github.com/yewstack/yew", branch = "master" }
|
||||||
yewprint = { path = ".." }
|
yewprint = { path = ".." }
|
||||||
yew-router = "0.15"
|
|
||||||
|
|
||||||
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
|
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
|
||||||
# compared to the default allocator's ~10K. It is slower than the default
|
# compared to the default allocator's ~10K. It is slower than the default
|
||||||
|
|
|
@ -22,19 +22,21 @@ use crate::tag::*;
|
||||||
use crate::text::*;
|
use crate::text::*;
|
||||||
use crate::text_area::*;
|
use crate::text_area::*;
|
||||||
use crate::tree::*;
|
use crate::tree::*;
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::{
|
use yew_router::prelude::*;
|
||||||
agent::{RouteAgentDispatcher, RouteRequest},
|
|
||||||
router::Router,
|
|
||||||
Switch,
|
|
||||||
};
|
|
||||||
use yewprint::{IconName, Menu, MenuItem};
|
use yewprint::{IconName, Menu, MenuItem};
|
||||||
|
|
||||||
|
#[function_component(AppRoot)]
|
||||||
|
pub fn app_root() -> Html {
|
||||||
|
html! {
|
||||||
|
<BrowserRouter>
|
||||||
|
<App></App>
|
||||||
|
</BrowserRouter>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
link: ComponentLink<Self>,
|
|
||||||
dark_theme: bool,
|
dark_theme: bool,
|
||||||
route_dispatcher: RouteAgentDispatcher,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
|
@ -46,33 +48,30 @@ impl Component for App {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
App {
|
App {
|
||||||
dark_theme: web_sys::window()
|
dark_theme: web_sys::window()
|
||||||
.and_then(|x| x.match_media("(prefers-color-scheme: dark)").ok().flatten())
|
.and_then(|x| x.match_media("(prefers-color-scheme: dark)").ok().flatten())
|
||||||
.map(|x| x.matches())
|
.map(|x| x.matches())
|
||||||
.unwrap_or(true),
|
.unwrap_or(true),
|
||||||
link,
|
|
||||||
route_dispatcher: RouteAgentDispatcher::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::ToggleLight => self.dark_theme ^= true,
|
Msg::ToggleLight => self.dark_theme ^= true,
|
||||||
Msg::GoToMenu(doc_menu) => {
|
Msg::GoToMenu(doc_menu) => {
|
||||||
self.route_dispatcher
|
if let Some(history) = ctx.link().history() {
|
||||||
.send(RouteRequest::ChangeRoute(doc_menu.into()));
|
history.push(doc_menu);
|
||||||
|
} else {
|
||||||
|
gloo::console::warn!("Could not get history from Context");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let netlify_badge = if self.dark_theme {
|
let netlify_badge = if self.dark_theme {
|
||||||
"https://www.netlify.com/img/global/badges/netlify-color-accent.svg"
|
"https://www.netlify.com/img/global/badges/netlify-color-accent.svg"
|
||||||
} else {
|
} else {
|
||||||
|
@ -89,223 +88,178 @@ impl Component for App {
|
||||||
IconName::Moon
|
IconName::Moon
|
||||||
};
|
};
|
||||||
|
|
||||||
html! {
|
let menu = html! {
|
||||||
<div class=classes!("docs-root", self.dark_theme.then(|| "bp3-dark"))>
|
<Menu>
|
||||||
<div class=classes!("docs-app")>
|
<MenuItem
|
||||||
<div class=classes!("docs-nav-wrapper")>
|
text={html!(go_to_theme_label)}
|
||||||
<div class=classes!("docs-nav")>
|
onclick={ctx.link()
|
||||||
<div class=classes!("docs-nav-title")>
|
.callback(|_| Msg::ToggleLight)}
|
||||||
<a class=classes!("docs-logo") href="/">
|
icon={go_to_theme_icon}
|
||||||
{crate::include_raw_html!("logo.svg")}
|
/>
|
||||||
</a>
|
<MenuItem
|
||||||
<div>
|
text={html!("Button")}
|
||||||
<div class=classes!("bp3-navbar-heading", "docs-heading")>
|
onclick={ctx.link()
|
||||||
{"Yewprint"}
|
.callback(|_| Msg::GoToMenu(DocMenu::Button))}
|
||||||
</div>
|
/>
|
||||||
<a
|
<MenuItem
|
||||||
class=classes!("bp3-text-muted")
|
text={html!("ButtonGroup")}
|
||||||
href="https://github.com/yewprint/yewprint"
|
onclick={ctx.link()
|
||||||
target="_blank"
|
.callback(|_| Msg::GoToMenu(DocMenu::ButtonGroup))}
|
||||||
>
|
/>
|
||||||
<small>{"View on GitHub"}</small>
|
<MenuItem
|
||||||
</a>
|
text={html!("Callout")}
|
||||||
</div>
|
onclick={ctx.link()
|
||||||
</div>
|
.callback(|_| Msg::GoToMenu(DocMenu::Callout))}
|
||||||
<Menu>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={html!(go_to_theme_label)}
|
text={html!("Card")}
|
||||||
onclick=self.link
|
onclick={ctx.link()
|
||||||
.callback(|_| Msg::ToggleLight)
|
.callback(|_| Msg::GoToMenu(DocMenu::Card))}
|
||||||
icon=go_to_theme_icon
|
/>
|
||||||
/>
|
<MenuItem
|
||||||
<MenuItem
|
text={html!("Checkbox")}
|
||||||
text={html!("Button")}
|
onclick={ctx.link()
|
||||||
href=Cow::Borrowed("#button")
|
.callback(|_| Msg::GoToMenu(DocMenu::Checkbox))}
|
||||||
onclick=self.link
|
/>
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Button))
|
<MenuItem
|
||||||
/>
|
text={html!("Collapse")}
|
||||||
<MenuItem
|
onclick={ctx.link()
|
||||||
text={html!("ButtonGroup")}
|
.callback(|_| Msg::GoToMenu(DocMenu::Collapse))}
|
||||||
href=Cow::Borrowed("#button-group")
|
/>
|
||||||
onclick=self.link
|
<MenuItem
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::ButtonGroup))
|
text={html!("ControlGroup")}
|
||||||
/>
|
onclick={ctx.link()
|
||||||
<MenuItem
|
.callback(|_| Msg::GoToMenu(DocMenu::ControlGroup))}
|
||||||
text={html!("Callout")}
|
/>
|
||||||
href=Cow::Borrowed("#callout")
|
<MenuItem
|
||||||
onclick=self.link
|
text={html!("Divider")}
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Callout))
|
onclick={ctx.link()
|
||||||
/>
|
.callback(|_| Msg::GoToMenu(DocMenu::Divider))}
|
||||||
<MenuItem
|
/>
|
||||||
text={html!("Card")}
|
<MenuItem
|
||||||
href=Cow::Borrowed("#card")
|
text={html!("HtmlSelect")}
|
||||||
onclick=self.link
|
onclick={ctx.link()
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Card))
|
.callback(|_| Msg::GoToMenu(DocMenu::HtmlSelect))}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={html!("Checkbox")}
|
text={html!("Icon")}
|
||||||
href=Cow::Borrowed("#checkbox")
|
onclick={ctx.link()
|
||||||
onclick=self.link
|
.callback(|_| Msg::GoToMenu(DocMenu::Icon))}
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Checkbox))
|
/>
|
||||||
/>
|
<MenuItem
|
||||||
<MenuItem
|
text={html!("InputGroup")}
|
||||||
text={html!("Collapse")}
|
onclick={ctx.link()
|
||||||
href=Cow::Borrowed("#collapse")
|
.callback(|_| Msg::GoToMenu(DocMenu::InputGroup))}
|
||||||
onclick=self.link
|
/>
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Collapse))
|
<MenuItem
|
||||||
/>
|
text={html!("Menu")}
|
||||||
<MenuItem
|
onclick={ctx.link()
|
||||||
text={html!("ControlGroup")}
|
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||||
href=Cow::Borrowed("#control-group")
|
/>
|
||||||
onclick=self.link
|
<MenuItem
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::ControlGroup))
|
text={html!("NumericInput")}
|
||||||
/>
|
onclick={ctx.link()
|
||||||
<MenuItem
|
.callback(|_| Msg::GoToMenu(DocMenu::NumericInput))}
|
||||||
text={html!("Divider")}
|
/>
|
||||||
href=Cow::Borrowed("#divider")
|
<MenuItem
|
||||||
onclick=self.link
|
text={html!("PanelStack")}
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Divider))
|
onclick={ctx.link()
|
||||||
/>
|
.callback(|_| Msg::GoToMenu(DocMenu::PanelStack))}
|
||||||
<MenuItem
|
/>
|
||||||
text={html!("HtmlSelect")}
|
<MenuItem
|
||||||
href=Cow::Borrowed("#html-select")
|
text={html!("ProgressBar")}
|
||||||
onclick=self.link
|
onclick={ctx.link()
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::HtmlSelect))
|
.callback(|_| Msg::GoToMenu(DocMenu::ProgressBar))}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={html!("Icon")}
|
text={html!("Radio")}
|
||||||
href=Cow::Borrowed("#icon")
|
onclick={ctx.link()
|
||||||
onclick=self.link
|
.callback(|_| Msg::GoToMenu(DocMenu::Radio))}
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Icon))
|
/>
|
||||||
/>
|
<MenuItem
|
||||||
<MenuItem
|
text={html!("Slider")}
|
||||||
text={html!("InputGroup")}
|
onclick={ctx.link().callback(|_| Msg::GoToMenu(DocMenu::Slider))}
|
||||||
href=Cow::Borrowed("#input-group")
|
/>
|
||||||
onclick=self.link
|
<MenuItem
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::InputGroup))
|
text={html!("Spinner")}
|
||||||
/>
|
onclick={ctx.link()
|
||||||
<MenuItem
|
.callback(|_| Msg::GoToMenu(DocMenu::Spinner))}
|
||||||
text={html!("Menu")}
|
/>
|
||||||
href=Cow::Borrowed("#menu")
|
<MenuItem
|
||||||
onclick=self.link
|
text={html!("Switch")}
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
onclick={ctx.link()
|
||||||
/>
|
.callback(|_| Msg::GoToMenu(DocMenu::Switch))}
|
||||||
<MenuItem
|
/>
|
||||||
text={html!("NumericInput")}
|
<MenuItem
|
||||||
href=Cow::Borrowed("#numeric-input")
|
text={html!("Tabs")}
|
||||||
onclick=self.link
|
onclick={ctx.link()
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::NumericInput))
|
.callback(|_| Msg::GoToMenu(DocMenu::Tabs))}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={html!("PanelStack")}
|
text={html!("Tag")}
|
||||||
href=Cow::Borrowed("#panel-stack")
|
onclick={ctx.link()
|
||||||
onclick=self.link
|
.callback(|_| Msg::GoToMenu(DocMenu::Tag))}
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::PanelStack))
|
/>
|
||||||
/>
|
<MenuItem
|
||||||
<MenuItem
|
text={html!("Text")}
|
||||||
text={html!("ProgressBar")}
|
onclick={ctx.link()
|
||||||
href=Cow::Borrowed("#progress-bar")
|
.callback(|_| Msg::GoToMenu(DocMenu::Text))}
|
||||||
onclick=self.link
|
/>
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::ProgressBar))
|
<MenuItem
|
||||||
/>
|
text={html!("TextArea")}
|
||||||
<MenuItem
|
onclick={ctx.link()
|
||||||
text={html!("Radio")}
|
.callback(|_| Msg::GoToMenu(DocMenu::TextArea))}
|
||||||
href=Cow::Borrowed("#radio")
|
/>
|
||||||
onclick=self.link
|
<MenuItem
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Radio))
|
text={html!("Tree")}
|
||||||
/>
|
onclick={ctx.link()
|
||||||
<MenuItem
|
.callback(|_| Msg::GoToMenu(DocMenu::Tree))}
|
||||||
text={html!("Slider")}
|
/>
|
||||||
href=Cow::Borrowed("#slider")
|
// NOTE: thanks to keep this list of <MenuItem> sorted
|
||||||
onclick=self.link.callback(|_| Msg::GoToMenu(DocMenu::Slider))
|
// alphabetically (except for the light switch)
|
||||||
/>
|
</Menu>
|
||||||
<MenuItem
|
};
|
||||||
text={html!("Spinner")}
|
|
||||||
href=Cow::Borrowed("#spinner")
|
let navigation = html! {
|
||||||
onclick=self.link
|
<div class={classes!("docs-nav-wrapper")}>
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Spinner))
|
<div class={classes!("docs-nav")}>
|
||||||
/>
|
<div class={classes!("docs-nav-title")}>
|
||||||
<MenuItem
|
<a class={classes!("docs-logo")} href="/">
|
||||||
text={html!("Switch")}
|
{crate::include_raw_html!("logo.svg")}
|
||||||
href=Cow::Borrowed("#switch")
|
</a>
|
||||||
onclick=self.link
|
<div>
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Switch))
|
<div class={classes!("bp3-navbar-heading", "docs-heading")}>
|
||||||
/>
|
{"Yewprint"}
|
||||||
<MenuItem
|
|
||||||
text={html!("Tabs")}
|
|
||||||
href=Cow::Borrowed("#tabs")
|
|
||||||
onclick=self.link
|
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Tabs))
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
text={html!("Tag")}
|
|
||||||
href=Cow::Borrowed("#tag")
|
|
||||||
onclick=self.link
|
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Tag))
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
text={html!("Text")}
|
|
||||||
href=Cow::Borrowed("#text")
|
|
||||||
onclick=self.link
|
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Text))
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
text={html!("TextArea")}
|
|
||||||
href=Cow::Borrowed("#textarea")
|
|
||||||
onclick=self.link
|
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::TextArea))
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
text={html!("Tree")}
|
|
||||||
href=Cow::Borrowed("#tree")
|
|
||||||
onclick=self.link
|
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Tree))
|
|
||||||
/>
|
|
||||||
// NOTE: thanks to keep this list of <MenuItem> sorted
|
|
||||||
// alphabetically (except for the light switch)
|
|
||||||
</Menu>
|
|
||||||
<div class="docs-nav-sponsors">
|
|
||||||
<a href=Cow::Borrowed("https://www.netlify.com")>
|
|
||||||
<img
|
|
||||||
src=netlify_badge
|
|
||||||
alt="Deploys by Netlify"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
<a
|
||||||
|
class={classes!("bp3-text-muted")}
|
||||||
|
href="https://github.com/yewprint/yewprint"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<small>{"View on GitHub"}</small>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<main class=classes!("docs-content-wrapper") role="main">
|
{{ menu }}
|
||||||
<div class=classes!("docs-page")>
|
<div class="docs-nav-sponsors">
|
||||||
<Router<DocMenu, ()>
|
<a href={"https://www.netlify.com"}>
|
||||||
render=Router::render(|switch: DocMenu| {
|
<img
|
||||||
match switch {
|
src={netlify_badge}
|
||||||
DocMenu::Button | DocMenu::Home => html! (<ButtonDoc />),
|
alt="Deploys by Netlify"
|
||||||
DocMenu::ButtonGroup => html! (<ButtonGroupDoc />),
|
|
||||||
DocMenu::Callout => html!(<CalloutDoc />),
|
|
||||||
DocMenu::Card => html!(<CardDoc />),
|
|
||||||
DocMenu::Checkbox => html!(<CheckboxDoc />),
|
|
||||||
DocMenu::Collapse => html!(<CollapseDoc />),
|
|
||||||
DocMenu::ControlGroup => html!(<ControlGroupDoc />),
|
|
||||||
DocMenu::Divider => html!(<DividerDoc />),
|
|
||||||
DocMenu::HtmlSelect => html!(<HtmlSelectDoc />),
|
|
||||||
DocMenu::Icon => html!(<IconDoc />),
|
|
||||||
DocMenu::InputGroup => html!(<InputGroupDoc />),
|
|
||||||
DocMenu::Menu => html!(<MenuDoc />),
|
|
||||||
DocMenu::NumericInput => html!(<NumericInputDoc />),
|
|
||||||
DocMenu::PanelStack => html!(<PanelStackDoc />),
|
|
||||||
DocMenu::ProgressBar => html!(<ProgressBarDoc />),
|
|
||||||
DocMenu::Radio => html!(<RadioDoc />),
|
|
||||||
DocMenu::Slider => html!(<SliderDoc />),
|
|
||||||
DocMenu::Spinner => html!(<SpinnerDoc />),
|
|
||||||
DocMenu::Switch => html!(<SwitchDoc />),
|
|
||||||
DocMenu::Tabs => html!(<TabsDoc />),
|
|
||||||
DocMenu::Tag => html!(<TagDoc />),
|
|
||||||
DocMenu::Text => html!(<TextDoc />),
|
|
||||||
DocMenu::TextArea => html!(<TextAreaDoc />),
|
|
||||||
DocMenu::Tree => html!(<TreeDoc />),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
/>
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
};
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<div class={classes!("docs-root", self.dark_theme.then(|| "bp3-dark"))}>
|
||||||
|
<div class={classes!("docs-app")}>
|
||||||
|
{{ navigation }}
|
||||||
|
<main class={classes!("docs-content-wrapper")} role="main">
|
||||||
|
<div class={classes!("docs-page")}>
|
||||||
|
<Switch<DocMenu> render={Switch::render(switch)} />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
@ -314,56 +268,85 @@ impl Component for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Switch)]
|
fn switch(route: &DocMenu) -> Html {
|
||||||
|
match route {
|
||||||
|
DocMenu::Button | DocMenu::Home => html! (<ButtonDoc />),
|
||||||
|
DocMenu::ButtonGroup => html! (<ButtonGroupDoc />),
|
||||||
|
DocMenu::Callout => html!(<CalloutDoc />),
|
||||||
|
DocMenu::Card => html!(<CardDoc />),
|
||||||
|
DocMenu::Checkbox => html!(<CheckboxDoc />),
|
||||||
|
DocMenu::Collapse => html!(<CollapseDoc />),
|
||||||
|
DocMenu::ControlGroup => html!(<ControlGroupDoc />),
|
||||||
|
DocMenu::Divider => html!(<DividerDoc />),
|
||||||
|
DocMenu::HtmlSelect => html!(<HtmlSelectDoc />),
|
||||||
|
DocMenu::Icon => html!(<IconDoc />),
|
||||||
|
DocMenu::InputGroup => html!(<InputGroupDoc />),
|
||||||
|
DocMenu::Menu => html!(<MenuDoc />),
|
||||||
|
DocMenu::NumericInput => html!(<NumericInputDoc />),
|
||||||
|
DocMenu::PanelStack => html!(<PanelStackDoc />),
|
||||||
|
DocMenu::ProgressBar => html!(<ProgressBarDoc />),
|
||||||
|
DocMenu::Radio => html!(<RadioDoc />),
|
||||||
|
DocMenu::Slider => html!(<SliderDoc />),
|
||||||
|
DocMenu::Spinner => html!(<SpinnerDoc />),
|
||||||
|
DocMenu::Switch => html!(<SwitchDoc />),
|
||||||
|
DocMenu::Tabs => html!(<TabsDoc />),
|
||||||
|
DocMenu::Tag => html!(<TagDoc />),
|
||||||
|
DocMenu::Text => html!(<TextDoc />),
|
||||||
|
DocMenu::TextArea => html!(<TextAreaDoc />),
|
||||||
|
DocMenu::Tree => html!(<TreeDoc />),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Routable)]
|
||||||
pub enum DocMenu {
|
pub enum DocMenu {
|
||||||
#[to = "/#button-group"]
|
#[at("/button-group")]
|
||||||
ButtonGroup,
|
ButtonGroup,
|
||||||
#[to = "/#button"]
|
#[at("/button")]
|
||||||
Button,
|
Button,
|
||||||
#[to = "/#callout"]
|
#[at("/callout")]
|
||||||
Callout,
|
Callout,
|
||||||
#[to = "/#card"]
|
#[at("/card")]
|
||||||
Card,
|
Card,
|
||||||
#[to = "/#checkbox"]
|
#[at("/checkbox")]
|
||||||
Checkbox,
|
Checkbox,
|
||||||
#[to = "/#collapse"]
|
#[at("/collapse")]
|
||||||
Collapse,
|
Collapse,
|
||||||
#[to = "/#control-group"]
|
#[at("/control-group")]
|
||||||
ControlGroup,
|
ControlGroup,
|
||||||
#[to = "/#html-select"]
|
#[at("/html-select")]
|
||||||
HtmlSelect,
|
HtmlSelect,
|
||||||
#[to = "/#divider"]
|
#[at("/divider")]
|
||||||
Divider,
|
Divider,
|
||||||
#[to = "/#icon"]
|
#[at("/icon")]
|
||||||
Icon,
|
Icon,
|
||||||
#[to = "/#input-group"]
|
#[at("/input-group")]
|
||||||
InputGroup,
|
InputGroup,
|
||||||
#[to = "/#menu"]
|
#[at("/menu")]
|
||||||
Menu,
|
Menu,
|
||||||
#[to = "/#numeric-input"]
|
#[at("/numeric-input")]
|
||||||
NumericInput,
|
NumericInput,
|
||||||
#[to = "/#panel-stack"]
|
#[at("/panel-stack")]
|
||||||
PanelStack,
|
PanelStack,
|
||||||
#[to = "/#progress-bar"]
|
#[at("/progress-bar")]
|
||||||
ProgressBar,
|
ProgressBar,
|
||||||
#[to = "/#radio"]
|
#[at("/radio")]
|
||||||
Radio,
|
Radio,
|
||||||
#[to = "/#slider"]
|
#[at("/slider")]
|
||||||
Slider,
|
Slider,
|
||||||
#[to = "/#spinner"]
|
#[at("/spinner")]
|
||||||
Spinner,
|
Spinner,
|
||||||
#[to = "/#switch"]
|
#[at("/switch")]
|
||||||
Switch,
|
Switch,
|
||||||
#[to = "/#tabs"]
|
#[at("/tabs")]
|
||||||
Tabs,
|
Tabs,
|
||||||
#[to = "/#tag"]
|
#[at("/tag")]
|
||||||
Tag,
|
Tag,
|
||||||
#[to = "/#textarea"]
|
#[at("/textarea")]
|
||||||
TextArea,
|
TextArea,
|
||||||
#[to = "/#text"]
|
#[at("/text")]
|
||||||
Text,
|
Text,
|
||||||
#[to = "/#tree"]
|
#[at("/tree")]
|
||||||
Tree,
|
Tree,
|
||||||
#[to = "/"]
|
#[at("/")]
|
||||||
Home,
|
Home,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Button, ButtonGroup, IconName};
|
use yewprint::{Button, ButtonGroup, IconName};
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
props: ExampleProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ExampleProps {
|
pub struct ExampleProps {
|
||||||
pub minimal: bool,
|
pub minimal: bool,
|
||||||
|
@ -14,40 +9,19 @@ pub struct ExampleProps {
|
||||||
pub vertical: bool,
|
pub vertical: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Example {
|
#[function_component(Example)]
|
||||||
type Message = ();
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
type Properties = ExampleProps;
|
html! {
|
||||||
|
<ButtonGroup
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
minimal={props.minimal}
|
||||||
Example { props }
|
fill={props.fill}
|
||||||
}
|
large={props.large}
|
||||||
|
vertical={props.vertical}
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
style={"margin:0;"}
|
||||||
true
|
>
|
||||||
}
|
<Button icon={IconName::Database}> {"Queries"}</Button>
|
||||||
|
<Button icon={IconName::Function}>{"Functions"}</Button>
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
<Button icon={IconName::Cog}>{"Options"}</Button>
|
||||||
if self.props != props {
|
</ButtonGroup>
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<ButtonGroup
|
|
||||||
minimal=self.props.minimal
|
|
||||||
fill=self.props.fill
|
|
||||||
large=self.props.large
|
|
||||||
vertical=self.props.vertical
|
|
||||||
style=Cow::Borrowed("margin:0;")
|
|
||||||
>
|
|
||||||
<Button icon=IconName::Database>{"Queries"}</Button>
|
|
||||||
<Button icon=IconName::Function>{"Functions"}</Button>
|
|
||||||
<Button icon=IconName::Cog>{"Options"}</Button>
|
|
||||||
</ButtonGroup>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for ButtonGroupDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
ButtonGroupDoc {
|
ButtonGroupDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
minimal: false,
|
minimal: false,
|
||||||
fill: false,
|
fill: false,
|
||||||
|
@ -26,16 +26,12 @@ impl Component for ButtonGroupDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -44,19 +40,19 @@ impl Component for ButtonGroupDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Button Group"}</H1>
|
<H1 class={classes!("docs-title")}>{"Button Group"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<ButtonGroupProps
|
<ButtonGroupProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
>
|
>
|
||||||
</ButtonGroupProps>
|
</ButtonGroupProps>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -65,41 +61,41 @@ impl Component for ButtonGroupDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
ButtonGroupProps for ExampleProps =>
|
ButtonGroupProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
minimal: !props.minimal,
|
minimal: !props.minimal,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.minimal
|
checked={ctx.props().example_props.minimal}
|
||||||
label=html!("Minimal")
|
label={html!("Minimal")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps{
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps{
|
||||||
fill: !props.fill,
|
fill: !props.fill,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.fill
|
checked={ctx.props().example_props.fill}
|
||||||
label=html!("Fill")
|
label={html!("Fill")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps{
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps{
|
||||||
large: !props.large,
|
large: !props.large,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.large
|
checked={ctx.props().example_props.large}
|
||||||
label=html!("Large")
|
label={html!("Large")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
vertical: !props.vertical,
|
vertical: !props.vertical,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.vertical
|
checked={ctx.props().example_props.vertical}
|
||||||
label=html!("Vertical")
|
label={html!("Vertical")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@ use yew::prelude::*;
|
||||||
use yewprint::Button;
|
use yewprint::Button;
|
||||||
|
|
||||||
pub struct Example {
|
pub struct Example {
|
||||||
link: ComponentLink<Self>,
|
|
||||||
counter: i64,
|
counter: i64,
|
||||||
props: ExampleProps,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
@ -27,45 +25,32 @@ impl Component for Example {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = ExampleProps;
|
type Properties = ExampleProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Example {
|
Example { counter: 0 }
|
||||||
counter: 0,
|
|
||||||
link,
|
|
||||||
props,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::AddOne => self.counter += 1,
|
Msg::AddOne => self.counter += 1,
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<p>{"Counter: "}{self.counter}</p>
|
<p>{"Counter: "}{self.counter}</p>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
onclick=self.link.callback(|_| Msg::AddOne)
|
onclick={ctx.link().callback(|_| Msg::AddOne)}
|
||||||
minimal=self.props.minimal
|
minimal={ctx.props().minimal}
|
||||||
fill=self.props.fill
|
fill={ctx.props().fill}
|
||||||
small=self.props.small
|
small={ctx.props().small}
|
||||||
outlined=self.props.outlined
|
outlined={ctx.props().outlined}
|
||||||
loading=self.props.loading
|
loading={ctx.props().loading}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
active=self.props.active
|
active={ctx.props().active}
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
>
|
>
|
||||||
{"Add 1"}
|
{"Add 1"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for ButtonDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
ButtonDoc {
|
ButtonDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
minimal: false,
|
minimal: false,
|
||||||
fill: false,
|
fill: false,
|
||||||
|
@ -30,37 +30,35 @@ impl Component for ButtonDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
"bp3-code-block"
|
"bp3-code-block"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let props_component = html! {
|
||||||
|
<ButtonProps
|
||||||
|
callback={self.callback.clone()}
|
||||||
|
example_props={example_props.clone()}
|
||||||
|
/>
|
||||||
|
};
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Button"}</H1>
|
<H1 class={classes!("docs-title")}>{"Button"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<div>
|
<div>
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(props_component)}
|
||||||
<ButtonProps
|
|
||||||
callback={self.callback.clone()}
|
|
||||||
props=example_props.clone()
|
|
||||||
/>
|
|
||||||
})
|
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -70,77 +68,77 @@ impl Component for ButtonDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
ButtonProps for ExampleProps =>
|
ButtonProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
minimal: !props.minimal,
|
minimal: !props.minimal,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.minimal
|
checked={ctx.props().example_props.minimal}
|
||||||
label=html!("Minimal")
|
label={html!("Minimal")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
fill: !props.fill,
|
fill: !props.fill,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.fill
|
checked={ctx.props().example_props.fill}
|
||||||
label=html!("Fill")
|
label={html!("Fill")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
small: !props.small,
|
small: !props.small,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.small
|
checked={ctx.props().example_props.small}
|
||||||
label=html!("Small")
|
label={html!("Small")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
outlined: !props.outlined,
|
outlined: !props.outlined,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.outlined
|
checked={ctx.props().example_props.outlined}
|
||||||
label=html!("Outlined")
|
label={html!("Outlined")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
loading: !props.loading,
|
loading: !props.loading,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.loading
|
checked={ctx.props().example_props.loading}
|
||||||
label=html!("Loading")
|
label={html!("Loading")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
large: !props.large,
|
large: !props.large,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.large
|
checked={ctx.props().example_props.large}
|
||||||
label=html!("Large")
|
label={html!("Large")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
active: !props.active,
|
active: !props.active,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.active
|
checked={ctx.props().example_props.active}
|
||||||
label=html!("Active")
|
label={html!("Active")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
disabled: !props.disabled,
|
disabled: !props.disabled,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.disabled
|
checked={ctx.props().example_props.disabled}
|
||||||
label=html!("Disabled")
|
label={html!("Disabled")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::build_source_code_component!();
|
crate::build_source_code_component!();
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Callout, Intent};
|
use yewprint::{Callout, Intent};
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
props: ExampleProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ExampleProps {
|
pub struct ExampleProps {
|
||||||
pub intent: Option<Intent>,
|
pub intent: Option<Intent>,
|
||||||
|
@ -13,36 +8,15 @@ pub struct ExampleProps {
|
||||||
pub show_title: bool,
|
pub show_title: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Example {
|
#[function_component(Example)]
|
||||||
type Message = ();
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
type Properties = ExampleProps;
|
html! {
|
||||||
|
<Callout
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
title={props.show_title.then(|| "Visually important content")}
|
||||||
Example { props }
|
without_icon={!props.show_icon}
|
||||||
}
|
intent={props.intent}
|
||||||
|
>
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
<p>{"The Callout element's background reflects its intent, if any."}</p>
|
||||||
true
|
</Callout>
|
||||||
}
|
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<Callout
|
|
||||||
title=self.props.show_title.then(|| Cow::Borrowed("Visually important content"))
|
|
||||||
without_icon=!self.props.show_icon
|
|
||||||
intent=self.props.intent
|
|
||||||
>
|
|
||||||
<p>{"The Callout element's background reflects its intent, if any."}</p>
|
|
||||||
</Callout>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for CalloutDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
CalloutDoc {
|
CalloutDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
show_icon: false,
|
show_icon: false,
|
||||||
intent: None,
|
intent: None,
|
||||||
|
@ -25,16 +25,12 @@ impl Component for CalloutDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -43,18 +39,18 @@ impl Component for CalloutDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Callout"}</H1>
|
<H1 class={classes!("docs-title")}>{"Callout"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<CalloutProps
|
<CalloutProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -63,26 +59,26 @@ impl Component for CalloutDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
CalloutProps for ExampleProps =>
|
CalloutProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<div>
|
<div>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
show_icon: !props.show_icon,
|
show_icon: !props.show_icon,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.show_icon
|
checked={ctx.props().example_props.show_icon}
|
||||||
label=html!("Show/hide icon")
|
label={html!("Show/hide icon")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
show_title: !props.show_title,
|
show_title: !props.show_title,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.show_title
|
checked={ctx.props().example_props.show_title}
|
||||||
label=html!("Show/hide title")
|
label={html!("Show/hide title")}
|
||||||
/>
|
/>
|
||||||
<p>{"Select intent:"}</p>
|
<p>{"Select intent:"}</p>
|
||||||
<HtmlSelect<Option<Intent>>
|
<HtmlSelect<Option<Intent>>
|
||||||
|
@ -93,10 +89,10 @@ crate::build_example_prop_component! {
|
||||||
(Some(Intent::Warning), "Warning".to_string()),
|
(Some(Intent::Warning), "Warning".to_string()),
|
||||||
(Some(Intent::Danger), "Danger".to_string()),
|
(Some(Intent::Danger), "Danger".to_string()),
|
||||||
]}
|
]}
|
||||||
onchange=self.update_props(|props, intent| ExampleProps {
|
onchange={self.update_props(ctx.props(), |props, intent| ExampleProps {
|
||||||
intent,
|
intent,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,47 +1,22 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Card, Elevation};
|
use yewprint::{Card, Elevation};
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
props: ExampleProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ExampleProps {
|
pub struct ExampleProps {
|
||||||
pub elevation: Elevation,
|
pub elevation: Elevation,
|
||||||
pub interactive: bool,
|
pub interactive: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Example {
|
#[function_component(Example)]
|
||||||
type Message = ();
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
type Properties = ExampleProps;
|
html! {
|
||||||
|
<Card elevation={props.elevation} interactive={props.interactive}>
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
<p>
|
||||||
Example { props }
|
{
|
||||||
}
|
"This is a card component. The elevation of the card can be adjusted. \
|
||||||
|
An interactive card reacts to being moused over."
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
}
|
||||||
true
|
</p>
|
||||||
}
|
</Card>
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<Card elevation=self.props.elevation interactive=self.props.interactive>
|
|
||||||
<p>
|
|
||||||
{
|
|
||||||
"This is a card component. The elevation of the card can be adjusted. \
|
|
||||||
An interactive card reacts to being moused over."
|
|
||||||
}
|
|
||||||
</p>
|
|
||||||
</Card>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for CardDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
CardDoc {
|
CardDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
elevation: Elevation::Level0,
|
elevation: Elevation::Level0,
|
||||||
interactive: false,
|
interactive: false,
|
||||||
|
@ -24,16 +24,12 @@ impl Component for CardDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -42,18 +38,18 @@ impl Component for CardDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Card"}</H1>
|
<H1 class={classes!("docs-title")}>{"Card"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<CardProps
|
<CardProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -62,18 +58,20 @@ impl Component for CardDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
CardProps for ExampleProps =>
|
CardProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
let props = ctx.props();
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<div>
|
<div>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
interactive: !props.interactive,
|
interactive: !props.interactive,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.interactive
|
checked={ctx.props().example_props.interactive}
|
||||||
label=html!("Toggle interaction")
|
label={html!("Toggle interaction")}
|
||||||
/>
|
/>
|
||||||
<p>{"Elevation:"}</p>
|
<p>{"Elevation:"}</p>
|
||||||
<HtmlSelect<Elevation>
|
<HtmlSelect<Elevation>
|
||||||
|
@ -84,11 +82,11 @@ crate::build_example_prop_component! {
|
||||||
(Elevation::Level3, "Level 3".to_string()),
|
(Elevation::Level3, "Level 3".to_string()),
|
||||||
(Elevation::Level4, "Level 4".to_string()),
|
(Elevation::Level4, "Level 4".to_string()),
|
||||||
]}
|
]}
|
||||||
value=self.props.elevation
|
value={ctx.props().example_props.elevation}
|
||||||
onchange=self.update_props(|props, elevation| ExampleProps {
|
onchange={self.update_props(props, |props, elevation| ExampleProps {
|
||||||
elevation,
|
elevation,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Checkbox, Label};
|
use yewprint::{Checkbox, Label};
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
props: ExampleProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ExampleProps {
|
pub struct ExampleProps {
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
|
@ -12,50 +8,29 @@ pub struct ExampleProps {
|
||||||
pub large: bool,
|
pub large: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Example {
|
#[function_component(Example)]
|
||||||
type Message = ();
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
type Properties = ExampleProps;
|
html! {
|
||||||
|
<div>
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
<Label>{"Assign responsability"}</Label>
|
||||||
Example { props }
|
<Checkbox
|
||||||
}
|
disabled={props.disabled}
|
||||||
|
inline={props.inline}
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
large={props.large}
|
||||||
true
|
label={html!("Gilad Gray")}
|
||||||
}
|
/>
|
||||||
|
<Checkbox
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
disabled={props.disabled}
|
||||||
if self.props != props {
|
inline={props.inline}
|
||||||
self.props = props;
|
large={props.large}
|
||||||
true
|
label={html!("Jason Killian")}
|
||||||
} else {
|
/>
|
||||||
false
|
<Checkbox
|
||||||
}
|
disabled={props.disabled}
|
||||||
}
|
inline={props.inline}
|
||||||
|
large={props.large}
|
||||||
fn view(&self) -> Html {
|
label={html!("Antoine Llorca")}
|
||||||
html! {
|
/>
|
||||||
<div>
|
</div>
|
||||||
<Label>{"Assign responsability"}</Label>
|
|
||||||
<Checkbox
|
|
||||||
disabled=self.props.disabled
|
|
||||||
inline=self.props.inline
|
|
||||||
large=self.props.large
|
|
||||||
label=html!("Gilad Gray")
|
|
||||||
/>
|
|
||||||
<Checkbox
|
|
||||||
disabled=self.props.disabled
|
|
||||||
inline=self.props.inline
|
|
||||||
large=self.props.large
|
|
||||||
label=html!("Jason Killian")
|
|
||||||
/>
|
|
||||||
<Checkbox
|
|
||||||
disabled=self.props.disabled
|
|
||||||
inline=self.props.inline
|
|
||||||
large=self.props.large
|
|
||||||
label=html!("Antoine Llorca")
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for CheckboxDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
CheckboxDoc {
|
CheckboxDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
inline: false,
|
inline: false,
|
||||||
|
@ -25,16 +25,12 @@ impl Component for CheckboxDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -43,18 +39,18 @@ impl Component for CheckboxDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Checkbox"}</H1>
|
<H1 class={classes!("docs-title")}>{"Checkbox"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<CheckboxProps
|
<CheckboxProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -63,33 +59,33 @@ impl Component for CheckboxDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
CheckboxProps for ExampleProps =>
|
CheckboxProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
disabled: !props.disabled,
|
disabled: !props.disabled,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.disabled
|
checked={ctx.props().example_props.disabled}
|
||||||
label=html!("Disabled")
|
label={html!("Disabled")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
inline: !props.inline,
|
inline: !props.inline,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.inline
|
checked={ctx.props().example_props.inline}
|
||||||
label=html!("Inline")
|
label={html!("Inline")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
large: !props.large,
|
large: !props.large,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.large
|
checked={ctx.props().example_props.large}
|
||||||
label=html!("Large")
|
label={html!("Large")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ use yew::prelude::*;
|
||||||
use yewprint::{Button, Collapse};
|
use yewprint::{Button, Collapse};
|
||||||
|
|
||||||
pub struct Example {
|
pub struct Example {
|
||||||
link: ComponentLink<Self>,
|
|
||||||
collapsed: bool,
|
collapsed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,34 +13,27 @@ impl Component for Example {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Example {
|
Example { collapsed: true }
|
||||||
collapsed: true,
|
|
||||||
link,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::ToggleCollapse => self.collapsed ^= true,
|
Msg::ToggleCollapse => self.collapsed ^= true,
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let logs = include_str!("example.log");
|
let logs = include_str!("example.log");
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<Button onclick=self.link.callback(|_| Msg::ToggleCollapse)>
|
<Button onclick={ctx.link().callback(|_| Msg::ToggleCollapse)}>
|
||||||
{"Toggle collapse"}
|
{"Toggle collapse"}
|
||||||
</Button>
|
</Button>
|
||||||
<Collapse
|
<Collapse
|
||||||
is_open=!self.collapsed
|
is_open={!self.collapsed}
|
||||||
keep_children_mounted=true
|
keep_children_mounted=true
|
||||||
>
|
>
|
||||||
<pre class="bp3-code-block">
|
<pre class="bp3-code-block">
|
||||||
|
|
|
@ -11,19 +11,15 @@ impl Component for CollapseDoc {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
CollapseDoc
|
CollapseDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
"bp3-code-block"
|
"bp3-code-block"
|
||||||
|
@ -31,9 +27,9 @@ impl Component for CollapseDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Collapse"}</H1>
|
<H1 class={classes!("docs-title")}>{"Collapse"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer source=source>
|
<ExampleContainer source={source}>
|
||||||
<Example />
|
<Example />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,56 +1,31 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Button, ControlGroup, HtmlSelect, IconName, InputGroup};
|
use yewprint::{Button, ControlGroup, HtmlSelect, IconName, InputGroup};
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
props: ExampleProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ExampleProps {
|
pub struct ExampleProps {
|
||||||
pub fill: bool,
|
pub fill: bool,
|
||||||
pub vertical: bool,
|
pub vertical: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Example {
|
#[function_component(Example)]
|
||||||
type Message = ();
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
type Properties = ExampleProps;
|
html! {
|
||||||
|
<ControlGroup
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
fill={props.fill}
|
||||||
Example { props }
|
vertical={props.vertical}
|
||||||
}
|
>
|
||||||
|
<HtmlSelect<Option<Sorting>>
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
options={vec![
|
||||||
true
|
(None, "Filter".to_string()),
|
||||||
}
|
(Some(Sorting::NameAscending), "Name - ascending".to_string()),
|
||||||
|
(Some(Sorting::NameDescending), "Name - descending".to_string()),
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
(Some(Sorting::PriceAscending), "Price - ascending".to_string()),
|
||||||
if self.props != props {
|
(Some(Sorting::PriceDescending), "Price - descending".to_string()),
|
||||||
self.props = props;
|
]}
|
||||||
true
|
/>
|
||||||
} else {
|
<InputGroup placeholder="Find filters..." />
|
||||||
false
|
<Button icon={IconName::ArrowRight} />
|
||||||
}
|
</ControlGroup>
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<ControlGroup
|
|
||||||
fill=self.props.fill
|
|
||||||
vertical=self.props.vertical
|
|
||||||
>
|
|
||||||
<HtmlSelect<Option<Sorting>>
|
|
||||||
options={vec![
|
|
||||||
(None, "Filter".to_string()),
|
|
||||||
(Some(Sorting::NameAscending), "Name - ascending".to_string()),
|
|
||||||
(Some(Sorting::NameDescending), "Name - descending".to_string()),
|
|
||||||
(Some(Sorting::PriceAscending), "Price - ascending".to_string()),
|
|
||||||
(Some(Sorting::PriceDescending), "Price - descending".to_string()),
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<InputGroup placeholder="Find filters..." />
|
|
||||||
<Button icon=IconName::ArrowRight />
|
|
||||||
</ControlGroup>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for ControlGroupDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
ControlGroupDoc {
|
ControlGroupDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
fill: false,
|
fill: false,
|
||||||
vertical: false,
|
vertical: false,
|
||||||
|
@ -24,16 +24,12 @@ impl Component for ControlGroupDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -42,19 +38,19 @@ impl Component for ControlGroupDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"ControlGroup"}</H1>
|
<H1 class={classes!("docs-title")}>{"ControlGroup"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<ControlGroupProps
|
<ControlGroupProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
>
|
>
|
||||||
</ControlGroupProps>
|
</ControlGroupProps>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -63,25 +59,25 @@ impl Component for ControlGroupDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
ControlGroupProps for ExampleProps =>
|
ControlGroupProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
fill: !props.fill,
|
fill: !props.fill,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.fill
|
checked={ctx.props().example_props.fill}
|
||||||
label=html!("Fill")
|
label={html!("Fill")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
vertical: !props.vertical,
|
vertical: !props.vertical,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.vertical
|
checked={ctx.props().example_props.vertical}
|
||||||
label=html!("Vertical")
|
label={html!("Vertical")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +1,22 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Button, ButtonGroup, Divider};
|
use yewprint::{Button, ButtonGroup, Divider};
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
props: ExampleProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ExampleProps {
|
pub struct ExampleProps {
|
||||||
pub vertical: bool,
|
pub vertical: bool,
|
||||||
}
|
}
|
||||||
|
#[function_component(Example)]
|
||||||
impl Component for Example {
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
type Message = ();
|
html! {
|
||||||
type Properties = ExampleProps;
|
<ButtonGroup vertical={props.vertical}>
|
||||||
|
<Button>{"File"}</Button>
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
<Button>{"Edit"}</Button>
|
||||||
Example { props }
|
<Divider vertical={props.vertical} />
|
||||||
}
|
<Button>{"Create"}</Button>
|
||||||
|
<Button>{"Delete"}</Button>
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
<Divider vertical={props.vertical} />
|
||||||
true
|
// <Button icon=IconName::Add />
|
||||||
}
|
// <Button icon=IconName::Remove />
|
||||||
|
</ButtonGroup>
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<ButtonGroup vertical=self.props.vertical>
|
|
||||||
<Button>{"File"}</Button>
|
|
||||||
<Button>{"Edit"}</Button>
|
|
||||||
<Divider vertical=self.props.vertical />
|
|
||||||
<Button>{"Create"}</Button>
|
|
||||||
<Button>{"Delete"}</Button>
|
|
||||||
<Divider vertical=self.props.vertical />
|
|
||||||
// <Button icon=IconName::Add />
|
|
||||||
// <Button icon=IconName::Remove />
|
|
||||||
</ButtonGroup>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,23 +14,19 @@ impl Component for DividerDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
DividerDoc {
|
DividerDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps { vertical: false },
|
state: ExampleProps { vertical: false },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -39,18 +35,18 @@ impl Component for DividerDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Divider"}</H1>
|
<H1 class={classes!("docs-title")}>{"Divider"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<DividerProps
|
<DividerProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -59,16 +55,16 @@ impl Component for DividerDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
DividerProps for ExampleProps =>
|
DividerProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
vertical: !props.vertical
|
vertical: !props.vertical
|
||||||
})
|
})}
|
||||||
checked=self.props.vertical
|
checked={ctx.props().example_props.vertical}
|
||||||
label=html!("Vertical")
|
label={html!("Vertical")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@ use yewprint::{Button, Collapse, IconName, Intent};
|
||||||
|
|
||||||
pub struct ExampleContainer {
|
pub struct ExampleContainer {
|
||||||
collapsed: bool,
|
collapsed: bool,
|
||||||
props: ExampleContainerProps,
|
|
||||||
link: ComponentLink<Self>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
|
@ -23,41 +21,28 @@ impl Component for ExampleContainer {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = ExampleContainerProps;
|
type Properties = ExampleContainerProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
ExampleContainer {
|
ExampleContainer { collapsed: true }
|
||||||
collapsed: true,
|
|
||||||
props,
|
|
||||||
link,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::ToggleSource => self.collapsed ^= true,
|
Msg::ToggleSource => self.collapsed ^= true,
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
html! {
|
||||||
<div class=classes!("docs-example-wrapper")>
|
<div class={classes!("docs-example-wrapper")}>
|
||||||
<div class=classes!("docs-example-frame", "docs-example-frame-row")>
|
<div class={classes!("docs-example-frame", "docs-example-frame-row")}>
|
||||||
<div class=classes!("docs-example")>
|
<div class={classes!("docs-example")}>
|
||||||
{self.props.children.clone()}
|
{ctx.props().children.clone()}
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
if let Some(props) = self.props.props.clone() {
|
if let Some(props) = ctx.props().props.clone() {
|
||||||
html! {
|
html! {
|
||||||
<div class=classes!("docs-example-options")>
|
<div class={classes!("docs-example-options")}>
|
||||||
{props}
|
{props}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -66,21 +51,21 @@ impl Component for ExampleContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class=classes!("docs-source")>
|
<div class={classes!("docs-source")}>
|
||||||
<Button
|
<Button
|
||||||
icon=IconName::Code
|
icon={IconName::Code}
|
||||||
fill={true}
|
fill={{true}}
|
||||||
intent={Intent::Primary}
|
intent={{Intent::Primary}}
|
||||||
minimal={true}
|
minimal={{true}}
|
||||||
onclick=self.link.callback(|_| Msg::ToggleSource)
|
onclick={ctx.link().callback(|_| Msg::ToggleSource)}
|
||||||
>
|
>
|
||||||
{"View source"}
|
{"View source"}
|
||||||
</Button>
|
</Button>
|
||||||
<Collapse
|
<Collapse
|
||||||
is_open=!self.collapsed
|
is_open={!self.collapsed}
|
||||||
keep_children_mounted=true
|
keep_children_mounted=true
|
||||||
>
|
>
|
||||||
{self.props.source.clone()}
|
{ctx.props().source.clone()}
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -88,47 +73,40 @@ impl Component for ExampleContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The macro generates the component that will be used to render the editable
|
||||||
|
/// properties of an associated example.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! build_example_prop_component {
|
macro_rules! build_example_prop_component {
|
||||||
($name:ident for $prop_component:ty => $($view:tt)*) => {
|
($name:ident for $prop_component:ty => $($view:tt)*) => {
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct $name {
|
pub struct $name {
|
||||||
callback: Callback<$prop_component>,
|
callback: Callback<$prop_component>,
|
||||||
props: $prop_component,
|
example_props: $prop_component
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for $name {
|
impl Component for $name {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
type Properties = Self;
|
type Properties = Self;
|
||||||
|
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
props
|
ctx.props().clone()
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
|
||||||
if self.props != props.props || self.callback != props.callback {
|
|
||||||
self.props = props.props;
|
|
||||||
self.callback = props.callback;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$($view)*
|
$($view)*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $name {
|
impl $name {
|
||||||
|
/// Propagate the prop changes to the parent so the example is
|
||||||
|
/// re-rendered.
|
||||||
fn update_props<T>(
|
fn update_props<T>(
|
||||||
&self,
|
&self,
|
||||||
|
props: &Self,
|
||||||
updater: impl Fn($prop_component, T) -> $prop_component + 'static,
|
updater: impl Fn($prop_component, T) -> $prop_component + 'static,
|
||||||
) -> Callback<T> {
|
) -> Callback<T> {
|
||||||
let props = self.props.clone();
|
let example_props = props.example_props.clone();
|
||||||
self.callback.clone().reform(move |event| updater(props.clone(), event))
|
self.callback
|
||||||
|
.clone()
|
||||||
|
.reform(move |event| updater(example_props.clone(), event))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,8 +2,6 @@ use yew::prelude::*;
|
||||||
use yewprint::{HtmlSelect, Text};
|
use yewprint::{HtmlSelect, Text};
|
||||||
|
|
||||||
pub struct Example {
|
pub struct Example {
|
||||||
props: ExampleProps,
|
|
||||||
link: ComponentLink<Self>,
|
|
||||||
log_level: LogLevel,
|
log_level: LogLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,29 +17,18 @@ impl Component for Example {
|
||||||
type Message = LogLevel;
|
type Message = LogLevel;
|
||||||
type Properties = ExampleProps;
|
type Properties = ExampleProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Example {
|
Example {
|
||||||
props,
|
|
||||||
link,
|
|
||||||
log_level: LogLevel::Info,
|
log_level: LogLevel::Info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.log_level = msg;
|
self.log_level = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
html! {
|
||||||
<div style="width: 400px; text-align: center;">
|
<div style="width: 400px; text-align: center;">
|
||||||
<HtmlSelect<LogLevel>
|
<HtmlSelect<LogLevel>
|
||||||
|
@ -53,13 +40,13 @@ impl Component for Example {
|
||||||
(LogLevel::Error, "ERROR".to_string()),
|
(LogLevel::Error, "ERROR".to_string()),
|
||||||
(LogLevel::Off, "OFF".to_string()),
|
(LogLevel::Off, "OFF".to_string()),
|
||||||
]}
|
]}
|
||||||
minimal=self.props.minimal
|
minimal={ctx.props().minimal}
|
||||||
fill=self.props.fill
|
fill={ctx.props().fill}
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
value=Some(self.log_level)
|
value={Some(self.log_level)}
|
||||||
onchange=self.link.callback(|x| x)
|
onchange={ctx.link().callback(|x| x)}
|
||||||
title=format!("Selected: {:?}", self.log_level)
|
title={format!("Selected: {:?}", self.log_level)}
|
||||||
/>
|
/>
|
||||||
<Text>{format!("Selected: {:?}", self.log_level)}</Text>
|
<Text>{format!("Selected: {:?}", self.log_level)}</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for HtmlSelectDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
HtmlSelectDoc {
|
HtmlSelectDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
minimal: false,
|
minimal: false,
|
||||||
fill: false,
|
fill: false,
|
||||||
|
@ -26,16 +26,12 @@ impl Component for HtmlSelectDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -44,19 +40,19 @@ impl Component for HtmlSelectDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"HtmlSelect"}</H1>
|
<H1 class={classes!("docs-title")}>{"HtmlSelect"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<div>
|
<div>
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<HtmlSelectProps
|
<HtmlSelectProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -66,41 +62,41 @@ impl Component for HtmlSelectDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
HtmlSelectProps for ExampleProps =>
|
HtmlSelectProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
minimal: !props.minimal,
|
minimal: !props.minimal,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.minimal
|
checked={ctx.props().example_props.minimal}
|
||||||
label=html!("Minimal")
|
label={html!("Minimal")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps{
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps{
|
||||||
fill: !props.fill,
|
fill: !props.fill,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.fill
|
checked={ctx.props().example_props.fill}
|
||||||
label=html!("Fill")
|
label={html!("Fill")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
disabled: !props.disabled,
|
disabled: !props.disabled,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.disabled
|
checked={ctx.props().example_props.disabled}
|
||||||
label=html!("Disabled")
|
label={html!("Disabled")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps{
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps{
|
||||||
large: !props.large,
|
large: !props.large,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.large
|
checked={ctx.props().example_props.large}
|
||||||
label=html!("Large")
|
label={html!("Large")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,11 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Icon, IconName};
|
use yewprint::{Icon, IconName};
|
||||||
|
|
||||||
pub struct Example {}
|
#[function_component(Example)]
|
||||||
|
pub fn example() -> Html {
|
||||||
impl Component for Example {
|
html! {
|
||||||
type Message = ();
|
<div>
|
||||||
type Properties = ();
|
<Icon icon={IconName::Print} />
|
||||||
|
</div>
|
||||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
|
||||||
Example {}
|
|
||||||
}
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<div>
|
|
||||||
<Icon icon=IconName::Print />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,19 +11,15 @@ impl Component for IconDoc {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
IconDoc
|
IconDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
"bp3-code-block"
|
"bp3-code-block"
|
||||||
|
@ -31,9 +27,9 @@ impl Component for IconDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Icon"}</H1>
|
<H1 class={classes!("docs-title")}>{"Icon"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer source=source>
|
<ExampleContainer source={source}>
|
||||||
<Example />
|
<Example />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
use gloo::dialogs::alert;
|
||||||
|
use web_sys::HtmlInputElement;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Button, IconName, InputGroup, Tag};
|
use yewprint::{Button, IconName, InputGroup, Tag};
|
||||||
|
|
||||||
pub struct Example {
|
pub struct Example {
|
||||||
link: ComponentLink<Self>,
|
|
||||||
props: ExampleProps,
|
|
||||||
histogram_value: String,
|
histogram_value: String,
|
||||||
password_value: String,
|
password_value: String,
|
||||||
password_strength: Html,
|
password_strength: Html,
|
||||||
|
@ -29,22 +29,12 @@ pub enum Msg {
|
||||||
Noop,
|
Noop,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! alert {
|
|
||||||
($($arg:tt)*) => {
|
|
||||||
yew::services::DialogService::alert(&format!(
|
|
||||||
$($arg)*
|
|
||||||
))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for Example {
|
impl Component for Example {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = ExampleProps;
|
type Properties = ExampleProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Example {
|
Example {
|
||||||
props,
|
|
||||||
link,
|
|
||||||
histogram_value: Default::default(),
|
histogram_value: Default::default(),
|
||||||
password_value: Default::default(),
|
password_value: Default::default(),
|
||||||
password_strength: Default::default(),
|
password_strength: Default::default(),
|
||||||
|
@ -52,10 +42,10 @@ impl Component for Example {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> bool {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::AddHistogramEntry => {
|
Msg::AddHistogramEntry => {
|
||||||
alert!("You sent: {}", self.histogram_value);
|
alert(&format!("You sent: {}", self.histogram_value));
|
||||||
self.histogram_value = Default::default();
|
self.histogram_value = Default::default();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -64,7 +54,7 @@ impl Component for Example {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Msg::AddPasswordEntry => {
|
Msg::AddPasswordEntry => {
|
||||||
alert!("You sent: {}", self.password_value);
|
alert(&format!("You sent: {}", self.password_value));
|
||||||
self.password_value = Default::default();
|
self.password_value = Default::default();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -81,7 +71,7 @@ impl Component for Example {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Msg::AddTagsEntry => {
|
Msg::AddTagsEntry => {
|
||||||
alert!("You sent: {}", self.tags_value);
|
alert(&format!("You sent: {}", self.tags_value));
|
||||||
self.tags_value = Default::default();
|
self.tags_value = Default::default();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -93,74 +83,76 @@ impl Component for Example {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
fill=self.props.fill
|
fill={ctx.props().fill}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
small=self.props.small
|
small={ctx.props().small}
|
||||||
round=self.props.round
|
round={ctx.props().round}
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
left_icon=IconName::Filter
|
left_icon={IconName::Filter}
|
||||||
placeholder={"Filter histogram..."}
|
placeholder={"Filter histogram..."}
|
||||||
value=self.histogram_value.clone()
|
value={self.histogram_value.clone()}
|
||||||
oninput=self.link.callback(|e: InputData| Msg::UpdateHistogram(e.value))
|
oninput={ctx.link().callback(|e: InputEvent| {
|
||||||
onkeydown=self.link.callback(|e: KeyboardEvent| {
|
let value = e.target_unchecked_into::<HtmlInputElement>().value();
|
||||||
|
Msg::UpdateHistogram(value)
|
||||||
|
})}
|
||||||
|
onkeydown={ctx.link().callback(|e: KeyboardEvent| {
|
||||||
if e.key() == "Enter" { Msg::AddHistogramEntry } else { Msg::Noop }
|
if e.key() == "Enter" { Msg::AddHistogramEntry } else { Msg::Noop }
|
||||||
})
|
})}
|
||||||
/>
|
/>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
fill=self.props.fill
|
fill={ctx.props().fill}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
small=self.props.small
|
small={ctx.props().small}
|
||||||
round=self.props.round
|
round={ctx.props().round}
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
left_element=self.password_strength.clone()
|
left_element={self.password_strength.clone()}
|
||||||
placeholder={"Enter your password..."}
|
placeholder={"Enter your password..."}
|
||||||
value=self.password_value.clone()
|
value={self.password_value.clone()}
|
||||||
oninput=self.link.callback(|e: InputData| Msg::UpdatePassword(e.value))
|
oninput={ctx.link().callback(|e: InputEvent| {
|
||||||
onkeydown=self.link.callback(|e: KeyboardEvent| {
|
let value = e.target_unchecked_into::<HtmlInputElement>().value();
|
||||||
|
Msg::UpdatePassword(value)
|
||||||
|
})}
|
||||||
|
onkeydown={ctx.link().callback(|e: KeyboardEvent| {
|
||||||
if e.key() == "Enter" { Msg::AddPasswordEntry } else { Msg::Noop }
|
if e.key() == "Enter" { Msg::AddPasswordEntry } else { Msg::Noop }
|
||||||
})
|
})}
|
||||||
right_element=html! {
|
right_element={{ html! {
|
||||||
<Button
|
<Button
|
||||||
icon=IconName::Lock
|
icon={IconName::Lock}
|
||||||
minimal=true
|
minimal={true}
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
/>
|
/>
|
||||||
}
|
}}}
|
||||||
/>
|
/>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
fill=self.props.fill
|
fill={ctx.props().fill}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
small=self.props.small
|
small={ctx.props().small}
|
||||||
round=self.props.round
|
round={ctx.props().round}
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
left_icon=IconName::Tag
|
left_icon={IconName::Tag}
|
||||||
placeholder={"Find tags"}
|
placeholder={"Find tags"}
|
||||||
value=self.tags_value.clone()
|
value={self.tags_value.clone()}
|
||||||
oninput=self.link.callback(|e: InputData| Msg::UpdateTags(e.value))
|
oninput={ctx.link().callback(|e: InputEvent| {
|
||||||
onkeydown=self.link.callback(|e: KeyboardEvent| {
|
let value = e.target_unchecked_into::<HtmlInputElement>().value();
|
||||||
|
Msg::UpdateTags(value)
|
||||||
|
})}
|
||||||
|
onkeydown={ctx.link().callback(|e: KeyboardEvent| {
|
||||||
if e.key() == "Enter" { Msg::AddTagsEntry } else { Msg::Noop }
|
if e.key() == "Enter" { Msg::AddTagsEntry } else { Msg::Noop }
|
||||||
})
|
})}
|
||||||
right_element=html! {
|
right_element={{
|
||||||
<Tag
|
html!{
|
||||||
minimal=true
|
<Tag
|
||||||
round=self.props.round
|
minimal={true}
|
||||||
>
|
round={ctx.props().round}
|
||||||
{{10000 / 1.max(self.tags_value.len().pow(2))}}
|
>
|
||||||
</Tag>
|
{ (10000 / 1.max(self.tags_value.len().pow(2))).to_string() }
|
||||||
}
|
</Tag>
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for InputGroupDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
InputGroupDoc {
|
InputGroupDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
fill: false,
|
fill: false,
|
||||||
|
@ -27,16 +27,12 @@ impl Component for InputGroupDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -45,19 +41,19 @@ impl Component for InputGroupDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"InputGroup"}</H1>
|
<H1 class={classes!("docs-title")}>{"InputGroup"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<InputGroupProps
|
<InputGroupProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
>
|
>
|
||||||
</InputGroupProps>
|
</InputGroupProps>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -66,49 +62,49 @@ impl Component for InputGroupDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
InputGroupProps for ExampleProps =>
|
InputGroupProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
disabled: !props.disabled,
|
disabled: !props.disabled,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.disabled
|
checked={ctx.props().example_props.disabled}
|
||||||
label=html!("Disabled")
|
label={html!("Disabled")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
fill: !props.fill,
|
fill: !props.fill,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.fill
|
checked={ctx.props().example_props.fill}
|
||||||
label=html!("Fill")
|
label={html!("Fill")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
large: !props.large,
|
large: !props.large,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.large
|
checked={ctx.props().example_props.large}
|
||||||
label=html!("Large")
|
label={html!("Large")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
small: !props.small,
|
small: !props.small,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.small
|
checked={ctx.props().example_props.small}
|
||||||
label=html!("Small")
|
label={html!("Small")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
round: !props.round,
|
round: !props.round,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.round
|
checked={ctx.props().example_props.round}
|
||||||
label=html!("Round")
|
label={html!("Round")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,17 +32,10 @@ pub use app::*;
|
||||||
pub use example::*;
|
pub use example::*;
|
||||||
pub use logo::*;
|
pub use logo::*;
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! log {
|
|
||||||
($s:expr $(,$args:expr)*) => {{
|
|
||||||
yew::services::ConsoleService::log(format!($s $(,$args)*).as_str());
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! include_raw_html {
|
macro_rules! include_raw_html {
|
||||||
($file:expr $(, $class:expr)?) => {{
|
($file:expr $(, $class:expr)?) => {{
|
||||||
yew::virtual_dom::VNode::VRef(yew::web_sys::Node::from({
|
yew::virtual_dom::VNode::VRef(web_sys::Node::from({
|
||||||
let div = web_sys::window()
|
let div = web_sys::window()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.document()
|
.document()
|
||||||
|
@ -88,27 +81,23 @@ macro_rules! build_source_code_component {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
let url = SourceCodeUrl::generate_url();
|
let url = SourceCodeUrl::generate_url();
|
||||||
|
|
||||||
Self { url }
|
Self { url }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
use yewprint::Text;
|
use yewprint::Text;
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<a
|
<a
|
||||||
class=classes!("bp3-text-muted")
|
class={classes!("bp3-text-muted")}
|
||||||
href=self.url.clone()
|
href={self.url.clone()}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Text>{"Go to source code"}</Text>
|
<Text>{"Go to source code"}</Text>
|
||||||
|
@ -142,7 +131,7 @@ static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||||
pub fn run_app() -> Result<(), wasm_bindgen::JsValue> {
|
pub fn run_app() -> Result<(), wasm_bindgen::JsValue> {
|
||||||
#[cfg(feature = "console_error_panic_hook")]
|
#[cfg(feature = "console_error_panic_hook")]
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
yew::start_app::<app::App>();
|
yew::start_app::<app::AppRoot>();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,12 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Logo {
|
|
||||||
props: LogoProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct LogoProps {
|
pub struct LogoProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub class: Classes,
|
pub class: Classes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Logo {
|
#[function_component(Logo)]
|
||||||
type Message = ();
|
pub fn logo(props: &LogoProps) -> Html {
|
||||||
type Properties = LogoProps;
|
crate::include_raw_html!("logo.svg", &props.class.to_string())
|
||||||
|
|
||||||
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
|
|
||||||
Self { props }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
|
||||||
if props != self.props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
crate::include_raw_html!("logo.svg", &self.props.class.to_string())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
use crate::{DocMenu, Logo};
|
use crate::{DocMenu, Logo};
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Icon, IconName, Menu, MenuDivider, MenuItem};
|
use yewprint::{Icon, IconName, Menu, MenuDivider, MenuItem};
|
||||||
|
|
||||||
pub struct Example {
|
pub struct Example {}
|
||||||
link: ComponentLink<Self>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
GoToMenu(DocMenu),
|
GoToMenu(DocMenu),
|
||||||
|
@ -15,107 +12,106 @@ impl Component for Example {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Self { link }
|
Self {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
true
|
let custom_icon = html! {
|
||||||
}
|
<Logo class={classes!("custom-icon")} />
|
||||||
|
};
|
||||||
|
|
||||||
|
let share_icon = html! {
|
||||||
|
<Icon icon={IconName::Share} />
|
||||||
|
};
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<Menu>
|
<Menu>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={html!("Custom SVG icon")}
|
text={html!("Custom SVG icon")}
|
||||||
icon_html=html! {
|
icon_html={custom_icon}
|
||||||
<Logo class=classes!("custom-icon") />
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<MenuDivider />
|
<MenuDivider />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon=IconName::NewTextBox
|
icon={IconName::NewTextBox}
|
||||||
text={html!{"New text box"}}
|
text={html!("New text box")}
|
||||||
href=Cow::Borrowed("#menu")
|
href={"#menu"}
|
||||||
onclick=self.link
|
onclick={ctx.link()
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon=IconName::NewObject
|
icon={IconName::NewObject}
|
||||||
text={html!{"New object"}}
|
text={html!("New object")}
|
||||||
href=Cow::Borrowed("#menu")
|
href={"#menu"}
|
||||||
onclick=self.link
|
onclick={ctx.link()
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon=IconName::NewLink
|
icon={IconName::NewLink}
|
||||||
text={html!{"New link"}}
|
text={html!("New link")}
|
||||||
href=Cow::Borrowed("#menu")
|
href={"#menu"}
|
||||||
onclick=self.link
|
onclick={ctx.link()
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||||
/>
|
/>
|
||||||
<MenuDivider />
|
<MenuDivider />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon=IconName::Cog
|
icon={IconName::Cog}
|
||||||
text={html!{"Settings"}}
|
text={html!("Settings")}
|
||||||
label=html! {
|
label={share_icon}
|
||||||
<Icon icon=IconName::Share />
|
href={"#menu"}
|
||||||
}
|
onclick={ctx.link()
|
||||||
href=Cow::Borrowed("#menu")
|
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||||
onclick=self.link
|
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
|
||||||
/>
|
/>
|
||||||
</Menu>
|
</Menu>
|
||||||
<Menu>
|
<Menu>
|
||||||
<MenuDivider title={html!("Edit")} />
|
<MenuDivider title={html!("Edit")} />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon=IconName::Cut
|
icon={IconName::Cut}
|
||||||
text={html!("Cut")}
|
text={html!("Cut")}
|
||||||
label={html!("Ctrl+X")}
|
label={html!("Ctrl+X")}
|
||||||
href=Cow::Borrowed("#menu")
|
href={"#menu"}
|
||||||
onclick=self.link
|
onclick={ctx.link()
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon=IconName::Duplicate
|
icon={IconName::Duplicate}
|
||||||
text={html!("Copy")}
|
text={html!("Copy")}
|
||||||
label={html!("Ctrl+C")}
|
label={html!("Ctrl+C")}
|
||||||
href=Cow::Borrowed("#menu")
|
href={"#menu"}
|
||||||
onclick=self.link
|
onclick={ctx.link()
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon=IconName::Clipboard
|
icon={IconName::Clipboard}
|
||||||
text={html!("Paste")}
|
text={html!("Paste")}
|
||||||
label={html!("Ctrl+V")}
|
label={html!("Ctrl+V")}
|
||||||
disabled=true
|
disabled=true
|
||||||
/>
|
/>
|
||||||
<MenuDivider title={html!("Text")} />
|
<MenuDivider title={html!("Text")} />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon=IconName::AlignLeft
|
icon={IconName::AlignLeft}
|
||||||
text={html!("Alignment")}
|
text={html!("Alignment")}
|
||||||
href=Cow::Borrowed("#menu")
|
href={"#menu"}
|
||||||
onclick=self.link
|
onclick={ctx.link()
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon=IconName::Style
|
icon={IconName::Style}
|
||||||
text={html!("Style")}
|
text={html!("Style")}
|
||||||
href=Cow::Borrowed("#menu")
|
href={"#menu"}
|
||||||
onclick=self.link
|
onclick={ctx.link()
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon=IconName::Asterisk
|
icon={IconName::Asterisk}
|
||||||
text={html!("Miscellaneous")}
|
text={html!("Miscellaneous")}
|
||||||
href=Cow::Borrowed("#menu")
|
href={"#menu"}
|
||||||
onclick=self.link
|
onclick={ctx.link().callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
|
||||||
/>
|
/>
|
||||||
</Menu>
|
</Menu>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -11,19 +11,15 @@ impl Component for MenuDoc {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
MenuDoc
|
MenuDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
"bp3-code-block"
|
"bp3-code-block"
|
||||||
|
@ -31,9 +27,9 @@ impl Component for MenuDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Menu"}</H1>
|
<H1 class={classes!("docs-title")}>{"Menu"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer source=source>
|
<ExampleContainer source={source}>
|
||||||
<Example />
|
<Example />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Button, Callout, IconName, Intent, NumericInput};
|
use yewprint::{Button, Callout, IconName, Intent, NumericInput};
|
||||||
|
|
||||||
pub struct Example {
|
pub struct Example {
|
||||||
props: ExampleProps,
|
|
||||||
link: ComponentLink<Self>,
|
|
||||||
value: i32,
|
value: i32,
|
||||||
value_two: i32,
|
value_two: i32,
|
||||||
}
|
}
|
||||||
|
@ -29,16 +26,14 @@ impl Component for Example {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = ExampleProps;
|
type Properties = ExampleProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Example {
|
Example {
|
||||||
props,
|
|
||||||
link,
|
|
||||||
value: 0,
|
value: 0,
|
||||||
value_two: 0,
|
value_two: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::Reset => {
|
Msg::Reset => {
|
||||||
self.value = 4;
|
self.value = 4;
|
||||||
|
@ -54,52 +49,43 @@ impl Component for Example {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<NumericInput<i32>
|
<NumericInput<i32>
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
fill=self.props.large
|
fill={ctx.props().large}
|
||||||
value=self.value
|
value={self.value}
|
||||||
bounds={-105..}
|
bounds={-105..}
|
||||||
increment=10
|
increment=10
|
||||||
placeholder=String::from("Greater or equal to -105...")
|
placeholder={String::from("Greater or equal to -105...")}
|
||||||
onchange=self.link.callback(|x| Msg::UpdateValue(x))
|
onchange={ctx.link().callback(|x| Msg::UpdateValue(x))}
|
||||||
disable_buttons=self.props.disable_buttons
|
disable_buttons={ctx.props().disable_buttons}
|
||||||
buttons_on_the_left=self.props.buttons_on_the_left
|
buttons_on_the_left={ctx.props().buttons_on_the_left}
|
||||||
left_icon=self.props.left_icon.then(|| IconName::Dollar)
|
left_icon={ctx.props().left_icon.then(|| IconName::Dollar)}
|
||||||
/>
|
/>
|
||||||
<NumericInput<i32>
|
<NumericInput<i32>
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
fill=self.props.fill
|
fill={ctx.props().fill}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
value=self.value_two
|
value={self.value_two}
|
||||||
bounds={-10..=10}
|
bounds={-10..=10}
|
||||||
increment=1
|
increment=1
|
||||||
placeholder=String::from("Integer between -10 and 10")
|
placeholder={String::from("Integer between -10 and 10")}
|
||||||
onchange=self.link.callback(|x| Msg::UpdateValueTwo(x))
|
onchange={ctx.link().callback(|x| Msg::UpdateValueTwo(x))}
|
||||||
disable_buttons=self.props.disable_buttons
|
disable_buttons={ctx.props().disable_buttons}
|
||||||
buttons_on_the_left=self.props.buttons_on_the_left
|
buttons_on_the_left={ctx.props().buttons_on_the_left}
|
||||||
left_icon=self.props.left_icon.then(|| IconName::Dollar)
|
left_icon={ctx.props().left_icon.then(|| IconName::Dollar)}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
icon=IconName::Refresh
|
icon={IconName::Refresh}
|
||||||
onclick=self.link.callback(|_| Msg::Reset)
|
onclick={ctx.link().callback(|_| Msg::Reset)}
|
||||||
>
|
>
|
||||||
{"Reset at 4"}
|
{"Reset at 4"}
|
||||||
</Button>
|
</Button>
|
||||||
<Callout
|
<Callout
|
||||||
title=Cow::Borrowed("Selected values")
|
title={"Selected values"}
|
||||||
intent=Intent::Primary
|
intent={Intent::Primary}
|
||||||
>
|
>
|
||||||
<ul>
|
<ul>
|
||||||
<li>{self.value}</li>
|
<li>{self.value}</li>
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for NumericInputDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
NumericInputDoc {
|
NumericInputDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
fill: false,
|
fill: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
@ -28,16 +28,12 @@ impl Component for NumericInputDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -46,19 +42,19 @@ impl Component for NumericInputDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"NumericInput"}</H1>
|
<H1 class={classes!("docs-title")}>{"NumericInput"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<div>
|
<div>
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<NumericInputProps
|
<NumericInputProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -68,57 +64,57 @@ impl Component for NumericInputDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
NumericInputProps for ExampleProps =>
|
NumericInputProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
fill: !props.fill,
|
fill: !props.fill,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.fill
|
checked={ctx.props().example_props.fill}
|
||||||
label=html!("Fill")
|
label={html!("Fill")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
disabled: !props.disabled,
|
disabled: !props.disabled,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.disabled
|
checked={ctx.props().example_props.disabled}
|
||||||
label=html!("Disabled")
|
label={html!("Disabled")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
large: !props.large,
|
large: !props.large,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.large
|
checked={ctx.props().example_props.large}
|
||||||
label=html!("Large")
|
label={html!("Large")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
disable_buttons: !props.disable_buttons,
|
disable_buttons: !props.disable_buttons,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.disable_buttons
|
checked={ctx.props().example_props.disable_buttons}
|
||||||
label=html!("Disable buttons")
|
label={html!("Disable buttons")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
buttons_on_the_left: !props.buttons_on_the_left,
|
buttons_on_the_left: !props.buttons_on_the_left,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.buttons_on_the_left
|
checked={ctx.props().example_props.buttons_on_the_left}
|
||||||
label=html!("Buttons on the left")
|
label={html!("Buttons on the left")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
left_icon: !props.left_icon,
|
left_icon: !props.left_icon,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.left_icon
|
checked={ctx.props().example_props.left_icon}
|
||||||
label=html!("Left icon")
|
label={html!("Left icon")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@ use yew::prelude::*;
|
||||||
use yewprint::{Button, Intent, PanelStack, PanelStackState, Text};
|
use yewprint::{Button, Intent, PanelStack, PanelStackState, Text};
|
||||||
|
|
||||||
pub struct Example {
|
pub struct Example {
|
||||||
link: ComponentLink<Self>,
|
|
||||||
props: ExampleProps,
|
|
||||||
state: PanelStackState,
|
state: PanelStackState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,37 +21,38 @@ impl Component for Example {
|
||||||
type Message = ExampleMessage;
|
type Message = ExampleMessage;
|
||||||
type Properties = ExampleProps;
|
type Properties = ExampleProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
let state = PanelStackState::new(html! {
|
let state = PanelStackState::new(html! {
|
||||||
<div class=classes!("docs-panel-stack-contents-example")>
|
<div class={classes!("docs-panel-stack-contents-example")}>
|
||||||
<div>{"Hello World!"}</div>
|
<div>{"Hello World!"}</div>
|
||||||
<Button
|
<Button
|
||||||
intent=Intent::Primary
|
intent={Intent::Primary}
|
||||||
onclick=link.callback(|_| ExampleMessage::OpenPanel2)
|
onclick={ctx.link().callback(|_| ExampleMessage::OpenPanel2)}
|
||||||
>
|
>
|
||||||
{"Open panel 2"}
|
{"Open panel 2"}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
})
|
})
|
||||||
.with_title(html! {
|
.with_title(html! {
|
||||||
<Text class=classes!("bp3-heading") ellipsize=true>
|
<Text class={classes!("bp3-heading")} ellipsize=true>
|
||||||
{"Root Panel"}
|
{"Root Panel"}
|
||||||
</Text>
|
</Text>
|
||||||
})
|
})
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
Example { link, props, state }
|
Example { state }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
|
// Open
|
||||||
ExampleMessage::OpenPanel2 => self
|
ExampleMessage::OpenPanel2 => self
|
||||||
.state
|
.state
|
||||||
.open_panel(html! {
|
.open_panel(html! {
|
||||||
<div class=classes!("docs-panel-stack-contents-example")>
|
<div class={classes!("docs-panel-stack-contents-example")}>
|
||||||
<Button
|
<Button
|
||||||
intent=Intent::Success
|
intent={Intent::Success}
|
||||||
onclick=self.link.callback(|_| ExampleMessage::OpenPanel2)
|
onclick={ctx.link().callback(|_| ExampleMessage::OpenPanel2)}
|
||||||
>
|
>
|
||||||
{"Open another panel 2"}
|
{"Open another panel 2"}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -61,7 +60,7 @@ impl Component for Example {
|
||||||
</div>
|
</div>
|
||||||
})
|
})
|
||||||
.with_title(html! {
|
.with_title(html! {
|
||||||
<Text class=classes!("bp3-heading") ellipsize=true>
|
<Text class={classes!("bp3-heading")} ellipsize=true>
|
||||||
{"Panel 2"}
|
{"Panel 2"}
|
||||||
</Text>
|
</Text>
|
||||||
})
|
})
|
||||||
|
@ -71,70 +70,34 @@ impl Component for Example {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<PanelStack
|
<PanelStack
|
||||||
state=self.state.clone()
|
state={self.state.clone()}
|
||||||
onclose=self.link.callback(|_| ExampleMessage::ClosePanel)
|
onclose={ctx.link().callback(|_| ExampleMessage::ClosePanel)}
|
||||||
class=classes!("docs-panel-stack-example")
|
class={classes!("docs-panel-stack-example")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second panel: a simple counter
|
/// Second panel: a simple counter
|
||||||
|
#[function_component(Panel2)]
|
||||||
|
pub fn panel2() -> Html {
|
||||||
|
let counter = use_state(|| 0);
|
||||||
|
let onclick = {
|
||||||
|
let counter = counter.clone();
|
||||||
|
Callback::from(move |_| counter.set(*counter + 1))
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Panel2 {
|
html! {
|
||||||
link: ComponentLink<Self>,
|
<div>
|
||||||
counter: i64,
|
<p>{"Counter: "}{ *counter}</p>
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Panel2Message {
|
|
||||||
AddOne,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for Panel2 {
|
|
||||||
type Message = Panel2Message;
|
|
||||||
type Properties = ();
|
|
||||||
|
|
||||||
fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
|
||||||
Panel2 { counter: 0, link }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
|
||||||
match msg {
|
|
||||||
Panel2Message::AddOne => {
|
|
||||||
self.counter += 1;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<div>
|
<div>
|
||||||
<p>{"Counter: "}{self.counter}</p>
|
<Button {onclick}>{ "Add 1" }</Button>
|
||||||
<div>
|
|
||||||
<Button onclick=self.link.callback(|_| Panel2Message::AddOne)>
|
|
||||||
{"Add 1"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for PanelStackDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
PanelStackDoc {
|
PanelStackDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
animate: true,
|
animate: true,
|
||||||
vertical: false,
|
vertical: false,
|
||||||
|
@ -24,16 +24,12 @@ impl Component for PanelStackDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -42,14 +38,14 @@ impl Component for PanelStackDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"PanelStack"}</H1>
|
<H1 class={classes!("docs-title")}>{"PanelStack"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<div>
|
<div>
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=None
|
props={None}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Intent, ProgressBar};
|
use yewprint::{Intent, ProgressBar};
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
props: ExampleProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ExampleProps {
|
pub struct ExampleProps {
|
||||||
pub intent: Option<Intent>,
|
pub intent: Option<Intent>,
|
||||||
|
@ -12,32 +8,14 @@ pub struct ExampleProps {
|
||||||
pub stripes: bool,
|
pub stripes: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Example {
|
#[function_component(Example)]
|
||||||
type Message = ();
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
type Properties = ExampleProps;
|
html! {
|
||||||
|
<ProgressBar
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
animate={props.animate}
|
||||||
Example { props }
|
stripes={props.stripes}
|
||||||
}
|
intent={props.intent}
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
value=0.3
|
||||||
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
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for ProgressBarDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
ProgressBarDoc {
|
ProgressBarDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
intent: None,
|
intent: None,
|
||||||
animate: false,
|
animate: false,
|
||||||
|
@ -25,16 +25,12 @@ impl Component for ProgressBarDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -43,18 +39,18 @@ impl Component for ProgressBarDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"ProgressBar"}</H1>
|
<H1 class={classes!("docs-title")}>{"ProgressBar"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<ProgressBarProps
|
<ProgressBarProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -63,26 +59,26 @@ impl Component for ProgressBarDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
ProgressBarProps for ExampleProps =>
|
ProgressBarProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<div>
|
<div>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
stripes: !props.stripes,
|
stripes: !props.stripes,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.stripes
|
checked={ctx.props().example_props.stripes}
|
||||||
label=html!("Stripes")
|
label={html!("Stripes")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
animate: !props.animate,
|
animate: !props.animate,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.animate
|
checked={ctx.props().example_props.animate}
|
||||||
label=html!("Animate")
|
label={html!("Animate")}
|
||||||
/>
|
/>
|
||||||
<p>{"Select intent:"}</p>
|
<p>{"Select intent:"}</p>
|
||||||
<HtmlSelect<Option<Intent>>
|
<HtmlSelect<Option<Intent>>
|
||||||
|
@ -93,10 +89,10 @@ crate::build_example_prop_component! {
|
||||||
(Some(Intent::Warning), "Warning".to_string()),
|
(Some(Intent::Warning), "Warning".to_string()),
|
||||||
(Some(Intent::Danger), "Danger".to_string()),
|
(Some(Intent::Danger), "Danger".to_string()),
|
||||||
]}
|
]}
|
||||||
onchange=self.update_props(|props, intent| ExampleProps {
|
onchange={self.update_props(ctx.props(), |props, intent| ExampleProps {
|
||||||
intent,
|
intent,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,8 +2,6 @@ use yew::prelude::*;
|
||||||
use yewprint::{Label, Radio, RadioGroup};
|
use yewprint::{Label, Radio, RadioGroup};
|
||||||
|
|
||||||
pub struct Example {
|
pub struct Example {
|
||||||
props: ExampleProps,
|
|
||||||
link: ComponentLink<Self>,
|
|
||||||
selected_value: Lunch,
|
selected_value: Lunch,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,15 +20,13 @@ impl Component for Example {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = ExampleProps;
|
type Properties = ExampleProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Example {
|
Example {
|
||||||
props,
|
|
||||||
selected_value: Lunch::Salad,
|
selected_value: Lunch::Salad,
|
||||||
link,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::ValueUpdate(value) => {
|
Msg::ValueUpdate(value) => {
|
||||||
self.selected_value = value;
|
self.selected_value = value;
|
||||||
|
@ -39,51 +35,42 @@ impl Component for Example {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
<Radio
|
<Radio
|
||||||
label=html!("Blue pill")
|
label={html!("Blue pill")}
|
||||||
inline=self.props.inline
|
inline={ctx.props().inline}
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
name="group".to_string()
|
name={"group".to_string()}
|
||||||
/>
|
/>
|
||||||
<Radio
|
<Radio
|
||||||
label=html!("Red pill")
|
label={html!("Red pill")}
|
||||||
inline=self.props.inline
|
inline={ctx.props().inline}
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
name="group".to_string()
|
name={"group".to_string()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<RadioGroup<Lunch>
|
<RadioGroup<Lunch>
|
||||||
label=Some(html!(
|
label={Some(html!(
|
||||||
<Label>
|
<Label>
|
||||||
{"Determine Lunch"}
|
{"Determine Lunch"}
|
||||||
</Label>
|
</Label>
|
||||||
))
|
))}
|
||||||
options=vec![
|
options={vec![
|
||||||
(Lunch::Soup, "Soup".to_string()),
|
(Lunch::Soup, "Soup".to_string()),
|
||||||
(Lunch::Salad, "Salad".to_string()),
|
(Lunch::Salad, "Salad".to_string()),
|
||||||
(Lunch::Sandwich, "Sandwich".to_string()),
|
(Lunch::Sandwich, "Sandwich".to_string()),
|
||||||
]
|
]}
|
||||||
value=self.selected_value
|
value={self.selected_value}
|
||||||
onchange=self.link.callback(|v| Msg::ValueUpdate(v))
|
onchange={ctx.link().callback(|v| Msg::ValueUpdate(v))}
|
||||||
inline=self.props.inline
|
inline={ctx.props().inline}
|
||||||
disabled=self.props.disabled
|
disabled={ctx.props().disabled}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for RadioDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
RadioDoc {
|
RadioDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
inline: false,
|
inline: false,
|
||||||
|
@ -25,16 +25,12 @@ impl Component for RadioDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -43,18 +39,18 @@ impl Component for RadioDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Radio"}</H1>
|
<H1 class={classes!("docs-title")}>{"Radio"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<RadioProps
|
<RadioProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -63,33 +59,33 @@ impl Component for RadioDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
RadioProps for ExampleProps =>
|
RadioProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
disabled: !props.disabled,
|
disabled: !props.disabled,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.disabled
|
checked={ctx.props().example_props.disabled}
|
||||||
label=html!("Disabled")
|
label={html!("Disabled")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
inline: !props.inline,
|
inline: !props.inline,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.inline
|
checked={ctx.props().example_props.inline}
|
||||||
label=html!("Inline")
|
label={html!("Inline")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
large: !props.large,
|
large: !props.large,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.large
|
checked={ctx.props().example_props.large}
|
||||||
label=html!("Large")
|
label={html!("Large")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,9 @@ use yew::prelude::*;
|
||||||
use yewprint::{Intent, Slider, Tag};
|
use yewprint::{Intent, Slider, Tag};
|
||||||
|
|
||||||
pub struct Example {
|
pub struct Example {
|
||||||
props: ExampleProps,
|
|
||||||
float: f64,
|
float: f64,
|
||||||
integer: i32,
|
integer: i32,
|
||||||
log_level: Option<LogLevel>,
|
log_level: Option<LogLevel>,
|
||||||
link: ComponentLink<Self>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
@ -27,17 +25,15 @@ impl Component for Example {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = ExampleProps;
|
type Properties = ExampleProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Example {
|
Example {
|
||||||
props,
|
|
||||||
float: 1.2,
|
float: 1.2,
|
||||||
integer: 30,
|
integer: 30,
|
||||||
log_level: None,
|
log_level: None,
|
||||||
link,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::FloatUpdate(value) => {
|
Msg::FloatUpdate(value) => {
|
||||||
self.float = value;
|
self.float = value;
|
||||||
|
@ -53,16 +49,7 @@ impl Component for Example {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let percentage_labels = (0..=100)
|
let percentage_labels = (0..=100)
|
||||||
.step_by(1)
|
.step_by(1)
|
||||||
.map(|x| (x, (x % 10 == 0).then(|| format!("{}%", x).into())))
|
.map(|x| (x, (x % 10 == 0).then(|| format!("{}%", x).into())))
|
||||||
|
@ -74,8 +61,8 @@ impl Component for Example {
|
||||||
style="display: flex; align-items: flex-start; width: 100%"
|
style="display: flex; align-items: flex-start; width: 100%"
|
||||||
>
|
>
|
||||||
<Slider<f64>
|
<Slider<f64>
|
||||||
selected=self.float
|
selected={self.float}
|
||||||
values=vec![
|
values={vec![
|
||||||
(0.0, Some("0".into())),
|
(0.0, Some("0".into())),
|
||||||
(0.1, None),
|
(0.1, None),
|
||||||
(0.2, None),
|
(0.2, None),
|
||||||
|
@ -87,43 +74,43 @@ impl Component for Example {
|
||||||
(0.8, None),
|
(0.8, None),
|
||||||
(0.9, None),
|
(0.9, None),
|
||||||
(1.0, Some("1".into())),
|
(1.0, Some("1".into())),
|
||||||
]
|
]}
|
||||||
intent=self.props.intent
|
intent={ctx.props().intent}
|
||||||
onchange=self.link.callback(|x| Msg::FloatUpdate(x))
|
onchange={ctx.link().callback(|x| Msg::FloatUpdate(x))}
|
||||||
/>
|
/>
|
||||||
<Tag
|
<Tag
|
||||||
style=Cow::Borrowed("width: 32px; margin-left: 16px")
|
style={"width: 32px; margin-left: 16px"}
|
||||||
minimal=true
|
minimal=true
|
||||||
intent=self.props.intent
|
intent={ctx.props().intent}
|
||||||
>
|
>
|
||||||
{format!("{:.1}", self.float)}
|
{format!("{:.1}", self.float)}
|
||||||
</Tag>
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
<Slider<i32>
|
<Slider<i32>
|
||||||
values=percentage_labels
|
values={percentage_labels}
|
||||||
selected=self.integer
|
selected={self.integer}
|
||||||
intent=self.props.intent
|
intent={ctx.props().intent}
|
||||||
value_label=Cow::Owned(format!("{}%", self.integer))
|
value_label={Cow::Owned(format!("{}%", self.integer))}
|
||||||
onchange=self.link.callback(|x| Msg::IntegerUpdate(x))
|
onchange={ctx.link().callback(|x| Msg::IntegerUpdate(x))}
|
||||||
/>
|
/>
|
||||||
<Slider<LogLevel>
|
<Slider<LogLevel>
|
||||||
values=vec![
|
values={vec![
|
||||||
(LogLevel::Off, Some("OFF".into())),
|
(LogLevel::Off, Some("OFF".into())),
|
||||||
(LogLevel::Error, Some("ERROR".into())),
|
(LogLevel::Error, Some("ERROR".into())),
|
||||||
(LogLevel::Warn, Some("WARN".into())),
|
(LogLevel::Warn, Some("WARN".into())),
|
||||||
(LogLevel::Info, Some("INFO".into())),
|
(LogLevel::Info, Some("INFO".into())),
|
||||||
(LogLevel::Debug, Some("DEBUG".into())),
|
(LogLevel::Debug, Some("DEBUG".into())),
|
||||||
(LogLevel::Trace, Some("TRACE".into())),
|
(LogLevel::Trace, Some("TRACE".into())),
|
||||||
]
|
]}
|
||||||
intent=self.props.intent
|
intent={ctx.props().intent}
|
||||||
selected=self.log_level.clone()
|
selected={self.log_level.clone()}
|
||||||
onchange=self.link.callback(|x| Msg::LogLevelUpdate(x))
|
onchange={ctx.link().callback(|x| Msg::LogLevelUpdate(x))}
|
||||||
/>
|
/>
|
||||||
<Slider<()>
|
<Slider<()>
|
||||||
values=vec![((), Some("Neo".into()))]
|
values={vec![((), Some("Neo".into()))]}
|
||||||
intent=self.props.intent
|
intent={ctx.props().intent}
|
||||||
selected=()
|
selected={()}
|
||||||
onchange=self.link.callback(|_| Msg::Noop)
|
onchange={ctx.link().callback(|_| Msg::Noop)}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for SliderDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
SliderDoc {
|
SliderDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
vertical: false,
|
vertical: false,
|
||||||
intent: None,
|
intent: None,
|
||||||
|
@ -24,16 +24,12 @@ impl Component for SliderDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -42,21 +38,21 @@ impl Component for SliderDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Slider"}</H1>
|
<H1 class={classes!("docs-title")}>{"Slider"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<SliderProps
|
<SliderProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
<H2>{"Edge Cases"}</H2>
|
<H2>{"Edge Cases"}</H2>
|
||||||
<div class=classes!("bp3-running-text")>
|
<div class={classes!("bp3-running-text")}>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<p>
|
<p>
|
||||||
|
@ -108,17 +104,17 @@ impl Component for SliderDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
SliderProps for ExampleProps =>
|
SliderProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
vertical: !props.vertical,
|
vertical: !props.vertical,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.vertical
|
checked={ctx.props().example_props.vertical}
|
||||||
label=html!("Vertical")
|
label={html!("Vertical")}
|
||||||
disabled=true
|
disabled=true
|
||||||
/>
|
/>
|
||||||
<p>{"Select intent:"}</p>
|
<p>{"Select intent:"}</p>
|
||||||
|
@ -130,10 +126,10 @@ crate::build_example_prop_component! {
|
||||||
(Some(Intent::Warning), "Warning".to_string()),
|
(Some(Intent::Warning), "Warning".to_string()),
|
||||||
(Some(Intent::Danger), "Danger".to_string()),
|
(Some(Intent::Danger), "Danger".to_string()),
|
||||||
]}
|
]}
|
||||||
onchange=self.update_props(|props, intent| ExampleProps {
|
onchange={self.update_props(ctx.props(), |props, intent| ExampleProps {
|
||||||
intent,
|
intent,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,20 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Intent, Spinner};
|
use yewprint::{Intent, Spinner};
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
props: ExampleProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ExampleProps {
|
pub struct ExampleProps {
|
||||||
pub intent: Option<Intent>,
|
pub intent: Option<Intent>,
|
||||||
pub size: u32,
|
pub size: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Example {
|
#[function_component(Example)]
|
||||||
type Message = ();
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
type Properties = ExampleProps;
|
html! {
|
||||||
|
<div>
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
<Spinner
|
||||||
Example { props }
|
size={props.size as f32}
|
||||||
}
|
intent={props.intent}
|
||||||
|
/>
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
</div>
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<div>
|
|
||||||
<Spinner
|
|
||||||
size=self.props.size as f32
|
|
||||||
intent=self.props.intent
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for SpinnerDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
SpinnerDoc {
|
SpinnerDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
intent: None,
|
intent: None,
|
||||||
size: 50,
|
size: 50,
|
||||||
|
@ -24,16 +24,12 @@ impl Component for SpinnerDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -42,19 +38,19 @@ impl Component for SpinnerDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Spinner"}</H1>
|
<H1 class={classes!("docs-title")}>{"Spinner"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<div>
|
<div>
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<SpinnerProps
|
<SpinnerProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -64,7 +60,7 @@ impl Component for SpinnerDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
SpinnerProps for ExampleProps =>
|
SpinnerProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
|
@ -78,10 +74,10 @@ crate::build_example_prop_component! {
|
||||||
(Some(Intent::Warning), "Warning".to_string()),
|
(Some(Intent::Warning), "Warning".to_string()),
|
||||||
(Some(Intent::Danger), "Danger".to_string()),
|
(Some(Intent::Danger), "Danger".to_string()),
|
||||||
]}
|
]}
|
||||||
onchange=self.update_props(|props, intent| ExampleProps {
|
onchange={self.update_props(ctx.props(), |props, intent| ExampleProps {
|
||||||
intent,
|
intent,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
/>
|
/>
|
||||||
<p
|
<p
|
||||||
style="margin-top: 5px;"
|
style="margin-top: 5px;"
|
||||||
|
@ -89,7 +85,7 @@ crate::build_example_prop_component! {
|
||||||
{"Select Size:"}
|
{"Select Size:"}
|
||||||
</p>
|
</p>
|
||||||
<Slider<u32>
|
<Slider<u32>
|
||||||
selected=self.props.size
|
selected={ctx.props().example_props.size}
|
||||||
values={vec![
|
values={vec![
|
||||||
(10, Some("10".into())),
|
(10, Some("10".into())),
|
||||||
(20, None),
|
(20, None),
|
||||||
|
@ -102,10 +98,10 @@ crate::build_example_prop_component! {
|
||||||
(90, None),
|
(90, None),
|
||||||
(100, Some("100".into())),
|
(100, Some("100".into())),
|
||||||
]}
|
]}
|
||||||
onchange=self.update_props(|props, size| ExampleProps {
|
onchange={self.update_props(ctx.props(), |props, size| ExampleProps {
|
||||||
size,
|
size,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Label, Switch};
|
use yewprint::{Label, Switch};
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
props: ExampleProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ExampleProps {
|
pub struct ExampleProps {
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
|
@ -13,63 +9,41 @@ pub struct ExampleProps {
|
||||||
pub align_right: bool,
|
pub align_right: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Example {
|
#[function_component(Example)]
|
||||||
type Message = ();
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
type Properties = ExampleProps;
|
html! {
|
||||||
|
<div>
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
<Label>{"Privacy settings"}</Label>
|
||||||
Example { props }
|
<Switch
|
||||||
}
|
disabled={props.disabled}
|
||||||
|
inline={props.inline}
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
large={props.large}
|
||||||
true
|
align_right={props.align_right}
|
||||||
}
|
label={html!("Enabled")}
|
||||||
|
/>
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
<Switch
|
||||||
if self.props != props {
|
disabled={props.disabled}
|
||||||
self.props = props;
|
inline={props.inline}
|
||||||
true
|
large={props.large}
|
||||||
} else {
|
align_right={props.align_right}
|
||||||
false
|
label={html!(<em>{"Public"}</em>)}
|
||||||
}
|
/>
|
||||||
}
|
<Switch
|
||||||
|
disabled={props.disabled}
|
||||||
fn view(&self) -> Html {
|
inline={props.inline}
|
||||||
html! {
|
large={props.large}
|
||||||
<div>
|
align_right={props.align_right}
|
||||||
<Label>{"Privacy settings"}</Label>
|
label={html!(<strong>{"Cooperative"}</strong>)}
|
||||||
<Switch
|
/>
|
||||||
disabled=self.props.disabled
|
<Switch
|
||||||
inline=self.props.inline
|
disabled={props.disabled}
|
||||||
large=self.props.large
|
inline={props.inline}
|
||||||
label=html!{<strong>{"Enabled"}</strong>}
|
large={props.large}
|
||||||
align_right=self.props.align_right
|
align_right={props.align_right}
|
||||||
/>
|
label={html!(<u>{"Containing Text"}</u>)}
|
||||||
<Switch
|
inner_label_checked={"on".to_string()}
|
||||||
disabled=self.props.disabled
|
inner_label={"off".to_string()}
|
||||||
inline=self.props.inline
|
/>
|
||||||
large=self.props.large
|
</div>
|
||||||
label=html!{<em>{"Public"}</em>}
|
|
||||||
align_right=self.props.align_right
|
|
||||||
/>
|
|
||||||
<Switch
|
|
||||||
disabled=self.props.disabled
|
|
||||||
inline=self.props.inline
|
|
||||||
large=self.props.large
|
|
||||||
checked=true
|
|
||||||
label=html!{<u>{"Cooperative"}</u>}
|
|
||||||
align_right=self.props.align_right
|
|
||||||
/>
|
|
||||||
<Switch
|
|
||||||
disabled=self.props.disabled
|
|
||||||
inline=self.props.inline
|
|
||||||
large=self.props.large
|
|
||||||
label=html!{"Containing Text"}
|
|
||||||
inner_label_checked={"on".to_string()}
|
|
||||||
inner_label={"off".to_string()}
|
|
||||||
align_right=self.props.align_right
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for SwitchDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
SwitchDoc {
|
SwitchDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
inline: false,
|
inline: false,
|
||||||
|
@ -26,16 +26,12 @@ impl Component for SwitchDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -44,19 +40,19 @@ impl Component for SwitchDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Switch"}</H1>
|
<H1 class={classes!("docs-title")}>{"Switch"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<SwitchProps
|
<SwitchProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
>
|
>
|
||||||
</SwitchProps>
|
</SwitchProps>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -65,41 +61,41 @@ impl Component for SwitchDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
SwitchProps for ExampleProps =>
|
SwitchProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
disabled: !props.disabled,
|
disabled: !props.disabled,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.disabled
|
checked={ctx.props().example_props.disabled}
|
||||||
label=html!("Disabled")
|
label={html!("Disabled")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
inline: !props.inline,
|
inline: !props.inline,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.inline
|
checked={ctx.props().example_props.inline}
|
||||||
label=html!("Inline")
|
label={html!("Inline")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
large: !props.large,
|
large: !props.large,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.large
|
checked={ctx.props().example_props.large}
|
||||||
label=html!("Large")
|
label={html!("Large")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
align_right: !props.align_right,
|
align_right: !props.align_right,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.align_right
|
checked={ctx.props().example_props.align_right}
|
||||||
label=html!("Align right")
|
label={html!("Align right")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@ use yew::prelude::*;
|
||||||
use yewprint::{Tab, Tabs};
|
use yewprint::{Tab, Tabs};
|
||||||
|
|
||||||
pub struct Example {
|
pub struct Example {
|
||||||
link: ComponentLink<Self>,
|
|
||||||
props: ExampleProps,
|
|
||||||
selected: Civilization,
|
selected: Civilization,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,15 +15,13 @@ impl Component for Example {
|
||||||
type Message = Civilization;
|
type Message = Civilization;
|
||||||
type Properties = ExampleProps;
|
type Properties = ExampleProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Example {
|
Example {
|
||||||
link,
|
|
||||||
props,
|
|
||||||
selected: Civilization::Minoan,
|
selected: Civilization::Minoan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
if self.selected != msg {
|
if self.selected != msg {
|
||||||
self.selected = msg;
|
self.selected = msg;
|
||||||
true
|
true
|
||||||
|
@ -34,25 +30,16 @@ impl Component for Example {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<Tabs<Civilization>
|
<Tabs<Civilization>
|
||||||
id="civilizations"
|
id="civilizations"
|
||||||
animate=self.props.animate
|
animate={ctx.props().animate}
|
||||||
vertical=self.props.vertical
|
vertical={ctx.props().vertical}
|
||||||
selected_tab_id=self.selected
|
selected_tab_id={self.selected}
|
||||||
onchange=self.link.callback(|x| x)
|
onchange={ctx.link().callback(|x| x)}
|
||||||
tabs=vec![
|
tabs={vec![
|
||||||
Tab {
|
Tab {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
id: Civilization::Sumer,
|
id: Civilization::Sumer,
|
||||||
|
@ -133,7 +120,7 @@ impl Component for Example {
|
||||||
panel_class: Classes::default(),
|
panel_class: Classes::default(),
|
||||||
title_class: Classes::default(),
|
title_class: Classes::default(),
|
||||||
},
|
},
|
||||||
]
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for TabsDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
TabsDoc {
|
TabsDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
animate: true,
|
animate: true,
|
||||||
vertical: false,
|
vertical: false,
|
||||||
|
@ -24,16 +24,12 @@ impl Component for TabsDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -42,19 +38,19 @@ impl Component for TabsDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Tabs"}</H1>
|
<H1 class={classes!("docs-title")}>{"Tabs"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<div>
|
<div>
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<TabsProps
|
<TabsProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -64,25 +60,25 @@ impl Component for TabsDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
TabsProps for ExampleProps =>
|
TabsProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
animate: !props.animate,
|
animate: !props.animate,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.animate
|
checked={ctx.props().example_props.animate}
|
||||||
label=html!("Animate indicator")
|
label={html!("Animate indicator")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
vertical: !props.vertical,
|
vertical: !props.vertical,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.vertical
|
checked={ctx.props().example_props.vertical}
|
||||||
label=html!("Use vertical tabs")
|
label={html!("Use vertical tabs")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@ use yew::prelude::*;
|
||||||
use yewprint::{IconName, Intent, Tag};
|
use yewprint::{IconName, Intent, Tag};
|
||||||
|
|
||||||
pub struct Example {
|
pub struct Example {
|
||||||
props: ExampleProps,
|
|
||||||
link: ComponentLink<Self>,
|
|
||||||
tags: Vec<String>,
|
tags: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,12 +31,12 @@ impl Component for Example {
|
||||||
type Message = ExampleMsg;
|
type Message = ExampleMsg;
|
||||||
type Properties = ExampleProps;
|
type Properties = ExampleProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
let tags = props.initial_tags.clone();
|
let tags = ctx.props().initial_tags.clone();
|
||||||
Example { props, link, tags }
|
Example { tags }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
ExampleMsg::Remove(label) => {
|
ExampleMsg::Remove(label) => {
|
||||||
self.tags = self
|
self.tags = self
|
||||||
|
@ -53,43 +51,38 @@ impl Component for Example {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
fn changed(&mut self, ctx: &Context<Self>) -> bool {
|
||||||
if self.props != props {
|
if ctx.props().reset_tags != ctx.props().reset_tags {
|
||||||
if self.props.reset_tags != props.reset_tags {
|
self.tags = ctx.props().initial_tags.clone();
|
||||||
self.tags = props.initial_tags.clone();
|
|
||||||
}
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
self.tags
|
self.tags
|
||||||
.iter()
|
.iter()
|
||||||
.map(|label| {
|
.map(|label| {
|
||||||
let remove = {
|
let remove = {
|
||||||
let label = label.clone();
|
let label = label.clone();
|
||||||
self.props.removable.then(|| {
|
ctx.props().removable.then(|| {
|
||||||
self.link
|
ctx.link()
|
||||||
.callback(move |_| ExampleMsg::Remove(label.clone()))
|
.callback(move |_| ExampleMsg::Remove(label.clone()))
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
html! {
|
html! {
|
||||||
<Tag
|
<Tag
|
||||||
active=self.props.active
|
active={ctx.props().active}
|
||||||
fill=self.props.fill
|
fill={ctx.props().fill}
|
||||||
icon=self.props.icon.then(|| IconName::Print)
|
icon={ctx.props().icon.then(|| IconName::Print)}
|
||||||
intent=self.props.intent
|
intent={ctx.props().intent}
|
||||||
interactive=self.props.interactive
|
interactive={ctx.props().interactive}
|
||||||
large=self.props.large
|
large={ctx.props().large}
|
||||||
minimal=self.props.minimal
|
minimal={ctx.props().minimal}
|
||||||
multiline=self.props.multiline
|
multiline={ctx.props().multiline}
|
||||||
right_icon=self.props.right_icon.then(|| IconName::Star)
|
right_icon={ctx.props().right_icon.then(|| IconName::Star)}
|
||||||
round=self.props.round
|
round={ctx.props().round}
|
||||||
onremove=remove
|
onremove={remove}
|
||||||
onclick=self.link.callback(|_| ExampleMsg::Click)
|
onclick={ctx.link().callback(|_| ExampleMsg::Click)}
|
||||||
>
|
>
|
||||||
{label.clone()}
|
{label.clone()}
|
||||||
</Tag>
|
</Tag>
|
||||||
|
|
|
@ -28,9 +28,9 @@ impl Component for TagDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
TagDoc {
|
TagDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
initial_tags: initial_tags(),
|
initial_tags: initial_tags(),
|
||||||
active: false,
|
active: false,
|
||||||
|
@ -49,16 +49,12 @@ impl Component for TagDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -67,18 +63,18 @@ impl Component for TagDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Tag"}</H1>
|
<H1 class={classes!("docs-title")}>{"Tag"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html!{
|
props={Some(html!{
|
||||||
<TagProps
|
<TagProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props/>
|
<Example ..example_props/>
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -87,90 +83,92 @@ impl Component for TagDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
TagProps for ExampleProps =>
|
TagProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
let props = ctx.props();
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<div>
|
<div>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
active: !props.active,
|
active: !props.active,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.active
|
checked={props.example_props.active}
|
||||||
label=html!("Active")
|
label={html!("Active")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
fill: !props.fill,
|
fill: !props.fill,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.fill
|
checked={props.example_props.fill}
|
||||||
label=html!("Fill")
|
label={html!("Fill")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
interactive: !props.interactive,
|
interactive: !props.interactive,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.interactive
|
checked={props.example_props.interactive}
|
||||||
label=html!("Interactive")
|
label={html!("Interactive")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
large: !props.large,
|
large: !props.large,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.large
|
checked={props.example_props.large}
|
||||||
label=html!("Large")
|
label={html!("Large")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
minimal: !props.minimal,
|
minimal: !props.minimal,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.minimal
|
checked={props.example_props.minimal}
|
||||||
label=html!("Minimal")
|
label={html!("Minimal")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
multiline: !props.multiline,
|
multiline: !props.multiline,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.multiline
|
checked={props.example_props.multiline}
|
||||||
label=html!("Multiline")
|
label={html!("Multiline")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
round: !props.round,
|
round: !props.round,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.round
|
checked={props.example_props.round}
|
||||||
label=html!("Round")
|
label={html!("Round")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
removable: !props.removable,
|
removable: !props.removable,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.removable
|
checked={props.example_props.removable}
|
||||||
label=html!("Removable")
|
label={html!("Removable")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
icon: !props.icon,
|
icon: !props.icon,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.icon
|
checked={props.example_props.icon}
|
||||||
label=html!("Icon")
|
label={html!("Icon")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
right_icon: !props.right_icon,
|
right_icon: !props.right_icon,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.right_icon
|
checked={props.example_props.right_icon}
|
||||||
label=html!("Right icon")
|
label={html!("Right icon")}
|
||||||
/>
|
/>
|
||||||
<p>{"Select intent:"}</p>
|
<p>{"Select intent:"}</p>
|
||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
|
@ -184,17 +182,17 @@ crate::build_example_prop_component! {
|
||||||
(Some(Intent::Warning), "Warning".to_string()),
|
(Some(Intent::Warning), "Warning".to_string()),
|
||||||
(Some(Intent::Danger), "Danger".to_string()),
|
(Some(Intent::Danger), "Danger".to_string()),
|
||||||
]}
|
]}
|
||||||
onchange=self.update_props(|props, intent| ExampleProps {
|
onchange={self.update_props(props, |props, intent| ExampleProps {
|
||||||
intent,
|
intent,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
icon=IconName::Refresh
|
icon={IconName::Refresh}
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||||
reset_tags: props.reset_tags + 1,
|
reset_tags: props.reset_tags + 1,
|
||||||
..props
|
..props.clone()
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
{"Reset tags"}
|
{"Reset tags"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -1,44 +1,19 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::Text;
|
use yewprint::Text;
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
props: ExampleProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ExampleProps {
|
pub struct ExampleProps {
|
||||||
pub ellipsize: bool,
|
pub ellipsize: bool,
|
||||||
pub text: String,
|
pub text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Example {
|
#[function_component(Example)]
|
||||||
type Message = ();
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
type Properties = ExampleProps;
|
html! {
|
||||||
|
<div style="width: 150px; height: 20px">
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
<Text ellipsize={props.ellipsize}>
|
||||||
Example { props }
|
{&props.text}
|
||||||
}
|
</Text>
|
||||||
|
</div>
|
||||||
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! {
|
|
||||||
<div style="width: 150px; height: 20px">
|
|
||||||
<Text ellipsize=self.props.ellipsize>
|
|
||||||
{&self.props.text}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ mod example;
|
||||||
|
|
||||||
use crate::ExampleContainer;
|
use crate::ExampleContainer;
|
||||||
use example::*;
|
use example::*;
|
||||||
|
use web_sys::HtmlInputElement;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Switch, H1, H5};
|
use yewprint::{Switch, H1, H5};
|
||||||
|
|
||||||
|
@ -14,9 +15,9 @@ impl Component for TextDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
TextDoc {
|
TextDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
ellipsize: false,
|
ellipsize: false,
|
||||||
text: String::from("Hello, world!"),
|
text: String::from("Hello, world!"),
|
||||||
|
@ -24,16 +25,12 @@ impl Component for TextDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -42,19 +39,19 @@ impl Component for TextDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Text"}</H1>
|
<H1 class={classes!("docs-title")}>{"Text"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<div>
|
<div>
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<TextProps
|
<TextProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -64,37 +61,36 @@ impl Component for TextDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
TextProps for ExampleProps =>
|
TextProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
ellipsize: !props.ellipsize,
|
ellipsize: !props.ellipsize,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.ellipsize
|
checked={ctx.props().example_props.ellipsize}
|
||||||
label=html!("Ellipsize")
|
label={html!("Ellipsize")}
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
class="bp3-input"
|
class="bp3-input"
|
||||||
onchange=self.update_props(|props, e|
|
onchange={self.update_props(ctx.props(), |props, e: Event| {
|
||||||
match e {
|
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
||||||
ChangeData::Value(text) => {
|
|
||||||
ExampleProps {
|
ExampleProps {
|
||||||
text,
|
text: input.value(),
|
||||||
..props
|
..props
|
||||||
}
|
}
|
||||||
},
|
} else {
|
||||||
_ => {
|
|
||||||
ExampleProps {
|
ExampleProps {
|
||||||
text: "Hello, world!".to_string(),
|
text: "Hello, world!".to_string(),
|
||||||
..props
|
..props
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)}
|
||||||
type="text"
|
type="text"
|
||||||
value={self.props.text.clone()}
|
value={ctx.props().example_props.text.clone()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{Intent, TextArea};
|
use yewprint::{Intent, TextArea};
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
props: ExampleProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct ExampleProps {
|
pub struct ExampleProps {
|
||||||
pub intent: Option<Intent>,
|
pub intent: Option<Intent>,
|
||||||
|
@ -13,36 +9,15 @@ pub struct ExampleProps {
|
||||||
pub fill: bool,
|
pub fill: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Example {
|
#[function_component(Example)]
|
||||||
type Message = ();
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
type Properties = ExampleProps;
|
html! {
|
||||||
|
<div style="width: 200px; height: 50px">
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
<TextArea intent={props.intent}
|
||||||
Example { props }
|
large={props.large}
|
||||||
}
|
fill={props.fill}
|
||||||
|
small={props.small}
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
/>
|
||||||
true
|
</div>
|
||||||
}
|
|
||||||
|
|
||||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
|
||||||
if self.props != props {
|
|
||||||
self.props = props;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<div style="width: 200px; height: 50px">
|
|
||||||
<TextArea intent=self.props.intent
|
|
||||||
large=self.props.large
|
|
||||||
fill=self.props.fill
|
|
||||||
small=self.props.small
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ impl Component for TextAreaDoc {
|
||||||
type Message = ExampleProps;
|
type Message = ExampleProps;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
TextAreaDoc {
|
TextAreaDoc {
|
||||||
callback: link.callback(|x| x),
|
callback: ctx.link().callback(|x| x),
|
||||||
state: ExampleProps {
|
state: ExampleProps {
|
||||||
intent: None,
|
intent: None,
|
||||||
large: false,
|
large: false,
|
||||||
|
@ -26,16 +26,12 @@ impl Component for TextAreaDoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
self.state = msg;
|
self.state = msg;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let example_props = self.state.clone();
|
let example_props = self.state.clone();
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
@ -44,19 +40,19 @@ impl Component for TextAreaDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Text"}</H1>
|
<H1 class={classes!("docs-title")}>{"Text"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<div>
|
<div>
|
||||||
<ExampleContainer
|
<ExampleContainer
|
||||||
source=source
|
source={source}
|
||||||
props=Some(html! {
|
props={Some(html! {
|
||||||
<TextAreaProps
|
<TextAreaProps
|
||||||
callback={self.callback.clone()}
|
callback={self.callback.clone()}
|
||||||
props=example_props.clone()
|
example_props={example_props.clone()}
|
||||||
/>
|
/>
|
||||||
})
|
})}
|
||||||
>
|
>
|
||||||
<Example with example_props />
|
<Example ..example_props />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -66,33 +62,33 @@ impl Component for TextAreaDoc {
|
||||||
|
|
||||||
crate::build_example_prop_component! {
|
crate::build_example_prop_component! {
|
||||||
TextAreaProps for ExampleProps =>
|
TextAreaProps for ExampleProps =>
|
||||||
fn view(&self) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H5>{"Props"}</H5>
|
<H5>{"Props"}</H5>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
fill: !props.fill,
|
fill: !props.fill,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.fill
|
checked={ctx.props().example_props.fill}
|
||||||
label=html!("Fill")
|
label={html!("Fill")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
large: !props.large,
|
large: !props.large,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.large
|
checked={ctx.props().example_props.large}
|
||||||
label=html!("Large")
|
label={html!("Large")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
onclick=self.update_props(|props, _| ExampleProps {
|
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||||
small: !props.small,
|
small: !props.small,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
checked=self.props.small
|
checked={ctx.props().example_props.small}
|
||||||
label=html!("Small")
|
label={html!("Small")}
|
||||||
/>
|
/>
|
||||||
<HtmlSelect<Option<Intent>>
|
<HtmlSelect<Option<Intent>>
|
||||||
options={vec![
|
options={vec![
|
||||||
|
@ -102,10 +98,10 @@ crate::build_example_prop_component! {
|
||||||
(Some(Intent::Warning), "Warning".to_string()),
|
(Some(Intent::Warning), "Warning".to_string()),
|
||||||
(Some(Intent::Danger), "Danger".to_string()),
|
(Some(Intent::Danger), "Danger".to_string()),
|
||||||
]}
|
]}
|
||||||
onchange=self.update_props(|props, intent| ExampleProps {
|
onchange={self.update_props(ctx.props(), |props, intent| ExampleProps {
|
||||||
intent,
|
intent,
|
||||||
..props
|
..props
|
||||||
})
|
})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ impl Component for Example {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
let mut tree = TreeBuilder::new().build();
|
let mut tree = TreeBuilder::new().build();
|
||||||
let root_id = tree
|
let root_id = tree
|
||||||
.insert(
|
.insert(
|
||||||
|
@ -71,7 +71,7 @@ impl Component for Example {
|
||||||
icon: Some(IconName::Tag),
|
icon: Some(IconName::Tag),
|
||||||
icon_intent: Some(Intent::Primary),
|
icon_intent: Some(Intent::Primary),
|
||||||
label: "Outer file".into(),
|
label: "Outer file".into(),
|
||||||
secondary_label: Some(html!(<Icon icon=IconName::EyeOpen />)),
|
secondary_label: Some(html!(<Icon icon={IconName::EyeOpen} />)),
|
||||||
data: 3,
|
data: 3,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
|
@ -81,12 +81,12 @@ impl Component for Example {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
tree: tree.into(),
|
tree: tree.into(),
|
||||||
callback_expand_node: link.callback(|(node_id, _)| Msg::ExpandNode(node_id)),
|
callback_expand_node: ctx.link().callback(|(node_id, _)| Msg::ExpandNode(node_id)),
|
||||||
callback_select_node: link.callback(|(node_id, _)| Msg::SelectNode(node_id)),
|
callback_select_node: ctx.link().callback(|(node_id, _)| Msg::SelectNode(node_id)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::ExpandNode(node_id) => {
|
Msg::ExpandNode(node_id) => {
|
||||||
let mut tree = self.tree.borrow_mut();
|
let mut tree = self.tree.borrow_mut();
|
||||||
|
@ -109,17 +109,13 @@ impl Component for Example {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
html! {
|
html! {
|
||||||
<Tree<i32>
|
<Tree<i32>
|
||||||
tree=self.tree.clone()
|
tree={self.tree.clone()}
|
||||||
on_collapse=Some(self.callback_expand_node.clone())
|
on_collapse={Some(self.callback_expand_node.clone())}
|
||||||
on_expand=Some(self.callback_expand_node.clone())
|
on_expand={Some(self.callback_expand_node.clone())}
|
||||||
onclick=Some(self.callback_select_node.clone())
|
onclick={Some(self.callback_select_node.clone())}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,19 +11,15 @@ impl Component for TreeDoc {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
TreeDoc
|
TreeDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let source = crate::include_raw_html!(
|
let source = crate::include_raw_html!(
|
||||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
"bp3-code-block"
|
"bp3-code-block"
|
||||||
|
@ -31,9 +27,9 @@ impl Component for TreeDoc {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<H1 class=classes!("docs-title")>{"Tree"}</H1>
|
<H1 class={classes!("docs-title")}>{"Tree"}</H1>
|
||||||
<SourceCodeUrl />
|
<SourceCodeUrl />
|
||||||
<ExampleContainer source=source>
|
<ExampleContainer source={source}>
|
||||||
<Example />
|
<Example />
|
||||||
</ExampleContainer>
|
</ExampleContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue