Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Components implementation #91

Merged
merged 43 commits into from
Jan 15, 2018
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d6b0872
Add minimal components implementation
therustmonk Jan 7, 2018
d043202
Add context specification to components
therustmonk Jan 7, 2018
0bb89e2
Remove message type restriction of services
therustmonk Jan 7, 2018
1b18a07
Add local sender to keep a context
therustmonk Jan 8, 2018
9e87d74
Add initialize method to Component trait
therustmonk Jan 8, 2018
0b9ace1
Add documentation for components feature
therustmonk Jan 8, 2018
95d728c
Move the context to the first place
therustmonk Jan 8, 2018
a7d9bf5
Use reference to a local sender (context)
therustmonk Jan 8, 2018
c07e921
Add reuse method to App to reuse a shared context
therustmonk Jan 8, 2018
5cd1fc6
Rewrite examples with Component approach
therustmonk Jan 8, 2018
4d7f957
Fix tests
therustmonk Jan 8, 2018
808d8b4
Add create method to Component trait
therustmonk Jan 8, 2018
9d377be
Add warning about using of callbacks
therustmonk Jan 9, 2018
0d67a33
Add Properties type parameter and optimize MSG requirement of Scope
therustmonk Jan 9, 2018
928ce71
Replace message type to complex component type
therustmonk Jan 9, 2018
269b7a3
Add ComponentUpdate message
therustmonk Jan 9, 2018
6c5a29a
Add ScopeBuilder
therustmonk Jan 9, 2018
c172ff7
Add minimal properties implementation
therustmonk Jan 10, 2018
1aefc2a
Add TypeId to VComp
therustmonk Jan 10, 2018
6c6ef18
Update properties when tree rerendered
therustmonk Jan 10, 2018
827836b
Add ScopeEnv
therustmonk Jan 10, 2018
eacb814
Use ScopeSender to update properties
therustmonk Jan 10, 2018
7ec2824
Fix custom components example
therustmonk Jan 10, 2018
6440442
Send a new properties set to a component when it was changed
therustmonk Jan 10, 2018
0570e6b
Add should_update flag
therustmonk Jan 10, 2018
9ce5a1f
Wrap callback type to a struct
therustmonk Jan 10, 2018
1d51d1c
Replace internal serialization with memory transmuting
therustmonk Jan 10, 2018
40913f8
Add events to components
therustmonk Jan 10, 2018
5a75b70
Link callback with parent's component scope
therustmonk Jan 10, 2018
5228e39
Send messages from child component to a parent
therustmonk Jan 11, 2018
9623202
Add property transformation for string types
therustmonk Jan 11, 2018
b5949c3
Add scopes hierarchy example
therustmonk Jan 11, 2018
ecf3641
Reimplement App type based on scope
therustmonk Jan 11, 2018
f84e08c
Revert part of examples back to App type workflow
therustmonk Jan 11, 2018
7b758fb
Fix all examples
therustmonk Jan 11, 2018
251739f
Improve performance: bulk update calls to a single timeout call
therustmonk Jan 11, 2018
8a6f387
Fix missing docs
therustmonk Jan 11, 2018
fdaebdb
Improve AppSender ergonomics
therustmonk Jan 12, 2018
4618497
Merge branch 'master' into components
therustmonk Jan 12, 2018
0c1b266
Fix dashed attributes in macro
therustmonk Jan 12, 2018
f9ffe67
Fix tests
therustmonk Jan 14, 2018
daf1ddd
Add Renderable trait, remove redundant App struct, rename ScopeRef to…
therustmonk Jan 14, 2018
da54bd5
Add information about Components to README
therustmonk Jan 15, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions examples/counter/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ extern crate chrono;
extern crate yew;

use chrono::prelude::*;
use yew::html::*;
use yew::prelude::*;
use yew::services::console::ConsoleService;

struct Context {
Expand All @@ -20,7 +20,7 @@ enum Msg {
Bulk(Vec<Msg>),
}

fn update(context: &mut Context, model: &mut Model, msg: Msg) {
fn update(context: &mut AppContext<Context, Model, Msg>, model: &mut Model, msg: Msg) -> ShouldUpdate {
match msg {
Msg::Increment => {
model.value = model.value + 1;
Expand All @@ -36,9 +36,10 @@ fn update(context: &mut Context, model: &mut Model, msg: Msg) {
}
}
}
true
}

fn view(model: &Model) -> Html<Msg> {
fn view(model: &Model) -> AppHtml<Context, Model, Msg> {
html! {
<div>
<nav class="menu",>
Expand All @@ -54,7 +55,7 @@ fn view(model: &Model) -> Html<Msg> {

fn main() {
yew::initialize();
let mut app = App::new();
let app = App::new();
let context = Context {
console: ConsoleService,
};
Expand Down
17 changes: 9 additions & 8 deletions examples/crm/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ extern crate serde_derive;
#[macro_use]
extern crate yew;

use yew::html::*;
use yew::prelude::*;
use yew::format::Json;
use yew::services::dialog::DialogService;
use yew::services::storage::{StorageService, Scope};
use yew::services::storage::{StorageService, Area};

const KEY: &'static str = "yew.crm.database";

Expand Down Expand Up @@ -64,7 +64,7 @@ fn load_database(context: &mut Context) -> Database {
})
}

fn update(context: &mut Context, model: &mut Model, msg: Msg) {
fn update(context: &mut AppContext<Context, Model, Msg>, model: &mut Model, msg: Msg) -> ShouldUpdate {
let mut new_scene = None;
match model.scene {
Scene::Initialization => {
Expand Down Expand Up @@ -134,9 +134,10 @@ fn update(context: &mut Context, model: &mut Model, msg: Msg) {
if let Some(new_scene) = new_scene.take() {
model.scene = new_scene;
}
true
}

fn view(model: &Model) -> Html<Msg> {
fn view(model: &Model) -> AppHtml<Context, Model, Msg> {
match model.scene {
Scene::Initialization => html! {
<div>{ "Loading..." }</div>
Expand Down Expand Up @@ -170,7 +171,7 @@ fn view(model: &Model) -> Html<Msg> {
}
}

fn view_client(client: &Client) -> Html<Msg> {
fn view_client(client: &Client) -> AppHtml<Context, Model, Msg> {
html! {
<div class="client",>
<p>{ format!("First Name: {}", client.first_name) }</p>
Expand All @@ -179,7 +180,7 @@ fn view_client(client: &Client) -> Html<Msg> {
}
}

fn view_first_name_input(client: &Client) -> Html<Msg> {
fn view_first_name_input(client: &Client) -> AppHtml<Context, Model, Msg> {
html! {
<input class=("new-client", "firstname"),
placeholder="First name",
Expand All @@ -189,7 +190,7 @@ fn view_first_name_input(client: &Client) -> Html<Msg> {
}
}

fn view_last_name_input(client: &Client) -> Html<Msg> {
fn view_last_name_input(client: &Client) -> AppHtml<Context, Model, Msg> {
html! {
<input class=("new-client", "lastname"),
placeholder="Last name",
Expand All @@ -203,7 +204,7 @@ fn main() {
yew::initialize();
let mut app = App::new();
let mut context = Context {
storage: StorageService::new(Scope::Local),
storage: StorageService::new(Area::Local),
dialog: DialogService,
};
let database = load_database(&mut context);
Expand Down
7 changes: 7 additions & 0 deletions examples/custom_components/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "custom_components"
version = "0.1.0"
authors = ["Denis Kolodin <[email protected]>"]

[dependencies]
yew = { path = "../.." }
76 changes: 76 additions & 0 deletions examples/custom_components/src/barrier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use yew::prelude::*;
use button::Button;

pub struct Barrier {
limit: u32,
counter: u32,
onsignal: Option<Callback<()>>,
}

pub enum Msg {
ChildClicked,
}

#[derive(PartialEq, Clone)]
pub struct Props {
pub limit: u32,
pub onsignal: Option<Callback<()>>,
}

impl Default for Props {
fn default() -> Self {
Props {
limit: 0,
onsignal: None,
}
}
}


impl<CTX: 'static> Component<CTX> for Barrier {
type Msg = Msg;
type Properties = Props;

fn create(_: &mut ScopeRef<CTX, Self>) -> Self {
Barrier {
limit: 0,
counter: 0,
onsignal: None,
}
}

fn update(&mut self, msg: Self::Msg, _: &mut ScopeRef<CTX, Self>) -> ShouldUpdate {
match msg {
Msg::ChildClicked => {
self.counter += 1;
if self.counter >= self.limit {
if let Some(ref mut callback) = self.onsignal {
callback.emit(());
self.counter = 0;
}
}
}
}
true
}

fn change(&mut self, props: Self::Properties, _: &mut ScopeRef<CTX, Self>) -> ShouldUpdate {
self.limit = props.limit;
self.onsignal = props.onsignal;
true
}

fn view(&self) -> Html<CTX, Self> {
html! {
<div>
<p>{ format!("{} on {} clicked", self.counter, self.limit) }</p>
<Button: onsignal=|_| Msg::ChildClicked, />
<Button: onsignal=|_| Msg::ChildClicked, />
<Button: onsignal=|_| Msg::ChildClicked, title="Middle", />
<Button: onsignal=|_| Msg::ChildClicked, />
<Button: onsignal=|_| Msg::ChildClicked, />
</div>
}
}
}

61 changes: 61 additions & 0 deletions examples/custom_components/src/button.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use yew::prelude::*;

pub struct Button {
title: String,
onsignal: Option<Callback<()>>,
}

pub enum Msg {
Clicked,
}

#[derive(PartialEq, Clone)]
pub struct Props {
pub title: String,
pub onsignal: Option<Callback<()>>,
}

impl Default for Props {
fn default() -> Self {
Props {
title: "Send Signal".into(),
onsignal: None,
}
}
}

impl<CTX: 'static> Component<CTX> for Button {
type Msg = Msg;
type Properties = Props;

fn create(_: &mut ScopeRef<CTX, Self>) -> Self {
Button {
title: "Send Signal".into(),
onsignal: None,
}
}

fn update(&mut self, msg: Self::Msg, _: &mut ScopeRef<CTX, Self>) -> ShouldUpdate {
match msg {
Msg::Clicked => {
if let Some(ref mut callback) = self.onsignal {
callback.emit(());
}
}
}
false
}

fn change(&mut self, props: Self::Properties, _: &mut ScopeRef<CTX, Self>) -> ShouldUpdate {
self.title = props.title;
self.onsignal = props.onsignal;
true
}

fn view(&self) -> Html<CTX, Self> {
html! {
<button onclick=|_| Msg::Clicked,>{ &self.title }</button>
}
}
}

86 changes: 86 additions & 0 deletions examples/custom_components/src/counter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use yew::prelude::*;

#[derive(PartialEq, Clone)]
pub enum Color {
Red,
Green,
Blue,
}

pub struct Counter {
value: u32,
color: Color,
onclick: Option<Callback<u32>>,
}

pub enum Msg {
Increase,
}

#[derive(PartialEq, Clone)]
pub struct Props {
pub color: Color,
pub onclick: Option<Callback<u32>>,
}

impl Default for Props {
fn default() -> Self {
Props {
color: Color::Green,
onclick: None,
}
}
}

impl<CTX: Printer + 'static> Component<CTX> for Counter {
type Msg = Msg;
type Properties = Props;

fn create(_: &mut ScopeRef<CTX, Self>) -> Self {
Counter {
value: 0,
color: Color::Green,
onclick: None,
}
}

fn update(&mut self, msg: Self::Msg, context: &mut ScopeRef<CTX, Self>) -> ShouldUpdate {
match msg {
Msg::Increase => {
self.value = self.value + 1;
if let Some(ref onclick) = self.onclick {
onclick.emit(self.value);
}
context.print(format!("<printer> value of model is {}", self.value).as_str());
}
}
true
}

fn change(&mut self, props: Self::Properties, _: &mut ScopeRef<CTX, Self>) -> ShouldUpdate {
self.color = props.color;
self.onclick = props.onclick;
true
}

fn view(&self) -> Html<CTX, Self> {
let colorize = {
match self.color {
Color::Red => "background: red;",
Color::Green => "background: green;",
Color::Blue => "background: blue;",
}
};
html! {
<div>
<p>{ self.value }</p>
<button style=colorize, onclick=|_| Msg::Increase,>{ "Increase internal counter" }</button>
</div>
}
}
}


pub trait Printer {
fn print(&mut self, data: &str);
}
Loading