Use classes within html (#23)

This commit is contained in:
Cecile Tonglet 2020-09-27 11:37:03 +02:00 committed by GitHub
parent a5813d0fc0
commit 8a7c0ee6ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 106 additions and 71 deletions

View file

@ -1,15 +1,15 @@
use crate::buttons::doc::*;
use crate::collapse::doc::*;
use crate::icon::doc::*;
use crate::menu::*;
use crate::switch::doc::SwitchDoc;
use crate::switch::doc::*;
use crate::tree::doc::*;
use crate::{ConditionalClass, Menu, MenuItem};
use yew::prelude::*;
pub struct App {
link: ComponentLink<Self>,
doc_menu: DocMenu,
dark_theme: bool,
dark_theme: ConditionalClass,
}
pub enum Msg {
@ -23,7 +23,7 @@ impl Component for App {
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
App {
dark_theme: true,
dark_theme: true.into(),
doc_menu: DocMenu::Button,
link,
}
@ -31,7 +31,7 @@ impl Component for App {
fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
Msg::ToggleLight => self.dark_theme ^= true,
Msg::ToggleLight => *self.dark_theme ^= true,
Msg::GoToMenu(doc_menu) => {
self.doc_menu = doc_menu;
}
@ -44,13 +44,8 @@ impl Component for App {
}
fn view(&self) -> Html {
let mut class = Classes::from("docs-app");
if self.dark_theme {
class.push("bp3-dark");
}
html! {
<div class=class>
<div class=("docs-app", self.dark_theme.map_some("bp3-dark"))>
<div class="docs-nav-wrapper">
<div class="docs-nav">
<div class="docs-nav-title">

View file

@ -1,7 +1,7 @@
#[cfg(feature = "doc")]
pub mod doc;
use crate::{Icon, IconName, Intent};
use crate::{ConditionalClass, Icon, IconName, Intent};
use yew::prelude::*;
pub struct Button {
@ -11,9 +11,9 @@ pub struct Button {
#[derive(Clone, PartialEq, Properties)]
pub struct Props {
#[prop_or_default]
pub fill: bool,
pub fill: ConditionalClass,
#[prop_or_default]
pub minimal: bool,
pub minimal: ConditionalClass,
#[prop_or_default]
pub icon: Option<IconName>,
#[prop_or_default]
@ -47,17 +47,16 @@ impl Component for Button {
}
fn view(&self) -> Html {
let mut class = Classes::from("bp3-button");
if self.props.fill {
class.push("bp3-fill");
}
if self.props.minimal {
class.push("bp3-minimal");
}
class = class.extend(&self.props.intent);
html! {
<button class=class onclick={self.props.onclick.clone()}>
<button
class=(
"bp3-button",
self.props.fill.map_some("bp3-fill"),
self.props.minimal.map_some("bp3-minimal"),
self.props.intent,
)
onclick={self.props.onclick.clone()}
>
{
if let Some(icon) = self.props.icon {
html! {

View file

@ -58,10 +58,6 @@ impl Component for Icon {
}
fn view(&self) -> Html {
let mut class = Classes::from("bp3-icon");
class.push(self.props.class.as_str());
class = class.extend(&self.props.intent);
let paths = if self.props.icon_size == SIZE_STANDARD {
icon_svg_paths_16(self.props.icon)
} else {
@ -75,7 +71,7 @@ impl Component for Icon {
let icon_string = format!("{:?}", self.props.icon);
html! {
<span class=class onclick?={self.props.onclick.clone()}>
<span class=("bp3-icon", self.props.class.clone(), self.props.intent) onclick?={self.props.onclick.clone()}>
<svg
fill?={self.props.color.clone()}
data-icon={icon_string.clone()}

View file

@ -26,7 +26,8 @@ pub use menu::*;
pub use switch::*;
pub use tree::*;
use yew::virtual_dom::Classes;
use std::ops::{Deref, DerefMut};
use yew::virtual_dom::{Classes, Transformer, VComp};
#[cfg(feature = "doc")]
#[macro_export]
@ -63,6 +64,54 @@ macro_rules! include_raw_html {
}};
}
// NOTE: this class needs to become deprecated when the feature bool_to_option lands in stable
//
// https://github.com/rust-lang/rust/issues/64260
#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct ConditionalClass(bool);
impl Transformer<bool, ConditionalClass> for VComp {
fn transform(value: bool) -> ConditionalClass {
ConditionalClass(value)
}
}
impl Transformer<ConditionalClass, bool> for VComp {
fn transform(value: ConditionalClass) -> bool {
value.0
}
}
impl From<bool> for ConditionalClass {
fn from(value: bool) -> Self {
ConditionalClass(value)
}
}
impl ConditionalClass {
pub fn map_some(&self, value: &'static str) -> Option<&'static str> {
if self.0 {
Some(value)
} else {
None
}
}
}
impl Deref for ConditionalClass {
type Target = bool;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for ConditionalClass {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(feature = "doc")]
#[wasm_bindgen::prelude::wasm_bindgen(start)]
pub fn run_app() -> Result<(), wasm_bindgen::JsValue> {

View file

@ -1,5 +1,5 @@
use crate::icon::{Icon, IconName};
use crate::Intent;
use crate::{ConditionalClass, Intent};
use yew::prelude::*;
pub struct Menu {
@ -9,7 +9,7 @@ pub struct Menu {
#[derive(Clone, PartialEq, Properties)]
pub struct MenuProps {
#[prop_or_default]
pub large: bool,
pub large: ConditionalClass,
#[prop_or_default]
pub class: Option<String>,
#[prop_or_default]
@ -39,14 +39,15 @@ impl Component for Menu {
}
fn view(&self) -> Html {
let mut class = Classes::from("bp3-menu");
if self.props.large {
class.push("bp3-large");
}
class = class.extend(self.props.class.clone());
html! {
<ul class=class ref={self.props.r#ref.clone()}>
<ul
class=(
"bp3-menu",
self.props.large.map_some("bp3-large"),
self.props.class.clone(),
)
ref={self.props.r#ref.clone()}
>
{self.props.children.clone()}
</ul>
}
@ -64,7 +65,7 @@ pub struct MenuItemProps {
#[prop_or_default]
pub text_class: Option<String>,
#[prop_or_default]
pub active: bool,
pub active: ConditionalClass,
#[prop_or_default]
pub class: Option<String>,
// TODO: pub disabled: bool,
@ -105,37 +106,33 @@ impl Component for MenuItem {
}
fn view(&self) -> Html {
let mut anchor_class = Classes::from("bp3-menu-item");
if self.props.active {
anchor_class.push("bp3-active");
}
if let Some(intent) = self.props.intent {
anchor_class = anchor_class.extend(intent);
} else if self.props.active {
anchor_class = anchor_class.extend(Intent::Primary);
}
anchor_class = anchor_class.extend(self.props.class.clone());
let mut text_class = Classes::from("bp3-text");
text_class.push("bp3-fill");
text_class = text_class.extend(self.props.text_class.clone());
html! {
<li>
<a
class=anchor_class
class=(
"bp3-menu-item",
self.props.active.map_some("bp3-active"),
self.props.intent
.and(self.props.active.map_some(Intent::Primary.as_ref())),
self.props.class.clone(),
)
onclick={self.props.onclick.clone()}
>
<Icon icon={self.props.icon} />
<div class=text_class>
<div class=("bp3-text", "bp3-fill", self.props.text_class.clone())>
{self.props.text.clone()}
</div>
{
if let Some(label) = self.props.label.clone() {
let mut label_class = Classes::from("bp3-menu-item-label");
label_class = label_class.extend(self.props.label_class.clone());
html!(<span class=label_class>{label}</span>)
html! {
<span
class=(
"bp3-menu-item-label",
self.props.label_class.clone())
>
{label}
</span>
}
} else {
html!()
}

View file

@ -1,6 +1,6 @@
use crate::collapse::Collapse;
use crate::icon::{Icon, IconName};
use crate::Intent;
use crate::{ConditionalClass, Intent};
use id_tree::*;
use std::cell::{Ref, RefCell, RefMut};
use std::collections::hash_map::DefaultHasher;
@ -219,7 +219,7 @@ struct TreeNodeProps {
icon_color: Option<String>,
icon_intent: Option<Intent>,
is_expanded: bool,
is_selected: bool,
is_selected: ConditionalClass,
label: yew::virtual_dom::VNode,
secondary_label: Option<yew::virtual_dom::VNode>,
on_collapse: Option<Callback<(NodeId, MouseEvent)>>,
@ -309,16 +309,15 @@ impl Component for TreeNode {
}
fn view(&self) -> Html {
let mut container_class = Classes::from("bp3-tree-node");
if self.props.is_selected {
container_class.push("bp3-tree-node-selected");
}
let mut content_class = Classes::from("bp3-tree-node-content");
content_class.push(&format!("bp3-tree-node-content-{}", self.props.depth));
let content_style = format!("padding-left: {}px;", 23 * self.props.depth);
html! {
<li class=container_class>
<div class=content_class onclick=self.handler_click.clone()>
<li class=("bp3-tree-node", self.props.is_selected.map_some("bp3-tree-node-selected"))>
<div
class="bp3-tree-node-content"
style=content_style
onclick=self.handler_click.clone()
>
{
if self.props.has_caret {
let mut class = Classes::from("bp3-tree-node-caret");