mirror of
https://github.com/yewprint/yewprint
synced 2024-11-25 04:50:20 +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"]
|
||||
|
||||
[dependencies]
|
||||
web-sys = { version = "0.3", features = ["DomRect", "Element"] }
|
||||
yew = "0.18"
|
||||
web-sys = { version = "0.3", features = ["DomRect", "Element", "Event", "HtmlSelectElement"] }
|
||||
# yew = { git = "https://github.com/yewstack/yew", branch = "master" }
|
||||
yew = "0.19"
|
||||
id_tree = { version = "1.7", optional = true }
|
||||
yewtil = { version = "0.4", features = ["pure"] }
|
||||
wasm-bindgen = "0.2"
|
||||
gloo = "0.6"
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
regex = { version = "1", default-features = false, features = ["std", "unicode-perl"] }
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct ButtonGroup {
|
||||
props: ButtonGroupProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ButtonGroupProps {
|
||||
#[prop_or_default]
|
||||
|
@ -16,49 +11,28 @@ pub struct ButtonGroupProps {
|
|||
#[prop_or_default]
|
||||
pub large: bool,
|
||||
#[prop_or_default]
|
||||
pub style: Option<Cow<'static, str>>,
|
||||
pub style: Option<String>,
|
||||
#[prop_or_default]
|
||||
pub children: html::Children,
|
||||
#[prop_or_default]
|
||||
pub class: Classes,
|
||||
}
|
||||
|
||||
impl Component for ButtonGroup {
|
||||
type Message = ();
|
||||
type Properties = ButtonGroupProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self { props }
|
||||
}
|
||||
|
||||
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! {
|
||||
<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>
|
||||
}
|
||||
#[function_component(ButtonGroup)]
|
||||
pub fn button_group(props: &ButtonGroupProps) -> Html {
|
||||
html! {
|
||||
<div
|
||||
class={classes!(
|
||||
"bp3-button-group",
|
||||
props.minimal.then(|| "bp3-minimal"),
|
||||
props.fill.then(|| "bp3-fill"),
|
||||
props.large.then(|| "bp3-large"),
|
||||
props.vertical.then(|| "bp3-vertical"),
|
||||
props.class.clone(),
|
||||
)}
|
||||
style={props.style.clone()}
|
||||
>
|
||||
{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 std::borrow::Cow;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct Button {
|
||||
props: ButtonProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ButtonProps {
|
||||
#[prop_or_default]
|
||||
|
@ -35,84 +30,62 @@ pub struct ButtonProps {
|
|||
#[prop_or_default]
|
||||
pub class: Classes,
|
||||
#[prop_or_default]
|
||||
pub style: Option<Cow<'static, str>>,
|
||||
pub style: Option<String>,
|
||||
#[prop_or_default]
|
||||
pub children: html::Children,
|
||||
}
|
||||
|
||||
impl Component for Button {
|
||||
type Message = ();
|
||||
type Properties = ButtonProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Button { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<button
|
||||
class=classes!(
|
||||
"bp3-button",
|
||||
self.props.fill.then(|| "bp3-fill"),
|
||||
self.props.minimal.then(|| "bp3-minimal"),
|
||||
self.props.small.then(|| "bp3-small"),
|
||||
self.props.outlined.then(|| "bp3-outlined"),
|
||||
self.props.loading.then(|| "bp3-loading"),
|
||||
self.props.large.then(|| "bp3-large"),
|
||||
(self.props.active && !self.props.disabled).then(|| "bp3-active"),
|
||||
self.props.disabled.then(|| "bp3-disabled"),
|
||||
self.props.intent,
|
||||
self.props.class.clone(),
|
||||
)
|
||||
style=self.props.style.clone()
|
||||
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()
|
||||
#[function_component(Button)]
|
||||
pub fn button(props: &ButtonProps) -> Html {
|
||||
html! {
|
||||
<button
|
||||
class={classes!(
|
||||
"bp3-button",
|
||||
props.fill.then(|| "bp3-fill"),
|
||||
props.minimal.then(|| "bp3-minimal"),
|
||||
props.small.then(|| "bp3-small"),
|
||||
props.outlined.then(|| "bp3-outlined"),
|
||||
props.loading.then(|| "bp3-loading"),
|
||||
props.large.then(|| "bp3-large"),
|
||||
(props.active && !props.disabled).then(|| "bp3-active"),
|
||||
props.disabled.then(|| "bp3-disabled"),
|
||||
props.intent,
|
||||
props.class.clone(),
|
||||
)}
|
||||
style={props.style.clone()}
|
||||
onclick={(!props.disabled).then(|| props.onclick.clone())}
|
||||
>
|
||||
{
|
||||
props
|
||||
.loading
|
||||
.then(|| html! {
|
||||
<Spinner
|
||||
class={classes!("bp3-button-spinner")}
|
||||
size={ICON_SIZE_LARGE as f32}
|
||||
/>
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
{
|
||||
if let Some(icon) = props.icon {
|
||||
html! {
|
||||
<Icon icon={icon} />
|
||||
}
|
||||
} else {
|
||||
html!()
|
||||
}
|
||||
{
|
||||
if let Some(icon) = self.props.icon {
|
||||
html! {
|
||||
<Icon icon=icon />
|
||||
}
|
||||
} else {
|
||||
html!()
|
||||
}
|
||||
{
|
||||
if props.children.is_empty() {
|
||||
html! ()
|
||||
} else {
|
||||
html! {
|
||||
<span class="bp3-button-text">
|
||||
{for props.children.iter()}
|
||||
</span>
|
||||
}
|
||||
}
|
||||
{
|
||||
if self.props.children.is_empty() {
|
||||
html! ()
|
||||
} else {
|
||||
html! {
|
||||
<span class="bp3-button-text">
|
||||
{for self.props.children.iter()}
|
||||
</span>
|
||||
}
|
||||
}
|
||||
}
|
||||
</button>
|
||||
}
|
||||
}
|
||||
</button>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
use crate::icon::ICON_SIZE_LARGE;
|
||||
use crate::{Icon, IconName, Intent};
|
||||
use std::borrow::Cow;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct Callout {
|
||||
props: CalloutProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct CalloutProps {
|
||||
#[prop_or_default]
|
||||
|
@ -18,63 +13,43 @@ pub struct CalloutProps {
|
|||
#[prop_or_default]
|
||||
pub intent: Option<Intent>,
|
||||
#[prop_or_default]
|
||||
pub title: Option<Cow<'static, str>>,
|
||||
pub title: Option<String>,
|
||||
pub children: html::Children,
|
||||
}
|
||||
|
||||
impl Component for Callout {
|
||||
type Message = ();
|
||||
type Properties = CalloutProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props == props {
|
||||
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,
|
||||
})
|
||||
#[function_component(Callout)]
|
||||
pub fn callout(props: &CalloutProps) -> Html {
|
||||
let icon = if props.without_icon {
|
||||
None
|
||||
} else {
|
||||
props.icon.or_else(|| {
|
||||
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(),
|
||||
"bp3-callout",
|
||||
icon.map(|_| "bp3-callout-icon"),
|
||||
self.props.intent,
|
||||
);
|
||||
html! {
|
||||
<div class=classes>
|
||||
{
|
||||
icon.iter()
|
||||
.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>})
|
||||
.collect::<Html>()
|
||||
}
|
||||
{ self.props.children.clone() }
|
||||
</div>
|
||||
}
|
||||
})
|
||||
};
|
||||
let classes = classes!(
|
||||
props.class.clone(),
|
||||
"bp3-callout",
|
||||
icon.map(|_| "bp3-callout-icon"),
|
||||
props.intent,
|
||||
);
|
||||
html! {
|
||||
<div class={classes}>
|
||||
{
|
||||
icon.iter()
|
||||
.map(|name| html!{<Icon icon={*name} icon_size={ICON_SIZE_LARGE}/>})
|
||||
.collect::<Html>()
|
||||
}
|
||||
{
|
||||
props.title.iter()
|
||||
.map(|title| html!{<h4 class={"bp3-heading"}>{title}</h4>})
|
||||
.collect::<Html>()
|
||||
}
|
||||
{ props.children.clone() }
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
49
src/card.rs
49
src/card.rs
|
@ -14,42 +14,17 @@ pub struct CardProps {
|
|||
pub children: html::Children,
|
||||
}
|
||||
|
||||
pub struct Card {
|
||||
props: CardProps,
|
||||
}
|
||||
|
||||
impl Component for Card {
|
||||
type Message = ();
|
||||
type Properties = CardProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self { props }
|
||||
}
|
||||
|
||||
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>
|
||||
}
|
||||
#[function_component(Card)]
|
||||
pub fn card(props: &CardProps) -> Html {
|
||||
html! {
|
||||
<div class={classes!(
|
||||
"bp3-card",
|
||||
props.class.clone(),
|
||||
props.elevation,
|
||||
props.interactive.then(|| "bp3-interactive"),
|
||||
)}
|
||||
onclick={props.onclick.clone()}>
|
||||
{props.children.clone()}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
use yew::prelude::*;
|
||||
|
||||
pub struct Checkbox {
|
||||
props: Props,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct Props {
|
||||
pub struct CheckboxProps {
|
||||
#[prop_or_default]
|
||||
pub disabled: bool,
|
||||
#[prop_or_default]
|
||||
|
@ -15,56 +11,35 @@ pub struct Props {
|
|||
#[prop_or_default]
|
||||
pub checked: bool,
|
||||
#[prop_or_default]
|
||||
pub onchange: Callback<ChangeData>,
|
||||
pub onchange: Callback<Event>,
|
||||
#[prop_or_default]
|
||||
pub label: yew::virtual_dom::VNode,
|
||||
#[prop_or_default]
|
||||
pub indeterminate_state: bool,
|
||||
}
|
||||
|
||||
impl Component for Checkbox {
|
||||
type Message = ();
|
||||
type Properties = Props;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
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")
|
||||
)
|
||||
#[function_component(Checkbox)]
|
||||
pub fn checkbox(props: &CheckboxProps) -> Html {
|
||||
html! {
|
||||
<label
|
||||
class={classes!(
|
||||
"bp3-control", "bp3-checkbox",
|
||||
props.disabled.then(|| "bp3-disabled"),
|
||||
props.inline.then(|| "bp3-inline"),
|
||||
props.large.then(|| "bp3-large")
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={props.checked}
|
||||
onchange={props.onchange.clone()}
|
||||
disabled={props.disabled}
|
||||
/>
|
||||
<span
|
||||
class="bp3-control-indicator"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={self.props.checked}
|
||||
onchange={self.props.onchange.clone()}
|
||||
disabled=self.props.disabled
|
||||
/>
|
||||
<span
|
||||
class="bp3-control-indicator"
|
||||
>
|
||||
</span>
|
||||
{self.props.label.clone()}
|
||||
</label>
|
||||
}
|
||||
</span>
|
||||
{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 yew::prelude::*;
|
||||
use yew::services::*;
|
||||
|
||||
pub struct Collapse {
|
||||
height: Height,
|
||||
|
@ -11,10 +11,7 @@ pub struct Collapse {
|
|||
height_when_open: Option<String>,
|
||||
animation_state: AnimationState,
|
||||
contents_ref: NodeRef,
|
||||
callback_delayed_state_change: Callback<()>,
|
||||
handle_delayed_state_change: Option<Box<dyn Task>>,
|
||||
props: CollapseProps,
|
||||
link: ComponentLink<Self>,
|
||||
handle_delayed_state_change: Option<Timeout>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
|
@ -52,77 +49,83 @@ impl Component for Collapse {
|
|||
type Message = ();
|
||||
type Properties = CollapseProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
Collapse {
|
||||
height: if props.is_open {
|
||||
height: if ctx.props().is_open {
|
||||
Height::Auto
|
||||
} else {
|
||||
Height::Zero
|
||||
},
|
||||
overflow_visible: 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,
|
||||
animation_state: if props.is_open {
|
||||
animation_state: if ctx.props().is_open {
|
||||
AnimationState::Open
|
||||
} else {
|
||||
AnimationState::Closed
|
||||
},
|
||||
contents_ref: NodeRef::default(),
|
||||
callback_delayed_state_change: link.callback(|_| ()),
|
||||
handle_delayed_state_change: None,
|
||||
props,
|
||||
link,
|
||||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
if props.is_open {
|
||||
match self.animation_state {
|
||||
AnimationState::Open | AnimationState::Opening => {}
|
||||
_ => {
|
||||
self.animation_state = AnimationState::OpenStart;
|
||||
self.render_children = true;
|
||||
self.translated = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match self.animation_state {
|
||||
AnimationState::Closed | AnimationState::Closing => {}
|
||||
_ => {
|
||||
self.animation_state = AnimationState::ClosingStart;
|
||||
self.height = Height::Full;
|
||||
self.translated = true;
|
||||
}
|
||||
fn changed(&mut self, ctx: &Context<Self>) -> bool {
|
||||
if ctx.props().is_open {
|
||||
match self.animation_state {
|
||||
AnimationState::Open | AnimationState::Opening => {}
|
||||
_ => {
|
||||
self.animation_state = AnimationState::OpenStart;
|
||||
self.render_children = true;
|
||||
self.translated = false;
|
||||
}
|
||||
}
|
||||
|
||||
self.props = props;
|
||||
true
|
||||
} 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 {
|
||||
AnimationState::OpenStart => {
|
||||
let link = ctx.link().clone();
|
||||
self.animation_state = AnimationState::Opening;
|
||||
self.height = Height::Full;
|
||||
self.handle_delayed_state_change = Some(Box::new(TimeoutService::spawn(
|
||||
self.props.transition_duration,
|
||||
self.callback_delayed_state_change.clone(),
|
||||
)));
|
||||
self.handle_delayed_state_change = Some(Timeout::new(
|
||||
ctx.props()
|
||||
.transition_duration
|
||||
.as_millis()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
move || {
|
||||
link.send_message(());
|
||||
},
|
||||
));
|
||||
true
|
||||
}
|
||||
AnimationState::ClosingStart => {
|
||||
let link = ctx.link().clone();
|
||||
self.animation_state = AnimationState::Closing;
|
||||
self.height = Height::Zero;
|
||||
self.handle_delayed_state_change = Some(Box::new(TimeoutService::spawn(
|
||||
self.props.transition_duration,
|
||||
self.callback_delayed_state_change.clone(),
|
||||
)));
|
||||
self.handle_delayed_state_change = Some(Timeout::new(
|
||||
ctx.props()
|
||||
.transition_duration
|
||||
.as_millis()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
move || {
|
||||
link.send_message(());
|
||||
},
|
||||
));
|
||||
true
|
||||
}
|
||||
AnimationState::Opening => {
|
||||
|
@ -132,7 +135,7 @@ impl Component for Collapse {
|
|||
}
|
||||
AnimationState::Closing => {
|
||||
self.animation_state = AnimationState::Closed;
|
||||
if !self.props.keep_children_mounted {
|
||||
if !ctx.props().keep_children_mounted {
|
||||
self.render_children = false;
|
||||
}
|
||||
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 {
|
||||
let client_height = self.contents_ref.cast::<Element>().unwrap().client_height();
|
||||
self.height_when_open = Some(format!("{}px", client_height));
|
||||
}
|
||||
|
||||
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);
|
||||
match (self.height, self.height_when_open.as_ref()) {
|
||||
(Height::Zero, _) => container_style.push_str("height: 0px; "),
|
||||
|
@ -179,19 +182,19 @@ impl Component for Collapse {
|
|||
}
|
||||
|
||||
html! {
|
||||
<div class=classes!("bp3-collapse") style={container_style}>
|
||||
<div class={classes!("bp3-collapse")} style={container_style}>
|
||||
<div
|
||||
class=classes!(
|
||||
class={classes!(
|
||||
"bp3-collapse-body",
|
||||
self.props.class.clone(),
|
||||
)
|
||||
ctx.props().class.clone(),
|
||||
)}
|
||||
style={content_style}
|
||||
aria-hidden={(!self.render_children).then(|| "true")}
|
||||
ref={self.contents_ref.clone()}
|
||||
>
|
||||
{
|
||||
if self.render_children {
|
||||
self.props.children.clone()
|
||||
ctx.props().children.clone()
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
use yew::prelude::*;
|
||||
|
||||
pub struct ControlGroup {
|
||||
props: ControlGroupProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ControlGroupProps {
|
||||
#[prop_or_default]
|
||||
|
@ -18,39 +14,18 @@ pub struct ControlGroupProps {
|
|||
pub class: Classes,
|
||||
}
|
||||
|
||||
impl Component for ControlGroup {
|
||||
type Message = ();
|
||||
type Properties = ControlGroupProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self { props }
|
||||
}
|
||||
|
||||
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! {
|
||||
<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>
|
||||
}
|
||||
#[function_component(ControlGroup)]
|
||||
pub fn control_group(props: &ControlGroupProps) -> Html {
|
||||
html! {
|
||||
<div
|
||||
class={classes!(
|
||||
"bp3-control-group",
|
||||
props.fill.then(|| "bp3-fill"),
|
||||
props.vertical.then(|| "bp3-vertical"),
|
||||
props.class.clone(),
|
||||
)}
|
||||
>
|
||||
{props.children.clone()}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
use yew::prelude::*;
|
||||
|
||||
pub struct Divider {
|
||||
props: DividerProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct DividerProps {
|
||||
#[prop_or_default]
|
||||
|
@ -14,36 +10,15 @@ pub struct DividerProps {
|
|||
pub class: Classes,
|
||||
}
|
||||
|
||||
impl Component for Divider {
|
||||
type Message = ();
|
||||
type Properties = DividerProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self { props }
|
||||
}
|
||||
|
||||
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(),
|
||||
)
|
||||
/>
|
||||
}
|
||||
#[function_component(Divider)]
|
||||
pub fn view(props: &DividerProps) -> Html {
|
||||
html! {
|
||||
<span
|
||||
class={classes!(
|
||||
"bp3-divider",
|
||||
props.vertical.then(|| "bp3-vertical"),
|
||||
props.class.clone(),
|
||||
)}
|
||||
/>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +1,36 @@
|
|||
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 {
|
||||
($name:ident, $props_name:ident, $tag:tt, $class:literal) => {
|
||||
pub type $name = Pure<$props_name>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||
pub struct $props_name {
|
||||
#[prop_or_default]
|
||||
pub class: Classes,
|
||||
#[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>
|
||||
}
|
||||
($name:ident, $tag:tt, $class:literal) => {
|
||||
#[function_component($name)]
|
||||
pub fn $tag(props: &ChildrenOnlyProps) -> Html {
|
||||
html! {
|
||||
<$tag class={classes!($class, props.class.clone())}>
|
||||
{ props.children.clone() }
|
||||
</$tag>
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
build_component!(H1, H1Props, h1, "bp3-heading");
|
||||
build_component!(H2, H2Props, h2, "bp3-heading");
|
||||
build_component!(H3, H3Props, h3, "bp3-heading");
|
||||
build_component!(H4, H4Props, h4, "bp3-heading");
|
||||
build_component!(H5, H5Props, h5, "bp3-heading");
|
||||
build_component!(H6, H6Props, h6, "bp3-heading");
|
||||
build_component!(H1, h1, "bp3-heading");
|
||||
build_component!(H2, h2, "bp3-heading");
|
||||
build_component!(H3, h3, "bp3-heading");
|
||||
build_component!(H4, h4, "bp3-heading");
|
||||
build_component!(H5, h5, "bp3-heading");
|
||||
build_component!(H6, h6, "bp3-heading");
|
||||
|
||||
build_component!(Blockquote, BlockquoteProps, blockquote, "bp3-blockquote");
|
||||
build_component!(Code, CodeProps, code, "bp3-code");
|
||||
build_component!(Label, LabelProps, label, "bp3-label");
|
||||
build_component!(Pre, PreProps, pre, "bp3-pre");
|
||||
build_component!(Ol, OlProps, ol, "bp3-ol");
|
||||
build_component!(Ul, UlProps, ul, "bp3-ul");
|
||||
build_component!(Blockquote, blockquote, "bp3-blockquote");
|
||||
build_component!(Code, code, "bp3-code");
|
||||
build_component!(Label, label, "bp3-label");
|
||||
build_component!(Pre, pre, "bp3-pre");
|
||||
build_component!(Ol, ol, "bp3-ol");
|
||||
build_component!(Ul, ul, "bp3-ul");
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{Icon, IconName};
|
||||
use web_sys::HtmlSelectElement;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct HtmlSelect<T: Clone + PartialEq + 'static> {
|
||||
props: HtmlSelectProps<T>,
|
||||
link: ComponentLink<Self>,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
|
@ -30,51 +32,44 @@ pub struct HtmlSelectProps<T: Clone + PartialEq + 'static> {
|
|||
}
|
||||
|
||||
impl<T: Clone + PartialEq + 'static> Component for HtmlSelect<T> {
|
||||
type Message = ChangeData;
|
||||
type Message = Event;
|
||||
type Properties = HtmlSelectProps<T>;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Self { props, link }
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Self {
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
let i = if let ChangeData::Select(select) = msg {
|
||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
let i = if let Some(select) = msg.target_dyn_into::<HtmlSelectElement>() {
|
||||
select.selected_index()
|
||||
} else {
|
||||
unreachable!("unexpected ChangeData variant: {:?}", msg);
|
||||
unreachable!("unexpected Event: {:?}", msg);
|
||||
};
|
||||
if i >= 0 {
|
||||
let i = i as usize;
|
||||
let variant = self.props.options[i].0.clone();
|
||||
self.props.onchange.emit(variant);
|
||||
let variant = ctx.props().options[i].0.clone();
|
||||
ctx.props().onchange.emit(variant);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let option_children = self
|
||||
.props
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let option_children = ctx
|
||||
.props()
|
||||
.options
|
||||
.iter()
|
||||
.map(|(value, label)| {
|
||||
let selected = self
|
||||
.props
|
||||
let selected = ctx
|
||||
.props()
|
||||
.value
|
||||
.as_ref()
|
||||
.map(|x| value == x)
|
||||
.unwrap_or_default();
|
||||
|
||||
html! {
|
||||
<option selected=selected>
|
||||
<option selected={selected}>
|
||||
{label}
|
||||
</option>
|
||||
}
|
||||
|
@ -83,24 +78,24 @@ impl<T: Clone + PartialEq + 'static> Component for HtmlSelect<T> {
|
|||
|
||||
html! {
|
||||
<div
|
||||
class=classes!(
|
||||
class={classes!(
|
||||
"bp3-html-select",
|
||||
self.props.minimal.then(|| "bp3-minimal"),
|
||||
self.props.large.then(|| "bp3-large"),
|
||||
self.props.fill.then(|| "bp3-fill"),
|
||||
self.props.disabled.then(|| "bp3-disabled"),
|
||||
self.props.class.clone(),
|
||||
)
|
||||
ctx.props().minimal.then(|| "bp3-minimal"),
|
||||
ctx.props().large.then(|| "bp3-large"),
|
||||
ctx.props().fill.then(|| "bp3-fill"),
|
||||
ctx.props().disabled.then(|| "bp3-disabled"),
|
||||
ctx.props().class.clone(),
|
||||
)}
|
||||
>
|
||||
<select
|
||||
disabled=self.props.disabled
|
||||
onchange={self.link.callback(|x| x)}
|
||||
title={self.props.title.clone()}
|
||||
disabled={ctx.props().disabled}
|
||||
onchange={ctx.link().callback(|x| x)}
|
||||
title={ctx.props().title.clone()}
|
||||
value={"".to_string()}
|
||||
>
|
||||
{option_children}
|
||||
</select>
|
||||
<Icon icon=IconName::DoubleCaretVertical/>
|
||||
<Icon icon={IconName::DoubleCaretVertical}/>
|
||||
</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_LARGE: i32 = 20;
|
||||
|
||||
pub struct Icon {
|
||||
props: IconProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct IconProps {
|
||||
pub icon: IconName,
|
||||
|
@ -33,62 +29,41 @@ pub struct IconProps {
|
|||
pub onclick: Callback<MouseEvent>,
|
||||
}
|
||||
|
||||
impl Component for Icon {
|
||||
type Message = ();
|
||||
type Properties = IconProps;
|
||||
#[function_component(Icon)]
|
||||
pub fn icon(props: &IconProps) -> Html {
|
||||
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 {
|
||||
Icon { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let 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()
|
||||
html! {
|
||||
<span
|
||||
class={classes!("bp3-icon", props.class.clone(), props.intent)}
|
||||
onclick={props.onclick.clone()}
|
||||
>
|
||||
<svg
|
||||
fill={props.color.clone()}
|
||||
data-icon={icon_string.clone()}
|
||||
width={props.icon_size.to_string()}
|
||||
height={props.icon_size.to_string()}
|
||||
viewBox={format!("0 0 {x} {x}", x=pixel_grid_size)}
|
||||
>
|
||||
<svg
|
||||
fill={self.props.color.clone()}
|
||||
data-icon={icon_string.clone()}
|
||||
width={self.props.icon_size.to_string()}
|
||||
height={self.props.icon_size.to_string()}
|
||||
viewBox={format!("0 0 {x} {x}", x=pixel_grid_size)}
|
||||
>
|
||||
<desc>{self.props.title.clone().unwrap_or(icon_string)}</desc>
|
||||
{
|
||||
paths.iter()
|
||||
.map(|x| html! {
|
||||
<path d=*x fillRule="evenodd" />
|
||||
})
|
||||
.collect::<Html>()
|
||||
}
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
<desc>{props.title.clone().unwrap_or(icon_string)}</desc>
|
||||
{
|
||||
paths.iter()
|
||||
.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;
|
||||
|
||||
pub struct InputGroup {
|
||||
props: InputGroupProps,
|
||||
link: ComponentLink<Self>,
|
||||
left_element_ref: NodeRef,
|
||||
left_element_width: Option<i32>,
|
||||
right_element_ref: NodeRef,
|
||||
|
@ -74,7 +72,7 @@ pub struct InputGroupProps {
|
|||
#[prop_or_default]
|
||||
pub input_type: TextInputType,
|
||||
#[prop_or_default]
|
||||
pub oninput: Callback<InputData>,
|
||||
pub oninput: Callback<InputEvent>,
|
||||
#[prop_or_default]
|
||||
pub onkeyup: Callback<KeyboardEvent>,
|
||||
#[prop_or_default]
|
||||
|
@ -91,10 +89,8 @@ impl Component for InputGroup {
|
|||
type Message = ();
|
||||
type Properties = InputGroupProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Self {
|
||||
props,
|
||||
link,
|
||||
left_element_ref: Default::default(),
|
||||
left_element_width: 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
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let input_style = match (self.left_element_width, self.right_element_width) {
|
||||
(Some(left), None) => format!("padding-left:{}px", left.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! {
|
||||
<div
|
||||
class=classes!(
|
||||
class={classes!(
|
||||
"bp3-input-group",
|
||||
self.props.disabled.then(|| "bp3-disabled"),
|
||||
self.props.fill.then(|| "bp3-fill"),
|
||||
self.props.large.then(|| "bp3-large"),
|
||||
self.props.small.then(|| "bp3-small"),
|
||||
self.props.round.then(|| "bp3-round"),
|
||||
self.props.placeholder.clone(),
|
||||
self.props.class.clone(),
|
||||
)
|
||||
ctx.props().disabled.then(|| "bp3-disabled"),
|
||||
ctx.props().fill.then(|| "bp3-fill"),
|
||||
ctx.props().large.then(|| "bp3-large"),
|
||||
ctx.props().small.then(|| "bp3-small"),
|
||||
ctx.props().round.then(|| "bp3-round"),
|
||||
ctx.props().placeholder.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! {
|
||||
<span
|
||||
class="bp3-input-left-container"
|
||||
ref=self.left_element_ref.clone()
|
||||
ref={self.left_element_ref.clone()}
|
||||
>
|
||||
{left_element}
|
||||
</span>
|
||||
}
|
||||
} else if let Some(icon) = self.props.left_icon {
|
||||
} else if let Some(icon) = ctx.props().left_icon {
|
||||
html! {
|
||||
<Icon icon=icon />
|
||||
<Icon icon={icon} />
|
||||
}
|
||||
} else {
|
||||
html!()
|
||||
}
|
||||
}
|
||||
<input
|
||||
ref=self.props.input_ref.clone()
|
||||
ref={ctx.props().input_ref.clone()}
|
||||
class="bp3-input"
|
||||
type=self.props.input_type.as_str()
|
||||
placeholder=self.props.placeholder.clone()
|
||||
disabled=self.props.disabled
|
||||
oninput={self.props.oninput.clone()}
|
||||
onkeyup={self.props.onkeyup.clone()}
|
||||
onkeydown={self.props.onkeydown.clone()}
|
||||
value=self.props.value.clone()
|
||||
style=input_style
|
||||
type={ctx.props().input_type.as_str()}
|
||||
placeholder={ctx.props().placeholder.clone()}
|
||||
disabled={ctx.props().disabled}
|
||||
oninput={ctx.props().oninput.clone()}
|
||||
onkeyup={ctx.props().onkeyup.clone()}
|
||||
onkeydown={ctx.props().onkeydown.clone()}
|
||||
value={ctx.props().value.clone()}
|
||||
style={input_style}
|
||||
/>
|
||||
{
|
||||
if let Some(right_element) = self.props.right_element.clone() {
|
||||
if let Some(right_element) = ctx.props().right_element.clone() {
|
||||
html! {
|
||||
<span
|
||||
class="bp3-input-action"
|
||||
ref=self.right_element_ref.clone()
|
||||
ref={self.right_element_ref.clone()}
|
||||
>
|
||||
{right_element}
|
||||
</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();
|
||||
self.left_element_width = self
|
||||
.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
|
||||
{
|
||||
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 std::borrow::Cow;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct Menu {
|
||||
props: MenuProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct MenuProps {
|
||||
#[prop_or_default]
|
||||
|
@ -17,45 +12,20 @@ pub struct MenuProps {
|
|||
pub children: html::Children,
|
||||
}
|
||||
|
||||
impl Component for Menu {
|
||||
type Message = ();
|
||||
type Properties = MenuProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Menu { props }
|
||||
#[function_component(Menu)]
|
||||
pub fn menu(props: &MenuProps) -> Html {
|
||||
html! {
|
||||
<ul
|
||||
class={classes!(
|
||||
"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)]
|
||||
|
@ -71,7 +41,7 @@ pub struct MenuItemProps {
|
|||
#[prop_or_default]
|
||||
pub disabled: bool,
|
||||
#[prop_or_default]
|
||||
pub href: Option<Cow<'static, str>>,
|
||||
pub href: Option<String>,
|
||||
#[prop_or_default]
|
||||
pub label: Option<yew::virtual_dom::VNode>,
|
||||
#[prop_or_default]
|
||||
|
@ -89,127 +59,81 @@ pub struct MenuItemProps {
|
|||
// TODO: pub children: html::Children,
|
||||
}
|
||||
|
||||
impl Component for MenuItem {
|
||||
type Message = ();
|
||||
type Properties = MenuItemProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
MenuItem { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<li>
|
||||
<a
|
||||
class=classes!(
|
||||
"bp3-menu-item",
|
||||
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 />
|
||||
}
|
||||
#[function_component(MenuItem)]
|
||||
pub fn menu_item(props: &MenuItemProps) -> Html {
|
||||
html! {
|
||||
<li>
|
||||
<a
|
||||
class={classes!(
|
||||
"bp3-menu-item",
|
||||
props.active.then(|| "bp3-active"),
|
||||
props.disabled.then(|| "bp3-disabled"),
|
||||
props.intent
|
||||
.or_else(|| props.active.then(|| Intent::Primary)),
|
||||
props.class.clone(),
|
||||
)}
|
||||
href={(!props.disabled).then(|| props.href.clone()).flatten()}
|
||||
tabIndex={(!props.disabled).then(|| "0")}
|
||||
onclick={(!props.disabled).then(|| props.onclick.clone())}
|
||||
>
|
||||
{
|
||||
if let Some(icon_name) = props.icon {
|
||||
html! {
|
||||
<Icon icon={icon_name} />
|
||||
}
|
||||
} else if let Some(html) = 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>
|
||||
{
|
||||
if let Some(label) = self.props.label.clone() {
|
||||
html! {
|
||||
<span
|
||||
class=classes!(
|
||||
"bp3-menu-item-label",
|
||||
self.props.label_class.clone())
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
}
|
||||
} else {
|
||||
html!()
|
||||
}
|
||||
<div class={classes!("bp3-text", "bp3-fill", props.text_class.clone())}>
|
||||
{props.text.clone()}
|
||||
</div>
|
||||
{
|
||||
if let Some(label) = props.label.clone() {
|
||||
html! {
|
||||
<span
|
||||
class={classes!(
|
||||
"bp3-menu-item-label",
|
||||
props.label_class.clone())}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
}
|
||||
} else {
|
||||
html!()
|
||||
}
|
||||
}
|
||||
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MenuDivider {
|
||||
props: MenuDividerProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct MenuDividerProps {
|
||||
#[prop_or_default]
|
||||
pub title: Option<yew::virtual_dom::VNode>,
|
||||
}
|
||||
|
||||
impl Component for MenuDivider {
|
||||
type Message = ();
|
||||
type Properties = MenuDividerProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
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") />
|
||||
}
|
||||
#[function_component(MenuDivider)]
|
||||
pub fn menu_divider(props: &MenuDividerProps) -> Html {
|
||||
html! {
|
||||
{if let Some(title) = props.title.clone() {
|
||||
html! {
|
||||
<li
|
||||
class={classes!("bp3-menu-header")}
|
||||
>
|
||||
<H6>{title}</H6>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
} else {
|
||||
html! {
|
||||
<li class={classes!("bp3-menu-divider")} />
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use crate::{Button, ButtonGroup, ControlGroup, IconName, InputGroup, Intent};
|
||||
use std::fmt::Display;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Add, Bound, RangeBounds, Sub};
|
||||
use std::str::FromStr;
|
||||
use web_sys::HtmlInputElement;
|
||||
use yew::html::IntoPropValue;
|
||||
use yew::prelude::*;
|
||||
|
||||
|
@ -16,9 +18,8 @@ where
|
|||
+ PartialOrd
|
||||
+ 'static,
|
||||
{
|
||||
props: NumericInputProps<T>,
|
||||
link: ComponentLink<Self>,
|
||||
input: String,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
|
@ -84,42 +85,46 @@ where
|
|||
type Message = Msg;
|
||||
type Properties = NumericInputProps<T>;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Self {
|
||||
props,
|
||||
link,
|
||||
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 {
|
||||
Msg::InputUpdate(new_value) => {
|
||||
if let Ok(new_value) = new_value.trim().parse::<T>() {
|
||||
self.update_value(new_value)
|
||||
update_value(new_value)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
Msg::Up => self.update_value(self.props.value + self.props.increment),
|
||||
Msg::Down => self.update_value(self.props.value - self.props.increment),
|
||||
Msg::Up => update_value(ctx.props().value + ctx.props().increment),
|
||||
Msg::Down => update_value(ctx.props().value - ctx.props().increment),
|
||||
Msg::Noop => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
if self.props.value != props.value {
|
||||
self.input = props.value.to_string();
|
||||
}
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
fn changed(&mut self, ctx: &Context<Self>) -> bool {
|
||||
self.input = ctx.props().value.to_string();
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let NumericInputProps {
|
||||
value,
|
||||
increment,
|
||||
|
@ -127,8 +132,9 @@ where
|
|||
disable_buttons,
|
||||
buttons_on_the_left,
|
||||
..
|
||||
} = self.props;
|
||||
let bounds = &self.props.bounds;
|
||||
} = *ctx.props();
|
||||
|
||||
let bounds = &ctx.props().bounds;
|
||||
let button_up_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!()
|
||||
} else {
|
||||
html! {
|
||||
<ButtonGroup vertical=true class=classes!("bp3-fixed")>
|
||||
<ButtonGroup vertical=true class={classes!("bp3-fixed")}>
|
||||
<Button
|
||||
icon=IconName::ChevronUp
|
||||
disabled=button_up_disabled
|
||||
onclick=self.link.callback(|_| Msg::Up)
|
||||
icon={IconName::ChevronUp}
|
||||
disabled={button_up_disabled}
|
||||
onclick={ctx.link().callback(|_| Msg::Up)}
|
||||
/>
|
||||
<Button
|
||||
icon=IconName::ChevronDown
|
||||
disabled=button_down_disabled
|
||||
onclick=self.link.callback(|_| Msg::Down)
|
||||
icon={IconName::ChevronDown}
|
||||
disabled={button_down_disabled}
|
||||
onclick={ctx.link().callback(|_| Msg::Down)}
|
||||
/>
|
||||
</ButtonGroup>
|
||||
}
|
||||
|
@ -153,15 +159,18 @@ where
|
|||
|
||||
let input_group = html! {
|
||||
<InputGroup
|
||||
placeholder=self.props.placeholder.clone()
|
||||
large=self.props.large
|
||||
disabled=self.props.disabled
|
||||
left_icon=self.props.left_icon
|
||||
left_element=self.props.left_element.clone()
|
||||
right_element=self.props.right_element.clone()
|
||||
value=self.input.clone()
|
||||
oninput=self.link.callback(|e: InputData| Msg::InputUpdate(e.value))
|
||||
onkeydown=self.link.callback(|e: KeyboardEvent| {
|
||||
placeholder={ctx.props().placeholder.clone()}
|
||||
large={ctx.props().large}
|
||||
disabled={ctx.props().disabled}
|
||||
left_icon={ctx.props().left_icon}
|
||||
left_element={ctx.props().left_element.clone()}
|
||||
right_element={ctx.props().right_element.clone()}
|
||||
value={self.input.clone()}
|
||||
oninput={ctx.link().callback(|e: InputEvent| {
|
||||
let value = e.target_unchecked_into::<HtmlInputElement>().value();
|
||||
Msg::InputUpdate(value)
|
||||
})}
|
||||
onkeydown={ctx.link().callback(|e: KeyboardEvent| {
|
||||
if e.key() == "ArrowUp" {
|
||||
Msg::Up
|
||||
} else if e.key() == "ArrowDown" {
|
||||
|
@ -169,16 +178,16 @@ where
|
|||
} else {
|
||||
Msg::Noop
|
||||
}
|
||||
})
|
||||
})}
|
||||
/>
|
||||
};
|
||||
|
||||
if buttons_on_the_left {
|
||||
html! {
|
||||
<ControlGroup
|
||||
class=classes!("bp3-numeric-input")
|
||||
fill=self.props.fill
|
||||
large=self.props.large
|
||||
class={classes!("bp3-numeric-input")}
|
||||
fill={ctx.props().fill}
|
||||
large={ctx.props().large}
|
||||
>
|
||||
{buttons}
|
||||
{input_group}
|
||||
|
@ -187,9 +196,9 @@ where
|
|||
} else {
|
||||
html! {
|
||||
<ControlGroup
|
||||
class=classes!("bp3-numeric-input")
|
||||
fill=self.props.fill
|
||||
large=self.props.large
|
||||
class={classes!("bp3-numeric-input")}
|
||||
fill={ctx.props().fill}
|
||||
large={ctx.props().large}
|
||||
>
|
||||
{input_group}
|
||||
{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)]
|
||||
pub struct NumericInputRangeBounds<T> {
|
||||
pub start: Bound<T>,
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use crate::{Button, IconName};
|
||||
use std::borrow::Cow;
|
||||
use gloo::timers::callback::Timeout;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
use yew::prelude::*;
|
||||
use yew::services::timeout::{TimeoutService, TimeoutTask};
|
||||
|
||||
pub struct PanelBuilder<F: Fn(Option<Html>, I) -> O, I, O> {
|
||||
title: Option<Html>,
|
||||
|
@ -119,9 +117,11 @@ impl From<StateAction> for Classes {
|
|||
}
|
||||
|
||||
pub struct PanelStack {
|
||||
timeout_task: Option<TimeoutTask>,
|
||||
props: PanelStackProps,
|
||||
link: ComponentLink<Self>,
|
||||
timeout_task: Option<Timeout>,
|
||||
|
||||
// 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)]
|
||||
|
@ -141,47 +141,36 @@ impl Component for PanelStack {
|
|||
type Message = PanelStackMessage;
|
||||
type Properties = PanelStackProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Self {
|
||||
timeout_task: None,
|
||||
props,
|
||||
link,
|
||||
action_to_perform: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
PanelStackMessage::PopPanel => {
|
||||
self.props.state.opened_panels.borrow_mut().pop();
|
||||
ctx.props().state.opened_panels.borrow_mut().pop();
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
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 {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let opened_panels = ctx.props().state.opened_panels.borrow();
|
||||
let last = match self.action_to_perform {
|
||||
Some(StateAction::Pop) => opened_panels.len() - 2,
|
||||
_ => opened_panels.len() - 1,
|
||||
};
|
||||
|
||||
html! {
|
||||
<div
|
||||
class=classes!(
|
||||
class={classes!(
|
||||
"bp3-panel-stack2",
|
||||
action,
|
||||
self.props.class.clone(),
|
||||
)
|
||||
self.action_to_perform,
|
||||
ctx.props().class.clone(),
|
||||
)}
|
||||
>
|
||||
{
|
||||
opened_panels
|
||||
|
@ -190,9 +179,9 @@ impl Component for PanelStack {
|
|||
.rev()
|
||||
.map(|(i, (title, content))| html! {
|
||||
<Panel
|
||||
title=title.clone()
|
||||
title={title.clone()}
|
||||
animation={
|
||||
match action {
|
||||
match self.action_to_perform {
|
||||
_ if i == last => Animation::EnterStart,
|
||||
Some(StateAction::Push) if i == last - 1 =>
|
||||
Animation::ExitStart,
|
||||
|
@ -201,8 +190,8 @@ impl Component for PanelStack {
|
|||
_ => Animation::Exited,
|
||||
}
|
||||
}
|
||||
onclose=(i > 0).then(|| self.props.onclose.clone()).flatten()
|
||||
key=i
|
||||
onclose={(i > 0).then(|| ctx.props().onclose.clone()).flatten()}
|
||||
key={i}
|
||||
>
|
||||
// TODO the state of content doesn't seem to be kept when re-opening
|
||||
// a panel using the same components
|
||||
|
@ -215,21 +204,24 @@ impl Component for PanelStack {
|
|||
}
|
||||
}
|
||||
|
||||
fn rendered(&mut self, _first_render: bool) {
|
||||
if self.props.state.action.take() == Some(StateAction::Pop) {
|
||||
self.timeout_task.replace(TimeoutService::spawn(
|
||||
Duration::from_millis(400),
|
||||
self.link.callback(|_| PanelStackMessage::PopPanel),
|
||||
));
|
||||
fn changed(&mut self, ctx: &Context<Self>) -> bool {
|
||||
self.action_to_perform = ctx.props().state.action;
|
||||
true
|
||||
}
|
||||
|
||||
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 {
|
||||
animation: Animation,
|
||||
timeout_task: Option<TimeoutTask>,
|
||||
props: PanelProps,
|
||||
link: ComponentLink<Self>,
|
||||
timeout_task: Option<Timeout>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||
|
@ -249,16 +241,14 @@ impl Component for Panel {
|
|||
type Message = PanelMessage;
|
||||
type Properties = PanelProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
Self {
|
||||
animation: props.animation,
|
||||
animation: ctx.props().animation,
|
||||
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 {
|
||||
PanelMessage::UpdateAnimation(animation) => {
|
||||
self.animation = animation;
|
||||
|
@ -267,17 +257,7 @@ impl Component for Panel {
|
|||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.animation = props.animation;
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let style = if self.animation == Animation::Exited {
|
||||
"display:none"
|
||||
} else {
|
||||
|
@ -294,15 +274,15 @@ impl Component for Panel {
|
|||
Animation::Exited => None,
|
||||
}
|
||||
);
|
||||
let back_button = self.props.onclose.clone().map(|onclose| {
|
||||
let back_button = ctx.props().onclose.clone().map(|onclose| {
|
||||
html! {
|
||||
<Button
|
||||
class=classes!("bp3-panel-stack-header-back")
|
||||
style=Cow::Borrowed("padding-right:0")
|
||||
icon=IconName::ChevronLeft
|
||||
minimal=true
|
||||
small=true
|
||||
onclick=onclose.reform(|_| ())
|
||||
class={classes!("bp3-panel-stack-header-back")}
|
||||
style={"padding-right:0"}
|
||||
icon={IconName::ChevronLeft}
|
||||
minimal={true}
|
||||
small={true}
|
||||
onclick={onclose.reform(|_| ())}
|
||||
>
|
||||
// TODO: I get a lot of "VComp is not mounted" if I try to use the title
|
||||
// of the previous panel
|
||||
|
@ -311,47 +291,48 @@ impl Component for Panel {
|
|||
});
|
||||
|
||||
html! {
|
||||
<div class=classes style=style>
|
||||
<div class={classes} style={style}>
|
||||
<div class="bp3-panel-stack-header">
|
||||
<span>{back_button.unwrap_or_default()}</span>
|
||||
{self.props.title.clone().unwrap_or_default()}
|
||||
{ctx.props().title.clone().unwrap_or_default()}
|
||||
<span/>
|
||||
</div>
|
||||
{for self.props.children.iter()}
|
||||
{for ctx.props().children.iter()}
|
||||
</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 {
|
||||
Animation::EnterStart => {
|
||||
self.timeout_task.replace(TimeoutService::spawn(
|
||||
Duration::from_millis(0),
|
||||
self.link
|
||||
.callback(|_| PanelMessage::UpdateAnimation(Animation::Entering)),
|
||||
));
|
||||
let link = ctx.link().clone();
|
||||
self.timeout_task.replace(Timeout::new(0, move || {
|
||||
link.send_message(PanelMessage::UpdateAnimation(Animation::Entering));
|
||||
}));
|
||||
}
|
||||
Animation::Entering => {
|
||||
self.timeout_task.replace(TimeoutService::spawn(
|
||||
Duration::from_millis(400),
|
||||
self.link
|
||||
.callback(|_| PanelMessage::UpdateAnimation(Animation::Entered)),
|
||||
));
|
||||
let link = ctx.link().clone();
|
||||
self.timeout_task.replace(Timeout::new(400, move || {
|
||||
link.send_message(PanelMessage::UpdateAnimation(Animation::Entered));
|
||||
}));
|
||||
}
|
||||
Animation::Entered => {}
|
||||
Animation::ExitStart => {
|
||||
self.timeout_task.replace(TimeoutService::spawn(
|
||||
Duration::from_millis(0),
|
||||
self.link
|
||||
.callback(|_| PanelMessage::UpdateAnimation(Animation::Exiting)),
|
||||
));
|
||||
let link = ctx.link().clone();
|
||||
self.timeout_task.replace(Timeout::new(0, move || {
|
||||
link.send_message(PanelMessage::UpdateAnimation(Animation::Exiting));
|
||||
}));
|
||||
}
|
||||
Animation::Exiting => {
|
||||
self.timeout_task.replace(TimeoutService::spawn(
|
||||
Duration::from_millis(400),
|
||||
self.link
|
||||
.callback(|_| PanelMessage::UpdateAnimation(Animation::Exited)),
|
||||
));
|
||||
let link = ctx.link().clone();
|
||||
self.timeout_task.replace(Timeout::new(400, move || {
|
||||
link.send_message(PanelMessage::UpdateAnimation(Animation::Exited));
|
||||
}));
|
||||
}
|
||||
Animation::Exited => {}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
use crate::Intent;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct ProgressBar {
|
||||
props: ProgressBarProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ProgressBarProps {
|
||||
#[prop_or_default]
|
||||
|
@ -19,48 +15,27 @@ pub struct ProgressBarProps {
|
|||
pub class: Classes,
|
||||
}
|
||||
|
||||
impl Component for ProgressBar {
|
||||
type Message = ();
|
||||
type Properties = ProgressBarProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let width = if let Some(value) = self.props.value {
|
||||
// NOTE: nightly, issue #44095 for f32::clamp
|
||||
// let percent = ((1000. * value).ceil() / 10.).clamp(0.,100.);
|
||||
let percent = ((1000. * value).ceil() / 10.).max(0.).min(100.);
|
||||
format!("width: {}%;", percent)
|
||||
} else {
|
||||
"".into()
|
||||
};
|
||||
html! {
|
||||
<div
|
||||
class=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>
|
||||
}
|
||||
#[function_component(ProgressBar)]
|
||||
pub fn progress_bar(props: &ProgressBarProps) -> Html {
|
||||
let width = if let Some(value) = 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",
|
||||
props.intent,
|
||||
(!props.animate).then(|| "bp3-no-animation"),
|
||||
(!props.stripes).then(|| "bp3-no-stripes"),
|
||||
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::*;
|
||||
|
||||
pub struct Radio {
|
||||
props: RadioProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct RadioProps {
|
||||
#[prop_or_default]
|
||||
|
@ -17,59 +13,38 @@ pub struct RadioProps {
|
|||
#[prop_or_default]
|
||||
pub name: Option<String>,
|
||||
#[prop_or_default]
|
||||
pub onchange: Option<Callback<ChangeData>>,
|
||||
pub onchange: Option<Callback<Event>>,
|
||||
#[prop_or_default]
|
||||
pub label: yew::virtual_dom::VNode,
|
||||
#[prop_or_default]
|
||||
pub value: Option<String>,
|
||||
}
|
||||
|
||||
impl Component for Radio {
|
||||
type Message = ();
|
||||
type Properties = RadioProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
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"),
|
||||
)
|
||||
#[function_component(Radio)]
|
||||
pub fn radio(props: &RadioProps) -> Html {
|
||||
html! {
|
||||
<label
|
||||
class={classes!(
|
||||
"bp3-control",
|
||||
"bp3-radio",
|
||||
props.disabled.then(|| "bp3-disabled"),
|
||||
props.inline.then(|| "bp3-inline"),
|
||||
props.large.then(|| "bp3-large"),
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
onchange={props.onchange.clone().unwrap_or_default()}
|
||||
disabled={props.disabled}
|
||||
value={props.value.clone().unwrap_or_default()}
|
||||
checked={props.checked.unwrap_or(false)}
|
||||
name={props.name.clone().unwrap_or_default()}
|
||||
/>
|
||||
<span
|
||||
class={classes!("bp3-control-indicator")}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
onchange={self.props.onchange.clone().unwrap_or_default()}
|
||||
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>
|
||||
}
|
||||
</span>
|
||||
{props.label.clone()}
|
||||
</label>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
use crate::Radio;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct RadioGroup<T: Clone + PartialEq + 'static> {
|
||||
props: RadioGroupProps<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct RadioGroupProps<T: Clone + PartialEq + 'static> {
|
||||
#[prop_or_default]
|
||||
|
@ -24,71 +20,46 @@ pub struct RadioGroupProps<T: Clone + PartialEq + 'static> {
|
|||
pub class: Classes,
|
||||
}
|
||||
|
||||
impl<T: Clone + PartialEq + 'static> Component for RadioGroup<T> {
|
||||
type Message = ();
|
||||
type Properties = RadioGroupProps<T>;
|
||||
// impl<T: Clone + PartialEq + 'static> Component for RadioGroup<T> {
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self { props }
|
||||
}
|
||||
#[function_component(RadioGroup)]
|
||||
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 {
|
||||
true
|
||||
}
|
||||
html! {
|
||||
<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 {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let option_children = self
|
||||
.props
|
||||
.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
|
||||
/>
|
||||
html! {
|
||||
<div
|
||||
class={classes!(
|
||||
"bp3-radio-group",
|
||||
props.class.clone(),
|
||||
)}
|
||||
>
|
||||
{
|
||||
if let Some(label) = props.label.clone() {
|
||||
label
|
||||
} else {
|
||||
html!()
|
||||
}
|
||||
})
|
||||
.collect::<Html>();
|
||||
|
||||
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>
|
||||
}
|
||||
}
|
||||
{option_children}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
160
src/slider.rs
160
src/slider.rs
|
@ -1,19 +1,19 @@
|
|||
use crate::Intent;
|
||||
use std::borrow::Cow;
|
||||
use std::marker::PhantomData;
|
||||
use wasm_bindgen::closure::Closure;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::Element;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct Slider<T: Clone + PartialEq + 'static> {
|
||||
props: SliderProps<T>,
|
||||
mouse_move: Closure<dyn FnMut(MouseEvent)>,
|
||||
mouse_up: Closure<dyn FnMut(MouseEvent)>,
|
||||
link: ComponentLink<Self>,
|
||||
handle_ref: NodeRef,
|
||||
track_ref: NodeRef,
|
||||
is_moving: bool,
|
||||
focus_handle: bool,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
|
@ -42,35 +42,34 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
type Message = Msg;
|
||||
type Properties = SliderProps<T>;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
let mouse_move = {
|
||||
let link = link.clone();
|
||||
let link = ctx.link().clone();
|
||||
Closure::wrap(Box::new(move |event: web_sys::MouseEvent| {
|
||||
link.send_message(Msg::Mouse(event));
|
||||
}) as Box<dyn FnMut(_)>)
|
||||
};
|
||||
let mouse_up = {
|
||||
let link = link.clone();
|
||||
let link = ctx.link().clone();
|
||||
Closure::wrap(Box::new(move |_event: web_sys::MouseEvent| {
|
||||
link.send_message(Msg::StopChange);
|
||||
}) as Box<dyn FnMut(_)>)
|
||||
};
|
||||
Self {
|
||||
props,
|
||||
mouse_move,
|
||||
mouse_up,
|
||||
link,
|
||||
handle_ref: NodeRef::default(),
|
||||
track_ref: NodeRef::default(),
|
||||
is_moving: 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 {
|
||||
Msg::StartChange if self.props.values.len() > 1 => {
|
||||
let document = yew::utils::document();
|
||||
Msg::StartChange if ctx.props().values.len() > 1 => {
|
||||
let document = gloo::utils::document();
|
||||
let event_target: &web_sys::EventTarget = document.as_ref();
|
||||
self.is_moving = true;
|
||||
event_target
|
||||
|
@ -89,23 +88,23 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
true
|
||||
}
|
||||
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 {
|
||||
let track_rect = self.track_ref.cast::<Element>().expect("no track ref");
|
||||
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 =
|
||||
(event.client_x() as f64) - track_rect.get_bounding_client_rect().left();
|
||||
|
||||
let position = (pixel_delta / tick_size).round() as usize;
|
||||
|
||||
let (value, _) =
|
||||
self.props.values.get(position).unwrap_or_else(|| {
|
||||
self.props.values.last().expect("No value in the vec")
|
||||
ctx.props().values.get(position).unwrap_or_else(|| {
|
||||
ctx.props().values.last().expect("No value in the vec")
|
||||
});
|
||||
|
||||
if Some(value) != self.props.selected.as_ref() {
|
||||
self.props.onchange.emit(value.clone());
|
||||
if Some(value) != ctx.props().selected.as_ref() {
|
||||
ctx.props().onchange.emit(value.clone());
|
||||
}
|
||||
|
||||
true
|
||||
|
@ -115,7 +114,7 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
}
|
||||
Msg::Mouse(_) => false,
|
||||
Msg::StopChange => {
|
||||
let document = yew::utils::document();
|
||||
let document = gloo::utils::document();
|
||||
let event_target: &web_sys::EventTarget = document.as_ref();
|
||||
self.is_moving = false;
|
||||
event_target
|
||||
|
@ -132,43 +131,43 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
.expect("No event listener to remove");
|
||||
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" => {
|
||||
self.focus_handle = true;
|
||||
event.prevent_default();
|
||||
let index = self
|
||||
.props
|
||||
let index = ctx
|
||||
.props()
|
||||
.values
|
||||
.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))
|
||||
.unwrap_or(0);
|
||||
let (value, _) = self.props.values[index].clone();
|
||||
self.props.onchange.emit(value);
|
||||
let (value, _) = ctx.props().values[index].clone();
|
||||
ctx.props().onchange.emit(value);
|
||||
true
|
||||
}
|
||||
"ArrowUp" | "ArrowRight" => {
|
||||
self.focus_handle = true;
|
||||
event.prevent_default();
|
||||
let index = self
|
||||
.props
|
||||
let index = ctx
|
||||
.props()
|
||||
.values
|
||||
.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))
|
||||
.unwrap_or(0);
|
||||
let (value, _) = self
|
||||
.props
|
||||
let (value, _) = ctx
|
||||
.props()
|
||||
.values
|
||||
.get(index)
|
||||
.unwrap_or_else(|| {
|
||||
self.props.values.last().expect(
|
||||
ctx.props().values.last().expect(
|
||||
"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();
|
||||
self.props.onchange.emit(value);
|
||||
ctx.props().onchange.emit(value);
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
|
@ -177,23 +176,14 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let value_index = self
|
||||
.props
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let value_index = ctx
|
||||
.props()
|
||||
.values
|
||||
.iter()
|
||||
.position(|(value, _)| Some(value) == self.props.selected.as_ref());
|
||||
let labels = if self.props.values.len() > 1 {
|
||||
self.props
|
||||
.position(|(value, _)| Some(value) == ctx.props().selected.as_ref());
|
||||
let labels = if ctx.props().values.len() > 1 {
|
||||
ctx.props()
|
||||
.values
|
||||
.iter()
|
||||
.enumerate()
|
||||
|
@ -201,11 +191,11 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
label.clone().map(|x| {
|
||||
html! {
|
||||
<div
|
||||
class=classes!("bp3-slider-label")
|
||||
style=format!(
|
||||
class={classes!("bp3-slider-label")}
|
||||
style={format!(
|
||||
"left: {}%;", (i as f64) * 100.0
|
||||
/ ((self.props.values.len() as f64) - 1.0)
|
||||
)
|
||||
/ ((ctx.props().values.len() as f64) - 1.0)
|
||||
)}
|
||||
>
|
||||
{x}
|
||||
</div>
|
||||
|
@ -213,11 +203,11 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
})
|
||||
})
|
||||
.collect::<Html>()
|
||||
} else if let Some((_, Some(label))) = self.props.values.first() {
|
||||
} else if let Some((_, Some(label))) = ctx.props().values.first() {
|
||||
html! {
|
||||
<div
|
||||
class=classes!("bp3-slider-label")
|
||||
style="left: 50%;"
|
||||
class={classes!("bp3-slider-label")}
|
||||
style={"left: 50%;"}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
|
@ -225,9 +215,9 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
} else {
|
||||
html!()
|
||||
};
|
||||
let value_label = self.props.value_label.clone().map(|x| {
|
||||
let value_label = ctx.props().value_label.clone().map(|x| {
|
||||
html! {
|
||||
<span class=classes!("bp3-slider-label")>
|
||||
<span class={classes!("bp3-slider-label")}>
|
||||
{x}
|
||||
</span>
|
||||
}
|
||||
|
@ -235,12 +225,12 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
|
||||
html! {
|
||||
<div
|
||||
class=classes!(
|
||||
class={classes!(
|
||||
"bp3-slider",
|
||||
self.props.vertical.then(|| "bp3-vertical"),
|
||||
)
|
||||
onmousedown=(self.props.values.len() > 1).then(
|
||||
|| self.link.batch_callback(
|
||||
ctx.props().vertical.then(|| "bp3-vertical"),
|
||||
)}
|
||||
onmousedown={(ctx.props().values.len() > 1).then(
|
||||
|| ctx.link().batch_callback(
|
||||
|event: MouseEvent| {
|
||||
if event.buttons() ==
|
||||
crate::MOUSE_EVENT_BUTTONS_PRIMARY
|
||||
|
@ -251,19 +241,19 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
)}
|
||||
>
|
||||
<div
|
||||
class=classes!("bp3-slider-track")
|
||||
class={classes!("bp3-slider-track")}
|
||||
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! {
|
||||
<div
|
||||
class=classes!("bp3-slider-progress")
|
||||
class={classes!("bp3-slider-progress")}
|
||||
style="top: 0px;"
|
||||
onkeydown=self.link.callback(|event| Msg::Keyboard(event))
|
||||
onkeydown={ctx.link().callback(|event| Msg::Keyboard(event))}
|
||||
tabindex=0
|
||||
>
|
||||
</div>
|
||||
|
@ -271,7 +261,7 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
} else {
|
||||
html! {
|
||||
<div
|
||||
class=classes!("bp3-slider-progress")
|
||||
class={classes!("bp3-slider-progress")}
|
||||
style="top: 0px;"
|
||||
>
|
||||
</div>
|
||||
|
@ -280,18 +270,18 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
}
|
||||
{
|
||||
match value_index {
|
||||
Some(index) if self.props.values.len() > 1
|
||||
&& self.props.intent.is_some() => {
|
||||
Some(index) if ctx.props().values.len() > 1
|
||||
&& ctx.props().intent.is_some() => {
|
||||
html! {
|
||||
<div
|
||||
class=classes!("bp3-slider-progress", self.props.intent)
|
||||
style=format!(
|
||||
class={classes!("bp3-slider-progress", ctx.props().intent)}
|
||||
style={format!(
|
||||
"left: 0%; right: {}%; top: 0px;",
|
||||
100.0 - (
|
||||
100.0 * (index as f64)
|
||||
/ (self.props.values.len() as f64 - 1.0)
|
||||
/ (ctx.props().values.len() as f64 - 1.0)
|
||||
)
|
||||
)
|
||||
)}
|
||||
>
|
||||
</div>
|
||||
}
|
||||
|
@ -300,34 +290,34 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
}
|
||||
}
|
||||
</div>
|
||||
<div class=classes!("bp3-slider-axis")>
|
||||
<div class={classes!("bp3-slider-axis")}>
|
||||
{labels}
|
||||
</div>
|
||||
{
|
||||
match value_index {
|
||||
Some(index) if self.props.values.len() > 1 =>
|
||||
Some(index) if ctx.props().values.len() > 1 =>
|
||||
{
|
||||
html! {
|
||||
<span
|
||||
class=classes!(
|
||||
class={classes!(
|
||||
"bp3-slider-handle",
|
||||
self.is_moving.then(|| "bp3-active"),
|
||||
)
|
||||
)}
|
||||
ref={self.handle_ref.clone()}
|
||||
style=format!(
|
||||
style={format!(
|
||||
"left: calc({}% - 8px);",
|
||||
100.0 * (index as f64)
|
||||
/ (self.props.values.len() as f64 - 1.0),
|
||||
)
|
||||
onmousedown=self.link.batch_callback(
|
||||
/ (ctx.props().values.len() as f64 - 1.0),
|
||||
)}
|
||||
onmousedown={ctx.link().batch_callback(
|
||||
|event: MouseEvent| {
|
||||
if event.buttons() == crate::MOUSE_EVENT_BUTTONS_PRIMARY {
|
||||
vec![Msg::StartChange]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
})
|
||||
onkeydown=self.link.callback(|event| Msg::Keyboard(event))
|
||||
})}
|
||||
onkeydown={ctx.link().callback(|event| Msg::Keyboard(event))}
|
||||
tabindex=0
|
||||
>
|
||||
{value_label.clone().unwrap_or_default()}
|
||||
|
@ -337,10 +327,10 @@ impl<T: Clone + PartialEq + 'static> Component for Slider<T> {
|
|||
Some(_) => {
|
||||
html! {
|
||||
<span
|
||||
class=classes!(
|
||||
class={classes!(
|
||||
"bp3-slider-handle",
|
||||
self.is_moving.then(|| "bp3-active"),
|
||||
)
|
||||
)}
|
||||
ref={self.handle_ref.clone()}
|
||||
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 let Some(element) = self.handle_ref.cast::<web_sys::HtmlElement>() {
|
||||
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_LARGE: f32 = 100.0;
|
||||
|
||||
pub struct Spinner {
|
||||
props: SpinnerProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct SpinnerProps {
|
||||
#[prop_or_default]
|
||||
|
@ -26,77 +22,56 @@ pub struct SpinnerProps {
|
|||
pub value: f32,
|
||||
}
|
||||
|
||||
impl Component for Spinner {
|
||||
type Message = ();
|
||||
type Properties = SpinnerProps;
|
||||
#[function_component(Spinner)]
|
||||
pub fn spinner(props: &SpinnerProps) -> Html {
|
||||
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 {
|
||||
Spinner { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let 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! {
|
||||
html! {
|
||||
<div
|
||||
class={classes!(
|
||||
"bp3-spinner",
|
||||
props.intent,
|
||||
props.class.clone(),
|
||||
)}
|
||||
>
|
||||
<div
|
||||
class=classes!(
|
||||
"bp3-spinner",
|
||||
self.props.intent,
|
||||
self.props.class.clone(),
|
||||
)
|
||||
class={classes!("bp3-spinner-animation")}
|
||||
>
|
||||
<div
|
||||
class=classes!("bp3-spinner-animation")
|
||||
<svg
|
||||
width={size.to_string()}
|
||||
height={size.to_string()}
|
||||
stroke-width={stroke_width.to_string()}
|
||||
viewBox={view_box}
|
||||
>
|
||||
<svg
|
||||
width=size.to_string()
|
||||
height=size.to_string()
|
||||
stroke-width=stroke_width.to_string()
|
||||
viewBox=view_box
|
||||
>
|
||||
<path
|
||||
class=classes!("bp3-spinner-track")
|
||||
d=spinner_track.clone()
|
||||
/>
|
||||
<path
|
||||
class=classes!("bp3-spinner-head")
|
||||
d=spinner_track
|
||||
pathLength=PATH_LENGTH.to_string()
|
||||
stroke-dasharray=format!("{} {}", PATH_LENGTH, PATH_LENGTH)
|
||||
stroke-dashoffset=stroke_offset.to_string()
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<path
|
||||
class={classes!("bp3-spinner-track")}
|
||||
d={spinner_track.clone()}
|
||||
/>
|
||||
<path
|
||||
class={classes!("bp3-spinner-head")}
|
||||
d={spinner_track}
|
||||
pathLength={PATH_LENGTH.to_string()}
|
||||
stroke-dasharray={format!("{} {}", PATH_LENGTH, PATH_LENGTH)}
|
||||
stroke-dashoffset={stroke_offset.to_string()}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
133
src/switch.rs
133
src/switch.rs
|
@ -1,9 +1,5 @@
|
|||
use yew::prelude::*;
|
||||
|
||||
pub struct Switch {
|
||||
props: SwitchProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct SwitchProps {
|
||||
#[prop_or_default]
|
||||
|
@ -28,85 +24,64 @@ pub struct SwitchProps {
|
|||
pub align_right: bool,
|
||||
}
|
||||
|
||||
impl Component for Switch {
|
||||
type Message = ();
|
||||
type Properties = SwitchProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let 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()
|
||||
}
|
||||
#[function_component(Switch)]
|
||||
pub fn switch(props: &SwitchProps) -> Html {
|
||||
let display_label = {
|
||||
if props.inner_label.is_some() || props.inner_label_checked.is_some() {
|
||||
let inner_label = props.inner_label.as_deref().unwrap_or_default();
|
||||
let inner_label_checked = 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 class=classes!("bp3-control-indicator-child")>
|
||||
<div class=classes!("bp3-switch-inner-text")>
|
||||
{inner_label.to_string()}
|
||||
</div>
|
||||
</div>
|
||||
<div class={classes!("bp3-control-indicator-child")}>
|
||||
<div class={classes!("bp3-switch-inner-text")}>
|
||||
{inner_label.to_string()}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
} else {
|
||||
Html::default()
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
};
|
||||
html! {
|
||||
<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>
|
||||
} else {
|
||||
Html::default()
|
||||
}
|
||||
};
|
||||
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::hash::{Hash, Hasher};
|
||||
use std::marker::PhantomData;
|
||||
use web_sys::HtmlElement;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct Tabs<T: Clone + PartialEq + Hash + 'static> {
|
||||
props: TabsProps<T>,
|
||||
tab_refs: HashMap<u64, NodeRef>,
|
||||
indicator_ref: NodeRef,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
|
@ -34,8 +35,9 @@ impl<T: Clone + PartialEq + Hash + 'static> Component for Tabs<T> {
|
|||
type Message = ();
|
||||
type Properties = TabsProps<T>;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
let tab_refs = props
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
let tab_refs = ctx
|
||||
.props()
|
||||
.tabs
|
||||
.iter()
|
||||
.map(|x| {
|
||||
|
@ -46,62 +48,53 @@ impl<T: Clone + PartialEq + Hash + 'static> Component for Tabs<T> {
|
|||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
Tabs {
|
||||
props,
|
||||
Self {
|
||||
tab_refs,
|
||||
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
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let tabs = self
|
||||
.props
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let tabs = ctx
|
||||
.props()
|
||||
.tabs
|
||||
.iter()
|
||||
.map(|x| {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
x.id.hash(&mut hasher);
|
||||
let id = hasher.finish();
|
||||
let title_id = format!("bp3-tab-title_{}_{}", self.props.id, id);
|
||||
let panel_id = format!("bp3-tab-panel_{}_{}", self.props.id, id);
|
||||
let selected = self.props.selected_tab_id == x.id;
|
||||
let title_id = format!("bp3-tab-title_{}_{}", ctx.props().id, id);
|
||||
let panel_id = format!("bp3-tab-panel_{}_{}", ctx.props().id, id);
|
||||
let selected = ctx.props().selected_tab_id == x.id;
|
||||
(x, id, title_id, panel_id, selected)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
html! {
|
||||
<div
|
||||
class=classes!(
|
||||
class={classes!(
|
||||
"bp3-tabs",
|
||||
self.props.vertical.then(|| "bp3-vertical"),
|
||||
self.props.class.clone(),
|
||||
)
|
||||
ctx.props().vertical.then(|| "bp3-vertical"),
|
||||
ctx.props().class.clone(),
|
||||
)}
|
||||
>
|
||||
<div
|
||||
class=classes!(
|
||||
class={classes!(
|
||||
"bp3-tab-list",
|
||||
self.props.large.then(|| "bp3-large"),
|
||||
)
|
||||
ctx.props().large.then(|| "bp3-large"),
|
||||
)}
|
||||
>
|
||||
{
|
||||
if self.props.animate {
|
||||
if ctx.props().animate {
|
||||
html! {
|
||||
<div
|
||||
class="bp3-tab-indicator-wrapper"
|
||||
ref=self.indicator_ref.clone()
|
||||
ref={self.indicator_ref.clone()}
|
||||
>
|
||||
<div class="bp3-tab-indicator" />
|
||||
</div>
|
||||
|
@ -115,27 +108,27 @@ impl<T: Clone + PartialEq + Hash + 'static> Component for Tabs<T> {
|
|||
.iter()
|
||||
.map(|(props, id, title_id, panel_id, selected)| html! {
|
||||
<div
|
||||
class=classes!(
|
||||
class={classes!(
|
||||
"bp3-tab",
|
||||
props.title_class.clone(),
|
||||
)
|
||||
aria-disabled=props.disabled.then(|| "true")
|
||||
aria-expanded=selected.to_string()
|
||||
aria-selected=selected.to_string()
|
||||
)}
|
||||
aria-disabled={props.disabled.then(|| "true")}
|
||||
aria-expanded={selected.to_string()}
|
||||
aria-selected={selected.to_string()}
|
||||
role="tab"
|
||||
tabIndex={(!props.disabled).then(|| "0")}
|
||||
id=title_id.to_string()
|
||||
aria-controls=panel_id.to_string()
|
||||
data-tab-id=id.to_string()
|
||||
id={title_id.to_string()}
|
||||
aria-controls={panel_id.to_string()}
|
||||
data-tab-id={id.to_string()}
|
||||
onclick={(!props.disabled).then(|| {
|
||||
let tab_id = props.id.clone();
|
||||
self
|
||||
.props
|
||||
ctx
|
||||
.props()
|
||||
.onchange
|
||||
.reform(move |_| tab_id.clone())
|
||||
})}
|
||||
key=*id
|
||||
ref=self.tab_refs[id].clone()
|
||||
key={*id}
|
||||
ref={self.tab_refs[id].clone()}
|
||||
>
|
||||
{ props.title.clone() }
|
||||
</div>
|
||||
|
@ -147,19 +140,19 @@ impl<T: Clone + PartialEq + Hash + 'static> Component for Tabs<T> {
|
|||
tabs
|
||||
.iter()
|
||||
.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! {
|
||||
<div
|
||||
class=classes!(
|
||||
class={classes!(
|
||||
"bp3-tab-panel",
|
||||
selected.then(|| props.panel_class.clone()),
|
||||
)
|
||||
aria-labelledby=title_id.to_string()
|
||||
aria-hidden=(!selected).then(|| "true")
|
||||
)}
|
||||
aria-labelledby={title_id.to_string()}
|
||||
aria-hidden={(!selected).then(|| "true")}
|
||||
role="tabpanel"
|
||||
id=panel_id.to_string()
|
||||
key=*id
|
||||
id={panel_id.to_string()}
|
||||
key={*id}
|
||||
>
|
||||
{ props.panel.clone() }
|
||||
</div>
|
||||
|
@ -170,10 +163,10 @@ impl<T: Clone + PartialEq + Hash + 'static> Component for Tabs<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn rendered(&mut self, _first_render: bool) {
|
||||
if self.props.animate {
|
||||
fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
|
||||
if ctx.props().animate {
|
||||
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 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 std::borrow::Cow;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct Tag {
|
||||
props: TagProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct TagProps {
|
||||
#[prop_or_default]
|
||||
|
@ -36,81 +31,60 @@ pub struct TagProps {
|
|||
#[prop_or_default]
|
||||
pub round: bool,
|
||||
#[prop_or_default]
|
||||
pub title: Option<Cow<'static, str>>,
|
||||
pub title: Option<String>,
|
||||
#[prop_or_default]
|
||||
pub class: Classes,
|
||||
#[prop_or_default]
|
||||
pub style: Option<Cow<'static, str>>,
|
||||
pub style: Option<String>,
|
||||
}
|
||||
|
||||
impl Component for Tag {
|
||||
type Message = ();
|
||||
type Properties = TagProps;
|
||||
#[function_component(Tag)]
|
||||
pub fn tag(props: &TagProps) -> Html {
|
||||
let icon = if_html!(let Some(icon) = props.icon => <Icon icon={icon} />);
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Tag { props }
|
||||
}
|
||||
let right_icon =
|
||||
if_html!(let Some(right_icon) = props.right_icon => <Icon icon={right_icon} />);
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let 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()}
|
||||
let remove_button = if_html! {
|
||||
let Some(callback) = props.onremove.clone() =>
|
||||
html!(
|
||||
<button
|
||||
class={classes!("bp3-tag-remove")}
|
||||
onclick={callback}
|
||||
tabindex={props.interactive.then(|| "0")}
|
||||
>
|
||||
{icon}
|
||||
<Text
|
||||
class=classes!("bp3-fill")
|
||||
ellipsize={!self.props.multiline}
|
||||
title=self.props.title.clone()
|
||||
inline=true
|
||||
>
|
||||
{self.props.children.clone()}
|
||||
</Text>
|
||||
{right_icon}
|
||||
{remove_button}
|
||||
</span>
|
||||
}
|
||||
<Icon icon={IconName::SmallCross} />
|
||||
</button>
|
||||
)
|
||||
};
|
||||
|
||||
html! {
|
||||
<span
|
||||
class={classes!(
|
||||
"bp3-tag",
|
||||
props.intent,
|
||||
props.active.then(|| "bp3-active"),
|
||||
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::*;
|
||||
|
||||
pub struct Text {
|
||||
props: TextProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct TextProps {
|
||||
#[prop_or_default]
|
||||
|
@ -17,44 +12,23 @@ pub struct TextProps {
|
|||
#[prop_or_default]
|
||||
pub inline: bool,
|
||||
#[prop_or_default]
|
||||
pub title: Option<Cow<'static, str>>,
|
||||
pub title: Option<String>,
|
||||
#[prop_or_default]
|
||||
pub style: Option<Cow<'static, str>>,
|
||||
pub style: Option<String>,
|
||||
}
|
||||
|
||||
impl Component for Text {
|
||||
type Message = ();
|
||||
type Properties = TextProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Text { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<@{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()}
|
||||
</@>
|
||||
}
|
||||
#[function_component(Text)]
|
||||
pub fn text(props: &TextProps) -> Html {
|
||||
html! {
|
||||
<@{if props.inline { "span" } else { "div"}}
|
||||
class={classes!(
|
||||
props.class.clone(),
|
||||
props.ellipsize.then (|| "bp3-text-overflow-ellipsis"),
|
||||
)}
|
||||
style={props.style.clone()}
|
||||
title={props.title.clone()}
|
||||
>
|
||||
{props.children.clone()}
|
||||
</@>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
use crate::Intent;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct TextArea {
|
||||
props: TextAreaProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct TextAreaProps {
|
||||
#[prop_or_default]
|
||||
|
@ -22,44 +18,23 @@ pub struct TextAreaProps {
|
|||
#[prop_or_default]
|
||||
pub small: bool,
|
||||
#[prop_or_default]
|
||||
pub onchange: Option<Callback<ChangeData>>,
|
||||
pub onchange: Option<Callback<Event>>,
|
||||
}
|
||||
|
||||
impl Component for TextArea {
|
||||
type Message = ();
|
||||
type Properties = TextAreaProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
TextArea { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let 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()
|
||||
/>
|
||||
}
|
||||
#[function_component(TextArea)]
|
||||
pub fn text_area(props: &TextAreaProps) -> Html {
|
||||
let classes = classes!(
|
||||
"bp3-input",
|
||||
props.intent,
|
||||
props.class.clone(),
|
||||
props.fill.then(|| "bp3-fill"),
|
||||
props.small.then(|| "bp3-small"),
|
||||
props.large.then(|| "bp3-large"),
|
||||
);
|
||||
html! {
|
||||
<textarea
|
||||
class={classes}
|
||||
onchange={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::HashMap;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use yew::prelude::*;
|
||||
|
||||
|
@ -41,13 +42,13 @@ impl<T> From<id_tree::Tree<NodeData<T>>> for TreeData<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Tree<T: Clone> {
|
||||
props: TreeProps<T>,
|
||||
pub struct Tree<T: Clone + PartialEq> {
|
||||
previous_expanded_state: RefCell<HashMap<u64, bool>>,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct TreeProps<T: Clone> {
|
||||
pub struct TreeProps<T: Clone + PartialEq> {
|
||||
#[prop_or_default]
|
||||
pub is_expanded: bool,
|
||||
pub tree: TreeData<T>,
|
||||
|
@ -112,41 +113,32 @@ impl<T: Clone + PartialEq + 'static> Component for Tree<T> {
|
|||
type Message = ();
|
||||
type Properties = TreeProps<T>;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Tree {
|
||||
props,
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Self {
|
||||
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
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let tree = self.props.tree.borrow();
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let tree = ctx.props().tree.borrow();
|
||||
|
||||
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 {
|
||||
html!()
|
||||
};
|
||||
|
||||
html! {
|
||||
<div class=classes!(
|
||||
<div class={classes!(
|
||||
"bp3-tree",
|
||||
self.props.class.clone(),
|
||||
)>
|
||||
<ul class=classes!("bp3-tree-node-list")>
|
||||
ctx.props().class.clone(),
|
||||
)}>
|
||||
<ul class={classes!("bp3-tree-node-list")}>
|
||||
{nodes}
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -154,9 +146,15 @@ impl<T: Clone + PartialEq + 'static> Component for Tree<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Tree<T> {
|
||||
fn render_children(&self, node_id: &NodeId, depth: u32) -> yew::virtual_dom::VNode {
|
||||
let tree = self.props.tree.borrow();
|
||||
// FIXME: The 'static bound here is probably wrong. Fix this at the end of PR.
|
||||
impl<T: 'static + Clone + PartialEq> Tree<T> {
|
||||
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 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) {
|
||||
Default::default()
|
||||
} else {
|
||||
self.render_children(node_id, depth + 1)
|
||||
self.render_children(ctx, node_id, depth + 1)
|
||||
};
|
||||
|
||||
html! {
|
||||
<TreeNode
|
||||
disabled=data.disabled
|
||||
has_caret=data.has_caret
|
||||
icon=data.icon
|
||||
icon_color=data.icon_color.clone()
|
||||
icon_intent=data.icon_intent
|
||||
is_expanded=data.is_expanded
|
||||
is_selected=data.is_selected
|
||||
label=data.label.clone()
|
||||
secondary_label=data.secondary_label.clone()
|
||||
on_collapse=self.props.on_collapse.clone()
|
||||
on_expand=self.props.on_expand.clone()
|
||||
onclick=self.props.onclick.clone()
|
||||
depth=depth
|
||||
node_id=node_id.clone()
|
||||
key=key
|
||||
disabled={data.disabled}
|
||||
has_caret={data.has_caret}
|
||||
icon={data.icon}
|
||||
icon_color={data.icon_color.clone()}
|
||||
icon_intent={data.icon_intent}
|
||||
is_expanded={data.is_expanded}
|
||||
is_selected={data.is_selected}
|
||||
label={data.label.clone()}
|
||||
secondary_label={data.secondary_label.clone()}
|
||||
on_collapse={ctx.props().on_collapse.clone()}
|
||||
on_expand={ctx.props().on_expand.clone()}
|
||||
onclick={ctx.props().onclick.clone()}
|
||||
depth={depth}
|
||||
node_id={node_id.clone()}
|
||||
key={key}
|
||||
>
|
||||
{inner_nodes}
|
||||
</TreeNode>
|
||||
|
@ -207,7 +205,6 @@ impl<T: Clone> Tree<T> {
|
|||
}
|
||||
|
||||
struct TreeNode {
|
||||
props: TreeNodeProps,
|
||||
handler_caret_click: Callback<MouseEvent>,
|
||||
handler_click: Callback<MouseEvent>,
|
||||
}
|
||||
|
@ -260,34 +257,33 @@ impl Component for TreeNode {
|
|||
type Message = TreeNodeMessage;
|
||||
type Properties = TreeNodeProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
TreeNode {
|
||||
handler_caret_click: link.callback(TreeNodeMessage::CaretClick),
|
||||
handler_click: link.callback(TreeNodeMessage::Click),
|
||||
props,
|
||||
handler_caret_click: ctx.link().callback(TreeNodeMessage::CaretClick),
|
||||
handler_click: ctx.link().callback(TreeNodeMessage::Click),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
if self.props.disabled {
|
||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
if ctx.props().disabled {
|
||||
return false;
|
||||
}
|
||||
|
||||
match msg {
|
||||
TreeNodeMessage::CaretClick(event) => {
|
||||
if self.props.is_expanded {
|
||||
if let Some(on_collapse) = self.props.on_collapse.as_ref() {
|
||||
if ctx.props().is_expanded {
|
||||
if let Some(on_collapse) = ctx.props().on_collapse.as_ref() {
|
||||
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();
|
||||
on_expand.emit((self.props.node_id.clone(), event));
|
||||
on_expand.emit((ctx.props().node_id.clone(), event));
|
||||
}
|
||||
}
|
||||
TreeNodeMessage::Click(event) => {
|
||||
if let Some(onclick) = self.props.onclick.as_ref() {
|
||||
onclick.emit((self.props.node_id.clone(), event));
|
||||
if let Some(onclick) = ctx.props().onclick.as_ref() {
|
||||
onclick.emit((ctx.props().node_id.clone(), event));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -295,38 +291,23 @@ impl Component for TreeNode {
|
|||
false
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
// 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);
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let content_style = format!("padding-left: {}px;", 23 * ctx.props().depth);
|
||||
|
||||
html! {
|
||||
<li class=classes!(
|
||||
<li class={classes!(
|
||||
"bp3-tree-node",
|
||||
self.props.is_selected.then(|| "bp3-tree-node-selected")
|
||||
)>
|
||||
ctx.props().is_selected.then(|| "bp3-tree-node-selected")
|
||||
)}>
|
||||
<div
|
||||
class="bp3-tree-node-content"
|
||||
style=content_style
|
||||
onclick=self.handler_click.clone()
|
||||
style={content_style}
|
||||
onclick={self.handler_click.clone()}
|
||||
>
|
||||
{
|
||||
if self.props.has_caret {
|
||||
if ctx.props().has_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"
|
||||
} else {
|
||||
"bp3-tree-node-caret-closed"
|
||||
|
@ -334,9 +315,9 @@ impl Component for TreeNode {
|
|||
|
||||
html! {
|
||||
<Icon
|
||||
class=classes!(class.to_string())
|
||||
icon=IconName::ChevronRight
|
||||
onclick=self.handler_caret_click.clone()
|
||||
class={classes!(class.to_string())}
|
||||
icon={IconName::ChevronRight}
|
||||
onclick={self.handler_caret_click.clone()}
|
||||
/>
|
||||
}
|
||||
} else {
|
||||
|
@ -346,16 +327,16 @@ impl Component for TreeNode {
|
|||
}
|
||||
}
|
||||
<Icon
|
||||
class=classes!("bp3-tree-node-icon")
|
||||
icon=self.props.icon.unwrap_or_default()
|
||||
color=self.props.icon_color.clone()
|
||||
intent=self.props.icon_intent
|
||||
class={classes!("bp3-tree-node-icon")}
|
||||
icon={ctx.props().icon.unwrap_or_default()}
|
||||
color={ctx.props().icon_color.clone()}
|
||||
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!(
|
||||
<span class=classes!("bp3-tree-node-secondary-label")>
|
||||
<span class={classes!("bp3-tree-node-secondary-label")}>
|
||||
{label}
|
||||
</span>
|
||||
)
|
||||
|
@ -364,9 +345,9 @@ impl Component for TreeNode {
|
|||
}
|
||||
}
|
||||
</div>
|
||||
<Collapse is_open=self.props.is_expanded>
|
||||
<ul class=classes!("bp3-tree-node-list")>
|
||||
{self.props.children.clone()}
|
||||
<Collapse is_open={ctx.props().is_expanded}>
|
||||
<ul class={classes!("bp3-tree-node-list")}>
|
||||
{ctx.props().children.clone()}
|
||||
</ul>
|
||||
</Collapse>
|
||||
</li>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
name = "yewprint-doc"
|
||||
version = "0.1.0"
|
||||
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
|
||||
|
||||
|
@ -10,11 +10,14 @@ edition = "2018"
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = "=0.2"
|
||||
yew = "0.18"
|
||||
web-sys = { version = "0.3", features = ["Window", "MediaQueryList"] }
|
||||
wasm-bindgen = "0.2"
|
||||
web-sys = { version = "0.3", features = ["Window", "MediaQueryList", "Event", "HtmlInputElement"] }
|
||||
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 = ".." }
|
||||
yew-router = "0.15"
|
||||
|
||||
# `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
|
||||
|
|
|
@ -22,19 +22,21 @@ use crate::tag::*;
|
|||
use crate::text::*;
|
||||
use crate::text_area::*;
|
||||
use crate::tree::*;
|
||||
use std::borrow::Cow;
|
||||
use yew::prelude::*;
|
||||
use yew_router::{
|
||||
agent::{RouteAgentDispatcher, RouteRequest},
|
||||
router::Router,
|
||||
Switch,
|
||||
};
|
||||
use yew_router::prelude::*;
|
||||
use yewprint::{IconName, Menu, MenuItem};
|
||||
|
||||
#[function_component(AppRoot)]
|
||||
pub fn app_root() -> Html {
|
||||
html! {
|
||||
<BrowserRouter>
|
||||
<App></App>
|
||||
</BrowserRouter>
|
||||
}
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
link: ComponentLink<Self>,
|
||||
dark_theme: bool,
|
||||
route_dispatcher: RouteAgentDispatcher,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
|
@ -46,33 +48,30 @@ impl Component for App {
|
|||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
App {
|
||||
dark_theme: web_sys::window()
|
||||
.and_then(|x| x.match_media("(prefers-color-scheme: dark)").ok().flatten())
|
||||
.map(|x| x.matches())
|
||||
.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 {
|
||||
Msg::ToggleLight => self.dark_theme ^= true,
|
||||
Msg::GoToMenu(doc_menu) => {
|
||||
self.route_dispatcher
|
||||
.send(RouteRequest::ChangeRoute(doc_menu.into()));
|
||||
if let Some(history) = ctx.link().history() {
|
||||
history.push(doc_menu);
|
||||
} else {
|
||||
gloo::console::warn!("Could not get history from Context");
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let netlify_badge = if self.dark_theme {
|
||||
"https://www.netlify.com/img/global/badges/netlify-color-accent.svg"
|
||||
} else {
|
||||
|
@ -89,223 +88,178 @@ impl Component for App {
|
|||
IconName::Moon
|
||||
};
|
||||
|
||||
html! {
|
||||
<div class=classes!("docs-root", self.dark_theme.then(|| "bp3-dark"))>
|
||||
<div class=classes!("docs-app")>
|
||||
<div class=classes!("docs-nav-wrapper")>
|
||||
<div class=classes!("docs-nav")>
|
||||
<div class=classes!("docs-nav-title")>
|
||||
<a class=classes!("docs-logo") href="/">
|
||||
{crate::include_raw_html!("logo.svg")}
|
||||
</a>
|
||||
<div>
|
||||
<div class=classes!("bp3-navbar-heading", "docs-heading")>
|
||||
{"Yewprint"}
|
||||
</div>
|
||||
<a
|
||||
class=classes!("bp3-text-muted")
|
||||
href="https://github.com/yewprint/yewprint"
|
||||
target="_blank"
|
||||
>
|
||||
<small>{"View on GitHub"}</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<Menu>
|
||||
<MenuItem
|
||||
text={html!(go_to_theme_label)}
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::ToggleLight)
|
||||
icon=go_to_theme_icon
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Button")}
|
||||
href=Cow::Borrowed("#button")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Button))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("ButtonGroup")}
|
||||
href=Cow::Borrowed("#button-group")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::ButtonGroup))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Callout")}
|
||||
href=Cow::Borrowed("#callout")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Callout))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Card")}
|
||||
href=Cow::Borrowed("#card")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Card))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Checkbox")}
|
||||
href=Cow::Borrowed("#checkbox")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Checkbox))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Collapse")}
|
||||
href=Cow::Borrowed("#collapse")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Collapse))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("ControlGroup")}
|
||||
href=Cow::Borrowed("#control-group")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::ControlGroup))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Divider")}
|
||||
href=Cow::Borrowed("#divider")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Divider))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("HtmlSelect")}
|
||||
href=Cow::Borrowed("#html-select")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::HtmlSelect))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Icon")}
|
||||
href=Cow::Borrowed("#icon")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Icon))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("InputGroup")}
|
||||
href=Cow::Borrowed("#input-group")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::InputGroup))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Menu")}
|
||||
href=Cow::Borrowed("#menu")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("NumericInput")}
|
||||
href=Cow::Borrowed("#numeric-input")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::NumericInput))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("PanelStack")}
|
||||
href=Cow::Borrowed("#panel-stack")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::PanelStack))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("ProgressBar")}
|
||||
href=Cow::Borrowed("#progress-bar")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::ProgressBar))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Radio")}
|
||||
href=Cow::Borrowed("#radio")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Radio))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Slider")}
|
||||
href=Cow::Borrowed("#slider")
|
||||
onclick=self.link.callback(|_| Msg::GoToMenu(DocMenu::Slider))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Spinner")}
|
||||
href=Cow::Borrowed("#spinner")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Spinner))
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Switch")}
|
||||
href=Cow::Borrowed("#switch")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Switch))
|
||||
/>
|
||||
<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>
|
||||
let menu = html! {
|
||||
<Menu>
|
||||
<MenuItem
|
||||
text={html!(go_to_theme_label)}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::ToggleLight)}
|
||||
icon={go_to_theme_icon}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Button")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Button))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("ButtonGroup")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::ButtonGroup))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Callout")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Callout))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Card")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Card))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Checkbox")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Checkbox))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Collapse")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Collapse))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("ControlGroup")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::ControlGroup))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Divider")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Divider))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("HtmlSelect")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::HtmlSelect))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Icon")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Icon))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("InputGroup")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::InputGroup))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Menu")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("NumericInput")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::NumericInput))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("PanelStack")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::PanelStack))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("ProgressBar")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::ProgressBar))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Radio")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Radio))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Slider")}
|
||||
onclick={ctx.link().callback(|_| Msg::GoToMenu(DocMenu::Slider))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Spinner")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Spinner))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Switch")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Switch))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Tabs")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Tabs))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Tag")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Tag))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Text")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Text))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("TextArea")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::TextArea))}
|
||||
/>
|
||||
<MenuItem
|
||||
text={html!("Tree")}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Tree))}
|
||||
/>
|
||||
// NOTE: thanks to keep this list of <MenuItem> sorted
|
||||
// alphabetically (except for the light switch)
|
||||
</Menu>
|
||||
};
|
||||
|
||||
let navigation = html! {
|
||||
<div class={classes!("docs-nav-wrapper")}>
|
||||
<div class={classes!("docs-nav")}>
|
||||
<div class={classes!("docs-nav-title")}>
|
||||
<a class={classes!("docs-logo")} href="/">
|
||||
{crate::include_raw_html!("logo.svg")}
|
||||
</a>
|
||||
<div>
|
||||
<div class={classes!("bp3-navbar-heading", "docs-heading")}>
|
||||
{"Yewprint"}
|
||||
</div>
|
||||
<a
|
||||
class={classes!("bp3-text-muted")}
|
||||
href="https://github.com/yewprint/yewprint"
|
||||
target="_blank"
|
||||
>
|
||||
<small>{"View on GitHub"}</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<main class=classes!("docs-content-wrapper") role="main">
|
||||
<div class=classes!("docs-page")>
|
||||
<Router<DocMenu, ()>
|
||||
render=Router::render(|switch: DocMenu| {
|
||||
match switch {
|
||||
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 />),
|
||||
}
|
||||
})
|
||||
{{ menu }}
|
||||
<div class="docs-nav-sponsors">
|
||||
<a href={"https://www.netlify.com"}>
|
||||
<img
|
||||
src={netlify_badge}
|
||||
alt="Deploys by Netlify"
|
||||
/>
|
||||
</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>
|
||||
</main>
|
||||
</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 {
|
||||
#[to = "/#button-group"]
|
||||
#[at("/button-group")]
|
||||
ButtonGroup,
|
||||
#[to = "/#button"]
|
||||
#[at("/button")]
|
||||
Button,
|
||||
#[to = "/#callout"]
|
||||
#[at("/callout")]
|
||||
Callout,
|
||||
#[to = "/#card"]
|
||||
#[at("/card")]
|
||||
Card,
|
||||
#[to = "/#checkbox"]
|
||||
#[at("/checkbox")]
|
||||
Checkbox,
|
||||
#[to = "/#collapse"]
|
||||
#[at("/collapse")]
|
||||
Collapse,
|
||||
#[to = "/#control-group"]
|
||||
#[at("/control-group")]
|
||||
ControlGroup,
|
||||
#[to = "/#html-select"]
|
||||
#[at("/html-select")]
|
||||
HtmlSelect,
|
||||
#[to = "/#divider"]
|
||||
#[at("/divider")]
|
||||
Divider,
|
||||
#[to = "/#icon"]
|
||||
#[at("/icon")]
|
||||
Icon,
|
||||
#[to = "/#input-group"]
|
||||
#[at("/input-group")]
|
||||
InputGroup,
|
||||
#[to = "/#menu"]
|
||||
#[at("/menu")]
|
||||
Menu,
|
||||
#[to = "/#numeric-input"]
|
||||
#[at("/numeric-input")]
|
||||
NumericInput,
|
||||
#[to = "/#panel-stack"]
|
||||
#[at("/panel-stack")]
|
||||
PanelStack,
|
||||
#[to = "/#progress-bar"]
|
||||
#[at("/progress-bar")]
|
||||
ProgressBar,
|
||||
#[to = "/#radio"]
|
||||
#[at("/radio")]
|
||||
Radio,
|
||||
#[to = "/#slider"]
|
||||
#[at("/slider")]
|
||||
Slider,
|
||||
#[to = "/#spinner"]
|
||||
#[at("/spinner")]
|
||||
Spinner,
|
||||
#[to = "/#switch"]
|
||||
#[at("/switch")]
|
||||
Switch,
|
||||
#[to = "/#tabs"]
|
||||
#[at("/tabs")]
|
||||
Tabs,
|
||||
#[to = "/#tag"]
|
||||
#[at("/tag")]
|
||||
Tag,
|
||||
#[to = "/#textarea"]
|
||||
#[at("/textarea")]
|
||||
TextArea,
|
||||
#[to = "/#text"]
|
||||
#[at("/text")]
|
||||
Text,
|
||||
#[to = "/#tree"]
|
||||
#[at("/tree")]
|
||||
Tree,
|
||||
#[to = "/"]
|
||||
#[at("/")]
|
||||
Home,
|
||||
}
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
use yew::prelude::*;
|
||||
use yewprint::{Button, ButtonGroup, IconName};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ExampleProps {
|
||||
pub minimal: bool,
|
||||
|
@ -14,40 +9,19 @@ pub struct ExampleProps {
|
|||
pub vertical: bool,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<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>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example(props: &ExampleProps) -> Html {
|
||||
html! {
|
||||
<ButtonGroup
|
||||
minimal={props.minimal}
|
||||
fill={props.fill}
|
||||
large={props.large}
|
||||
vertical={props.vertical}
|
||||
style={"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 Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
ButtonGroupDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
minimal: 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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -44,19 +40,19 @@ impl Component for ButtonGroupDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Button Group"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Button Group"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<ButtonGroupProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
>
|
||||
</ButtonGroupProps>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
}
|
||||
|
@ -65,41 +61,41 @@ impl Component for ButtonGroupDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
ButtonGroupProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
minimal: !props.minimal,
|
||||
..props
|
||||
})
|
||||
checked=self.props.minimal
|
||||
label=html!("Minimal")
|
||||
})}
|
||||
checked={ctx.props().example_props.minimal}
|
||||
label={html!("Minimal")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps{
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps{
|
||||
fill: !props.fill,
|
||||
..props
|
||||
})
|
||||
checked=self.props.fill
|
||||
label=html!("Fill")
|
||||
})}
|
||||
checked={ctx.props().example_props.fill}
|
||||
label={html!("Fill")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps{
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps{
|
||||
large: !props.large,
|
||||
..props
|
||||
})
|
||||
checked=self.props.large
|
||||
label=html!("Large")
|
||||
})}
|
||||
checked={ctx.props().example_props.large}
|
||||
label={html!("Large")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
vertical: !props.vertical,
|
||||
..props
|
||||
})
|
||||
checked=self.props.vertical
|
||||
label=html!("Vertical")
|
||||
})}
|
||||
checked={ctx.props().example_props.vertical}
|
||||
label={html!("Vertical")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -2,9 +2,7 @@ use yew::prelude::*;
|
|||
use yewprint::Button;
|
||||
|
||||
pub struct Example {
|
||||
link: ComponentLink<Self>,
|
||||
counter: i64,
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
|
@ -27,45 +25,32 @@ impl Component for Example {
|
|||
type Message = Msg;
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Example {
|
||||
counter: 0,
|
||||
link,
|
||||
props,
|
||||
}
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Example { counter: 0 }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
Msg::AddOne => self.counter += 1,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<p>{"Counter: "}{self.counter}</p>
|
||||
<div>
|
||||
<Button
|
||||
onclick=self.link.callback(|_| Msg::AddOne)
|
||||
minimal=self.props.minimal
|
||||
fill=self.props.fill
|
||||
small=self.props.small
|
||||
outlined=self.props.outlined
|
||||
loading=self.props.loading
|
||||
large=self.props.large
|
||||
active=self.props.active
|
||||
disabled=self.props.disabled
|
||||
onclick={ctx.link().callback(|_| Msg::AddOne)}
|
||||
minimal={ctx.props().minimal}
|
||||
fill={ctx.props().fill}
|
||||
small={ctx.props().small}
|
||||
outlined={ctx.props().outlined}
|
||||
loading={ctx.props().loading}
|
||||
large={ctx.props().large}
|
||||
active={ctx.props().active}
|
||||
disabled={ctx.props().disabled}
|
||||
>
|
||||
{"Add 1"}
|
||||
</Button>
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for ButtonDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
ButtonDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
minimal: 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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
"bp3-code-block"
|
||||
);
|
||||
|
||||
let props_component = html! {
|
||||
<ButtonProps
|
||||
callback={self.callback.clone()}
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
};
|
||||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Button"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Button"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<div>
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
<ButtonProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
/>
|
||||
})
|
||||
source={source}
|
||||
props={Some(props_component)}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -70,77 +68,77 @@ impl Component for ButtonDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
ButtonProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
minimal: !props.minimal,
|
||||
..props
|
||||
})
|
||||
checked=self.props.minimal
|
||||
label=html!("Minimal")
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
fill: !props.fill,
|
||||
..props
|
||||
})
|
||||
checked=self.props.fill
|
||||
label=html!("Fill")
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
small: !props.small,
|
||||
..props
|
||||
})
|
||||
checked=self.props.small
|
||||
label=html!("Small")
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
outlined: !props.outlined,
|
||||
..props
|
||||
})
|
||||
checked=self.props.outlined
|
||||
label=html!("Outlined")
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
loading: !props.loading,
|
||||
..props
|
||||
})
|
||||
checked=self.props.loading
|
||||
label=html!("Loading")
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
large: !props.large,
|
||||
..props
|
||||
})
|
||||
checked=self.props.large
|
||||
label=html!("Large")
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
active: !props.active,
|
||||
..props
|
||||
})
|
||||
checked=self.props.active
|
||||
label=html!("Active")
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
disabled: !props.disabled,
|
||||
..props
|
||||
})
|
||||
checked=self.props.disabled
|
||||
label=html!("Disabled")
|
||||
/>
|
||||
</div>
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
minimal: !props.minimal,
|
||||
..props
|
||||
})}
|
||||
checked={ctx.props().example_props.minimal}
|
||||
label={html!("Minimal")}
|
||||
/>
|
||||
<Switch
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
fill: !props.fill,
|
||||
..props
|
||||
})}
|
||||
checked={ctx.props().example_props.fill}
|
||||
label={html!("Fill")}
|
||||
/>
|
||||
<Switch
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
small: !props.small,
|
||||
..props
|
||||
})}
|
||||
checked={ctx.props().example_props.small}
|
||||
label={html!("Small")}
|
||||
/>
|
||||
<Switch
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
outlined: !props.outlined,
|
||||
..props
|
||||
})}
|
||||
checked={ctx.props().example_props.outlined}
|
||||
label={html!("Outlined")}
|
||||
/>
|
||||
<Switch
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
loading: !props.loading,
|
||||
..props
|
||||
})}
|
||||
checked={ctx.props().example_props.loading}
|
||||
label={html!("Loading")}
|
||||
/>
|
||||
<Switch
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
large: !props.large,
|
||||
..props
|
||||
})}
|
||||
checked={ctx.props().example_props.large}
|
||||
label={html!("Large")}
|
||||
/>
|
||||
<Switch
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
active: !props.active,
|
||||
..props
|
||||
})}
|
||||
checked={ctx.props().example_props.active}
|
||||
label={html!("Active")}
|
||||
/>
|
||||
<Switch
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
disabled: !props.disabled,
|
||||
..props
|
||||
})}
|
||||
checked={ctx.props().example_props.disabled}
|
||||
label={html!("Disabled")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate::build_source_code_component!();
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
use yew::prelude::*;
|
||||
use yewprint::{Callout, Intent};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ExampleProps {
|
||||
pub intent: Option<Intent>,
|
||||
|
@ -13,36 +8,15 @@ pub struct ExampleProps {
|
|||
pub show_title: bool,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<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>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example(props: &ExampleProps) -> Html {
|
||||
html! {
|
||||
<Callout
|
||||
title={props.show_title.then(|| "Visually important content")}
|
||||
without_icon={!props.show_icon}
|
||||
intent={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 Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
CalloutDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
show_icon: false,
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -43,18 +39,18 @@ impl Component for CalloutDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Callout"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Callout"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<CalloutProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
}
|
||||
|
@ -63,26 +59,26 @@ impl Component for CalloutDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
CalloutProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<div>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
show_icon: !props.show_icon,
|
||||
..props
|
||||
})
|
||||
checked=self.props.show_icon
|
||||
label=html!("Show/hide icon")
|
||||
})}
|
||||
checked={ctx.props().example_props.show_icon}
|
||||
label={html!("Show/hide icon")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
show_title: !props.show_title,
|
||||
..props
|
||||
})
|
||||
checked=self.props.show_title
|
||||
label=html!("Show/hide title")
|
||||
})}
|
||||
checked={ctx.props().example_props.show_title}
|
||||
label={html!("Show/hide title")}
|
||||
/>
|
||||
<p>{"Select intent:"}</p>
|
||||
<HtmlSelect<Option<Intent>>
|
||||
|
@ -93,10 +89,10 @@ crate::build_example_prop_component! {
|
|||
(Some(Intent::Warning), "Warning".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,
|
||||
..props
|
||||
})
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,47 +1,22 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::{Card, Elevation};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ExampleProps {
|
||||
pub elevation: Elevation,
|
||||
pub interactive: bool,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<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>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example(props: &ExampleProps) -> Html {
|
||||
html! {
|
||||
<Card elevation={props.elevation} interactive={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 Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
CardDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
elevation: Elevation::Level0,
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -42,18 +38,18 @@ impl Component for CardDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Card"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Card"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<CardProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
}
|
||||
|
@ -62,18 +58,20 @@ impl Component for CardDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
CardProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let props = ctx.props();
|
||||
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<div>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
interactive: !props.interactive,
|
||||
..props
|
||||
})
|
||||
checked=self.props.interactive
|
||||
label=html!("Toggle interaction")
|
||||
})}
|
||||
checked={ctx.props().example_props.interactive}
|
||||
label={html!("Toggle interaction")}
|
||||
/>
|
||||
<p>{"Elevation:"}</p>
|
||||
<HtmlSelect<Elevation>
|
||||
|
@ -84,11 +82,11 @@ crate::build_example_prop_component! {
|
|||
(Elevation::Level3, "Level 3".to_string()),
|
||||
(Elevation::Level4, "Level 4".to_string()),
|
||||
]}
|
||||
value=self.props.elevation
|
||||
onchange=self.update_props(|props, elevation| ExampleProps {
|
||||
value={ctx.props().example_props.elevation}
|
||||
onchange={self.update_props(props, |props, elevation| ExampleProps {
|
||||
elevation,
|
||||
..props
|
||||
})
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::{Checkbox, Label};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ExampleProps {
|
||||
pub disabled: bool,
|
||||
|
@ -12,50 +8,29 @@ pub struct ExampleProps {
|
|||
pub large: bool,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<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>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example(props: &ExampleProps) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<Label>{"Assign responsability"}</Label>
|
||||
<Checkbox
|
||||
disabled={props.disabled}
|
||||
inline={props.inline}
|
||||
large={props.large}
|
||||
label={html!("Gilad Gray")}
|
||||
/>
|
||||
<Checkbox
|
||||
disabled={props.disabled}
|
||||
inline={props.inline}
|
||||
large={props.large}
|
||||
label={html!("Jason Killian")}
|
||||
/>
|
||||
<Checkbox
|
||||
disabled={props.disabled}
|
||||
inline={props.inline}
|
||||
large={props.large}
|
||||
label={html!("Antoine Llorca")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for CheckboxDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
CheckboxDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
disabled: 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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -43,18 +39,18 @@ impl Component for CheckboxDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Checkbox"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Checkbox"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<CheckboxProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
}
|
||||
|
@ -63,33 +59,33 @@ impl Component for CheckboxDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
CheckboxProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
disabled: !props.disabled,
|
||||
..props
|
||||
})
|
||||
checked=self.props.disabled
|
||||
label=html!("Disabled")
|
||||
})}
|
||||
checked={ctx.props().example_props.disabled}
|
||||
label={html!("Disabled")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
inline: !props.inline,
|
||||
..props
|
||||
})
|
||||
checked=self.props.inline
|
||||
label=html!("Inline")
|
||||
})}
|
||||
checked={ctx.props().example_props.inline}
|
||||
label={html!("Inline")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
large: !props.large,
|
||||
..props
|
||||
})
|
||||
checked=self.props.large
|
||||
label=html!("Large")
|
||||
})}
|
||||
checked={ctx.props().example_props.large}
|
||||
label={html!("Large")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ use yew::prelude::*;
|
|||
use yewprint::{Button, Collapse};
|
||||
|
||||
pub struct Example {
|
||||
link: ComponentLink<Self>,
|
||||
collapsed: bool,
|
||||
}
|
||||
|
||||
|
@ -14,34 +13,27 @@ impl Component for Example {
|
|||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Example {
|
||||
collapsed: true,
|
||||
link,
|
||||
}
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Example { collapsed: true }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
Msg::ToggleCollapse => self.collapsed ^= true,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let logs = include_str!("example.log");
|
||||
|
||||
html! {
|
||||
<div>
|
||||
<Button onclick=self.link.callback(|_| Msg::ToggleCollapse)>
|
||||
<Button onclick={ctx.link().callback(|_| Msg::ToggleCollapse)}>
|
||||
{"Toggle collapse"}
|
||||
</Button>
|
||||
<Collapse
|
||||
is_open=!self.collapsed
|
||||
is_open={!self.collapsed}
|
||||
keep_children_mounted=true
|
||||
>
|
||||
<pre class="bp3-code-block">
|
||||
|
|
|
@ -11,19 +11,15 @@ impl Component for CollapseDoc {
|
|||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
CollapseDoc
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
"bp3-code-block"
|
||||
|
@ -31,9 +27,9 @@ impl Component for CollapseDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Collapse"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Collapse"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer source=source>
|
||||
<ExampleContainer source={source}>
|
||||
<Example />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
|
|
|
@ -1,56 +1,31 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::{Button, ControlGroup, HtmlSelect, IconName, InputGroup};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ExampleProps {
|
||||
pub fill: bool,
|
||||
pub vertical: bool,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<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>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example(props: &ExampleProps) -> Html {
|
||||
html! {
|
||||
<ControlGroup
|
||||
fill={props.fill}
|
||||
vertical={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 Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
ControlGroupDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
fill: 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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -42,19 +38,19 @@ impl Component for ControlGroupDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"ControlGroup"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"ControlGroup"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<ControlGroupProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
>
|
||||
</ControlGroupProps>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
}
|
||||
|
@ -63,25 +59,25 @@ impl Component for ControlGroupDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
ControlGroupProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
fill: !props.fill,
|
||||
..props
|
||||
})
|
||||
checked=self.props.fill
|
||||
label=html!("Fill")
|
||||
})}
|
||||
checked={ctx.props().example_props.fill}
|
||||
label={html!("Fill")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
vertical: !props.vertical,
|
||||
..props
|
||||
})
|
||||
checked=self.props.vertical
|
||||
label=html!("Vertical")
|
||||
})}
|
||||
checked={ctx.props().example_props.vertical}
|
||||
label={html!("Vertical")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -1,48 +1,22 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::{Button, ButtonGroup, Divider};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ExampleProps {
|
||||
pub vertical: bool,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<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>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example(props: &ExampleProps) -> Html {
|
||||
html! {
|
||||
<ButtonGroup vertical={props.vertical}>
|
||||
<Button>{"File"}</Button>
|
||||
<Button>{"Edit"}</Button>
|
||||
<Divider vertical={props.vertical} />
|
||||
<Button>{"Create"}</Button>
|
||||
<Button>{"Delete"}</Button>
|
||||
<Divider vertical={props.vertical} />
|
||||
// <Button icon=IconName::Add />
|
||||
// <Button icon=IconName::Remove />
|
||||
</ButtonGroup>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,23 +14,19 @@ impl Component for DividerDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
DividerDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -39,18 +35,18 @@ impl Component for DividerDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Divider"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Divider"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<DividerProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
}
|
||||
|
@ -59,16 +55,16 @@ impl Component for DividerDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
DividerProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
vertical: !props.vertical
|
||||
})
|
||||
checked=self.props.vertical
|
||||
label=html!("Vertical")
|
||||
})}
|
||||
checked={ctx.props().example_props.vertical}
|
||||
label={html!("Vertical")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ use yewprint::{Button, Collapse, IconName, Intent};
|
|||
|
||||
pub struct ExampleContainer {
|
||||
collapsed: bool,
|
||||
props: ExampleContainerProps,
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
|
@ -23,41 +21,28 @@ impl Component for ExampleContainer {
|
|||
type Message = Msg;
|
||||
type Properties = ExampleContainerProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
ExampleContainer {
|
||||
collapsed: true,
|
||||
props,
|
||||
link,
|
||||
}
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
ExampleContainer { collapsed: true }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
Msg::ToggleSource => self.collapsed ^= true,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div class=classes!("docs-example-wrapper")>
|
||||
<div class=classes!("docs-example-frame", "docs-example-frame-row")>
|
||||
<div class=classes!("docs-example")>
|
||||
{self.props.children.clone()}
|
||||
<div class={classes!("docs-example-wrapper")}>
|
||||
<div class={classes!("docs-example-frame", "docs-example-frame-row")}>
|
||||
<div class={classes!("docs-example")}>
|
||||
{ctx.props().children.clone()}
|
||||
</div>
|
||||
{
|
||||
if let Some(props) = self.props.props.clone() {
|
||||
if let Some(props) = ctx.props().props.clone() {
|
||||
html! {
|
||||
<div class=classes!("docs-example-options")>
|
||||
<div class={classes!("docs-example-options")}>
|
||||
{props}
|
||||
</div>
|
||||
}
|
||||
|
@ -66,21 +51,21 @@ impl Component for ExampleContainer {
|
|||
}
|
||||
}
|
||||
</div>
|
||||
<div class=classes!("docs-source")>
|
||||
<div class={classes!("docs-source")}>
|
||||
<Button
|
||||
icon=IconName::Code
|
||||
fill={true}
|
||||
intent={Intent::Primary}
|
||||
minimal={true}
|
||||
onclick=self.link.callback(|_| Msg::ToggleSource)
|
||||
icon={IconName::Code}
|
||||
fill={{true}}
|
||||
intent={{Intent::Primary}}
|
||||
minimal={{true}}
|
||||
onclick={ctx.link().callback(|_| Msg::ToggleSource)}
|
||||
>
|
||||
{"View source"}
|
||||
</Button>
|
||||
<Collapse
|
||||
is_open=!self.collapsed
|
||||
is_open={!self.collapsed}
|
||||
keep_children_mounted=true
|
||||
>
|
||||
{self.props.source.clone()}
|
||||
{ctx.props().source.clone()}
|
||||
</Collapse>
|
||||
</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_rules! build_example_prop_component {
|
||||
($name:ident for $prop_component:ty => $($view:tt)*) => {
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct $name {
|
||||
callback: Callback<$prop_component>,
|
||||
props: $prop_component,
|
||||
example_props: $prop_component
|
||||
}
|
||||
|
||||
impl Component for $name {
|
||||
type Message = ();
|
||||
type Properties = Self;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
props
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
ctx.props().clone()
|
||||
}
|
||||
|
||||
$($view)*
|
||||
}
|
||||
|
||||
impl $name {
|
||||
/// Propagate the prop changes to the parent so the example is
|
||||
/// re-rendered.
|
||||
fn update_props<T>(
|
||||
&self,
|
||||
props: &Self,
|
||||
updater: impl Fn($prop_component, T) -> $prop_component + 'static,
|
||||
) -> Callback<T> {
|
||||
let props = self.props.clone();
|
||||
self.callback.clone().reform(move |event| updater(props.clone(), event))
|
||||
let example_props = props.example_props.clone();
|
||||
self.callback
|
||||
.clone()
|
||||
.reform(move |event| updater(example_props.clone(), event))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2,8 +2,6 @@ use yew::prelude::*;
|
|||
use yewprint::{HtmlSelect, Text};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
link: ComponentLink<Self>,
|
||||
log_level: LogLevel,
|
||||
}
|
||||
|
||||
|
@ -19,29 +17,18 @@ impl Component for Example {
|
|||
type Message = LogLevel;
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Example {
|
||||
props,
|
||||
link,
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div style="width: 400px; text-align: center;">
|
||||
<HtmlSelect<LogLevel>
|
||||
|
@ -53,13 +40,13 @@ impl Component for Example {
|
|||
(LogLevel::Error, "ERROR".to_string()),
|
||||
(LogLevel::Off, "OFF".to_string()),
|
||||
]}
|
||||
minimal=self.props.minimal
|
||||
fill=self.props.fill
|
||||
disabled=self.props.disabled
|
||||
large=self.props.large
|
||||
value=Some(self.log_level)
|
||||
onchange=self.link.callback(|x| x)
|
||||
title=format!("Selected: {:?}", self.log_level)
|
||||
minimal={ctx.props().minimal}
|
||||
fill={ctx.props().fill}
|
||||
disabled={ctx.props().disabled}
|
||||
large={ctx.props().large}
|
||||
value={Some(self.log_level)}
|
||||
onchange={ctx.link().callback(|x| x)}
|
||||
title={format!("Selected: {:?}", self.log_level)}
|
||||
/>
|
||||
<Text>{format!("Selected: {:?}", self.log_level)}</Text>
|
||||
</div>
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for HtmlSelectDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
HtmlSelectDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
minimal: 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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -44,19 +40,19 @@ impl Component for HtmlSelectDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"HtmlSelect"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"HtmlSelect"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<div>
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<HtmlSelectProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -66,41 +62,41 @@ impl Component for HtmlSelectDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
HtmlSelectProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
minimal: !props.minimal,
|
||||
..props
|
||||
})
|
||||
checked=self.props.minimal
|
||||
label=html!("Minimal")
|
||||
})}
|
||||
checked={ctx.props().example_props.minimal}
|
||||
label={html!("Minimal")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps{
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps{
|
||||
fill: !props.fill,
|
||||
..props
|
||||
})
|
||||
checked=self.props.fill
|
||||
label=html!("Fill")
|
||||
})}
|
||||
checked={ctx.props().example_props.fill}
|
||||
label={html!("Fill")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
disabled: !props.disabled,
|
||||
..props
|
||||
})
|
||||
checked=self.props.disabled
|
||||
label=html!("Disabled")
|
||||
})}
|
||||
checked={ctx.props().example_props.disabled}
|
||||
label={html!("Disabled")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps{
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps{
|
||||
large: !props.large,
|
||||
..props
|
||||
})
|
||||
checked=self.props.large
|
||||
label=html!("Large")
|
||||
})}
|
||||
checked={ctx.props().example_props.large}
|
||||
label={html!("Large")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -1,26 +1,11 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::{Icon, IconName};
|
||||
|
||||
pub struct Example {}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
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>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example() -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<Icon icon={IconName::Print} />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,19 +11,15 @@ impl Component for IconDoc {
|
|||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
IconDoc
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
"bp3-code-block"
|
||||
|
@ -31,9 +27,9 @@ impl Component for IconDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Icon"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Icon"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer source=source>
|
||||
<ExampleContainer source={source}>
|
||||
<Example />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use gloo::dialogs::alert;
|
||||
use web_sys::HtmlInputElement;
|
||||
use yew::prelude::*;
|
||||
use yewprint::{Button, IconName, InputGroup, Tag};
|
||||
|
||||
pub struct Example {
|
||||
link: ComponentLink<Self>,
|
||||
props: ExampleProps,
|
||||
histogram_value: String,
|
||||
password_value: String,
|
||||
password_strength: Html,
|
||||
|
@ -29,22 +29,12 @@ pub enum Msg {
|
|||
Noop,
|
||||
}
|
||||
|
||||
macro_rules! alert {
|
||||
($($arg:tt)*) => {
|
||||
yew::services::DialogService::alert(&format!(
|
||||
$($arg)*
|
||||
))
|
||||
};
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = Msg;
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Example {
|
||||
props,
|
||||
link,
|
||||
histogram_value: Default::default(),
|
||||
password_value: 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 {
|
||||
Msg::AddHistogramEntry => {
|
||||
alert!("You sent: {}", self.histogram_value);
|
||||
alert(&format!("You sent: {}", self.histogram_value));
|
||||
self.histogram_value = Default::default();
|
||||
true
|
||||
}
|
||||
|
@ -64,7 +54,7 @@ impl Component for Example {
|
|||
true
|
||||
}
|
||||
Msg::AddPasswordEntry => {
|
||||
alert!("You sent: {}", self.password_value);
|
||||
alert(&format!("You sent: {}", self.password_value));
|
||||
self.password_value = Default::default();
|
||||
true
|
||||
}
|
||||
|
@ -81,7 +71,7 @@ impl Component for Example {
|
|||
true
|
||||
}
|
||||
Msg::AddTagsEntry => {
|
||||
alert!("You sent: {}", self.tags_value);
|
||||
alert(&format!("You sent: {}", self.tags_value));
|
||||
self.tags_value = Default::default();
|
||||
true
|
||||
}
|
||||
|
@ -93,74 +83,76 @@ impl Component for Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<>
|
||||
<InputGroup
|
||||
fill=self.props.fill
|
||||
large=self.props.large
|
||||
small=self.props.small
|
||||
round=self.props.round
|
||||
disabled=self.props.disabled
|
||||
left_icon=IconName::Filter
|
||||
fill={ctx.props().fill}
|
||||
large={ctx.props().large}
|
||||
small={ctx.props().small}
|
||||
round={ctx.props().round}
|
||||
disabled={ctx.props().disabled}
|
||||
left_icon={IconName::Filter}
|
||||
placeholder={"Filter histogram..."}
|
||||
value=self.histogram_value.clone()
|
||||
oninput=self.link.callback(|e: InputData| Msg::UpdateHistogram(e.value))
|
||||
onkeydown=self.link.callback(|e: KeyboardEvent| {
|
||||
value={self.histogram_value.clone()}
|
||||
oninput={ctx.link().callback(|e: InputEvent| {
|
||||
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 }
|
||||
})
|
||||
})}
|
||||
/>
|
||||
<InputGroup
|
||||
fill=self.props.fill
|
||||
large=self.props.large
|
||||
small=self.props.small
|
||||
round=self.props.round
|
||||
disabled=self.props.disabled
|
||||
left_element=self.password_strength.clone()
|
||||
fill={ctx.props().fill}
|
||||
large={ctx.props().large}
|
||||
small={ctx.props().small}
|
||||
round={ctx.props().round}
|
||||
disabled={ctx.props().disabled}
|
||||
left_element={self.password_strength.clone()}
|
||||
placeholder={"Enter your password..."}
|
||||
value=self.password_value.clone()
|
||||
oninput=self.link.callback(|e: InputData| Msg::UpdatePassword(e.value))
|
||||
onkeydown=self.link.callback(|e: KeyboardEvent| {
|
||||
value={self.password_value.clone()}
|
||||
oninput={ctx.link().callback(|e: InputEvent| {
|
||||
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 }
|
||||
})
|
||||
right_element=html! {
|
||||
})}
|
||||
right_element={{ html! {
|
||||
<Button
|
||||
icon=IconName::Lock
|
||||
minimal=true
|
||||
disabled=self.props.disabled
|
||||
icon={IconName::Lock}
|
||||
minimal={true}
|
||||
disabled={ctx.props().disabled}
|
||||
/>
|
||||
}
|
||||
}}}
|
||||
/>
|
||||
<InputGroup
|
||||
fill=self.props.fill
|
||||
large=self.props.large
|
||||
small=self.props.small
|
||||
round=self.props.round
|
||||
disabled=self.props.disabled
|
||||
left_icon=IconName::Tag
|
||||
fill={ctx.props().fill}
|
||||
large={ctx.props().large}
|
||||
small={ctx.props().small}
|
||||
round={ctx.props().round}
|
||||
disabled={ctx.props().disabled}
|
||||
left_icon={IconName::Tag}
|
||||
placeholder={"Find tags"}
|
||||
value=self.tags_value.clone()
|
||||
oninput=self.link.callback(|e: InputData| Msg::UpdateTags(e.value))
|
||||
onkeydown=self.link.callback(|e: KeyboardEvent| {
|
||||
value={self.tags_value.clone()}
|
||||
oninput={ctx.link().callback(|e: InputEvent| {
|
||||
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 }
|
||||
})
|
||||
right_element=html! {
|
||||
<Tag
|
||||
minimal=true
|
||||
round=self.props.round
|
||||
>
|
||||
{{10000 / 1.max(self.tags_value.len().pow(2))}}
|
||||
</Tag>
|
||||
}
|
||||
})}
|
||||
right_element={{
|
||||
html!{
|
||||
<Tag
|
||||
minimal={true}
|
||||
round={ctx.props().round}
|
||||
>
|
||||
{ (10000 / 1.max(self.tags_value.len().pow(2))).to_string() }
|
||||
</Tag>
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for InputGroupDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
InputGroupDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
disabled: 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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -45,19 +41,19 @@ impl Component for InputGroupDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"InputGroup"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"InputGroup"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<InputGroupProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
>
|
||||
</InputGroupProps>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
}
|
||||
|
@ -66,49 +62,49 @@ impl Component for InputGroupDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
InputGroupProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
disabled: !props.disabled,
|
||||
..props
|
||||
})
|
||||
checked=self.props.disabled
|
||||
label=html!("Disabled")
|
||||
})}
|
||||
checked={ctx.props().example_props.disabled}
|
||||
label={html!("Disabled")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
fill: !props.fill,
|
||||
..props
|
||||
})
|
||||
checked=self.props.fill
|
||||
label=html!("Fill")
|
||||
})}
|
||||
checked={ctx.props().example_props.fill}
|
||||
label={html!("Fill")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
large: !props.large,
|
||||
..props
|
||||
})
|
||||
checked=self.props.large
|
||||
label=html!("Large")
|
||||
})}
|
||||
checked={ctx.props().example_props.large}
|
||||
label={html!("Large")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
small: !props.small,
|
||||
..props
|
||||
})
|
||||
checked=self.props.small
|
||||
label=html!("Small")
|
||||
})}
|
||||
checked={ctx.props().example_props.small}
|
||||
label={html!("Small")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
round: !props.round,
|
||||
..props
|
||||
})
|
||||
checked=self.props.round
|
||||
label=html!("Round")
|
||||
})}
|
||||
checked={ctx.props().example_props.round}
|
||||
label={html!("Round")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -32,17 +32,10 @@ pub use app::*;
|
|||
pub use example::*;
|
||||
pub use logo::*;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! log {
|
||||
($s:expr $(,$args:expr)*) => {{
|
||||
yew::services::ConsoleService::log(format!($s $(,$args)*).as_str());
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! include_raw_html {
|
||||
($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()
|
||||
.unwrap()
|
||||
.document()
|
||||
|
@ -88,27 +81,23 @@ macro_rules! build_source_code_component {
|
|||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
let url = SourceCodeUrl::generate_url();
|
||||
|
||||
Self { url }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
use yewprint::Text;
|
||||
|
||||
html! {
|
||||
<a
|
||||
class=classes!("bp3-text-muted")
|
||||
href=self.url.clone()
|
||||
class={classes!("bp3-text-muted")}
|
||||
href={self.url.clone()}
|
||||
target="_blank"
|
||||
>
|
||||
<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> {
|
||||
#[cfg(feature = "console_error_panic_hook")]
|
||||
console_error_panic_hook::set_once();
|
||||
yew::start_app::<app::App>();
|
||||
yew::start_app::<app::AppRoot>();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,37 +1,12 @@
|
|||
use yew::prelude::*;
|
||||
|
||||
pub struct Logo {
|
||||
props: LogoProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct LogoProps {
|
||||
#[prop_or_default]
|
||||
pub class: Classes,
|
||||
}
|
||||
|
||||
impl Component for Logo {
|
||||
type Message = ();
|
||||
type Properties = LogoProps;
|
||||
|
||||
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())
|
||||
}
|
||||
#[function_component(Logo)]
|
||||
pub fn logo(props: &LogoProps) -> Html {
|
||||
crate::include_raw_html!("logo.svg", &props.class.to_string())
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
use crate::{DocMenu, Logo};
|
||||
use std::borrow::Cow;
|
||||
use yew::prelude::*;
|
||||
use yewprint::{Icon, IconName, Menu, MenuDivider, MenuItem};
|
||||
|
||||
pub struct Example {
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
pub struct Example {}
|
||||
|
||||
pub enum Msg {
|
||||
GoToMenu(DocMenu),
|
||||
|
@ -15,107 +12,106 @@ impl Component for Example {
|
|||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Self { link }
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let custom_icon = html! {
|
||||
<Logo class={classes!("custom-icon")} />
|
||||
};
|
||||
|
||||
let share_icon = html! {
|
||||
<Icon icon={IconName::Share} />
|
||||
};
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<>
|
||||
<Menu>
|
||||
<MenuItem
|
||||
text={html!("Custom SVG icon")}
|
||||
icon_html=html! {
|
||||
<Logo class=classes!("custom-icon") />
|
||||
}
|
||||
icon_html={custom_icon}
|
||||
/>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
icon=IconName::NewTextBox
|
||||
text={html!{"New text box"}}
|
||||
href=Cow::Borrowed("#menu")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
||||
icon={IconName::NewTextBox}
|
||||
text={html!("New text box")}
|
||||
href={"#menu"}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||
/>
|
||||
<MenuItem
|
||||
icon=IconName::NewObject
|
||||
text={html!{"New object"}}
|
||||
href=Cow::Borrowed("#menu")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
||||
icon={IconName::NewObject}
|
||||
text={html!("New object")}
|
||||
href={"#menu"}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||
/>
|
||||
<MenuItem
|
||||
icon=IconName::NewLink
|
||||
text={html!{"New link"}}
|
||||
href=Cow::Borrowed("#menu")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
||||
icon={IconName::NewLink}
|
||||
text={html!("New link")}
|
||||
href={"#menu"}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||
/>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
icon=IconName::Cog
|
||||
text={html!{"Settings"}}
|
||||
label=html! {
|
||||
<Icon icon=IconName::Share />
|
||||
}
|
||||
href=Cow::Borrowed("#menu")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
||||
icon={IconName::Cog}
|
||||
text={html!("Settings")}
|
||||
label={share_icon}
|
||||
href={"#menu"}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||
/>
|
||||
</Menu>
|
||||
<Menu>
|
||||
<MenuDivider title={html!("Edit")} />
|
||||
<MenuItem
|
||||
icon=IconName::Cut
|
||||
icon={IconName::Cut}
|
||||
text={html!("Cut")}
|
||||
label={html!("Ctrl+X")}
|
||||
href=Cow::Borrowed("#menu")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
||||
href={"#menu"}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||
/>
|
||||
<MenuItem
|
||||
icon=IconName::Duplicate
|
||||
icon={IconName::Duplicate}
|
||||
text={html!("Copy")}
|
||||
label={html!("Ctrl+C")}
|
||||
href=Cow::Borrowed("#menu")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
||||
href={"#menu"}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||
/>
|
||||
<MenuItem
|
||||
icon=IconName::Clipboard
|
||||
icon={IconName::Clipboard}
|
||||
text={html!("Paste")}
|
||||
label={html!("Ctrl+V")}
|
||||
disabled=true
|
||||
/>
|
||||
<MenuDivider title={html!("Text")} />
|
||||
<MenuItem
|
||||
icon=IconName::AlignLeft
|
||||
icon={IconName::AlignLeft}
|
||||
text={html!("Alignment")}
|
||||
href=Cow::Borrowed("#menu")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
||||
href={"#menu"}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||
/>
|
||||
<MenuItem
|
||||
icon=IconName::Style
|
||||
icon={IconName::Style}
|
||||
text={html!("Style")}
|
||||
href=Cow::Borrowed("#menu")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
||||
href={"#menu"}
|
||||
onclick={ctx.link()
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||
/>
|
||||
<MenuItem
|
||||
icon=IconName::Asterisk
|
||||
icon={IconName::Asterisk}
|
||||
text={html!("Miscellaneous")}
|
||||
href=Cow::Borrowed("#menu")
|
||||
onclick=self.link
|
||||
.callback(|_| Msg::GoToMenu(DocMenu::Menu))
|
||||
href={"#menu"}
|
||||
onclick={ctx.link().callback(|_| Msg::GoToMenu(DocMenu::Menu))}
|
||||
/>
|
||||
</Menu>
|
||||
</>
|
||||
|
|
|
@ -11,19 +11,15 @@ impl Component for MenuDoc {
|
|||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
MenuDoc
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
"bp3-code-block"
|
||||
|
@ -31,9 +27,9 @@ impl Component for MenuDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Menu"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Menu"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer source=source>
|
||||
<ExampleContainer source={source}>
|
||||
<Example />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
use std::borrow::Cow;
|
||||
use yew::prelude::*;
|
||||
use yewprint::{Button, Callout, IconName, Intent, NumericInput};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
link: ComponentLink<Self>,
|
||||
value: i32,
|
||||
value_two: i32,
|
||||
}
|
||||
|
@ -29,16 +26,14 @@ impl Component for Example {
|
|||
type Message = Msg;
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Example {
|
||||
props,
|
||||
link,
|
||||
value: 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 {
|
||||
Msg::Reset => {
|
||||
self.value = 4;
|
||||
|
@ -54,52 +49,43 @@ impl Component for Example {
|
|||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<>
|
||||
<NumericInput<i32>
|
||||
disabled=self.props.disabled
|
||||
fill=self.props.large
|
||||
value=self.value
|
||||
disabled={ctx.props().disabled}
|
||||
fill={ctx.props().large}
|
||||
value={self.value}
|
||||
bounds={-105..}
|
||||
increment=10
|
||||
placeholder=String::from("Greater or equal to -105...")
|
||||
onchange=self.link.callback(|x| Msg::UpdateValue(x))
|
||||
disable_buttons=self.props.disable_buttons
|
||||
buttons_on_the_left=self.props.buttons_on_the_left
|
||||
left_icon=self.props.left_icon.then(|| IconName::Dollar)
|
||||
placeholder={String::from("Greater or equal to -105...")}
|
||||
onchange={ctx.link().callback(|x| Msg::UpdateValue(x))}
|
||||
disable_buttons={ctx.props().disable_buttons}
|
||||
buttons_on_the_left={ctx.props().buttons_on_the_left}
|
||||
left_icon={ctx.props().left_icon.then(|| IconName::Dollar)}
|
||||
/>
|
||||
<NumericInput<i32>
|
||||
disabled=self.props.disabled
|
||||
fill=self.props.fill
|
||||
large=self.props.large
|
||||
value=self.value_two
|
||||
disabled={ctx.props().disabled}
|
||||
fill={ctx.props().fill}
|
||||
large={ctx.props().large}
|
||||
value={self.value_two}
|
||||
bounds={-10..=10}
|
||||
increment=1
|
||||
placeholder=String::from("Integer between -10 and 10")
|
||||
onchange=self.link.callback(|x| Msg::UpdateValueTwo(x))
|
||||
disable_buttons=self.props.disable_buttons
|
||||
buttons_on_the_left=self.props.buttons_on_the_left
|
||||
left_icon=self.props.left_icon.then(|| IconName::Dollar)
|
||||
placeholder={String::from("Integer between -10 and 10")}
|
||||
onchange={ctx.link().callback(|x| Msg::UpdateValueTwo(x))}
|
||||
disable_buttons={ctx.props().disable_buttons}
|
||||
buttons_on_the_left={ctx.props().buttons_on_the_left}
|
||||
left_icon={ctx.props().left_icon.then(|| IconName::Dollar)}
|
||||
/>
|
||||
<Button
|
||||
icon=IconName::Refresh
|
||||
onclick=self.link.callback(|_| Msg::Reset)
|
||||
icon={IconName::Refresh}
|
||||
onclick={ctx.link().callback(|_| Msg::Reset)}
|
||||
>
|
||||
{"Reset at 4"}
|
||||
</Button>
|
||||
<Callout
|
||||
title=Cow::Borrowed("Selected values")
|
||||
intent=Intent::Primary
|
||||
title={"Selected values"}
|
||||
intent={Intent::Primary}
|
||||
>
|
||||
<ul>
|
||||
<li>{self.value}</li>
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for NumericInputDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
NumericInputDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
fill: 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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -46,19 +42,19 @@ impl Component for NumericInputDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"NumericInput"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"NumericInput"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<div>
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<NumericInputProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -68,57 +64,57 @@ impl Component for NumericInputDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
NumericInputProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
fill: !props.fill,
|
||||
..props
|
||||
})
|
||||
checked=self.props.fill
|
||||
label=html!("Fill")
|
||||
})}
|
||||
checked={ctx.props().example_props.fill}
|
||||
label={html!("Fill")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
disabled: !props.disabled,
|
||||
..props
|
||||
})
|
||||
checked=self.props.disabled
|
||||
label=html!("Disabled")
|
||||
})}
|
||||
checked={ctx.props().example_props.disabled}
|
||||
label={html!("Disabled")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
large: !props.large,
|
||||
..props
|
||||
})
|
||||
checked=self.props.large
|
||||
label=html!("Large")
|
||||
})}
|
||||
checked={ctx.props().example_props.large}
|
||||
label={html!("Large")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
disable_buttons: !props.disable_buttons,
|
||||
..props
|
||||
})
|
||||
checked=self.props.disable_buttons
|
||||
label=html!("Disable buttons")
|
||||
})}
|
||||
checked={ctx.props().example_props.disable_buttons}
|
||||
label={html!("Disable buttons")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
buttons_on_the_left: !props.buttons_on_the_left,
|
||||
..props
|
||||
})
|
||||
checked=self.props.buttons_on_the_left
|
||||
label=html!("Buttons on the left")
|
||||
})}
|
||||
checked={ctx.props().example_props.buttons_on_the_left}
|
||||
label={html!("Buttons on the left")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
left_icon: !props.left_icon,
|
||||
..props
|
||||
})
|
||||
checked=self.props.left_icon
|
||||
label=html!("Left icon")
|
||||
})}
|
||||
checked={ctx.props().example_props.left_icon}
|
||||
label={html!("Left icon")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ use yew::prelude::*;
|
|||
use yewprint::{Button, Intent, PanelStack, PanelStackState, Text};
|
||||
|
||||
pub struct Example {
|
||||
link: ComponentLink<Self>,
|
||||
props: ExampleProps,
|
||||
state: PanelStackState,
|
||||
}
|
||||
|
||||
|
@ -23,37 +21,38 @@ impl Component for Example {
|
|||
type Message = ExampleMessage;
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
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>
|
||||
<Button
|
||||
intent=Intent::Primary
|
||||
onclick=link.callback(|_| ExampleMessage::OpenPanel2)
|
||||
intent={Intent::Primary}
|
||||
onclick={ctx.link().callback(|_| ExampleMessage::OpenPanel2)}
|
||||
>
|
||||
{"Open panel 2"}
|
||||
</Button>
|
||||
</div>
|
||||
})
|
||||
.with_title(html! {
|
||||
<Text class=classes!("bp3-heading") ellipsize=true>
|
||||
<Text class={classes!("bp3-heading")} ellipsize=true>
|
||||
{"Root Panel"}
|
||||
</Text>
|
||||
})
|
||||
.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 {
|
||||
// Open
|
||||
ExampleMessage::OpenPanel2 => self
|
||||
.state
|
||||
.open_panel(html! {
|
||||
<div class=classes!("docs-panel-stack-contents-example")>
|
||||
<div class={classes!("docs-panel-stack-contents-example")}>
|
||||
<Button
|
||||
intent=Intent::Success
|
||||
onclick=self.link.callback(|_| ExampleMessage::OpenPanel2)
|
||||
intent={Intent::Success}
|
||||
onclick={ctx.link().callback(|_| ExampleMessage::OpenPanel2)}
|
||||
>
|
||||
{"Open another panel 2"}
|
||||
</Button>
|
||||
|
@ -61,7 +60,7 @@ impl Component for Example {
|
|||
</div>
|
||||
})
|
||||
.with_title(html! {
|
||||
<Text class=classes!("bp3-heading") ellipsize=true>
|
||||
<Text class={classes!("bp3-heading")} ellipsize=true>
|
||||
{"Panel 2"}
|
||||
</Text>
|
||||
})
|
||||
|
@ -71,70 +70,34 @@ impl Component for Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<PanelStack
|
||||
state=self.state.clone()
|
||||
onclose=self.link.callback(|_| ExampleMessage::ClosePanel)
|
||||
class=classes!("docs-panel-stack-example")
|
||||
state={self.state.clone()}
|
||||
onclose={ctx.link().callback(|_| ExampleMessage::ClosePanel)}
|
||||
class={classes!("docs-panel-stack-example")}
|
||||
/>
|
||||
</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 {
|
||||
link: ComponentLink<Self>,
|
||||
counter: i64,
|
||||
}
|
||||
|
||||
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! {
|
||||
html! {
|
||||
<div>
|
||||
<p>{"Counter: "}{ *counter}</p>
|
||||
<div>
|
||||
<p>{"Counter: "}{self.counter}</p>
|
||||
<div>
|
||||
<Button onclick=self.link.callback(|_| Panel2Message::AddOne)>
|
||||
{"Add 1"}
|
||||
</Button>
|
||||
</div>
|
||||
<Button {onclick}>{ "Add 1" }</Button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for PanelStackDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
PanelStackDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
animate: true,
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -42,14 +38,14 @@ impl Component for PanelStackDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"PanelStack"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"PanelStack"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<div>
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=None
|
||||
source={source}
|
||||
props={None}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::{Intent, ProgressBar};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ExampleProps {
|
||||
pub intent: Option<Intent>,
|
||||
|
@ -12,32 +8,14 @@ pub struct ExampleProps {
|
|||
pub stripes: bool,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
}
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<ProgressBar
|
||||
animate=self.props.animate
|
||||
stripes=self.props.stripes
|
||||
intent=self.props.intent
|
||||
value=0.3
|
||||
/>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example(props: &ExampleProps) -> Html {
|
||||
html! {
|
||||
<ProgressBar
|
||||
animate={props.animate}
|
||||
stripes={props.stripes}
|
||||
intent={props.intent}
|
||||
value=0.3
|
||||
/>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for ProgressBarDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
ProgressBarDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
intent: None,
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -43,18 +39,18 @@ impl Component for ProgressBarDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"ProgressBar"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"ProgressBar"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<ProgressBarProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
}
|
||||
|
@ -63,26 +59,26 @@ impl Component for ProgressBarDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
ProgressBarProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<div>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
stripes: !props.stripes,
|
||||
..props
|
||||
})
|
||||
checked=self.props.stripes
|
||||
label=html!("Stripes")
|
||||
})}
|
||||
checked={ctx.props().example_props.stripes}
|
||||
label={html!("Stripes")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
animate: !props.animate,
|
||||
..props
|
||||
})
|
||||
checked=self.props.animate
|
||||
label=html!("Animate")
|
||||
})}
|
||||
checked={ctx.props().example_props.animate}
|
||||
label={html!("Animate")}
|
||||
/>
|
||||
<p>{"Select intent:"}</p>
|
||||
<HtmlSelect<Option<Intent>>
|
||||
|
@ -93,10 +89,10 @@ crate::build_example_prop_component! {
|
|||
(Some(Intent::Warning), "Warning".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,
|
||||
..props
|
||||
})
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,8 +2,6 @@ use yew::prelude::*;
|
|||
use yewprint::{Label, Radio, RadioGroup};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
link: ComponentLink<Self>,
|
||||
selected_value: Lunch,
|
||||
}
|
||||
|
||||
|
@ -22,15 +20,13 @@ impl Component for Example {
|
|||
type Message = Msg;
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Example {
|
||||
props,
|
||||
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 {
|
||||
Msg::ValueUpdate(value) => {
|
||||
self.selected_value = value;
|
||||
|
@ -39,51 +35,42 @@ impl Component for Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<>
|
||||
<div>
|
||||
<Radio
|
||||
label=html!("Blue pill")
|
||||
inline=self.props.inline
|
||||
disabled=self.props.disabled
|
||||
large=self.props.large
|
||||
name="group".to_string()
|
||||
label={html!("Blue pill")}
|
||||
inline={ctx.props().inline}
|
||||
disabled={ctx.props().disabled}
|
||||
large={ctx.props().large}
|
||||
name={"group".to_string()}
|
||||
/>
|
||||
<Radio
|
||||
label=html!("Red pill")
|
||||
inline=self.props.inline
|
||||
disabled=self.props.disabled
|
||||
large=self.props.large
|
||||
name="group".to_string()
|
||||
label={html!("Red pill")}
|
||||
inline={ctx.props().inline}
|
||||
disabled={ctx.props().disabled}
|
||||
large={ctx.props().large}
|
||||
name={"group".to_string()}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<RadioGroup<Lunch>
|
||||
label=Some(html!(
|
||||
label={Some(html!(
|
||||
<Label>
|
||||
{"Determine Lunch"}
|
||||
</Label>
|
||||
))
|
||||
options=vec![
|
||||
))}
|
||||
options={vec![
|
||||
(Lunch::Soup, "Soup".to_string()),
|
||||
(Lunch::Salad, "Salad".to_string()),
|
||||
(Lunch::Sandwich, "Sandwich".to_string()),
|
||||
]
|
||||
value=self.selected_value
|
||||
onchange=self.link.callback(|v| Msg::ValueUpdate(v))
|
||||
inline=self.props.inline
|
||||
disabled=self.props.disabled
|
||||
large=self.props.large
|
||||
]}
|
||||
value={self.selected_value}
|
||||
onchange={ctx.link().callback(|v| Msg::ValueUpdate(v))}
|
||||
inline={ctx.props().inline}
|
||||
disabled={ctx.props().disabled}
|
||||
large={ctx.props().large}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for RadioDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
RadioDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
disabled: 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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -43,18 +39,18 @@ impl Component for RadioDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Radio"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Radio"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<RadioProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
}
|
||||
|
@ -63,33 +59,33 @@ impl Component for RadioDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
RadioProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
disabled: !props.disabled,
|
||||
..props
|
||||
})
|
||||
checked=self.props.disabled
|
||||
label=html!("Disabled")
|
||||
})}
|
||||
checked={ctx.props().example_props.disabled}
|
||||
label={html!("Disabled")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
inline: !props.inline,
|
||||
..props
|
||||
})
|
||||
checked=self.props.inline
|
||||
label=html!("Inline")
|
||||
})}
|
||||
checked={ctx.props().example_props.inline}
|
||||
label={html!("Inline")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
large: !props.large,
|
||||
..props
|
||||
})
|
||||
checked=self.props.large
|
||||
label=html!("Large")
|
||||
})}
|
||||
checked={ctx.props().example_props.large}
|
||||
label={html!("Large")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -3,11 +3,9 @@ use yew::prelude::*;
|
|||
use yewprint::{Intent, Slider, Tag};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
float: f64,
|
||||
integer: i32,
|
||||
log_level: Option<LogLevel>,
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
|
@ -27,17 +25,15 @@ impl Component for Example {
|
|||
type Message = Msg;
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Example {
|
||||
props,
|
||||
float: 1.2,
|
||||
integer: 30,
|
||||
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 {
|
||||
Msg::FloatUpdate(value) => {
|
||||
self.float = value;
|
||||
|
@ -53,16 +49,7 @@ impl Component for Example {
|
|||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let percentage_labels = (0..=100)
|
||||
.step_by(1)
|
||||
.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%"
|
||||
>
|
||||
<Slider<f64>
|
||||
selected=self.float
|
||||
values=vec![
|
||||
selected={self.float}
|
||||
values={vec![
|
||||
(0.0, Some("0".into())),
|
||||
(0.1, None),
|
||||
(0.2, None),
|
||||
|
@ -87,43 +74,43 @@ impl Component for Example {
|
|||
(0.8, None),
|
||||
(0.9, None),
|
||||
(1.0, Some("1".into())),
|
||||
]
|
||||
intent=self.props.intent
|
||||
onchange=self.link.callback(|x| Msg::FloatUpdate(x))
|
||||
]}
|
||||
intent={ctx.props().intent}
|
||||
onchange={ctx.link().callback(|x| Msg::FloatUpdate(x))}
|
||||
/>
|
||||
<Tag
|
||||
style=Cow::Borrowed("width: 32px; margin-left: 16px")
|
||||
style={"width: 32px; margin-left: 16px"}
|
||||
minimal=true
|
||||
intent=self.props.intent
|
||||
intent={ctx.props().intent}
|
||||
>
|
||||
{format!("{:.1}", self.float)}
|
||||
</Tag>
|
||||
</div>
|
||||
<Slider<i32>
|
||||
values=percentage_labels
|
||||
selected=self.integer
|
||||
intent=self.props.intent
|
||||
value_label=Cow::Owned(format!("{}%", self.integer))
|
||||
onchange=self.link.callback(|x| Msg::IntegerUpdate(x))
|
||||
values={percentage_labels}
|
||||
selected={self.integer}
|
||||
intent={ctx.props().intent}
|
||||
value_label={Cow::Owned(format!("{}%", self.integer))}
|
||||
onchange={ctx.link().callback(|x| Msg::IntegerUpdate(x))}
|
||||
/>
|
||||
<Slider<LogLevel>
|
||||
values=vec![
|
||||
values={vec![
|
||||
(LogLevel::Off, Some("OFF".into())),
|
||||
(LogLevel::Error, Some("ERROR".into())),
|
||||
(LogLevel::Warn, Some("WARN".into())),
|
||||
(LogLevel::Info, Some("INFO".into())),
|
||||
(LogLevel::Debug, Some("DEBUG".into())),
|
||||
(LogLevel::Trace, Some("TRACE".into())),
|
||||
]
|
||||
intent=self.props.intent
|
||||
selected=self.log_level.clone()
|
||||
onchange=self.link.callback(|x| Msg::LogLevelUpdate(x))
|
||||
]}
|
||||
intent={ctx.props().intent}
|
||||
selected={self.log_level.clone()}
|
||||
onchange={ctx.link().callback(|x| Msg::LogLevelUpdate(x))}
|
||||
/>
|
||||
<Slider<()>
|
||||
values=vec![((), Some("Neo".into()))]
|
||||
intent=self.props.intent
|
||||
selected=()
|
||||
onchange=self.link.callback(|_| Msg::Noop)
|
||||
values={vec![((), Some("Neo".into()))]}
|
||||
intent={ctx.props().intent}
|
||||
selected={()}
|
||||
onchange={ctx.link().callback(|_| Msg::Noop)}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for SliderDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
SliderDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
vertical: false,
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -42,21 +38,21 @@ impl Component for SliderDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Slider"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Slider"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<SliderProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
<H2>{"Edge Cases"}</H2>
|
||||
<div class=classes!("bp3-running-text")>
|
||||
<div class={classes!("bp3-running-text")}>
|
||||
<ul>
|
||||
<li>
|
||||
<p>
|
||||
|
@ -108,17 +104,17 @@ impl Component for SliderDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
SliderProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
vertical: !props.vertical,
|
||||
..props
|
||||
})
|
||||
checked=self.props.vertical
|
||||
label=html!("Vertical")
|
||||
})}
|
||||
checked={ctx.props().example_props.vertical}
|
||||
label={html!("Vertical")}
|
||||
disabled=true
|
||||
/>
|
||||
<p>{"Select intent:"}</p>
|
||||
|
@ -130,10 +126,10 @@ crate::build_example_prop_component! {
|
|||
(Some(Intent::Warning), "Warning".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,
|
||||
..props
|
||||
})
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -1,45 +1,20 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::{Intent, Spinner};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ExampleProps {
|
||||
pub intent: Option<Intent>,
|
||||
pub size: u32,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<Spinner
|
||||
size=self.props.size as f32
|
||||
intent=self.props.intent
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example(props: &ExampleProps) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<Spinner
|
||||
size={props.size as f32}
|
||||
intent={props.intent}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for SpinnerDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
SpinnerDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
intent: None,
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -42,19 +38,19 @@ impl Component for SpinnerDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Spinner"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Spinner"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<div>
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<SpinnerProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -64,7 +60,7 @@ impl Component for SpinnerDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
SpinnerProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
|
@ -78,10 +74,10 @@ crate::build_example_prop_component! {
|
|||
(Some(Intent::Warning), "Warning".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,
|
||||
..props
|
||||
})
|
||||
})}
|
||||
/>
|
||||
<p
|
||||
style="margin-top: 5px;"
|
||||
|
@ -89,7 +85,7 @@ crate::build_example_prop_component! {
|
|||
{"Select Size:"}
|
||||
</p>
|
||||
<Slider<u32>
|
||||
selected=self.props.size
|
||||
selected={ctx.props().example_props.size}
|
||||
values={vec![
|
||||
(10, Some("10".into())),
|
||||
(20, None),
|
||||
|
@ -102,10 +98,10 @@ crate::build_example_prop_component! {
|
|||
(90, None),
|
||||
(100, Some("100".into())),
|
||||
]}
|
||||
onchange=self.update_props(|props, size| ExampleProps {
|
||||
onchange={self.update_props(ctx.props(), |props, size| ExampleProps {
|
||||
size,
|
||||
..props
|
||||
})
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::{Label, Switch};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ExampleProps {
|
||||
pub disabled: bool,
|
||||
|
@ -13,63 +9,41 @@ pub struct ExampleProps {
|
|||
pub align_right: bool,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<Label>{"Privacy settings"}</Label>
|
||||
<Switch
|
||||
disabled=self.props.disabled
|
||||
inline=self.props.inline
|
||||
large=self.props.large
|
||||
label=html!{<strong>{"Enabled"}</strong>}
|
||||
align_right=self.props.align_right
|
||||
/>
|
||||
<Switch
|
||||
disabled=self.props.disabled
|
||||
inline=self.props.inline
|
||||
large=self.props.large
|
||||
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>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example(props: &ExampleProps) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<Label>{"Privacy settings"}</Label>
|
||||
<Switch
|
||||
disabled={props.disabled}
|
||||
inline={props.inline}
|
||||
large={props.large}
|
||||
align_right={props.align_right}
|
||||
label={html!("Enabled")}
|
||||
/>
|
||||
<Switch
|
||||
disabled={props.disabled}
|
||||
inline={props.inline}
|
||||
large={props.large}
|
||||
align_right={props.align_right}
|
||||
label={html!(<em>{"Public"}</em>)}
|
||||
/>
|
||||
<Switch
|
||||
disabled={props.disabled}
|
||||
inline={props.inline}
|
||||
large={props.large}
|
||||
align_right={props.align_right}
|
||||
label={html!(<strong>{"Cooperative"}</strong>)}
|
||||
/>
|
||||
<Switch
|
||||
disabled={props.disabled}
|
||||
inline={props.inline}
|
||||
large={props.large}
|
||||
align_right={props.align_right}
|
||||
label={html!(<u>{"Containing Text"}</u>)}
|
||||
inner_label_checked={"on".to_string()}
|
||||
inner_label={"off".to_string()}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for SwitchDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
SwitchDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
disabled: 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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -44,19 +40,19 @@ impl Component for SwitchDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Switch"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Switch"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<SwitchProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
>
|
||||
</SwitchProps>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
}
|
||||
|
@ -65,41 +61,41 @@ impl Component for SwitchDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
SwitchProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
disabled: !props.disabled,
|
||||
..props
|
||||
})
|
||||
checked=self.props.disabled
|
||||
label=html!("Disabled")
|
||||
})}
|
||||
checked={ctx.props().example_props.disabled}
|
||||
label={html!("Disabled")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
inline: !props.inline,
|
||||
..props
|
||||
})
|
||||
checked=self.props.inline
|
||||
label=html!("Inline")
|
||||
})}
|
||||
checked={ctx.props().example_props.inline}
|
||||
label={html!("Inline")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
large: !props.large,
|
||||
..props
|
||||
})
|
||||
checked=self.props.large
|
||||
label=html!("Large")
|
||||
})}
|
||||
checked={ctx.props().example_props.large}
|
||||
label={html!("Large")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
align_right: !props.align_right,
|
||||
..props
|
||||
})
|
||||
checked=self.props.align_right
|
||||
label=html!("Align right")
|
||||
})}
|
||||
checked={ctx.props().example_props.align_right}
|
||||
label={html!("Align right")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ use yew::prelude::*;
|
|||
use yewprint::{Tab, Tabs};
|
||||
|
||||
pub struct Example {
|
||||
link: ComponentLink<Self>,
|
||||
props: ExampleProps,
|
||||
selected: Civilization,
|
||||
}
|
||||
|
||||
|
@ -17,15 +15,13 @@ impl Component for Example {
|
|||
type Message = Civilization;
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Example {
|
||||
link,
|
||||
props,
|
||||
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 {
|
||||
self.selected = msg;
|
||||
true
|
||||
|
@ -34,25 +30,16 @@ impl Component for Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<Tabs<Civilization>
|
||||
id="civilizations"
|
||||
animate=self.props.animate
|
||||
vertical=self.props.vertical
|
||||
selected_tab_id=self.selected
|
||||
onchange=self.link.callback(|x| x)
|
||||
tabs=vec![
|
||||
animate={ctx.props().animate}
|
||||
vertical={ctx.props().vertical}
|
||||
selected_tab_id={self.selected}
|
||||
onchange={ctx.link().callback(|x| x)}
|
||||
tabs={vec![
|
||||
Tab {
|
||||
disabled: false,
|
||||
id: Civilization::Sumer,
|
||||
|
@ -133,7 +120,7 @@ impl Component for Example {
|
|||
panel_class: Classes::default(),
|
||||
title_class: Classes::default(),
|
||||
},
|
||||
]
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for TabsDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
TabsDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
animate: true,
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -42,19 +38,19 @@ impl Component for TabsDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Tabs"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Tabs"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<div>
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<TabsProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -64,25 +60,25 @@ impl Component for TabsDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
TabsProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
animate: !props.animate,
|
||||
..props
|
||||
})
|
||||
checked=self.props.animate
|
||||
label=html!("Animate indicator")
|
||||
})}
|
||||
checked={ctx.props().example_props.animate}
|
||||
label={html!("Animate indicator")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
vertical: !props.vertical,
|
||||
..props
|
||||
})
|
||||
checked=self.props.vertical
|
||||
label=html!("Use vertical tabs")
|
||||
})}
|
||||
checked={ctx.props().example_props.vertical}
|
||||
label={html!("Use vertical tabs")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ use yew::prelude::*;
|
|||
use yewprint::{IconName, Intent, Tag};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
link: ComponentLink<Self>,
|
||||
tags: Vec<String>,
|
||||
}
|
||||
|
||||
|
@ -33,12 +31,12 @@ impl Component for Example {
|
|||
type Message = ExampleMsg;
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
let tags = props.initial_tags.clone();
|
||||
Example { props, link, tags }
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
let tags = ctx.props().initial_tags.clone();
|
||||
Example { tags }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
ExampleMsg::Remove(label) => {
|
||||
self.tags = self
|
||||
|
@ -53,43 +51,38 @@ impl Component for Example {
|
|||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
if self.props.reset_tags != props.reset_tags {
|
||||
self.tags = props.initial_tags.clone();
|
||||
}
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
fn changed(&mut self, ctx: &Context<Self>) -> bool {
|
||||
if ctx.props().reset_tags != ctx.props().reset_tags {
|
||||
self.tags = ctx.props().initial_tags.clone();
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
self.tags
|
||||
.iter()
|
||||
.map(|label| {
|
||||
let remove = {
|
||||
let label = label.clone();
|
||||
self.props.removable.then(|| {
|
||||
self.link
|
||||
ctx.props().removable.then(|| {
|
||||
ctx.link()
|
||||
.callback(move |_| ExampleMsg::Remove(label.clone()))
|
||||
})
|
||||
};
|
||||
html! {
|
||||
<Tag
|
||||
active=self.props.active
|
||||
fill=self.props.fill
|
||||
icon=self.props.icon.then(|| IconName::Print)
|
||||
intent=self.props.intent
|
||||
interactive=self.props.interactive
|
||||
large=self.props.large
|
||||
minimal=self.props.minimal
|
||||
multiline=self.props.multiline
|
||||
right_icon=self.props.right_icon.then(|| IconName::Star)
|
||||
round=self.props.round
|
||||
onremove=remove
|
||||
onclick=self.link.callback(|_| ExampleMsg::Click)
|
||||
active={ctx.props().active}
|
||||
fill={ctx.props().fill}
|
||||
icon={ctx.props().icon.then(|| IconName::Print)}
|
||||
intent={ctx.props().intent}
|
||||
interactive={ctx.props().interactive}
|
||||
large={ctx.props().large}
|
||||
minimal={ctx.props().minimal}
|
||||
multiline={ctx.props().multiline}
|
||||
right_icon={ctx.props().right_icon.then(|| IconName::Star)}
|
||||
round={ctx.props().round}
|
||||
onremove={remove}
|
||||
onclick={ctx.link().callback(|_| ExampleMsg::Click)}
|
||||
>
|
||||
{label.clone()}
|
||||
</Tag>
|
||||
|
|
|
@ -28,9 +28,9 @@ impl Component for TagDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
TagDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
initial_tags: initial_tags(),
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -67,18 +63,18 @@ impl Component for TagDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Tag"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Tag"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html!{
|
||||
source={source}
|
||||
props={Some(html!{
|
||||
<TagProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props/>
|
||||
<Example ..example_props/>
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
}
|
||||
|
@ -87,90 +83,92 @@ impl Component for TagDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
TagProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let props = ctx.props();
|
||||
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<div>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
active: !props.active,
|
||||
..props
|
||||
})
|
||||
checked=self.props.active
|
||||
label=html!("Active")
|
||||
})}
|
||||
checked={props.example_props.active}
|
||||
label={html!("Active")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
fill: !props.fill,
|
||||
..props
|
||||
})
|
||||
checked=self.props.fill
|
||||
label=html!("Fill")
|
||||
})}
|
||||
checked={props.example_props.fill}
|
||||
label={html!("Fill")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
interactive: !props.interactive,
|
||||
..props
|
||||
})
|
||||
checked=self.props.interactive
|
||||
label=html!("Interactive")
|
||||
})}
|
||||
checked={props.example_props.interactive}
|
||||
label={html!("Interactive")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
large: !props.large,
|
||||
..props
|
||||
})
|
||||
checked=self.props.large
|
||||
label=html!("Large")
|
||||
})}
|
||||
checked={props.example_props.large}
|
||||
label={html!("Large")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
minimal: !props.minimal,
|
||||
..props
|
||||
})
|
||||
checked=self.props.minimal
|
||||
label=html!("Minimal")
|
||||
})}
|
||||
checked={props.example_props.minimal}
|
||||
label={html!("Minimal")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
multiline: !props.multiline,
|
||||
..props
|
||||
})
|
||||
checked=self.props.multiline
|
||||
label=html!("Multiline")
|
||||
})}
|
||||
checked={props.example_props.multiline}
|
||||
label={html!("Multiline")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
round: !props.round,
|
||||
..props
|
||||
})
|
||||
checked=self.props.round
|
||||
label=html!("Round")
|
||||
})}
|
||||
checked={props.example_props.round}
|
||||
label={html!("Round")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
removable: !props.removable,
|
||||
..props
|
||||
})
|
||||
checked=self.props.removable
|
||||
label=html!("Removable")
|
||||
})}
|
||||
checked={props.example_props.removable}
|
||||
label={html!("Removable")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
icon: !props.icon,
|
||||
..props
|
||||
})
|
||||
checked=self.props.icon
|
||||
label=html!("Icon")
|
||||
})}
|
||||
checked={props.example_props.icon}
|
||||
label={html!("Icon")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
right_icon: !props.right_icon,
|
||||
..props
|
||||
})
|
||||
checked=self.props.right_icon
|
||||
label=html!("Right icon")
|
||||
})}
|
||||
checked={props.example_props.right_icon}
|
||||
label={html!("Right icon")}
|
||||
/>
|
||||
<p>{"Select intent:"}</p>
|
||||
<ButtonGroup
|
||||
|
@ -184,17 +182,17 @@ crate::build_example_prop_component! {
|
|||
(Some(Intent::Warning), "Warning".to_string()),
|
||||
(Some(Intent::Danger), "Danger".to_string()),
|
||||
]}
|
||||
onchange=self.update_props(|props, intent| ExampleProps {
|
||||
onchange={self.update_props(props, |props, intent| ExampleProps {
|
||||
intent,
|
||||
..props
|
||||
})
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
icon=IconName::Refresh
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
icon={IconName::Refresh}
|
||||
onclick={self.update_props(props, |props, _| ExampleProps {
|
||||
reset_tags: props.reset_tags + 1,
|
||||
..props
|
||||
})
|
||||
..props.clone()
|
||||
})}
|
||||
>
|
||||
{"Reset tags"}
|
||||
</Button>
|
||||
|
|
|
@ -1,44 +1,19 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::Text;
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ExampleProps {
|
||||
pub ellipsize: bool,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div style="width: 150px; height: 20px">
|
||||
<Text ellipsize=self.props.ellipsize>
|
||||
{&self.props.text}
|
||||
</Text>
|
||||
</div>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example(props: &ExampleProps) -> Html {
|
||||
html! {
|
||||
<div style="width: 150px; height: 20px">
|
||||
<Text ellipsize={props.ellipsize}>
|
||||
{&props.text}
|
||||
</Text>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ mod example;
|
|||
|
||||
use crate::ExampleContainer;
|
||||
use example::*;
|
||||
use web_sys::HtmlInputElement;
|
||||
use yew::prelude::*;
|
||||
use yewprint::{Switch, H1, H5};
|
||||
|
||||
|
@ -14,9 +15,9 @@ impl Component for TextDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
TextDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
ellipsize: false,
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -42,19 +39,19 @@ impl Component for TextDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Text"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Text"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<div>
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<TextProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -64,37 +61,36 @@ impl Component for TextDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
TextProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
ellipsize: !props.ellipsize,
|
||||
..props
|
||||
})
|
||||
checked=self.props.ellipsize
|
||||
label=html!("Ellipsize")
|
||||
})}
|
||||
checked={ctx.props().example_props.ellipsize}
|
||||
label={html!("Ellipsize")}
|
||||
/>
|
||||
<input
|
||||
class="bp3-input"
|
||||
onchange=self.update_props(|props, e|
|
||||
match e {
|
||||
ChangeData::Value(text) => {
|
||||
onchange={self.update_props(ctx.props(), |props, e: Event| {
|
||||
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
||||
ExampleProps {
|
||||
text,
|
||||
text: input.value(),
|
||||
..props
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
} else {
|
||||
ExampleProps {
|
||||
text: "Hello, world!".to_string(),
|
||||
..props
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
)}
|
||||
type="text"
|
||||
value={self.props.text.clone()}
|
||||
value={ctx.props().example_props.text.clone()}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::{Intent, TextArea};
|
||||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ExampleProps {
|
||||
pub intent: Option<Intent>,
|
||||
|
@ -13,36 +9,15 @@ pub struct ExampleProps {
|
|||
pub fill: bool,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div style="width: 200px; height: 50px">
|
||||
<TextArea intent=self.props.intent
|
||||
large=self.props.large
|
||||
fill=self.props.fill
|
||||
small=self.props.small
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
#[function_component(Example)]
|
||||
pub fn example(props: &ExampleProps) -> Html {
|
||||
html! {
|
||||
<div style="width: 200px; height: 50px">
|
||||
<TextArea intent={props.intent}
|
||||
large={props.large}
|
||||
fill={props.fill}
|
||||
small={props.small}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ impl Component for TextAreaDoc {
|
|||
type Message = ExampleProps;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
TextAreaDoc {
|
||||
callback: link.callback(|x| x),
|
||||
callback: ctx.link().callback(|x| x),
|
||||
state: ExampleProps {
|
||||
intent: None,
|
||||
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;
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let example_props = self.state.clone();
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
|
@ -44,19 +40,19 @@ impl Component for TextAreaDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Text"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Text"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<div>
|
||||
<ExampleContainer
|
||||
source=source
|
||||
props=Some(html! {
|
||||
source={source}
|
||||
props={Some(html! {
|
||||
<TextAreaProps
|
||||
callback={self.callback.clone()}
|
||||
props=example_props.clone()
|
||||
example_props={example_props.clone()}
|
||||
/>
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Example with example_props />
|
||||
<Example ..example_props />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -66,33 +62,33 @@ impl Component for TextAreaDoc {
|
|||
|
||||
crate::build_example_prop_component! {
|
||||
TextAreaProps for ExampleProps =>
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<H5>{"Props"}</H5>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
fill: !props.fill,
|
||||
..props
|
||||
})
|
||||
checked=self.props.fill
|
||||
label=html!("Fill")
|
||||
})}
|
||||
checked={ctx.props().example_props.fill}
|
||||
label={html!("Fill")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
large: !props.large,
|
||||
..props
|
||||
})
|
||||
checked=self.props.large
|
||||
label=html!("Large")
|
||||
})}
|
||||
checked={ctx.props().example_props.large}
|
||||
label={html!("Large")}
|
||||
/>
|
||||
<Switch
|
||||
onclick=self.update_props(|props, _| ExampleProps {
|
||||
onclick={self.update_props(ctx.props(), |props, _| ExampleProps {
|
||||
small: !props.small,
|
||||
..props
|
||||
})
|
||||
checked=self.props.small
|
||||
label=html!("Small")
|
||||
})}
|
||||
checked={ctx.props().example_props.small}
|
||||
label={html!("Small")}
|
||||
/>
|
||||
<HtmlSelect<Option<Intent>>
|
||||
options={vec![
|
||||
|
@ -102,10 +98,10 @@ crate::build_example_prop_component! {
|
|||
(Some(Intent::Warning), "Warning".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,
|
||||
..props
|
||||
})
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ impl Component for Example {
|
|||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
let mut tree = TreeBuilder::new().build();
|
||||
let root_id = tree
|
||||
.insert(
|
||||
|
@ -71,7 +71,7 @@ impl Component for Example {
|
|||
icon: Some(IconName::Tag),
|
||||
icon_intent: Some(Intent::Primary),
|
||||
label: "Outer file".into(),
|
||||
secondary_label: Some(html!(<Icon icon=IconName::EyeOpen />)),
|
||||
secondary_label: Some(html!(<Icon icon={IconName::EyeOpen} />)),
|
||||
data: 3,
|
||||
..Default::default()
|
||||
}),
|
||||
|
@ -81,12 +81,12 @@ impl Component for Example {
|
|||
|
||||
Self {
|
||||
tree: tree.into(),
|
||||
callback_expand_node: link.callback(|(node_id, _)| Msg::ExpandNode(node_id)),
|
||||
callback_select_node: link.callback(|(node_id, _)| Msg::SelectNode(node_id)),
|
||||
callback_expand_node: ctx.link().callback(|(node_id, _)| Msg::ExpandNode(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 {
|
||||
Msg::ExpandNode(node_id) => {
|
||||
let mut tree = self.tree.borrow_mut();
|
||||
|
@ -109,17 +109,13 @@ impl Component for Example {
|
|||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<Tree<i32>
|
||||
tree=self.tree.clone()
|
||||
on_collapse=Some(self.callback_expand_node.clone())
|
||||
on_expand=Some(self.callback_expand_node.clone())
|
||||
onclick=Some(self.callback_select_node.clone())
|
||||
tree={self.tree.clone()}
|
||||
on_collapse={Some(self.callback_expand_node.clone())}
|
||||
on_expand={Some(self.callback_expand_node.clone())}
|
||||
onclick={Some(self.callback_select_node.clone())}
|
||||
/>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,19 +11,15 @@ impl Component for TreeDoc {
|
|||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
TreeDoc
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
let source = crate::include_raw_html!(
|
||||
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||
"bp3-code-block"
|
||||
|
@ -31,9 +27,9 @@ impl Component for TreeDoc {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<H1 class=classes!("docs-title")>{"Tree"}</H1>
|
||||
<H1 class={classes!("docs-title")}>{"Tree"}</H1>
|
||||
<SourceCodeUrl />
|
||||
<ExampleContainer source=source>
|
||||
<ExampleContainer source={source}>
|
||||
<Example />
|
||||
</ExampleContainer>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue