Rewrite Icon API (#160)

This commit is contained in:
Cecile Tonglet 2022-12-14 17:42:43 +01:00 committed by GitHub
parent ebee832d39
commit b6a6004fcf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 1980 additions and 1880 deletions

1
Cargo.lock generated
View file

@ -2463,7 +2463,6 @@ dependencies = [
"console_error_panic_hook",
"gloo",
"implicit-clone",
"once_cell",
"syntect",
"ureq",
"wasm-bindgen",

View file

@ -1,4 +1,4 @@
use crate::{Icon, IconName, Intent, Spinner, ICON_SIZE_LARGE};
use crate::{Icon, IconSize, Intent, Spinner};
use yew::prelude::*;
use yew::virtual_dom::AttrValue;
@ -21,7 +21,7 @@ pub struct ButtonProps {
#[prop_or_default]
pub disabled: bool,
#[prop_or_default]
pub icon: Option<IconName>,
pub icon: Option<Icon>,
#[prop_or_default]
pub intent: Option<Intent>,
#[prop_or_default]
@ -80,11 +80,12 @@ pub fn button(props: &ButtonProps) -> Html {
.then(|| html! {
<Spinner
class={classes!("bp3-button-spinner")}
size={ICON_SIZE_LARGE as f32}
size={IconSize::LARGE}
/>
})
}
{icon.map(|icon| html!(<Icon {icon} />))}
<Icon {icon} />
//{icon.map(|icon| html!(<Icon {icon} />))}
{
(!children.is_empty())
.then(|| html! {

View file

@ -1,5 +1,5 @@
use crate::icon::ICON_SIZE_LARGE;
use crate::{Icon, IconName, Intent};
use crate::icon::IconSize;
use crate::{Icon, Intent};
use yew::prelude::*;
use yew::virtual_dom::AttrValue;
@ -10,7 +10,7 @@ pub struct CalloutProps {
#[prop_or(false)]
pub without_icon: bool,
#[prop_or_default]
pub icon: Option<IconName>,
pub icon: Option<Icon>,
#[prop_or_default]
pub intent: Option<Intent>,
#[prop_or_default]
@ -31,14 +31,14 @@ pub fn callout(
) -> Html {
let icon = if *without_icon {
None
} else if let Some(icon) = icon.clone() {
Some(icon)
} else {
icon.or_else(|| {
intent.map(|intent| match intent {
Intent::Primary => IconName::InfoSign,
Intent::Success => IconName::Tick,
Intent::Warning => IconName::WarningSign,
Intent::Danger => IconName::Error,
})
intent.map(|intent| match intent {
Intent::Primary => Icon::InfoSign,
Intent::Success => Icon::Tick,
Intent::Warning => Icon::WarningSign,
Intent::Danger => Icon::Error,
})
};
@ -46,16 +46,12 @@ pub fn callout(
<div
class={classes!(
"bp3-callout",
icon.map(|_| "bp3-callout-icon"),
icon.is_some().then_some("bp3-callout-icon"),
intent,
class.clone(),
)}
>
{
icon.iter()
.map(|icon| html!{<Icon {icon} icon_size={ICON_SIZE_LARGE}/>})
.collect::<Html>()
}
<Icon {icon} size={IconSize::LARGE} />
{
title.iter()
.map(|title| html!{<h4 class={"bp3-heading"}>{title}</h4>})

View file

@ -2,19 +2,16 @@ use yew::prelude::*;
#[derive(Clone, PartialEq, Properties)]
pub struct DividerProps {
#[prop_or_default]
pub vertical: bool,
#[prop_or_default]
pub class: Classes,
}
#[function_component(Divider)]
pub fn view(DividerProps { vertical, class }: &DividerProps) -> Html {
pub fn view(DividerProps { class }: &DividerProps) -> Html {
html! {
<span
<div
class={classes!(
"bp3-divider",
vertical.then_some("bp3-vertical"),
class.clone(),
)}
/>

View file

@ -1,7 +1,7 @@
use implicit_clone::{unsync::IArray, ImplicitClone};
use std::marker::PhantomData;
use crate::{Icon, IconName};
use crate::Icon;
use web_sys::HtmlSelectElement;
use yew::prelude::*;
@ -118,7 +118,7 @@ impl<T: ImplicitClone + PartialEq + 'static> Component for HtmlSelect<T> {
>
{option_children}
</select>
<Icon icon={IconName::DoubleCaretVertical}/>
<Icon icon={Icon::DoubleCaretVertical}/>
</div>
}
}

View file

@ -1,23 +1,152 @@
use crate::Intent;
use implicit_clone::ImplicitClone;
use std::fmt;
use yew::html::IntoPropValue;
use yew::prelude::*;
include!("icon_svg_paths.rs");
pub const ICON_SIZE_STANDARD: i32 = 16;
pub const ICON_SIZE_LARGE: i32 = 20;
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct IconSize(pub f64);
impl Default for IconName {
fn default() -> Self {
IconName::Blank
impl IconSize {
pub const STANDARD: IconSize = IconSize(16.0);
pub const LARGE: IconSize = IconSize(20.0);
pub fn as_f64(&self) -> f64 {
self.0 as f64
}
pub fn as_f32(&self) -> f32 {
self.0 as f32
}
}
impl ImplicitClone for IconName {}
impl Default for IconSize {
#[inline]
fn default() -> Self {
Self::STANDARD
}
}
#[derive(Clone, PartialEq, Properties)]
impl fmt::Display for IconSize {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
macro_rules! generate_into_prop_value {
($($ty:ty,)*) => {
$(
impl IntoPropValue<IconSize> for $ty {
fn into_prop_value(self) -> IconSize {
IconSize(self.into())
}
}
impl IntoPropValue<IconSize> for &$ty {
fn into_prop_value(self) -> IconSize {
IconSize((*self).into())
}
}
)*
}
}
#[rustfmt::skip]
generate_into_prop_value!(
u8, u16, u32,
i8, i16, i32,
f32,
);
impl IntoPropValue<f32> for IconSize {
fn into_prop_value(self) -> f32 {
self.as_f32()
}
}
impl IntoPropValue<f64> for IconSize {
fn into_prop_value(self) -> f64 {
self.as_f64()
}
}
impl Default for Icon {
#[inline]
fn default() -> Self {
Icon::Blank
}
}
impl ImplicitClone for Icon {}
impl Icon {
pub fn render(&self) -> Html {
self.render_with_props(&Default::default())
}
pub fn render_with_props(
&self,
IconProps {
icon,
class,
title,
color: fill,
intent,
size,
onclick,
}: &IconProps,
) -> Html {
if let Icon::Custom(html) = icon {
return html.clone();
}
let paths = if *size == IconSize::STANDARD {
icon_svg_paths_16(icon)
} else {
icon_svg_paths_20(icon)
};
let pixel_grid_size = if *size >= IconSize::LARGE {
IconSize::LARGE
} else {
IconSize::STANDARD
};
let icon_string = AttrValue::from(format!("{:?}", icon));
let width = AttrValue::from(format!("{size}"));
let height = width.clone();
html! {
<span
class={classes!("bp3-icon", class.clone(), intent)}
{onclick}
>
<svg
{fill}
data-icon={&icon_string}
{width}
{height}
viewBox={format!("0 0 {pixel_grid_size} {pixel_grid_size}")}
>
<desc>{title.clone().unwrap_or(icon_string)}</desc>
{
paths
.iter()
.map(|x| html! {
<path d={*x} fillRule="evenodd" />
})
.collect::<Html>()
}
</svg>
</span>
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Properties)]
pub struct IconProps {
pub icon: IconName,
pub icon: Icon,
#[prop_or_default]
pub class: Classes,
#[prop_or_default]
@ -26,60 +155,45 @@ pub struct IconProps {
pub color: Option<AttrValue>,
#[prop_or_default]
pub intent: Option<Intent>,
#[prop_or(16)]
pub icon_size: i32,
#[prop_or_default]
pub size: IconSize,
#[prop_or_default]
pub onclick: Callback<MouseEvent>,
}
#[function_component(Icon)]
pub fn icon(
IconProps {
icon,
class,
title,
color: fill,
intent,
icon_size,
onclick,
}: &IconProps,
) -> Html {
let paths = if *icon_size == ICON_SIZE_STANDARD {
icon_svg_paths_16(*icon)
} else {
icon_svg_paths_20(*icon)
};
let pixel_grid_size = if *icon_size >= ICON_SIZE_LARGE {
ICON_SIZE_LARGE
} else {
ICON_SIZE_STANDARD
};
let icon_string = AttrValue::from(format!("{:?}", icon));
let width = AttrValue::from(format!("{icon_size}"));
let height = width.clone();
impl Component for Icon {
type Properties = IconProps;
type Message = ();
html! {
<span
class={classes!("bp3-icon", class.clone(), intent)}
{onclick}
>
<svg
{fill}
data-icon={&icon_string}
{width}
{height}
viewBox={format!("0 0 {pixel_grid_size} {pixel_grid_size}")}
>
<desc>{title.clone().unwrap_or(icon_string)}</desc>
{
paths
.iter()
.map(|x| html! {
<path d={*x} fillRule="evenodd" />
})
.collect::<Html>()
}
</svg>
</span>
fn create(ctx: &Context<Self>) -> Self {
ctx.props().icon.clone()
}
fn view(&self, ctx: &Context<Self>) -> Html {
self.render_with_props(ctx.props())
}
}
impl IntoPropValue<Icon> for &Option<Icon> {
fn into_prop_value(self) -> Icon {
self.clone().unwrap_or_else(|| Icon::Custom(html!()))
}
}
impl IntoPropValue<Icon> for Option<Icon> {
fn into_prop_value(self) -> Icon {
self.unwrap_or_else(|| Icon::Custom(html!()))
}
}
impl IntoPropValue<Icon> for Html {
fn into_prop_value(self) -> Icon {
Icon::Custom(self)
}
}
impl IntoPropValue<Icon> for Option<Html> {
fn into_prop_value(self) -> Icon {
Icon::Custom(self.unwrap_or_default())
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
use crate::{Icon, IconName};
use crate::Icon;
use yew::prelude::*;
const MIN_HORIZONTAL_PADDING: i32 = 10;
@ -65,7 +65,7 @@ pub struct InputGroupProps {
#[prop_or_default]
pub placeholder: AttrValue,
#[prop_or_default]
pub left_icon: Option<IconName>,
pub left_icon: Option<Icon>,
#[prop_or_default]
pub left_element: Option<Html>,
#[prop_or_default]

View file

@ -1,4 +1,4 @@
use crate::{Icon, IconName, Intent, H6};
use crate::{Icon, Intent, H6};
use yew::prelude::*;
use yew::virtual_dom::AttrValue;
@ -52,7 +52,7 @@ pub struct MenuItemProps {
#[prop_or_default]
pub intent: Option<Intent>,
#[prop_or_default]
pub icon: Option<IconName>,
pub icon: Option<Icon>,
#[prop_or_default]
pub icon_html: Option<Html>,
#[prop_or_default]
@ -101,7 +101,7 @@ pub fn menu_item(
html
} else {
html! {
<Icon icon={IconName::Blank} />
<Icon icon={Icon::Blank} />
}
}
}

View file

@ -1,4 +1,4 @@
use crate::{Button, ButtonGroup, ControlGroup, IconName, InputGroup, Intent};
use crate::{Button, ButtonGroup, ControlGroup, Icon, InputGroup, Intent};
use std::fmt::Display;
use std::marker::PhantomData;
use std::ops::{Add, Bound, RangeBounds, Sub};
@ -46,7 +46,7 @@ where
#[prop_or_default]
pub placeholder: AttrValue,
#[prop_or_default]
pub left_icon: Option<IconName>,
pub left_icon: Option<Icon>,
#[prop_or_default]
pub left_element: Option<Html>,
#[prop_or_default]
@ -155,13 +155,13 @@ where
html! {
<ButtonGroup vertical=true class={classes!("bp3-fixed")}>
<Button
icon={IconName::ChevronUp}
icon={Icon::ChevronUp}
disabled={button_up_disabled}
onclick={ctx.link().callback(|_| Msg::Up)}
{intent}
/>
<Button
icon={IconName::ChevronDown}
icon={Icon::ChevronDown}
disabled={button_down_disabled}
onclick={ctx.link().callback(|_| Msg::Down)}
{intent}

View file

@ -1,4 +1,4 @@
use crate::{Button, IconName};
use crate::{Button, Icon};
use gloo::timers::callback::Timeout;
use implicit_clone::ImplicitClone;
use std::cell::RefCell;
@ -282,7 +282,7 @@ impl Component for Panel {
<Button
class={classes!("bp3-panel-stack-header-back")}
style={"padding-right:0"}
icon={IconName::ChevronLeft}
icon={Icon::ChevronLeft}
minimal={true}
small={true}
onclick={onclose.reform(|_| ())}

View file

@ -1,4 +1,4 @@
use crate::{Icon, IconName, Intent, Text};
use crate::{Icon, Intent, Text};
use yew::prelude::*;
use yew::virtual_dom::AttrValue;
@ -12,7 +12,7 @@ pub struct TagProps {
#[prop_or_default]
pub fill: bool,
#[prop_or_default]
pub icon: Option<IconName>,
pub icon: Option<Icon>,
#[prop_or_default]
pub intent: Option<Intent>,
#[prop_or_default]
@ -28,7 +28,7 @@ pub struct TagProps {
#[prop_or_default]
pub onremove: Option<Callback<MouseEvent>>,
#[prop_or_default]
pub right_icon: Option<IconName>,
pub right_icon: Option<Icon>,
#[prop_or_default]
pub round: bool,
#[prop_or_default]
@ -60,18 +60,6 @@ pub fn tag(
style,
}: &TagProps,
) -> Html {
let icon = icon.map(|icon| {
html! {
<Icon {icon} />
}
});
let right_icon = right_icon.map(|icon| {
html! {
<Icon {icon} />
}
});
let remove_button = onremove.clone().map(|onclick| {
html! {
<button
@ -79,7 +67,7 @@ pub fn tag(
{onclick}
tabindex={interactive.then_some("0")}
>
<Icon icon={IconName::SmallCross} />
<Icon icon={Icon::SmallCross} />
</button>
}
});
@ -100,7 +88,7 @@ pub fn tag(
{style}
{onclick}
>
{icon}
<Icon {icon} />
<Text
class={classes!("bp3-fill")}
ellipsize={!multiline}
@ -109,7 +97,7 @@ pub fn tag(
>
{children.clone()}
</Text>
{right_icon}
<Icon icon={right_icon} />
{remove_button}
</span>
}

View file

@ -1,5 +1,5 @@
use crate::collapse::Collapse;
use crate::icon::{Icon, IconName};
use crate::icon::Icon;
use crate::Intent;
use gloo::timers::callback::Timeout;
use id_tree::*;
@ -66,7 +66,7 @@ pub struct TreeProps<T: Clone + PartialEq> {
pub struct NodeData<T> {
pub disabled: bool,
pub has_caret: bool,
pub icon: Option<IconName>,
pub icon: Icon,
pub icon_color: Option<AttrValue>,
pub icon_intent: Option<Intent>,
pub is_expanded: bool,
@ -81,7 +81,7 @@ impl<T: Default> Default for NodeData<T> {
Self {
disabled: false,
has_caret: false,
icon: None,
icon: Default::default(),
icon_color: None,
icon_intent: None,
is_expanded: false,
@ -98,7 +98,7 @@ impl<T: Clone> Clone for NodeData<T> {
Self {
disabled: self.disabled,
has_caret: self.has_caret,
icon: self.icon,
icon: self.icon.clone(),
icon_color: self.icon_color.clone(),
icon_intent: self.icon_intent,
is_expanded: self.is_expanded,
@ -178,7 +178,7 @@ impl<T: 'static + Clone + PartialEq> Tree<T> {
<TreeNode
disabled={data.disabled}
has_caret={data.has_caret}
icon={data.icon}
icon={data.icon.clone()}
icon_color={data.icon_color.clone()}
icon_intent={data.icon_intent}
is_expanded={data.is_expanded}
@ -212,7 +212,7 @@ struct TreeNodeProps {
node_id: NodeId,
disabled: bool,
has_caret: bool,
icon: Option<IconName>,
icon: Icon,
icon_color: Option<AttrValue>,
icon_intent: Option<Intent>,
is_expanded: bool,
@ -314,7 +314,7 @@ impl Component for TreeNode {
"bp3-tree-node-caret-closed"
},
)}
icon={IconName::ChevronRight}
icon={Icon::ChevronRight}
onclick={self.handler_caret_click.clone()}
/>
}
@ -326,7 +326,7 @@ impl Component for TreeNode {
}
<Icon
class={classes!("bp3-tree-node-icon")}
icon={ctx.props().icon.unwrap_or(IconName::Blank)}
icon={ctx.props().icon.clone()}
color={ctx.props().icon_color.clone()}
intent={ctx.props().icon_intent}
/>

View file

@ -30,16 +30,17 @@ pub(crate) fn generate_icons() -> Result<()> {
for map in re_map.captures_iter(icon_svg_paths.as_str()) {
src.push_str("fn icon_svg_paths_");
src.push_str(&map[1]);
src.push_str("(icon: IconName) -> &'static [&'static str] { match icon {\n");
src.push_str("(icon: &Icon) -> &'static [&'static str] { match icon {\n");
for item in re_item.captures_iter(&map[2]) {
let key = item[1].to_upper_camel_case();
src.push_str("IconName::");
src.push_str("Icon::");
src.push_str(&key);
src.push_str(" => &");
src.push_str(&item[2]);
src.push_str(",\n");
keys.insert(key);
}
src.push_str("Icon::Custom(_) => &[],\n");
src.push_str(" }}\n\n");
}
@ -48,19 +49,20 @@ pub(crate) fn generate_icons() -> Result<()> {
let mut keys: Vec<_> = keys.iter().collect();
keys.sort();
src.push_str(
"#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]\n\
pub enum IconName {\n",
"#[derive(Debug, Clone, PartialEq)]\n\
pub enum Icon {\n",
);
for icon in &keys {
src.push_str(icon);
src.push_str(",\n");
}
src.push_str("Custom(Html),\n");
src.push_str("}\n\n");
src.push_str("impl IconName {\n");
src.push_str("pub const ALL: &[IconName] = &[\n");
src.push_str("impl Icon {\n");
src.push_str("pub const ALL: &[Icon] = &[\n");
for icon in keys {
src.push_str("IconName::");
src.push_str("Icon::");
src.push_str(icon);
src.push_str(",\n");
}

View file

@ -17,7 +17,6 @@ crate-type = ["cdylib"]
console_error_panic_hook = { version = "0.1.7", optional = true }
gloo = "0.8"
implicit-clone = "0.3.3"
once_cell = "1.16"
wasm-bindgen = "0.2"
web-sys = { version = "0.3", features = ["Window", "MediaQueryList", "Event", "HtmlInputElement"] }
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size

View file

@ -24,7 +24,7 @@ use crate::text_area::*;
use crate::tree::*;
use yew::prelude::*;
use yew_router::prelude::*;
use yewprint::{IconName, Menu, MenuItem};
use yewprint::{Icon, Menu, MenuItem};
#[function_component(AppRoot)]
pub fn app_root() -> Html {
@ -84,9 +84,9 @@ impl Component for App {
"Dark theme"
};
let go_to_theme_icon = if self.dark_theme {
IconName::Flash
Icon::Flash
} else {
IconName::Moon
Icon::Moon
};
let menu = html! {

View file

@ -1,5 +1,5 @@
use yew::prelude::*;
use yewprint::{Button, ButtonGroup, IconName};
use yewprint::{Button, ButtonGroup, Icon};
#[derive(Clone, PartialEq, Properties)]
pub struct ExampleProps {
@ -19,9 +19,9 @@ pub fn example(props: &ExampleProps) -> Html {
vertical={props.vertical}
style={"margin:0;"}
>
<Button icon={IconName::Database}> {"Queries"}</Button>
<Button icon={IconName::Function}>{"Functions"}</Button>
<Button icon={IconName::Cog}>{"Options"}</Button>
<Button icon={Icon::Database}> {"Queries"}</Button>
<Button icon={Icon::Function}>{"Functions"}</Button>
<Button icon={Icon::Cog}>{"Options"}</Button>
</ButtonGroup>
}
}

View file

@ -1,6 +1,6 @@
use implicit_clone::{unsync::IArray, ImplicitClone};
use yew::prelude::*;
use yewprint::{Button, ControlGroup, HtmlSelect, IconName, InputGroup};
use yewprint::{Button, ControlGroup, HtmlSelect, Icon, InputGroup};
#[derive(Clone, PartialEq, Properties)]
pub struct ExampleProps {
@ -25,7 +25,7 @@ pub fn example(ExampleProps { fill, vertical }: &ExampleProps) -> Html {
].into_iter().collect::<IArray<_>>()}
/>
<InputGroup placeholder="Find filters..." />
<Button icon={IconName::ArrowRight} />
<Button icon={Icon::ArrowRight} />
</ControlGroup>
}
}

View file

@ -1,22 +1,22 @@
use yew::prelude::*;
use yewprint::{Button, ButtonGroup, Divider};
use yewprint::{Button, ButtonGroup, Divider, Icon};
#[derive(Clone, PartialEq, Properties)]
pub struct ExampleProps {
pub vertical: bool,
}
#[function_component(Example)]
pub fn example(props: &ExampleProps) -> Html {
pub fn example(ExampleProps { vertical }: &ExampleProps) -> Html {
html! {
<ButtonGroup vertical={props.vertical}>
<ButtonGroup minimal=true {vertical} >
<Button>{"File"}</Button>
<Button>{"Edit"}</Button>
<Divider vertical={props.vertical} />
<Divider />
<Button>{"Create"}</Button>
<Button>{"Delete"}</Button>
<Divider vertical={props.vertical} />
// <Button icon=IconName::Add />
// <Button icon=IconName::Remove />
<Divider />
<Button icon={Icon::Add} />
<Button icon={Icon::Remove} />
</ButtonGroup>
}
}

View file

@ -1,5 +1,5 @@
use yew::prelude::*;
use yewprint::{Button, Collapse, IconName, Intent};
use yewprint::{Button, Collapse, Icon, Intent};
pub struct ExampleContainer {
collapsed: bool,
@ -53,7 +53,7 @@ impl Component for ExampleContainer {
</div>
<div class={classes!("docs-source")}>
<Button
icon={IconName::Code}
icon={Icon::Code}
fill={{true}}
intent={{Intent::Primary}}
minimal={{true}}

View file

@ -3,7 +3,7 @@ mod example;
use crate::ExampleContainer;
use example::*;
use yew::prelude::*;
use yewprint::{Button, IconName, Switch, H1, H5};
use yewprint::{Button, Icon, Switch, H1, H5};
pub struct HtmlSelectDoc {
callback: Callback<ExampleProps>,
@ -101,7 +101,7 @@ crate::build_example_prop_component! {
/>
<H5>{"Example"}</H5>
<Button
icon={IconName::Refresh}
icon={Icon::Refresh}
onclick={self.update_props(ctx, |props, _| ExampleProps {
reset: props.reset.wrapping_add(1),
..props

View file

@ -1,22 +1,18 @@
use yew::prelude::*;
use yewprint::{Icon, IconName, Intent};
use yewprint::{Icon, Intent};
#[derive(Clone, PartialEq, Properties)]
pub struct ExampleProps {
pub icon_name: IconName,
pub icon: Icon,
pub intent: Option<Intent>,
pub icon_size: i32,
pub size: i32,
}
#[function_component(Example)]
pub fn example(props: &ExampleProps) -> Html {
pub fn example(ExampleProps { icon, intent, size }: &ExampleProps) -> Html {
html! {
<div>
<Icon
icon={props.icon_name}
intent={props.intent}
icon_size={props.icon_size}
/>
<Icon {icon} {intent} {size} />
</div>
}
}

View file

@ -3,10 +3,9 @@ mod example;
use crate::ExampleContainer;
use example::*;
use implicit_clone::unsync::IArray;
use once_cell::sync::Lazy;
use web_sys::HtmlInputElement;
use yew::prelude::*;
use yewprint::{HtmlSelect, Icon, IconName, InputGroup, Intent, Slider, Text, H1, H5};
use yewprint::{HtmlSelect, Icon, InputGroup, Intent, Slider, Text, H1, H5};
pub struct IconDoc {
callback: Callback<ExampleProps>,
@ -20,12 +19,16 @@ pub enum IconDocMsg {
SearchIcon(String),
}
static ICON_LIST: Lazy<Vec<(String, IconName)>> = Lazy::new(|| {
IconName::ALL
.iter()
.map(|x| (format!("{:?}", x).to_lowercase(), *x))
.collect()
});
thread_local! {
static ICON_LIST: Vec<(String, Icon)> = {
gloo::console::log!("init");
Icon::ALL
.iter()
.cloned()
.map(|x| (format!("{:?}", x).to_lowercase(), x))
.collect()
};
}
impl Component for IconDoc {
type Message = IconDocMsg;
@ -35,9 +38,9 @@ impl Component for IconDoc {
IconDoc {
callback: ctx.link().callback(|x| IconDocMsg::Example(x)),
state: ExampleProps {
icon_name: IconName::Print,
icon: Icon::Print,
intent: None,
icon_size: 16,
size: 16,
},
search_string: Default::default(),
}
@ -59,25 +62,26 @@ impl Component for IconDoc {
);
let search_string = self.search_string.to_lowercase();
let icon_list = ICON_LIST
.iter()
.filter_map(|(icon_name, icon)| {
icon_name
.contains(&search_string)
.then_some(*icon)
.map(|icon| {
html! {
<div class={classes!("docs-icon-list-item")}>
<Icon
{icon}
icon_size=20
/>
<Text>{format!("{:?}", icon)}</Text>
</div>
}
})
})
.collect::<Html>();
let icon_list = ICON_LIST.with(|list| {
list.iter()
.filter_map(|(icon_name, icon)| {
icon_name
.contains(&search_string)
.then_some(icon)
.map(|icon| {
html! {
<div class={classes!("docs-icon-list-item")}>
<Icon
{icon}
size=20
/>
<Text>{format!("{:?}", icon)}</Text>
</div>
}
})
})
.collect::<Html>()
});
html! {
<div>
@ -99,7 +103,7 @@ impl Component for IconDoc {
large=true
fill=true
round=true
left_icon={IconName::Search}
left_icon={Icon::Search}
placeholder="Search for icons..."
value={self.search_string.clone()}
oninput={ctx.link().callback(|e: InputEvent| {
@ -131,24 +135,25 @@ crate::build_example_prop_component! {
<input
class="bp3-input"
onchange={self.update_props(ctx, |props, e: Event| {
let icon_name = e.target_dyn_into::<HtmlInputElement>()
let icon = e.target_dyn_into::<HtmlInputElement>()
.map(|x| x.value().to_lowercase())
.as_deref()
.and_then(|x| {
ICON_LIST
.iter()
.find_map(move |(icon_name, icon)| {
(icon_name == x).then_some(*icon)
})
.with(|list| list
.iter()
.find_map(move |(icon_name, icon)| {
(icon_name == x).then_some(icon.clone())
}))
});
ExampleProps {
icon_name: icon_name.unwrap_or_default(),
icon: icon.unwrap_or_default(),
..props
}
})}
type="text"
value={format!("{:?}", ctx.props().example_props.icon_name)}
value={format!("{:?}", ctx.props().example_props.icon)}
/>
<p
style="margin-top: 5px;"
@ -175,14 +180,14 @@ crate::build_example_prop_component! {
{"Select icon size"}
</p>
<Slider<i32>
selected={ctx.props().example_props.icon_size}
selected={ctx.props().example_props.size}
values={option_labels}
onchange={self.update_props(ctx, |props, icon_size| ExampleProps {
icon_size,
onchange={self.update_props(ctx, |props, size| ExampleProps {
size,
..props
})}
value_label={
format!("{}", ctx.props().example_props.icon_size)
format!("{}", ctx.props().example_props.size)
}
/>
</div>

View file

@ -1,7 +1,7 @@
use gloo::dialogs::alert;
use web_sys::HtmlInputElement;
use yew::prelude::*;
use yewprint::{Button, IconName, InputGroup, Tag};
use yewprint::{Button, Icon, InputGroup, Tag};
pub struct Example {
histogram_value: String,
@ -92,7 +92,7 @@ impl Component for Example {
small={ctx.props().small}
round={ctx.props().round}
disabled={ctx.props().disabled}
left_icon={IconName::Filter}
left_icon={Icon::Filter}
placeholder={"Filter histogram..."}
value={self.histogram_value.clone()}
oninput={ctx.link().callback(|e: InputEvent| {
@ -121,7 +121,7 @@ impl Component for Example {
})}
right_element={{ html! {
<Button
icon={IconName::Lock}
icon={Icon::Lock}
minimal={true}
disabled={ctx.props().disabled}
/>
@ -133,7 +133,7 @@ impl Component for Example {
small={ctx.props().small}
round={ctx.props().round}
disabled={ctx.props().disabled}
left_icon={IconName::Tag}
left_icon={Icon::Tag}
placeholder={"Find tags"}
value={self.tags_value.clone()}
oninput={ctx.link().callback(|e: InputEvent| {

View file

@ -1,6 +1,6 @@
use crate::{DocMenu, Logo};
use yew::prelude::*;
use yewprint::{Icon, IconName, Menu, MenuDivider, MenuItem};
use yewprint::{Icon, Menu, MenuDivider, MenuItem};
pub struct Example {}
@ -26,7 +26,7 @@ impl Component for Example {
};
let share_icon = html! {
<Icon icon={IconName::Share} />
<Icon icon={Icon::Share} />
};
html! {
@ -38,21 +38,21 @@ impl Component for Example {
/>
<MenuDivider />
<MenuItem
icon={IconName::NewTextBox}
icon={Icon::NewTextBox}
text={html!("New text box")}
href={"#menu"}
onclick={ctx.link()
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
/>
<MenuItem
icon={IconName::NewObject}
icon={Icon::NewObject}
text={html!("New object")}
href={"#menu"}
onclick={ctx.link()
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
/>
<MenuItem
icon={IconName::NewLink}
icon={Icon::NewLink}
text={html!("New link")}
href={"#menu"}
onclick={ctx.link()
@ -60,7 +60,7 @@ impl Component for Example {
/>
<MenuDivider />
<MenuItem
icon={IconName::Cog}
icon={Icon::Cog}
text={html!("Settings")}
label={share_icon}
href={"#menu"}
@ -71,7 +71,7 @@ impl Component for Example {
<Menu>
<MenuDivider title={html!("Edit")} />
<MenuItem
icon={IconName::Cut}
icon={Icon::Cut}
text={html!("Cut")}
label={html!("Ctrl+X")}
href={"#menu"}
@ -79,7 +79,7 @@ impl Component for Example {
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
/>
<MenuItem
icon={IconName::Duplicate}
icon={Icon::Duplicate}
text={html!("Copy")}
label={html!("Ctrl+C")}
href={"#menu"}
@ -87,28 +87,28 @@ impl Component for Example {
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
/>
<MenuItem
icon={IconName::Clipboard}
icon={Icon::Clipboard}
text={html!("Paste")}
label={html!("Ctrl+V")}
disabled=true
/>
<MenuDivider title={html!("Text")} />
<MenuItem
icon={IconName::AlignLeft}
icon={Icon::AlignLeft}
text={html!("Alignment")}
href={"#menu"}
onclick={ctx.link()
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
/>
<MenuItem
icon={IconName::Style}
icon={Icon::Style}
text={html!("Style")}
href={"#menu"}
onclick={ctx.link()
.callback(|_| Msg::GoToMenu(DocMenu::Menu))}
/>
<MenuItem
icon={IconName::Asterisk}
icon={Icon::Asterisk}
text={html!("Miscellaneous")}
href={"#menu"}
onclick={ctx.link().callback(|_| Msg::GoToMenu(DocMenu::Menu))}

View file

@ -1,5 +1,5 @@
use yew::prelude::*;
use yewprint::{Button, Callout, IconName, Intent, NumericInput};
use yewprint::{Button, Callout, Icon, Intent, NumericInput};
pub struct Example {
value: i32,
@ -74,7 +74,7 @@ impl Component for Example {
onchange={ctx.link().callback(|x| Msg::UpdateValue(x))}
{disable_buttons}
{buttons_on_the_left}
left_icon={left_icon.then_some(IconName::Dollar)}
left_icon={left_icon.then_some(Icon::Dollar)}
{intent}
/>
<NumericInput<i32>
@ -88,11 +88,11 @@ impl Component for Example {
onchange={ctx.link().callback(|x| Msg::UpdateValueTwo(x))}
{disable_buttons}
{buttons_on_the_left}
left_icon={left_icon.then_some(IconName::Dollar)}
left_icon={left_icon.then_some(Icon::Dollar)}
{intent}
/>
<Button
icon={IconName::Refresh}
icon={Icon::Refresh}
onclick={ctx.link().callback(|_| Msg::Reset)}
>
{"Reset at 4"}

View file

@ -1,6 +1,6 @@
use implicit_clone::unsync::IArray;
use yew::prelude::*;
use yewprint::{IconName, Intent, Tag};
use yewprint::{Icon, Intent, Tag};
pub struct Example {
tags: Vec<String>,
@ -84,13 +84,13 @@ impl Component for Example {
<Tag
active={ctx.props().active}
fill={ctx.props().fill}
icon={ctx.props().icon.then_some(IconName::Print)}
icon={ctx.props().icon.then_some(Icon::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_some(IconName::Star)}
right_icon={ctx.props().right_icon.then_some(Icon::Star)}
round={ctx.props().round}
onremove={remove}
onclick={ctx.link().callback(|_| ExampleMsg::Click)}

View file

@ -4,7 +4,7 @@ use crate::ExampleContainer;
use example::*;
use implicit_clone::unsync::{IArray, IString};
use yew::prelude::*;
use yewprint::{Button, ButtonGroup, HtmlSelect, IconName, Intent, Switch, H1, H5};
use yewprint::{Button, ButtonGroup, HtmlSelect, Icon, Intent, Switch, H1, H5};
pub struct TagDoc {
callback: Callback<ExampleProps>,
@ -190,7 +190,7 @@ crate::build_example_prop_component! {
value={ctx.props().example_props.intent}
/>
<Button
icon={IconName::Refresh}
icon={Icon::Refresh}
onclick={self.update_props(ctx, |props, _| ExampleProps {
reset_tags: props.reset_tags + 1,
..props.clone()

View file

@ -1,6 +1,6 @@
use yew::prelude::*;
use yewprint::id_tree::{InsertBehavior, Node, NodeId, TreeBuilder};
use yewprint::{Icon, IconName, Intent, NodeData, Tree, TreeData};
use yewprint::{Icon, Intent, NodeData, Tree, TreeData};
pub struct Example {
tree: TreeData<i32>,
@ -31,7 +31,7 @@ impl Component for Example {
let dir1 = tree
.insert(
Node::new(NodeData {
icon: Some(IconName::FolderClose),
icon: Icon::FolderClose,
label: "Big directory".into(),
has_caret: true,
data: 1,
@ -44,7 +44,7 @@ impl Component for Example {
let dir2 = tree
.insert(
Node::new(NodeData {
icon: Some(IconName::FolderClose),
icon: Icon::FolderClose,
label: format!("Directory {}", i + 1).into(),
has_caret: true,
data: 1,
@ -56,7 +56,7 @@ impl Component for Example {
for i in 0..10 {
tree.insert(
Node::new(NodeData {
icon: Some(IconName::Document),
icon: Icon::Document,
label: format!("File {}", i + 1).into(),
data: i,
..Default::default()
@ -68,10 +68,10 @@ impl Component for Example {
}
tree.insert(
Node::new(NodeData {
icon: Some(IconName::Tag),
icon: Icon::Tag,
icon_intent: Some(Intent::Primary),
label: "Outer file".into(),
secondary_label: Some(html!(<Icon icon={IconName::EyeOpen} />)),
secondary_label: Some(html!(<Icon icon={Icon::EyeOpen} />)),
data: 3,
..Default::default()
}),
@ -93,11 +93,11 @@ impl Component for Example {
let node = tree.get_mut(&node_id).unwrap();
let data = node.data_mut();
data.is_expanded ^= true;
data.icon = Some(if data.is_expanded {
IconName::FolderOpen
data.icon = if data.is_expanded {
Icon::FolderOpen
} else {
IconName::FolderClose
})
Icon::FolderClose
};
}
Msg::SelectNode(node_id) => {
let mut tree = self.tree.borrow_mut();