mirror of
https://github.com/yewprint/yewprint
synced 2024-11-25 13:00:19 +00:00
Macro to generate examples & fix CI (#9)
This commit is contained in:
parent
a4178c58f9
commit
ead6db471d
18 changed files with 545 additions and 257 deletions
|
@ -16,6 +16,5 @@ before_script:
|
|||
script:
|
||||
- 'if [ -n "$TRAVIS_PULL_REQUEST" ]; then rustfmt --check **/*.rs; fi'
|
||||
- 'if [ -n "$TRAVIS_PULL_REQUEST" ]; then cargo clippy --all-targets --all-features -- -D warnings; fi'
|
||||
- cargo build
|
||||
- cargo test
|
||||
- cargo test --all-features
|
||||
- cargo doc
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[![Build Status](https://travis-ci.org/cecton/yewprint.svg?branch=main)](https://travis-ci.org/cecton/yewprint)
|
||||
[![Netlify Status](https://api.netlify.com/api/v1/badges/17f076ed-49e5-4185-921e-5c5759de2fdb/deploy-status)](https://app.netlify.com/sites/epic-poincare-f8adaa/deploys)
|
||||
|
||||
![Demo](https://github.com/cecton/blueprint-rs/blob/main/demo.mp4?raw=true)
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::buttons::doc::*;
|
||||
use crate::collapse::doc::*;
|
||||
use crate::forms::controls::doc::SwitchDoc;
|
||||
use crate::icon::doc::*;
|
||||
use crate::menu::*;
|
||||
use crate::switch::doc::SwitchDoc;
|
||||
use crate::tree::doc::*;
|
||||
use yew::prelude::*;
|
||||
|
||||
|
@ -24,7 +24,7 @@ impl Component for App {
|
|||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
App {
|
||||
dark_theme: true,
|
||||
doc_menu: DocMenu::Tree,
|
||||
doc_menu: DocMenu::Button,
|
||||
link,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
use yew::prelude::*;
|
||||
|
||||
pub struct Button {
|
||||
props: Props,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct Props {
|
||||
#[prop_or_default]
|
||||
pub title: String,
|
||||
#[prop_or_default]
|
||||
pub onclick: Callback<MouseEvent>,
|
||||
pub children: html::Children,
|
||||
}
|
||||
|
||||
impl Component for Button {
|
||||
type Message = ();
|
||||
type Properties = Props;
|
||||
|
||||
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="bp3-button" onclick={self.props.onclick.clone()}>
|
||||
{self.props.children.clone()}
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "doc")]
|
||||
pub mod doc {
|
||||
use super::*;
|
||||
|
||||
pub struct ButtonDoc {
|
||||
link: ComponentLink<Self>,
|
||||
counter: i64,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
AddOne,
|
||||
}
|
||||
|
||||
impl Component for ButtonDoc {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
ButtonDoc { counter: 0, link }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::AddOne => self.counter += 1,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<h1>{"Button"}</h1>
|
||||
<p> {"Counter: "} { self.counter }</p>
|
||||
<div>
|
||||
<Button onclick=self.link.callback(|_| Msg::AddOne)>{ "Add 1" }</Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
42
src/buttons/example.rs
Normal file
42
src/buttons/example.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::Button;
|
||||
|
||||
pub struct Example {
|
||||
link: ComponentLink<Self>,
|
||||
counter: i64,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
AddOne,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Example { counter: 0, link }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::AddOne => self.counter += 1,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<p> {"Counter: "} { self.counter }</p>
|
||||
<div>
|
||||
<Button onclick=self.link.callback(|_| Msg::AddOne)>{ "Add 1" }</Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
108
src/buttons/mod.rs
Normal file
108
src/buttons/mod.rs
Normal file
|
@ -0,0 +1,108 @@
|
|||
use crate::{Icon, IconName, Intent};
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct Button {
|
||||
props: Props,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct Props {
|
||||
#[prop_or_default]
|
||||
pub fill: bool,
|
||||
#[prop_or_default]
|
||||
pub minimal: bool,
|
||||
#[prop_or_default]
|
||||
pub icon: Option<IconName>,
|
||||
#[prop_or_default]
|
||||
pub intent: Option<Intent>,
|
||||
#[prop_or_default]
|
||||
pub title: String,
|
||||
#[prop_or_default]
|
||||
pub onclick: Callback<MouseEvent>,
|
||||
pub children: html::Children,
|
||||
}
|
||||
|
||||
impl Component for Button {
|
||||
type Message = ();
|
||||
type Properties = Props;
|
||||
|
||||
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 {
|
||||
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()}>
|
||||
{
|
||||
if let Some(icon) = self.props.icon {
|
||||
html! {
|
||||
<Icon icon=icon />
|
||||
}
|
||||
} else {
|
||||
html!()
|
||||
}
|
||||
}
|
||||
<span class="bp3-button-text">
|
||||
{self.props.children.clone()}
|
||||
</span>
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "doc")]
|
||||
pub mod doc {
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct ButtonDoc;
|
||||
|
||||
impl Component for ButtonDoc {
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
ButtonDoc
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let source = crate::include_example!("example.rs");
|
||||
|
||||
html! {
|
||||
<div>
|
||||
<h1>{"Button"}</h1>
|
||||
<div>{source}</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
src/collapse/example.rs
Normal file
66
src/collapse/example.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::{Button,Collapse};
|
||||
|
||||
pub struct Example {
|
||||
link: ComponentLink<Self>,
|
||||
collapsed: bool,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
ToggleCollapse,
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Example {
|
||||
collapsed: true,
|
||||
link,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::ToggleCollapse => self.collapsed ^= true,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<Button onclick=self.link.callback(|_| Msg::ToggleCollapse)>
|
||||
{"Toggle collapse"}
|
||||
</Button>
|
||||
<Collapse
|
||||
is_open=!self.collapsed
|
||||
keep_children_mounted=true
|
||||
>
|
||||
<pre class="bp3-code-block">
|
||||
<div>{"[INFO]: Installing wasm-bindgen..."}</div>
|
||||
<div>{"[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended"}</div>
|
||||
<div>{"[INFO]: :-) Done in 0.69s"}</div>
|
||||
<div>{"[INFO]: :-) Your wasm pkg is ready to publish at /home/cecile/repos/blueprint-rs/./static."}</div>
|
||||
<div>{" Index: enabled, Upload: disabled, Cache: disabled, Cors: enabled, Range: enabled, Sort: enabled, Threads: 3"}</div>
|
||||
<div>{" Auth: disabled, Compression: disabled"}</div>
|
||||
<div>{" https: disabled, Cert: , Cert-Password: "}</div>
|
||||
<div>{" Root: /home/cecile/repos/blueprint-rs,"}</div>
|
||||
<div>{" TryFile404: "}</div>
|
||||
<div>{" Address: http://0.0.0.0:8000"}</div>
|
||||
<div>{" ======== [2020-09-07 20:39:46] ========"}</div>
|
||||
<div>{"[2020-09-07 20:39:46] - 127.0.0.1 - 200 - GET /"}</div>
|
||||
<div>{"[2020-09-07 20:39:46] - 127.0.0.1 - 200 - GET /static/blueprint.css"}</div>
|
||||
<div>{"[2020-09-07 20:39:46] - 127.0.0.1 - 200 - GET /static/wasm.js"}</div>
|
||||
<div>{"[2020-09-07 20:39:46] - 127.0.0.1 - 200 - GET /static/wasm_bg.wasm"}</div>
|
||||
</pre>
|
||||
</Collapse>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
|
@ -199,33 +199,19 @@ impl Component for Collapse {
|
|||
|
||||
#[cfg(feature = "doc")]
|
||||
pub mod doc {
|
||||
use super::*;
|
||||
use crate::buttons::Button;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct CollapseDoc {
|
||||
link: ComponentLink<Self>,
|
||||
collapsed: bool,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
ToggleCollapse,
|
||||
}
|
||||
pub struct CollapseDoc;
|
||||
|
||||
impl Component for CollapseDoc {
|
||||
type Message = Msg;
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
CollapseDoc {
|
||||
collapsed: true,
|
||||
link,
|
||||
}
|
||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
CollapseDoc
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::ToggleCollapse => self.collapsed ^= true,
|
||||
}
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -234,34 +220,12 @@ pub mod doc {
|
|||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let source = crate::include_example!("example.rs");
|
||||
|
||||
html! {
|
||||
<div>
|
||||
<h1>{"Collapse"}</h1>
|
||||
<Button onclick=self.link.callback(|_| Msg::ToggleCollapse)>
|
||||
{"Toggle collapse"}
|
||||
</Button>
|
||||
<Collapse
|
||||
is_open=!self.collapsed
|
||||
keep_children_mounted=true
|
||||
>
|
||||
<pre class="bp3-code-block">
|
||||
<div>{"[INFO]: Installing wasm-bindgen..."}</div>
|
||||
<div>{"[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended"}</div>
|
||||
<div>{"[INFO]: :-) Done in 0.69s"}</div>
|
||||
<div>{"[INFO]: :-) Your wasm pkg is ready to publish at /home/cecile/repos/blueprint-rs/./static."}</div>
|
||||
<div>{" Index: enabled, Upload: disabled, Cache: disabled, Cors: enabled, Range: enabled, Sort: enabled, Threads: 3"}</div>
|
||||
<div>{" Auth: disabled, Compression: disabled"}</div>
|
||||
<div>{" https: disabled, Cert: , Cert-Password: "}</div>
|
||||
<div>{" Root: /home/cecile/repos/blueprint-rs,"}</div>
|
||||
<div>{" TryFile404: "}</div>
|
||||
<div>{" Address: http://0.0.0.0:8000"}</div>
|
||||
<div>{" ======== [2020-09-07 20:39:46] ========"}</div>
|
||||
<div>{"[2020-09-07 20:39:46] - 127.0.0.1 - 200 - GET /"}</div>
|
||||
<div>{"[2020-09-07 20:39:46] - 127.0.0.1 - 200 - GET /static/blueprint.css"}</div>
|
||||
<div>{"[2020-09-07 20:39:46] - 127.0.0.1 - 200 - GET /static/wasm.js"}</div>
|
||||
<div>{"[2020-09-07 20:39:46] - 127.0.0.1 - 200 - GET /static/wasm_bg.wasm"}</div>
|
||||
</pre>
|
||||
</Collapse>
|
||||
<h1>{"Tree"}</h1>
|
||||
<div>{source}</div>
|
||||
</div>
|
||||
}
|
||||
}
|
91
src/example.rs
Normal file
91
src/example.rs
Normal file
|
@ -0,0 +1,91 @@
|
|||
use crate::{Button, Collapse, IconName, Intent};
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct ExampleContainer {
|
||||
collapsed: bool,
|
||||
props: Props,
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
ToggleSource,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct Props {
|
||||
pub source: &'static str,
|
||||
pub children: html::Children,
|
||||
}
|
||||
|
||||
impl Component for ExampleContainer {
|
||||
type Message = Msg;
|
||||
type Properties = Props;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
ExampleContainer {
|
||||
collapsed: true,
|
||||
props,
|
||||
link,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::ToggleSource => self.collapsed ^= true,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
// TODO: never re-render this component? How to optimize this
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div class="docs-example-wrapper">
|
||||
<div class="docs-example">
|
||||
{self.props.children.clone()}
|
||||
</div>
|
||||
<div class="docs-source">
|
||||
<Button
|
||||
icon=IconName::Code
|
||||
fill={true}
|
||||
intent={Intent::Primary}
|
||||
minimal={true}
|
||||
onclick=self.link.callback(|_| Msg::ToggleSource)
|
||||
>
|
||||
{"View source"}
|
||||
</Button>
|
||||
<Collapse
|
||||
is_open=!self.collapsed
|
||||
keep_children_mounted=true
|
||||
>
|
||||
<pre class="bp3-code-block">{self.props.source}</pre>
|
||||
</Collapse>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! include_example {
|
||||
($file:expr) => {{
|
||||
use crate::ExampleContainer;
|
||||
|
||||
let source = include_str!($file);
|
||||
|
||||
mod source {
|
||||
// TODO: example.rs files are not formatted because of this include
|
||||
include!($file);
|
||||
}
|
||||
use source::Example;
|
||||
|
||||
html! {
|
||||
<ExampleContainer source={source}>
|
||||
<Example />
|
||||
</ExampleContainer>
|
||||
}
|
||||
}};
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
pub mod controls;
|
26
src/icon/example.rs
Normal file
26
src/icon/example.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
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>
|
||||
}
|
||||
}
|
||||
}
|
|
@ -96,28 +96,33 @@ impl Component for Icon {
|
|||
|
||||
#[cfg(feature = "doc")]
|
||||
pub mod doc {
|
||||
use super::*;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct IconDoc {}
|
||||
pub struct IconDoc;
|
||||
|
||||
impl Component for IconDoc {
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
IconDoc {}
|
||||
IconDoc
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let source = crate::include_example!("example.rs");
|
||||
|
||||
html! {
|
||||
<div>
|
||||
<h1>{"Icon"}</h1>
|
||||
<Icon icon=IconName::Print />
|
||||
<div>{source}</div>
|
||||
</div>
|
||||
}
|
||||
}
|
29
src/lib.rs
29
src/lib.rs
|
@ -1,13 +1,30 @@
|
|||
#![recursion_limit = "512"]
|
||||
|
||||
#[cfg(feature = "doc")]
|
||||
extern crate self as yewprint;
|
||||
|
||||
#[cfg(feature = "doc")]
|
||||
mod app;
|
||||
pub mod buttons;
|
||||
pub mod collapse;
|
||||
pub mod forms;
|
||||
pub mod icon;
|
||||
pub mod menu;
|
||||
pub mod tree;
|
||||
mod buttons;
|
||||
mod collapse;
|
||||
#[cfg(feature = "doc")]
|
||||
mod example;
|
||||
mod icon;
|
||||
mod menu;
|
||||
mod switch;
|
||||
mod tree;
|
||||
|
||||
#[cfg(feature = "doc")]
|
||||
pub use app::*;
|
||||
pub use buttons::*;
|
||||
pub use collapse::*;
|
||||
#[cfg(feature = "doc")]
|
||||
pub use example::*;
|
||||
pub use icon::*;
|
||||
pub use id_tree;
|
||||
pub use menu::*;
|
||||
pub use switch::*;
|
||||
pub use tree::*;
|
||||
|
||||
use yew::virtual_dom::Classes;
|
||||
|
||||
|
|
126
src/tree/example.rs
Normal file
126
src/tree/example.rs
Normal file
|
@ -0,0 +1,126 @@
|
|||
use yew::prelude::*;
|
||||
use yewprint::{Tree, Icon, NodeData, IconName, Intent, TreeData};
|
||||
use yewprint::id_tree::{InsertBehavior, Node, TreeBuilder, NodeId};
|
||||
|
||||
pub struct Example {
|
||||
tree: TreeData<i32>,
|
||||
callback_expand_node: Callback<(NodeId, MouseEvent)>,
|
||||
callback_select_node: Callback<(NodeId, MouseEvent)>,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
ExpandNode(NodeId),
|
||||
SelectNode(NodeId),
|
||||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
let mut tree = TreeBuilder::new().build();
|
||||
let root_id = tree
|
||||
.insert(
|
||||
Node::new(NodeData {
|
||||
data: 0,
|
||||
..Default::default()
|
||||
}),
|
||||
InsertBehavior::AsRoot,
|
||||
)
|
||||
.unwrap();
|
||||
let dir1 = tree
|
||||
.insert(
|
||||
Node::new(NodeData {
|
||||
icon: Some(IconName::FolderClose),
|
||||
label: "Big directory".into(),
|
||||
has_caret: true,
|
||||
data: 1,
|
||||
..Default::default()
|
||||
}),
|
||||
InsertBehavior::UnderNode(&root_id),
|
||||
)
|
||||
.unwrap();
|
||||
for i in 0..10 {
|
||||
let dir2 = tree
|
||||
.insert(
|
||||
Node::new(NodeData {
|
||||
icon: Some(IconName::FolderClose),
|
||||
label: format!("Directory {}", i + 1).into(),
|
||||
has_caret: true,
|
||||
data: 1,
|
||||
..Default::default()
|
||||
}),
|
||||
InsertBehavior::UnderNode(&dir1),
|
||||
)
|
||||
.unwrap();
|
||||
for i in 0..10 {
|
||||
tree.insert(
|
||||
Node::new(NodeData {
|
||||
icon: Some(IconName::Document),
|
||||
label: format!("File {}", i + 1).into(),
|
||||
data: i,
|
||||
..Default::default()
|
||||
}),
|
||||
InsertBehavior::UnderNode(&dir2),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
tree.insert(
|
||||
Node::new(NodeData {
|
||||
icon: Some(IconName::Tag),
|
||||
icon_intent: Some(Intent::Primary),
|
||||
label: "Outer file".into(),
|
||||
secondary_label: Some(html!(<Icon icon=IconName::EyeOpen />)),
|
||||
data: 3,
|
||||
..Default::default()
|
||||
}),
|
||||
InsertBehavior::UnderNode(&root_id),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
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)),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::ExpandNode(node_id) => {
|
||||
let mut tree = self.tree.borrow_mut();
|
||||
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
|
||||
} else {
|
||||
IconName::FolderClose
|
||||
})
|
||||
}
|
||||
Msg::SelectNode(node_id) => {
|
||||
let mut tree = self.tree.borrow_mut();
|
||||
let node = tree.get_mut(&node_id).unwrap();
|
||||
node.data_mut().is_selected ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&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())
|
||||
/>
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
use crate::collapse::Collapse;
|
||||
use crate::icon::{Icon, IconName};
|
||||
use crate::Intent;
|
||||
pub use id_tree::*;
|
||||
use id_tree::*;
|
||||
use std::cell::{Ref, RefCell, RefMut};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::collections::HashMap;
|
||||
|
@ -365,112 +365,19 @@ impl Component for TreeNode {
|
|||
|
||||
#[cfg(feature = "doc")]
|
||||
pub mod doc {
|
||||
use super::*;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct TreeDoc {
|
||||
tree: TreeData<i32>,
|
||||
callback_expand_node: Callback<(NodeId, MouseEvent)>,
|
||||
callback_select_node: Callback<(NodeId, MouseEvent)>,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
ExpandNode(NodeId),
|
||||
SelectNode(NodeId),
|
||||
}
|
||||
pub struct TreeDoc;
|
||||
|
||||
impl Component for TreeDoc {
|
||||
type Message = Msg;
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
let mut tree = TreeBuilder::new().build();
|
||||
let root_id = tree
|
||||
.insert(
|
||||
Node::new(NodeData {
|
||||
data: 0,
|
||||
..Default::default()
|
||||
}),
|
||||
InsertBehavior::AsRoot,
|
||||
)
|
||||
.unwrap();
|
||||
let dir1 = tree
|
||||
.insert(
|
||||
Node::new(NodeData {
|
||||
icon: Some(IconName::FolderClose),
|
||||
label: "Big directory".into(),
|
||||
has_caret: true,
|
||||
data: 1,
|
||||
..Default::default()
|
||||
}),
|
||||
InsertBehavior::UnderNode(&root_id),
|
||||
)
|
||||
.unwrap();
|
||||
for i in 0..10 {
|
||||
let dir2 = tree
|
||||
.insert(
|
||||
Node::new(NodeData {
|
||||
icon: Some(IconName::FolderClose),
|
||||
label: format!("Directory {}", i + 1).into(),
|
||||
has_caret: true,
|
||||
data: 1,
|
||||
..Default::default()
|
||||
}),
|
||||
InsertBehavior::UnderNode(&dir1),
|
||||
)
|
||||
.unwrap();
|
||||
for i in 0..10 {
|
||||
tree.insert(
|
||||
Node::new(NodeData {
|
||||
icon: Some(IconName::Document),
|
||||
label: format!("File {}", i + 1).into(),
|
||||
data: i,
|
||||
..Default::default()
|
||||
}),
|
||||
InsertBehavior::UnderNode(&dir2),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
tree.insert(
|
||||
Node::new(NodeData {
|
||||
icon: Some(IconName::Tag),
|
||||
icon_intent: Some(Intent::Primary),
|
||||
label: "Outer file".into(),
|
||||
secondary_label: Some(html!(<Icon icon=IconName::EyeOpen />)),
|
||||
data: 3,
|
||||
..Default::default()
|
||||
}),
|
||||
InsertBehavior::UnderNode(&root_id),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
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)),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::ExpandNode(node_id) => {
|
||||
let mut tree = self.tree.borrow_mut();
|
||||
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
|
||||
} else {
|
||||
IconName::FolderClose
|
||||
})
|
||||
}
|
||||
Msg::SelectNode(node_id) => {
|
||||
let mut tree = self.tree.borrow_mut();
|
||||
let node = tree.get_mut(&node_id).unwrap();
|
||||
node.data_mut().is_selected ^= true;
|
||||
}
|
||||
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
TreeDoc
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -479,15 +386,12 @@ pub mod doc {
|
|||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let source = crate::include_example!("example.rs");
|
||||
|
||||
html! {
|
||||
<div>
|
||||
<h1>{"Tree"}</h1>
|
||||
<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())
|
||||
/>
|
||||
<div>{source}</div>
|
||||
</div>
|
||||
}
|
||||
}
|
|
@ -72,6 +72,36 @@
|
|||
line-height: 40px;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.docs-example-wrapper .bp3-code-block {
|
||||
/*
|
||||
display: inline-block;
|
||||
clear: both;
|
||||
*/
|
||||
}
|
||||
|
||||
.docs-example-wrapper .docs-example {
|
||||
border-radius: 6px;
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.bp3-dark .docs-example-wrapper .docs-example {
|
||||
background-color: #293742;
|
||||
}
|
||||
|
||||
.docs-example-wrapper > .docs-source > .bp3-button {
|
||||
background-color: #ebf1f5;
|
||||
}
|
||||
|
||||
.bp3-dark .docs-example-wrapper > .docs-source > .bp3-button {
|
||||
background-color: #394b59;
|
||||
}
|
||||
|
||||
.docs-example-wrapper > .docs-source {
|
||||
margin-bottom: 40px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body></body>
|
||||
|
|
Loading…
Reference in a new issue