mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Reorganize examples and general repo layout (#1092)
* Reorganize crates * Remove symlink * Check examples * Cleanup CI scripts * nits * cleanup * cargo fmt * Fix yew-stdweb * cargo clippy --all * stdweb-examples * run_emscripten_checks.sh * Fix typo * fix typo * yew-stdweb * Run tests from yew-stdweb * fix webgl script
This commit is contained in:
parent
6c16c8c134
commit
fa8a1d9f00
@ -1,2 +0,0 @@
|
||||
report_todo = "Unnumbered"
|
||||
report_fixme = "Unnumbered"
|
||||
@ -36,6 +36,6 @@ install:
|
||||
- ./ci/install_cargo_web.sh
|
||||
|
||||
script:
|
||||
- ./ci/run_checks.sh
|
||||
- ./ci/run_stable_checks.sh
|
||||
- GECKODRIVER=$(pwd)/geckodriver ./ci/run_tests.sh
|
||||
- ./ci/check_examples.sh
|
||||
- ./ci/run_emscripten_checks.sh
|
||||
|
||||
@ -404,7 +404,7 @@ cloned is when a wrapper component re-renders nested children components.
|
||||
|
||||
- #### ⚡️ Features
|
||||
|
||||
- `Future` support :tada: A `Component` can update following the completion of a `Future`. Check out [this example](https://github.com/yewstack/yew/tree/master/examples/futures) to see how it works. This approach was borrowed from a fork of Yew called [`plaster`](https://github.com/carlosdp/plaster) created by [@carlosdp]. [[@hgzimmerman], [#717](https://github.com/yewstack/yew/pull/717)]
|
||||
- `Future` support :tada: A `Component` can update following the completion of a `Future`. Check out [this example](https://github.com/yewstack/yew/tree/v0.14.0/examples/futures) to see how it works. This approach was borrowed from a fork of Yew called [`plaster`](https://github.com/carlosdp/plaster) created by [@carlosdp]. [[@hgzimmerman], [#717](https://github.com/yewstack/yew/pull/717)]
|
||||
- Added the `agent` and `services` features so that this functionality can be disabled (useful if you are switching to using `Future`s). [[@hgzimmerman], [#684](https://github.com/yewstack/yew/pull/684)]
|
||||
- Add `ref` keyword for allowing a `Component` to have a direct reference to its rendered elements. For example, you can now easily focus an `<input>` element after mounting. [[@jstarry], [#715](https://github.com/yewstack/yew/pull/715)]
|
||||
|
||||
|
||||
@ -8,31 +8,25 @@
|
||||
rustup target add wasm32-unknown-unknown
|
||||
```
|
||||
|
||||
#### Install [cargo-web]
|
||||
#### Build
|
||||
|
||||
This is an optional tool that simplifies running the examples:
|
||||
```bash
|
||||
cargo build --target wasm32-unknown-unknown
|
||||
```
|
||||
|
||||
#### Examples
|
||||
|
||||
TODO: Add more info
|
||||
|
||||
##### stdweb
|
||||
In order to run the examples in `./yew-stdweb`, you may wish to install [cargo-web]:
|
||||
|
||||
```bash
|
||||
cargo install cargo-web
|
||||
```
|
||||
|
||||
> Add `--force` option to ensure you install the latest version.
|
||||
|
||||
[cargo-web]: https://github.com/koute/cargo-web
|
||||
|
||||
#### Build
|
||||
|
||||
Either
|
||||
```bash
|
||||
cargo build --target wasm32-unknown-unknown --features web_sys
|
||||
```
|
||||
or
|
||||
```bash
|
||||
cargo build --target wasm32-unknown-unknown --features std_web
|
||||
```
|
||||
See more about features [here](https://docs.rs/yew/0.14.0/yew/#important-notes)
|
||||
|
||||
|
||||
#### Test
|
||||
|
||||
##### Web Tests
|
||||
@ -48,9 +42,9 @@ although more driver support may be added! You can download these at:
|
||||
* safaridriver - should be preinstalled on OSX
|
||||
|
||||
##### Macro Tests
|
||||
When adding or updating tests, please make sure you have updated the appropriate `stderr` file, which you can find [here](https://github.com/yewstack/yew/tree/master/crates/macro/tests/macro) for the `html!` macro. These files ensure that macro compilation errors are correct and easy to understand.
|
||||
When adding or updating tests, please make sure you have updated the appropriate `stderr` file, which you can find [here](https://github.com/yewstack/yew/tree/master/yew-macro/tests/macro) for the `html!` macro. These files ensure that macro compilation errors are correct and easy to understand.
|
||||
|
||||
To update or generate a new `stderr` file you can run `TRYBUILD=overwrite cargo test --test macro_test` or `TRYBUILD=overwrite cargo test --test derive_props_test` from the `crates/macro` directory.
|
||||
To update or generate a new `stderr` file you can run `TRYBUILD=overwrite cargo test --test macro_test` or `TRYBUILD=overwrite cargo test --test derive_props_test` from the `yew-macro` directory.
|
||||
|
||||
##### Running Tests
|
||||
|
||||
@ -60,10 +54,5 @@ To update or generate a new `stderr` file you can run `TRYBUILD=overwrite cargo
|
||||
or
|
||||
|
||||
```bash
|
||||
cargo test --target wasm32-unknown-unknown --features wasm_test --features web_sys
|
||||
```
|
||||
or
|
||||
|
||||
```bash
|
||||
cargo test --target wasm32-unknown-unknown --features wasm_test --features std_web
|
||||
cargo test --target wasm32-unknown-unknown --features wasm_test
|
||||
```
|
||||
|
||||
168
Cargo.toml
168
Cargo.toml
@ -1,142 +1,32 @@
|
||||
[package]
|
||||
name = "yew"
|
||||
version = "0.14.3"
|
||||
edition = "2018"
|
||||
authors = [
|
||||
"Denis Kolodin <deniskolodin@gmail.com>",
|
||||
"Justin Starry <justin@yew.rs>",
|
||||
]
|
||||
repository = "https://github.com/yewstack/yew"
|
||||
homepage = "https://github.com/yewstack/yew"
|
||||
documentation = "https://docs.rs/yew/"
|
||||
license = "MIT/Apache-2.0"
|
||||
readme = "README.md"
|
||||
keywords = ["web", "asmjs", "webasm", "javascript"]
|
||||
categories = ["gui", "web-programming"]
|
||||
description = "A framework for making client-side single-page apps"
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "yewstack/yew" }
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
anymap = "0.12"
|
||||
bincode = { version = "~1.2.1", optional = true }
|
||||
cfg-if = "0.1"
|
||||
cfg-match = "0.2"
|
||||
console_error_panic_hook = { version = "0.1", optional = true }
|
||||
futures = { version = "0.3", optional = true }
|
||||
gloo = { version = "0.2.1", optional = true }
|
||||
http = "0.2"
|
||||
indexmap = "1.0.2"
|
||||
js-sys = { version = "0.3", optional = true }
|
||||
log = "0.4"
|
||||
proc-macro-hack = "0.5"
|
||||
proc-macro-nested = "0.1"
|
||||
rmp-serde = { version = "0.14.0", optional = true }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_cbor = { version = "0.11.1", optional = true }
|
||||
serde_json = "1.0"
|
||||
serde_yaml = { version = "0.8.3", optional = true }
|
||||
slab = "0.4"
|
||||
stdweb = { version = "0.4.20", optional = true }
|
||||
thiserror = "1"
|
||||
toml = { version = "0.5", optional = true }
|
||||
wasm-bindgen = { version = "0.2.60", optional = true }
|
||||
wasm-bindgen-futures = { version = "0.4", optional = true }
|
||||
yew-macro = { version = "0.14.1", path = "crates/macro" }
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3"
|
||||
optional = true
|
||||
features = [
|
||||
"AbortController",
|
||||
"AbortSignal",
|
||||
"BinaryType",
|
||||
"Blob",
|
||||
"BlobPropertyBag",
|
||||
"console",
|
||||
"DedicatedWorkerGlobalScope",
|
||||
"Document",
|
||||
"DomTokenList",
|
||||
"DragEvent",
|
||||
"Element",
|
||||
"Event",
|
||||
"EventTarget",
|
||||
"File",
|
||||
"FileList",
|
||||
"FileReader",
|
||||
"FocusEvent",
|
||||
"Headers",
|
||||
"HtmlElement",
|
||||
"HtmlInputElement",
|
||||
"HtmlSelectElement",
|
||||
"HtmlTextAreaElement",
|
||||
"KeyboardEvent",
|
||||
"Location",
|
||||
"MessageEvent",
|
||||
"MouseEvent",
|
||||
"Node",
|
||||
"ObserverCallback",
|
||||
"PointerEvent",
|
||||
"ReferrerPolicy",
|
||||
"Request",
|
||||
"RequestCache",
|
||||
"RequestCredentials",
|
||||
"RequestInit",
|
||||
"RequestMode",
|
||||
"RequestRedirect",
|
||||
"Response",
|
||||
"Storage",
|
||||
"Text",
|
||||
"TouchEvent",
|
||||
"UiEvent",
|
||||
"Url",
|
||||
"WebSocket",
|
||||
"WheelEvent",
|
||||
"Window",
|
||||
"Worker",
|
||||
"WorkerGlobalScope",
|
||||
"WorkerOptions",
|
||||
]
|
||||
|
||||
# Changes here must be reflected in `build.rs`
|
||||
[target.'cfg(all(target_arch = "wasm32", not(target_os="wasi"), not(cargo_web)))'.dependencies]
|
||||
wasm-bindgen = "0.2.60"
|
||||
|
||||
# Changes here must be reflected in `build.rs`
|
||||
[target.'cfg(all(target_arch = "wasm32", not(target_os="wasi"), not(cargo_web)))'.dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.4"
|
||||
base64 = "0.12.0"
|
||||
ssri = "5.0.0"
|
||||
|
||||
[target.'cfg(target_os = "emscripten")'.dependencies]
|
||||
ryu = "1.0.2" # 1.0.1 breaks emscripten
|
||||
|
||||
[dev-dependencies]
|
||||
serde_derive = "1"
|
||||
trybuild = "1.0"
|
||||
rustversion = "1.0"
|
||||
rmp-serde = "0.14.0"
|
||||
bincode = "~1.2.1"
|
||||
|
||||
[features]
|
||||
default = ["services", "agent"]
|
||||
std_web = ["stdweb"]
|
||||
web_sys = ["console_error_panic_hook", "futures", "gloo", "js-sys", "web-sys", "wasm-bindgen", "wasm-bindgen-futures"]
|
||||
doc_test = []
|
||||
wasm_test = []
|
||||
services = []
|
||||
agent = ["bincode"]
|
||||
yaml = ["serde_yaml"]
|
||||
msgpack = ["rmp-serde"]
|
||||
cbor = ["serde_cbor"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["web_sys", "agent", "services", "yaml", "cbor", "toml", "msgpack", "doc_test"]
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"crates/macro",
|
||||
"crates/functional",
|
||||
"yew",
|
||||
"yew-functional",
|
||||
"yew-macro",
|
||||
|
||||
# Examples
|
||||
"examples/counter",
|
||||
"examples/crm",
|
||||
"examples/custom_components",
|
||||
"examples/dashboard",
|
||||
"examples/file_upload",
|
||||
"examples/fragments",
|
||||
"examples/futures",
|
||||
"examples/game_of_life",
|
||||
"examples/inner_html",
|
||||
"examples/js_callback",
|
||||
"examples/large_table",
|
||||
"examples/minimal",
|
||||
"examples/mount_point",
|
||||
"examples/multi_thread",
|
||||
"examples/nested_list",
|
||||
"examples/node_refs",
|
||||
"examples/npm_and_rest",
|
||||
"examples/pub_sub",
|
||||
"examples/server",
|
||||
"examples/textarea",
|
||||
"examples/timer",
|
||||
"examples/todomvc",
|
||||
"examples/two_apps",
|
||||
"examples/webgl",
|
||||
]
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
echo "$(rustup default)" | grep -q "1.39.0"
|
||||
emscripten_supported=$?
|
||||
set -euxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
|
||||
|
||||
# Some examples are known not to work with some builds, i.e. futures with the
|
||||
# std_web feature. Other items in the examples/ directory are helpers, i.e.
|
||||
# pub_sub and server. These block lists allow us to exempt some examples but
|
||||
# default opt-in any new examples to CI testing.
|
||||
COMMON_SKIP_EXAMPLES="examples/static examples/pub_sub examples/server \
|
||||
examples/target examples/web_sys examples/std_web"
|
||||
STD_WEB_SKIP_EXAMPLES="${COMMON_SKIP_EXAMPLES:?} examples/futures"
|
||||
WEB_SYS_SKIP_EXAMPLES="${COMMON_SKIP_EXAMPLES:?}"
|
||||
|
||||
# Make sure all examples are buildable with stdweb and web-sys.
|
||||
for ex in $(find examples -maxdepth 1 -mindepth 1 -type d); do
|
||||
pushd $ex
|
||||
|
||||
# TODO Can't build some demos with release, need fix
|
||||
|
||||
if [ "$emscripten_supported" == "0" ]; then
|
||||
if [[ ! " ${STD_WEB_SKIP_EXAMPLES[@]} " =~ " ${ex} " ]]; then
|
||||
# TODO - Emscripten builds are broken on rustc > 1.39.0
|
||||
cargo web build --target asmjs-unknown-emscripten --features std_web
|
||||
cargo web build --target wasm32-unknown-emscripten --features std_web
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ! " ${STD_WEB_SKIP_EXAMPLES[@]} " =~ " ${ex} " ]]; then
|
||||
cargo web build --target wasm32-unknown-unknown --features std_web
|
||||
fi
|
||||
if [[ ! " ${WEB_SYS_SKIP_EXAMPLES[@]} " =~ " ${ex} " ]]; then
|
||||
cargo build --target wasm32-unknown-unknown --features web_sys
|
||||
fi
|
||||
|
||||
# Reset cwd
|
||||
popd
|
||||
done
|
||||
@ -1,12 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "$(rustup default)" | grep -q "stable"
|
||||
if [ "$?" != "0" ]; then
|
||||
# only run checks on stable
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set -euxo pipefail
|
||||
cargo fmt --all -- --check
|
||||
cargo clippy --features std_web -- --deny=warnings
|
||||
cargo clippy --features web_sys -- --deny=warnings
|
||||
12
ci/run_emscripten_checks.sh
Executable file
12
ci/run_emscripten_checks.sh
Executable file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
echo "$(rustup default)" | grep -q "1.39.0"
|
||||
emscripten_supported=$?
|
||||
set -euxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
|
||||
|
||||
pushd yew-stdweb
|
||||
if [ "$emscripten_supported" == "0" ]; then
|
||||
# TODO - Emscripten builds are broken on rustc > 1.39.0
|
||||
cargo check --all --target asmjs-unknown-emscripten
|
||||
cargo check --all --target wasm32-unknown-emscripten
|
||||
fi
|
||||
popd
|
||||
28
ci/run_stable_checks.sh
Executable file
28
ci/run_stable_checks.sh
Executable file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "$(rustup default)" | grep -q "stable"
|
||||
if [ "$?" != "0" ]; then
|
||||
# only run checks on stable
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
cargo fmt --all -- --check
|
||||
cargo clippy --all -- --deny=warnings
|
||||
cargo check --all
|
||||
|
||||
# Enable all optional features
|
||||
(cd yew \
|
||||
&& cargo check --features cbor,msgpack,toml,yaml \
|
||||
&& cargo clippy --features cbor,msgpack,toml,yaml -- --deny=warnings)
|
||||
|
||||
# Check stdweb
|
||||
pushd yew-stdweb
|
||||
cargo fmt --all -- --check
|
||||
cargo clippy --all -- --deny=warnings
|
||||
cargo check --all --target wasm32-unknown-unknown
|
||||
|
||||
# webgl_stdweb doesn't play nice with wasm-bindgen
|
||||
(cd examples/webgl && cargo web check --target wasm32-unknown-unknown)
|
||||
popd
|
||||
@ -3,22 +3,25 @@ echo "$(rustup default)" | grep -q "1.39.0"
|
||||
emscripten_supported=$?
|
||||
set -euxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
|
||||
|
||||
cargo test --target wasm32-unknown-unknown --features wasm_test,std_web
|
||||
cargo test --target wasm32-unknown-unknown --features wasm_test,web_sys
|
||||
(cd yew \
|
||||
&& cargo test --target wasm32-unknown-unknown --features wasm_test \
|
||||
&& cargo test --doc --features doc_test,wasm_test,yaml,msgpack,cbor,toml \
|
||||
&& cargo test --doc --features doc_test,wasm_test,yaml,msgpack,cbor,toml \
|
||||
--features std_web,agent,services --no-default-features)
|
||||
|
||||
if [ "$emscripten_supported" == "0" ]; then
|
||||
# TODO - Emscripten builds are broken on rustc > 1.39.0
|
||||
cargo web test --target asmjs-unknown-emscripten --features std_web
|
||||
cargo web test --target wasm32-unknown-emscripten --features std_web
|
||||
fi
|
||||
(cd yew-functional \
|
||||
&& cargo test --target wasm32-unknown-unknown)
|
||||
|
||||
cargo test --doc --features doc_test,wasm_test,yaml,msgpack,cbor,std_web
|
||||
cargo test --doc --features doc_test,wasm_test,yaml,msgpack,cbor,web_sys
|
||||
|
||||
(cd crates/macro \
|
||||
(cd yew-macro \
|
||||
&& cargo test --test macro_test \
|
||||
&& cargo test --test derive_props_test \
|
||||
&& cargo test --doc)
|
||||
|
||||
(cd crates/functional \
|
||||
&& cargo test --features wasm_test --target wasm32-unknown-unknown)
|
||||
(cd yew-stdweb && cargo test --target wasm32-unknown-unknown --features wasm_test)
|
||||
|
||||
# TODO - Emscripten builds are broken on rustc > 1.39.0
|
||||
if [ "$emscripten_supported" == "0" ]; then
|
||||
(cd yew-stdweb \
|
||||
&& cargo web test --target asmjs-unknown-emscripten \
|
||||
&& cargo web test --target wasm32-unknown-emscripten)
|
||||
fi
|
||||
|
||||
@ -1,375 +0,0 @@
|
||||
#[cfg(test)]
|
||||
extern crate wasm_bindgen_test;
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "wasm_test")]
|
||||
mod test {
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
use std::rc::Rc;
|
||||
use wasm_bindgen_test::*;
|
||||
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
extern crate yew;
|
||||
|
||||
use self::yew::NodeRef;
|
||||
use yew::{html, App, Html, Properties};
|
||||
use yew_functional::{
|
||||
use_effect, use_effect_with_deps, use_reducer_with_init, use_ref, use_state,
|
||||
FunctionComponent, FunctionProvider,
|
||||
};
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn use_state_works() {
|
||||
struct UseStateFunction {}
|
||||
impl FunctionProvider for UseStateFunction {
|
||||
type TProps = ();
|
||||
|
||||
fn run(_: &Self::TProps) -> Html {
|
||||
let (counter, set_counter) = use_state(|| 0);
|
||||
if *counter < 5 {
|
||||
set_counter(*counter + 1)
|
||||
}
|
||||
return html! {
|
||||
<div>
|
||||
{"Test Output: "}
|
||||
<div id="result">{*counter}</div>
|
||||
{"\n"}
|
||||
</div>
|
||||
};
|
||||
}
|
||||
}
|
||||
type UseComponent = FunctionComponent<UseStateFunction>;
|
||||
let app: App<UseComponent> = yew::App::new();
|
||||
app.mount(yew::utils::document().get_element_by_id("output").unwrap());
|
||||
let result = obtain_result();
|
||||
assert_eq!(result.as_str(), "5");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn props_are_passed() {
|
||||
struct PropsPassedFunction {}
|
||||
#[derive(Properties, Clone, PartialEq)]
|
||||
struct PropsPassedFunctionProps {
|
||||
value: String,
|
||||
}
|
||||
impl FunctionProvider for PropsPassedFunction {
|
||||
type TProps = PropsPassedFunctionProps;
|
||||
|
||||
fn run(props: &Self::TProps) -> Html {
|
||||
assert_eq!(&props.value, "props");
|
||||
return html! {
|
||||
<div id="result">
|
||||
{"done"}
|
||||
</div>
|
||||
};
|
||||
}
|
||||
}
|
||||
type PropsComponent = FunctionComponent<PropsPassedFunction>;
|
||||
let app: App<PropsComponent> = yew::App::new();
|
||||
app.mount_with_props(
|
||||
yew::utils::document().get_element_by_id("output").unwrap(),
|
||||
PropsPassedFunctionProps {
|
||||
value: "props".to_string(),
|
||||
},
|
||||
);
|
||||
let result = obtain_result();
|
||||
assert_eq!(result.as_str(), "done");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn use_ref_works() {
|
||||
struct UseRefFunction {}
|
||||
impl FunctionProvider for UseRefFunction {
|
||||
type TProps = ();
|
||||
|
||||
fn run(_: &Self::TProps) -> Html {
|
||||
let ref_example = use_ref(|| 0);
|
||||
*ref_example.borrow_mut().deref_mut() += 1;
|
||||
let (counter, set_counter) = use_state(|| 0);
|
||||
if *counter < 5 {
|
||||
set_counter(*counter + 1)
|
||||
}
|
||||
return html! {
|
||||
<div>
|
||||
{"The test output is: "}
|
||||
<div id="result">{*ref_example.borrow_mut().deref_mut() > 4}</div>
|
||||
{"\n"}
|
||||
</div>
|
||||
};
|
||||
}
|
||||
}
|
||||
type UseRefComponent = FunctionComponent<UseRefFunction>;
|
||||
let app: App<UseRefComponent> = yew::App::new();
|
||||
app.mount(yew::utils::document().get_element_by_id("output").unwrap());
|
||||
|
||||
let result = obtain_result();
|
||||
assert_eq!(result.as_str(), "true");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn use_reducer_works() {
|
||||
struct UseReducerFunction {}
|
||||
impl FunctionProvider for UseReducerFunction {
|
||||
type TProps = ();
|
||||
fn run(_: &Self::TProps) -> Html {
|
||||
struct CounterState {
|
||||
counter: i32,
|
||||
}
|
||||
let (counter, dispatch) = use_reducer_with_init(
|
||||
|prev: std::rc::Rc<CounterState>, action: i32| CounterState {
|
||||
counter: prev.counter + action,
|
||||
},
|
||||
0,
|
||||
|initial: i32| CounterState {
|
||||
counter: initial + 10,
|
||||
},
|
||||
);
|
||||
|
||||
use_effect_with_deps(
|
||||
move |_| {
|
||||
dispatch(1);
|
||||
|| {}
|
||||
},
|
||||
(),
|
||||
);
|
||||
return html! {
|
||||
<div>
|
||||
{"The test result is"}
|
||||
<div id="result">{counter.counter}</div>
|
||||
{"\n"}
|
||||
</div>
|
||||
};
|
||||
}
|
||||
}
|
||||
type UseReducerComponent = FunctionComponent<UseReducerFunction>;
|
||||
let app: App<UseReducerComponent> = yew::App::new();
|
||||
app.mount(yew::utils::document().get_element_by_id("output").unwrap());
|
||||
let result = obtain_result();
|
||||
|
||||
assert_eq!(result.as_str(), "11");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn use_effect_destroys_on_component_drop() {
|
||||
struct UseEffectFunction {}
|
||||
struct UseEffectWrapper {}
|
||||
#[derive(Properties, Clone)]
|
||||
struct DestroyCalledProps {
|
||||
destroy_called: Rc<dyn Fn()>,
|
||||
}
|
||||
impl PartialEq for DestroyCalledProps {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
type UseEffectComponent = FunctionComponent<UseEffectFunction>;
|
||||
type UseEffectWrapperComponent = FunctionComponent<UseEffectWrapper>;
|
||||
impl FunctionProvider for UseEffectFunction {
|
||||
type TProps = DestroyCalledProps;
|
||||
|
||||
fn run(props: &Self::TProps) -> Html {
|
||||
let destroy_called = props.destroy_called.clone();
|
||||
use_effect_with_deps(
|
||||
move |_| {
|
||||
move || {
|
||||
destroy_called();
|
||||
}
|
||||
},
|
||||
(),
|
||||
);
|
||||
return html! {};
|
||||
}
|
||||
}
|
||||
impl FunctionProvider for UseEffectWrapper {
|
||||
type TProps = DestroyCalledProps;
|
||||
|
||||
fn run(props: &Self::TProps) -> Html {
|
||||
let (should_rerender, set_rerender) = use_state(|| true);
|
||||
if *should_rerender {
|
||||
set_rerender(false);
|
||||
return html! {
|
||||
<UseEffectComponent destroy_called=props.destroy_called.clone() />
|
||||
};
|
||||
} else {
|
||||
return html! {
|
||||
<div>{"EMPTY"}</div>
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
let app: App<UseEffectWrapperComponent> = yew::App::new();
|
||||
let destroy_counter = Rc::new(std::cell::RefCell::new(0));
|
||||
let destroy_country_c = destroy_counter.clone();
|
||||
app.mount_with_props(
|
||||
yew::utils::document().get_element_by_id("output").unwrap(),
|
||||
DestroyCalledProps {
|
||||
destroy_called: Rc::new(move || *destroy_country_c.borrow_mut().deref_mut() += 1),
|
||||
},
|
||||
);
|
||||
assert_eq!(1, *destroy_counter.borrow().deref());
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn use_effect_works_many_times() {
|
||||
struct UseEffectFunction {}
|
||||
impl FunctionProvider for UseEffectFunction {
|
||||
type TProps = ();
|
||||
|
||||
fn run(_: &Self::TProps) -> Html {
|
||||
let (counter, set_counter) = use_state(|| 0);
|
||||
if *counter < 4 {
|
||||
set_counter(*counter + 1);
|
||||
}
|
||||
|
||||
let node_ref = NodeRef::default();
|
||||
let node_ref_c = node_ref.clone();
|
||||
|
||||
use_effect(move || {
|
||||
let text_content = node_ref
|
||||
.get()
|
||||
.expect("Should have filled node_ref at this point")
|
||||
.text_content()
|
||||
.expect("Text node should have content");
|
||||
let mut previous = -1;
|
||||
if *counter == 0 {
|
||||
assert_eq!("placeholder that should not appear", &text_content);
|
||||
} else {
|
||||
previous = text_content
|
||||
.parse()
|
||||
.expect("Expected content to be number set last time");
|
||||
}
|
||||
assert_eq!(previous, *counter - 1);
|
||||
node_ref
|
||||
.get()
|
||||
.unwrap()
|
||||
.set_text_content(Some(&format!("{}", counter)));
|
||||
|| {}
|
||||
});
|
||||
|
||||
return html! {
|
||||
<div>
|
||||
{"The test result is"}
|
||||
<div id="result" ref=node_ref_c>{"placeholder that should not appear"}</div>
|
||||
{"\n"}
|
||||
</div>
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
type UseEffectComponent = FunctionComponent<UseEffectFunction>;
|
||||
let app: App<UseEffectComponent> = yew::App::new();
|
||||
app.mount(yew::utils::document().get_element_by_id("output").unwrap());
|
||||
let result = obtain_result();
|
||||
assert_eq!(result.as_str(), "4");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn use_effect_works_once() {
|
||||
struct UseEffectFunction {}
|
||||
impl FunctionProvider for UseEffectFunction {
|
||||
type TProps = ();
|
||||
|
||||
fn run(_: &Self::TProps) -> Html {
|
||||
let number_ref = use_ref(|| 0);
|
||||
let number_ref_c = number_ref.clone();
|
||||
let initially_true_ref = use_ref(|| false);
|
||||
let initially_true_ref_c = initially_true_ref.clone();
|
||||
|
||||
let node_ref = NodeRef::default();
|
||||
let node_ref_c = node_ref.clone();
|
||||
|
||||
use_effect_with_deps(
|
||||
move |_| {
|
||||
if *initially_true_ref.borrow() {
|
||||
panic!("use_effect should have been called post render!")
|
||||
}
|
||||
if *number_ref_c.borrow_mut().deref_mut() == 1 {
|
||||
panic!("This effect should have been called once only")
|
||||
}
|
||||
*number_ref_c.borrow_mut().deref_mut() += 1;
|
||||
node_ref
|
||||
.get()
|
||||
.expect("This NodeRef should point at the result!");
|
||||
|| panic!("Destructor should not have been called")
|
||||
},
|
||||
(),
|
||||
);
|
||||
*initially_true_ref_c.borrow_mut() = false;
|
||||
|
||||
let (do_rerender, set_rerender) = use_state(|| true);
|
||||
if *do_rerender {
|
||||
set_rerender(false);
|
||||
}
|
||||
|
||||
return html! {
|
||||
<div>
|
||||
{"The test result is"}
|
||||
<div id="result" ref=node_ref_c>{*number_ref.borrow_mut().deref_mut()}</div>
|
||||
{"\n"}
|
||||
</div>
|
||||
};
|
||||
}
|
||||
}
|
||||
type UseEffectComponent = FunctionComponent<UseEffectFunction>;
|
||||
let app: App<UseEffectComponent> = yew::App::new();
|
||||
app.mount(yew::utils::document().get_element_by_id("output").unwrap());
|
||||
let result = obtain_result();
|
||||
assert_eq!(result.as_str(), "1");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn use_effect_refires_on_dependency_change() {
|
||||
struct UseEffectFunction {}
|
||||
impl FunctionProvider for UseEffectFunction {
|
||||
type TProps = ();
|
||||
|
||||
fn run(_: &Self::TProps) -> Html {
|
||||
let number_ref = use_ref(|| 0);
|
||||
let number_ref_c = number_ref.clone();
|
||||
let number_ref2 = use_ref(|| 0);
|
||||
let number_ref2_c = number_ref2.clone();
|
||||
let arg = *number_ref.borrow_mut().deref_mut();
|
||||
let (_, set_counter) = use_state(|| 0);
|
||||
use_effect_with_deps(
|
||||
move |dep| {
|
||||
let mut ref_mut = number_ref_c.borrow_mut();
|
||||
let inner_ref_mut = ref_mut.deref_mut();
|
||||
if *inner_ref_mut < 1 {
|
||||
*inner_ref_mut += 1;
|
||||
assert_eq!(dep, &0);
|
||||
} else {
|
||||
assert_eq!(dep, &1);
|
||||
}
|
||||
set_counter(10); // we just need to make sure it does not panic
|
||||
move || {
|
||||
set_counter(11);
|
||||
*number_ref2_c.borrow_mut().deref_mut() += 1;
|
||||
}
|
||||
},
|
||||
arg,
|
||||
);
|
||||
return html! {
|
||||
<div>
|
||||
{"The test result is"}
|
||||
<div id="result">{*number_ref.borrow_mut().deref_mut()}{*number_ref2.borrow_mut().deref_mut()}</div>
|
||||
{"\n"}
|
||||
</div>
|
||||
};
|
||||
}
|
||||
}
|
||||
type UseEffectComponent = FunctionComponent<UseEffectFunction>;
|
||||
let app: App<UseEffectComponent> = yew::App::new();
|
||||
app.mount(yew::utils::document().get_element_by_id("output").unwrap());
|
||||
let result: String = obtain_result();
|
||||
|
||||
assert_eq!(result.as_str(), "11");
|
||||
}
|
||||
|
||||
fn obtain_result() -> String {
|
||||
return yew::utils::document()
|
||||
.get_element_by_id("result")
|
||||
.expect("No result found. Most likely, the application crashed and burned")
|
||||
.inner_html();
|
||||
}
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"crm",
|
||||
"custom_components",
|
||||
"dashboard",
|
||||
"fragments",
|
||||
"futures",
|
||||
"game_of_life",
|
||||
"large_table",
|
||||
"minimal",
|
||||
"nested_list",
|
||||
"pub_sub",
|
||||
"server",
|
||||
"showcase",
|
||||
"textarea",
|
||||
"timer",
|
||||
"std_web/counter",
|
||||
"std_web/file_upload",
|
||||
"std_web/inner_html",
|
||||
"std_web/js_callback",
|
||||
"std_web/mount_point",
|
||||
"std_web/multi_thread",
|
||||
"std_web/node_refs",
|
||||
"std_web/npm_and_rest",
|
||||
"std_web/todomvc",
|
||||
"std_web/two_apps",
|
||||
"std_web/webgl",
|
||||
"web_sys/counter",
|
||||
"web_sys/file_upload",
|
||||
"web_sys/inner_html",
|
||||
"web_sys/js_callback",
|
||||
"web_sys/mount_point",
|
||||
"web_sys/multi_thread",
|
||||
"web_sys/node_refs",
|
||||
"web_sys/npm_and_rest",
|
||||
"web_sys/todomvc",
|
||||
"web_sys/two_apps",
|
||||
"web_sys/webgl",
|
||||
]
|
||||
@ -1,140 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PID=-1
|
||||
|
||||
function ctrl_c() {
|
||||
echo "** Killing the demo..."
|
||||
kill $PID
|
||||
}
|
||||
|
||||
function build_std_web() {
|
||||
for example in */ ; do
|
||||
if [[ $example == server* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == static* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == web_sys* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == std_web* ]]; then
|
||||
build_std_web()
|
||||
else
|
||||
echo "Building: $example"
|
||||
cd $example
|
||||
cargo update
|
||||
cargo web build --target wasm32-unknown-unknown
|
||||
cd ..
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function build_web_sys() {
|
||||
for example in */ ; do
|
||||
if [[ $example == server* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == static* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == std_web* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == web_sys* ]]; then
|
||||
build_web_sys()
|
||||
else
|
||||
echo "Building: $example"
|
||||
cd $example
|
||||
cargo update
|
||||
cargo build --target wasm32-unknown-unknown
|
||||
wasm-bindgen --target web --no-typescript --out-dir ../static/ --out-name wasm ../target/wasm32-unknown-unknown/debug/$example.wasm
|
||||
cd ..
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function run_std_web() {
|
||||
trap ctrl_c INT
|
||||
for example in */ ; do
|
||||
if [[ $example == server* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == static* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == web_sys* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == std_web* ]]; then
|
||||
run_std_web()
|
||||
else
|
||||
echo "Running: $example"
|
||||
cd $example
|
||||
cargo web start --target wasm32-unknown-unknown &
|
||||
PID=$!
|
||||
wait $PID
|
||||
cd ..
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function run_web_sys() {
|
||||
trap ctrl_c INT
|
||||
for example in */ ; do
|
||||
if [[ $example == server* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == static* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == std_web* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $example == web_sys* ]]; then
|
||||
run_web_sys()
|
||||
else
|
||||
echo "Running: $example"
|
||||
cd $example
|
||||
cargo build --target wasm32-unknown-unknown
|
||||
wasm-bindgen --target web --no-typescript --out-dir ../static/ --out-name wasm ../target/wasm32-unknown-unknown/debug/$example.wasm
|
||||
http -r ../static/
|
||||
PID=$!
|
||||
wait $PID
|
||||
cd ..
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function clean() {
|
||||
trap ctrl_c INT
|
||||
for example in */ ; do
|
||||
echo "Cleaning: $example"
|
||||
cd $example
|
||||
cargo clean
|
||||
PID=$!
|
||||
wait $PID
|
||||
cd ..
|
||||
done
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
--help)
|
||||
echo "Available commands: build, run, clean"
|
||||
;;
|
||||
build_std_web)
|
||||
build_std_web
|
||||
;;
|
||||
build_web_sys)
|
||||
build_web_sys
|
||||
;;
|
||||
run_std_web)
|
||||
run_std_web
|
||||
;;
|
||||
run_web_sys)
|
||||
run_web_sys
|
||||
;;
|
||||
clean)
|
||||
clean
|
||||
;;
|
||||
esac
|
||||
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "counter_web_sys"
|
||||
name = "counter"
|
||||
version = "0.1.1"
|
||||
authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
@ -9,4 +9,4 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
js-sys = "0.3"
|
||||
yew = { path = "../../..", features = ["services", "web_sys"] }
|
||||
yew = { path = "../../yew" }
|
||||
@ -31,11 +31,11 @@ impl Component for Model {
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::Increment => {
|
||||
self.value = self.value + 1;
|
||||
self.value += 1;
|
||||
self.console.log("plus one");
|
||||
}
|
||||
Msg::Decrement => {
|
||||
self.value = self.value - 1;
|
||||
self.value -= 1;
|
||||
self.console.log("minus one");
|
||||
}
|
||||
Msg::Bulk(list) => {
|
||||
3
examples/counter/src/main.rs
Normal file
3
examples/counter/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
yew::start_app::<counter::Model>();
|
||||
}
|
||||
@ -7,7 +7,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
yew = { path = "../.." }
|
||||
yew = { path = "../../yew" }
|
||||
pulldown-cmark = "0.1.2"
|
||||
|
||||
[features]
|
||||
|
||||
@ -10,7 +10,7 @@ use yew::services::storage::Area;
|
||||
use yew::services::{DialogService, StorageService};
|
||||
use yew::{html, Component, ComponentLink, Html, InputData, Renderable, ShouldRender};
|
||||
|
||||
const KEY: &'static str = "yew.crm.database";
|
||||
const KEY: &str = "yew.crm.database";
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Database {
|
||||
|
||||
@ -34,9 +34,9 @@ pub fn render_markdown(src: &str) -> Html {
|
||||
top = pre;
|
||||
} else if let Tag::Table(aligns) = tag {
|
||||
for r in top.children.iter_mut() {
|
||||
if let &mut VNode::VTag(ref mut vtag) = r {
|
||||
if let VNode::VTag(ref mut vtag) = r {
|
||||
for (i, c) in vtag.children.iter_mut().enumerate() {
|
||||
if let &mut VNode::VTag(ref mut vtag) = c {
|
||||
if let VNode::VTag(ref mut vtag) = c {
|
||||
match aligns[i] {
|
||||
Alignment::None => {}
|
||||
Alignment::Left => vtag.add_class("text-left"),
|
||||
@ -49,7 +49,7 @@ pub fn render_markdown(src: &str) -> Html {
|
||||
}
|
||||
} else if let Tag::TableHead = tag {
|
||||
for c in top.children.iter_mut() {
|
||||
if let &mut VNode::VTag(ref mut vtag) = c {
|
||||
if let VNode::VTag(ref mut vtag) = c {
|
||||
// TODO
|
||||
// vtag.tag = "th".into();
|
||||
vtag.add_attribute("scope", &"col");
|
||||
|
||||
@ -5,7 +5,7 @@ authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../.." }
|
||||
yew = { path = "../../yew" }
|
||||
|
||||
[features]
|
||||
std_web = ["yew/std_web"]
|
||||
|
||||
@ -43,7 +43,7 @@ impl Component for Counter {
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::Increase => {
|
||||
self.value = self.value + 1;
|
||||
self.value += 1;
|
||||
self.onclick.emit(self.value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ edition = "2018"
|
||||
anyhow = "1"
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
yew = { path = "../..", features = ["toml"] }
|
||||
yew = { path = "../../yew", features = ["toml"] }
|
||||
|
||||
[features]
|
||||
std_web = ["yew/std_web"]
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "file_upload_web_sys"
|
||||
name = "file_upload"
|
||||
version = "0.1.0"
|
||||
authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
@ -9,4 +9,4 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
js-sys = "0.3"
|
||||
yew = { path = "../../..", features = ["web_sys"] }
|
||||
yew = { path = "../../yew" }
|
||||
@ -15,7 +15,7 @@ type Chunks = bool;
|
||||
|
||||
pub enum Msg {
|
||||
Loaded(FileData),
|
||||
Chunk(FileChunk),
|
||||
Chunk(Option<FileChunk>),
|
||||
Files(Vec<File>, Chunks),
|
||||
ToggleByChunks,
|
||||
}
|
||||
@ -40,7 +40,7 @@ impl Component for Model {
|
||||
let info = format!("file: {:?}", file);
|
||||
self.files.push(info);
|
||||
}
|
||||
Msg::Chunk(chunk) => {
|
||||
Msg::Chunk(Some(chunk)) => {
|
||||
let info = format!("chunk: {:?}", chunk);
|
||||
self.files.push(info);
|
||||
}
|
||||
@ -61,6 +61,7 @@ impl Component for Model {
|
||||
Msg::ToggleByChunks => {
|
||||
self.by_chunks = !self.by_chunks;
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
true
|
||||
}
|
||||
3
examples/file_upload/src/main.rs
Normal file
3
examples/file_upload/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
yew::start_app::<file_upload::Model>();
|
||||
}
|
||||
@ -5,7 +5,7 @@ authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../.." }
|
||||
yew = { path = "../../yew" }
|
||||
|
||||
[features]
|
||||
std_web = ["yew/std_web"]
|
||||
|
||||
@ -23,11 +23,11 @@ impl Component for Model {
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::More => {
|
||||
self.counter = self.counter + 1;
|
||||
self.counter += 1;
|
||||
}
|
||||
Msg::Less => {
|
||||
if self.counter > 0 {
|
||||
self.counter = self.counter - 1;
|
||||
self.counter -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,8 @@ repository = "https://github.com/yewstack/yew"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../.." }
|
||||
yew = { path = "../../yew" }
|
||||
wasm-bindgen = "0.2.60"
|
||||
wasm-bindgen-futures = "0.4.3"
|
||||
|
||||
[dependencies.web-sys]
|
||||
@ -24,10 +25,3 @@ features = [
|
||||
'Response',
|
||||
'Window',
|
||||
]
|
||||
|
||||
[target.'cfg(all(target_arch = "wasm32", not(cargo_web)))'.dependencies]
|
||||
wasm-bindgen = "0.2.60"
|
||||
|
||||
[features]
|
||||
std_web = ["yew/std_web"]
|
||||
web_sys = ["yew/web_sys"]
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
# Futures Example
|
||||
This example shows off how to make a asynchronous fetch request using web_sys and Yew's futures support.
|
||||
|
||||
Because this example uses features not allowed by cargo web, it cannot be included in the showcase, and must be built with a different toolchain instead.
|
||||
|
||||
### How to run:
|
||||
This example requires rustc v1.39.0 or above to compile due to its use of async/.await syntax.
|
||||
|
||||
```sh
|
||||
wasm-pack build --target web --out-dir ../static/ --out-name wasm -- --features (web_sys|std_web) && python -m SimpleHTTPServer 8080
|
||||
wasm-pack build --target web --out-dir ../static/ --out-name wasm && python -m SimpleHTTPServer 8080
|
||||
```
|
||||
This will compile the project, bundle up the compiler output and static assets, and start a http server on port 8080 so you can access the example at localhost:8080.
|
||||
|
||||
|
||||
@ -3,29 +3,23 @@ use std::fmt::{Error, Formatter};
|
||||
use std::future::Future;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use web_sys::{Request, RequestInit, RequestMode, Response, Window};
|
||||
use yew::{html, Component, ComponentLink, Html, ShouldRender};
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(cargo_web)))]
|
||||
/// This method processes a Future that returns a message and sends it back to the component's
|
||||
/// loop.
|
||||
///
|
||||
/// # Panics
|
||||
/// If the future panics, then the promise will not resolve, and will leak.
|
||||
pub fn send_future<COMP: Component, F>(link: &ComponentLink<COMP>, future: F)
|
||||
pub fn send_future<COMP: Component, F>(link: ComponentLink<COMP>, future: F)
|
||||
where
|
||||
F: Future<Output = COMP::Message> + 'static,
|
||||
{
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
|
||||
let mut link = link.clone();
|
||||
let js_future = async move {
|
||||
spawn_local(async move {
|
||||
link.send_message(future.await);
|
||||
Ok(JsValue::NULL)
|
||||
};
|
||||
|
||||
future_to_promise(js_future);
|
||||
});
|
||||
}
|
||||
|
||||
/// Something wrong has occurred while fetching an external resource.
|
||||
@ -118,7 +112,7 @@ impl Component for Model {
|
||||
Err(err) => Msg::SetMarkdownFetchState(FetchState::Failed(err)),
|
||||
}
|
||||
};
|
||||
send_future(&self.link, future);
|
||||
send_future(self.link.clone(), future);
|
||||
self.link
|
||||
.send_message(SetMarkdownFetchState(FetchState::Fetching));
|
||||
false
|
||||
|
||||
@ -10,7 +10,7 @@ edition = "2018"
|
||||
rand = "0.6.5"
|
||||
log = "0.4"
|
||||
web_logger = "0.2"
|
||||
yew = { path = "../.." }
|
||||
yew = { path = "../../yew" }
|
||||
|
||||
[features]
|
||||
std_web = ["rand/stdweb", "yew/std_web"]
|
||||
|
||||
@ -36,7 +36,7 @@ impl Cellule {
|
||||
self.life_state = LifeState::Dead;
|
||||
}
|
||||
|
||||
pub fn alive(&self) -> bool {
|
||||
pub fn alive(self) -> bool {
|
||||
self.life_state == LifeState::Alive
|
||||
}
|
||||
|
||||
@ -97,10 +97,8 @@ impl Model {
|
||||
if Cellule::alone(&neighbors) || Cellule::overpopulated(&neighbors) {
|
||||
to_dead.push(current_idx);
|
||||
}
|
||||
} else {
|
||||
if Cellule::can_be_revived(&neighbors) {
|
||||
to_live.push(current_idx);
|
||||
}
|
||||
} else if Cellule::can_be_revived(&neighbors) {
|
||||
to_live.push(current_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,4 +10,3 @@
|
||||
<script src="game_of_life.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
21
examples/inner_html/Cargo.toml
Normal file
21
examples/inner_html/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "inner_html"
|
||||
version = "0.1.0"
|
||||
authors = ["Garrett Berg <vitiral@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../../yew" }
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3"
|
||||
features = [
|
||||
"console",
|
||||
"Document",
|
||||
"Element",
|
||||
"Node",
|
||||
"Window",
|
||||
]
|
||||
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "js_callback_web_sys"
|
||||
name = "js_callback"
|
||||
version = "0.1.0"
|
||||
authors = ["Scott Steele <scottlsteele@gmail.com>"]
|
||||
edition = "2018"
|
||||
@ -8,7 +8,5 @@ edition = "2018"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../../..", features = ["web_sys"] }
|
||||
|
||||
[target.'cfg(all(target_arch = "wasm32", not(cargo_web)))'.dependencies]
|
||||
wasm-bindgen = "0.2.60"
|
||||
yew = { path = "../../yew" }
|
||||
3
examples/js_callback/src/main.rs
Normal file
3
examples/js_callback/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
yew::start_app::<js_callback::Model>();
|
||||
}
|
||||
@ -5,7 +5,7 @@ authors = ["qthree <qthree3@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../.." }
|
||||
yew = { path = "../../yew" }
|
||||
|
||||
[features]
|
||||
std_web = ["yew/std_web"]
|
||||
|
||||
@ -5,7 +5,7 @@ authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../.." }
|
||||
yew = { path = "../../yew" }
|
||||
|
||||
[features]
|
||||
std_web = ["yew/std_web"]
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "mount_point_web_sys"
|
||||
name = "mount_point"
|
||||
version = "0.1.0"
|
||||
authors = ["Ben Berman <ben@standardbots.com>"]
|
||||
edition = "2018"
|
||||
@ -9,7 +9,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
yew = { path = "../../..", features = ["web_sys"] }
|
||||
yew = { path = "../../yew" }
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3"
|
||||
@ -1,4 +1,4 @@
|
||||
use mount_point_web_sys::Model;
|
||||
use mount_point::Model;
|
||||
use wasm_bindgen::JsValue;
|
||||
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement};
|
||||
use yew::App;
|
||||
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "multi_thread_web_sys"
|
||||
name = "multi_thread"
|
||||
version = "0.1.0"
|
||||
authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
@ -20,4 +20,4 @@ log = "0.4"
|
||||
wasm-logger = "0.2"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
yew = { path = "../../..", features = ["agent", "services", "web_sys"]}
|
||||
yew = { path = "../../yew" }
|
||||
@ -1,4 +1,4 @@
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::default());
|
||||
yew::start_app::<multi_thread_web_sys::Model>();
|
||||
yew::start_app::<multi_thread::Model>();
|
||||
}
|
||||
@ -2,5 +2,5 @@ use yew::agent::Threaded;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::default());
|
||||
multi_thread_web_sys::native_worker::Worker::register();
|
||||
multi_thread::native_worker::Worker::register();
|
||||
}
|
||||
@ -7,4 +7,3 @@
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
|
||||
@ -7,7 +7,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
web_logger = "0.2"
|
||||
yew = { path = "../.." }
|
||||
yew = { path = "../../yew" }
|
||||
|
||||
[features]
|
||||
std_web = ["yew/std_web"]
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "node_refs_web_sys"
|
||||
name = "node_refs"
|
||||
version = "0.1.0"
|
||||
authors = ["Justin Starry <justin.starry@icloud.com>"]
|
||||
edition = "2018"
|
||||
@ -8,5 +8,5 @@ edition = "2018"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../../..", features = ["web_sys"] }
|
||||
yew = { path = "../../yew" }
|
||||
web-sys = { version = "0.3", features = ["HtmlElement", "HtmlInputElement", "Node"] }
|
||||
3
examples/node_refs/src/main.rs
Normal file
3
examples/node_refs/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
yew::start_app::<node_refs::Model>();
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "npm_and_rest_web_sys"
|
||||
name = "npm_and_rest"
|
||||
version = "0.1.0"
|
||||
authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
@ -14,4 +14,4 @@ serde = "1"
|
||||
serde_derive = "1"
|
||||
wasm-bindgen = "0.2"
|
||||
web-sys = { version = "0.3", features = ["console"] }
|
||||
yew = { path = "../../..", features = ["web_sys"] }
|
||||
yew = { path = "../../yew" }
|
||||
3
examples/npm_and_rest/src/main.rs
Normal file
3
examples/npm_and_rest/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
yew::start_app::<npm_and_rest::Model>();
|
||||
}
|
||||
@ -9,4 +9,3 @@
|
||||
<script src="/npm_and_rest.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
26
examples/old.Cargo.toml
Normal file
26
examples/old.Cargo.toml
Normal file
@ -0,0 +1,26 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"counter",
|
||||
"crm",
|
||||
"custom_components",
|
||||
"dashboard",
|
||||
"file_upload",
|
||||
"fragments",
|
||||
"futures",
|
||||
"game_of_life",
|
||||
"inner_html",
|
||||
"js_callback",
|
||||
"large_table",
|
||||
"minimal",
|
||||
"mount_point",
|
||||
"multi_thread",
|
||||
"nested_list",
|
||||
"node_refs",
|
||||
"npm_and_rest",
|
||||
"pub_sub",
|
||||
"textarea",
|
||||
"timer",
|
||||
"todomvc",
|
||||
"two_apps",
|
||||
"webgl",
|
||||
]
|
||||
@ -1,11 +1,14 @@
|
||||
[package]
|
||||
name = "event_bus"
|
||||
name = "pub_sub"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
web_logger = "0.1"
|
||||
web_logger = "0.2"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
yew = { path = "../..", features = ["std_web"] }
|
||||
stdweb = "0.4.20"
|
||||
yew = { path = "../../yew" }
|
||||
|
||||
[features]
|
||||
std_web = ["yew/std_web"]
|
||||
web_sys = ["yew/web_sys"]
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
fn main() {
|
||||
yew::start_app::<event_bus::Model>();
|
||||
yew::start_app::<pub_sub::Model>();
|
||||
}
|
||||
|
||||
@ -24,15 +24,15 @@ impl Component for Producer {
|
||||
Producer { event_bus, link }
|
||||
}
|
||||
|
||||
fn change(&mut self, _: Self::Properties) -> bool {
|
||||
false
|
||||
}
|
||||
fn change(&mut self, _: Self::Properties) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::Clicked => {
|
||||
self.event_bus
|
||||
.send(Request::EventBusMsg(format!("Message received")));
|
||||
.send(Request::EventBusMsg("Message received".to_string()));
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,10 +16,10 @@ impl Component for Subscriber {
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
let callback = link.callback(|s| Msg::NewMessage(s));
|
||||
let callback = link.callback(Msg::NewMessage);
|
||||
let _producer = EventBus::bridge(callback);
|
||||
Subscriber {
|
||||
message: format!("No message yet."),
|
||||
message: "No message yet.".to_string(),
|
||||
_producer,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,73 +0,0 @@
|
||||
[package]
|
||||
name = "showcase"
|
||||
version = "0.1.0"
|
||||
authors = ["Denis Kolodin <deniskolodin@gmail.com>", "Limira"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "0.1"
|
||||
log = "0.4"
|
||||
web_logger = "0.2"
|
||||
strum = "0.13"
|
||||
strum_macros = "0.13"
|
||||
yew = { path = "../.." }
|
||||
counter_std_web = { path = "../std_web/counter", optional = true }
|
||||
counter_web_sys = { path = "../web_sys/counter", optional = true }
|
||||
crm = { path = "../crm" }
|
||||
custom_components = { path = "../custom_components" }
|
||||
dashboard = { path = "../dashboard" }
|
||||
node_refs_std_web = { path = "../std_web/node_refs", optional = true }
|
||||
node_refs_web_sys = { path = "../web_sys/node_refs", optional = true }
|
||||
fragments = { path = "../fragments" }
|
||||
game_of_life = { path = "../game_of_life" }
|
||||
inner_html_std_web = { path = "../std_web/inner_html", optional = true }
|
||||
inner_html_web_sys = { path = "../web_sys/inner_html", optional = true }
|
||||
large_table = { path = "../large_table" }
|
||||
mount_point_std_web = { path = "../std_web/mount_point", optional = true }
|
||||
mount_point_web_sys = { path = "../web_sys/mount_point", optional = true }
|
||||
npm_and_rest_std_web = { path = "../std_web/npm_and_rest", optional = true }
|
||||
npm_and_rest_web_sys = { path = "../web_sys/npm_and_rest", optional = true }
|
||||
textarea = { path = "../textarea" }
|
||||
timer = { path = "../timer" }
|
||||
todomvc_std_web = { path = "../std_web/todomvc", optional = true }
|
||||
todomvc_web_sys = { path = "../web_sys/todomvc", optional = true }
|
||||
two_apps_std_web = { path = "../std_web/two_apps", optional = true }
|
||||
two_apps_web_sys = { path = "../web_sys/two_apps", optional = true }
|
||||
|
||||
[features]
|
||||
std_web = [
|
||||
"yew/std_web",
|
||||
"counter_std_web",
|
||||
"crm/std_web",
|
||||
"custom_components/std_web",
|
||||
"dashboard/std_web",
|
||||
"node_refs_std_web",
|
||||
"fragments/std_web",
|
||||
"game_of_life/std_web",
|
||||
"inner_html_std_web",
|
||||
"large_table/std_web",
|
||||
"mount_point_std_web",
|
||||
"npm_and_rest_std_web",
|
||||
"textarea/std_web",
|
||||
"timer/std_web",
|
||||
"todomvc_std_web",
|
||||
"two_apps_std_web",
|
||||
]
|
||||
web_sys = [
|
||||
"yew/web_sys",
|
||||
"counter_web_sys",
|
||||
"crm/web_sys",
|
||||
"custom_components/web_sys",
|
||||
"dashboard/web_sys",
|
||||
"node_refs_web_sys",
|
||||
"fragments/web_sys",
|
||||
"game_of_life/web_sys",
|
||||
"inner_html_web_sys",
|
||||
"large_table/web_sys",
|
||||
"mount_point_web_sys",
|
||||
"npm_and_rest_web_sys",
|
||||
"textarea/web_sys",
|
||||
"timer/web_sys",
|
||||
"todomvc_web_sys",
|
||||
"two_apps_web_sys",
|
||||
]
|
||||
@ -1,171 +0,0 @@
|
||||
#![recursion_limit = "128"]
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "std_web")] {
|
||||
use counter_std_web as counter;
|
||||
use inner_html_std_web as inner_html;
|
||||
use mount_point_std_web as mount_point;
|
||||
use node_refs_std_web as node_refs;
|
||||
use npm_and_rest_std_web as npm_and_rest;
|
||||
use todomvc_std_web as todomvc;
|
||||
use two_apps_std_web as two_apps;
|
||||
} else if #[cfg(feature = "web_sys")] {
|
||||
use counter_web_sys as counter;
|
||||
use inner_html_web_sys as inner_html;
|
||||
use mount_point_web_sys as mount_point;
|
||||
use node_refs_web_sys as node_refs;
|
||||
use npm_and_rest_web_sys as npm_and_rest;
|
||||
use todomvc_web_sys as todomvc;
|
||||
use two_apps_web_sys as two_apps;
|
||||
}
|
||||
}
|
||||
|
||||
use counter::Model as Counter;
|
||||
use crm::Model as Crm;
|
||||
use custom_components::Model as CustomComponents;
|
||||
use dashboard::Model as Dashboard;
|
||||
use fragments::Model as Fragments;
|
||||
use game_of_life::Model as GameOfLife;
|
||||
use inner_html::Model as InnerHtml;
|
||||
use large_table::Model as LargeTable;
|
||||
use log::trace;
|
||||
use mount_point::Model as MountPoint;
|
||||
use node_refs::Model as NodeRefs;
|
||||
use npm_and_rest::Model as NpmAndRest;
|
||||
use strum::IntoEnumIterator;
|
||||
use strum_macros::{Display, EnumIter, EnumString};
|
||||
use textarea::Model as Textarea;
|
||||
use timer::Model as Timer;
|
||||
use todomvc::Model as Todomvc;
|
||||
use two_apps::TwoModels as TwoApps;
|
||||
use yew::components::Select;
|
||||
use yew::{html, App, Component, ComponentLink, Html, ShouldRender};
|
||||
|
||||
#[derive(Clone, Debug, Display, EnumString, EnumIter, PartialEq)]
|
||||
enum Scene {
|
||||
Counter,
|
||||
Crm,
|
||||
CustomComponents,
|
||||
Dashboard,
|
||||
NodeRefs,
|
||||
Fragments,
|
||||
GameOfLife,
|
||||
InnerHtml,
|
||||
LargeTable,
|
||||
MountPoint,
|
||||
NpmAndRest,
|
||||
Textarea,
|
||||
Timer,
|
||||
Todomvc,
|
||||
TwoApps,
|
||||
}
|
||||
|
||||
struct Model {
|
||||
scene: Option<Scene>,
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
|
||||
enum Msg {
|
||||
SwitchTo(Scene),
|
||||
Reset,
|
||||
}
|
||||
|
||||
impl Component for Model {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Self { scene: None, link }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::SwitchTo(scene) => {
|
||||
self.scene = Some(scene);
|
||||
true
|
||||
}
|
||||
Msg::Reset => {
|
||||
self.scene = None;
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, _: Self::Properties) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div id="fullscreen">
|
||||
<style>{ self.view_style() }</style>
|
||||
<div id="left_pane">
|
||||
<h2>{ "Yew showcase" }</h2>
|
||||
<Select<Scene>
|
||||
selected=self.scene.clone()
|
||||
options=Scene::iter().collect::<Vec<_>>()
|
||||
onchange=self.link.callback(Msg::SwitchTo) />
|
||||
<button onclick=self.link.callback(|_| Msg::Reset)>
|
||||
{ "Reset" }
|
||||
</button>
|
||||
</div>
|
||||
<div id="right_pane">
|
||||
{ self.view_scene() }
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn view_scene(&self) -> Html {
|
||||
if let Some(scene) = self.scene.as_ref() {
|
||||
match scene {
|
||||
Scene::Counter => html! { <Counter /> },
|
||||
Scene::Crm => html! { <Crm /> },
|
||||
Scene::CustomComponents => html! { <CustomComponents /> },
|
||||
Scene::Dashboard => html! { <Dashboard /> },
|
||||
Scene::NodeRefs => html! { <NodeRefs /> },
|
||||
Scene::Fragments => html! { <Fragments /> },
|
||||
Scene::GameOfLife => html! { <GameOfLife /> },
|
||||
Scene::InnerHtml => html! { <InnerHtml /> },
|
||||
Scene::LargeTable => html! { <LargeTable /> },
|
||||
Scene::MountPoint => html! { <MountPoint /> },
|
||||
Scene::NpmAndRest => html! { <NpmAndRest /> },
|
||||
Scene::Textarea => html! { <Textarea /> },
|
||||
Scene::Timer => html! { <Timer /> },
|
||||
Scene::Todomvc => html! { <Todomvc /> },
|
||||
Scene::TwoApps => html! { <TwoApps /> },
|
||||
}
|
||||
} else {
|
||||
html! {
|
||||
<p>{ "Select the scene, please." }</p>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view_style(&self) -> &str {
|
||||
if let Some(scene) = self.scene.as_ref() {
|
||||
match scene {
|
||||
Scene::GameOfLife => include_str!("../../game_of_life/static/styles.css"),
|
||||
Scene::LargeTable => include_str!("../../large_table/static/styles.css"),
|
||||
Scene::Todomvc => include_str!("../static/todomvc.css"),
|
||||
_ => "",
|
||||
}
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
web_logger::init();
|
||||
trace!("Initializing yew...");
|
||||
yew::initialize();
|
||||
trace!("Creating an application instance...");
|
||||
let app: App<Model> = App::new();
|
||||
trace!("Mount the App to the body of the page...");
|
||||
app.mount_to_body();
|
||||
trace!("Run");
|
||||
yew::run_loop();
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Yew • Showcase</title>
|
||||
<script type="text/javascript" src="https://unpkg.com/ccxt"></script>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<script src="/showcase.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
html, body, #fullscreen {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#left_pane {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#right_pane {
|
||||
display: flex;
|
||||
}
|
||||
@ -1,521 +0,0 @@
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
font-size: 100%;
|
||||
vertical-align: baseline;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
body {
|
||||
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.4em;
|
||||
background: #f5f5f5;
|
||||
color: #4d4d4d;
|
||||
min-width: 230px;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todoapp {
|
||||
background: #fff;
|
||||
margin: 130px 0 40px 0;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
|
||||
0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.todoapp input::-webkit-input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::-moz-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp h1 {
|
||||
position: absolute;
|
||||
top: -155px;
|
||||
width: 100%;
|
||||
font-size: 100px;
|
||||
font-weight: 100;
|
||||
text-align: center;
|
||||
color: rgba(175, 47, 47, 0.15);
|
||||
-webkit-text-rendering: optimizeLegibility;
|
||||
-moz-text-rendering: optimizeLegibility;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.new-todo,
|
||||
.edit {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 24px;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: 1.4em;
|
||||
border: 0;
|
||||
color: inherit;
|
||||
padding: 6px;
|
||||
border: 1px solid #999;
|
||||
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
box-sizing: border-box;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.new-todo {
|
||||
padding: 16px 16px 16px 60px;
|
||||
border: none;
|
||||
background: rgba(0, 0, 0, 0.003);
|
||||
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.main {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border: none; /* Mobile Safari */
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
bottom: 100%;
|
||||
}
|
||||
|
||||
.toggle-all + label {
|
||||
width: 60px;
|
||||
height: 34px;
|
||||
font-size: 0;
|
||||
position: absolute;
|
||||
top: -52px;
|
||||
left: -13px;
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.toggle-all + label:before {
|
||||
content: '❯';
|
||||
font-size: 22px;
|
||||
color: #e6e6e6;
|
||||
padding: 10px 27px 10px 27px;
|
||||
}
|
||||
|
||||
.toggle-all:checked + label:before {
|
||||
color: #737373;
|
||||
}
|
||||
|
||||
.todo-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.todo-list li {
|
||||
position: relative;
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #ededed;
|
||||
}
|
||||
|
||||
.todo-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing {
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.todo-list li.editing .edit {
|
||||
display: block;
|
||||
width: 506px;
|
||||
padding: 12px 16px;
|
||||
margin: 0 0 0 43px;
|
||||
}
|
||||
|
||||
.todo-list li.editing .view {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
/* auto, since non-WebKit browsers doesn't support input styling */
|
||||
height: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto 0;
|
||||
border: none; /* Mobile Safari */
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.todo-list li .toggle + label {
|
||||
/*
|
||||
Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
|
||||
IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
|
||||
*/
|
||||
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center left;
|
||||
}
|
||||
|
||||
.todo-list li .toggle:checked + label {
|
||||
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.todo-list li label {
|
||||
word-break: break-all;
|
||||
padding: 15px 15px 15px 60px;
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
transition: color 0.4s;
|
||||
}
|
||||
|
||||
.todo-list li.completed label {
|
||||
color: #d9d9d9;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.todo-list li .destroy {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
bottom: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: auto 0;
|
||||
font-size: 30px;
|
||||
color: #cc9a9a;
|
||||
margin-bottom: 11px;
|
||||
transition: color 0.2s ease-out;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:hover {
|
||||
color: #af5b5e;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:after {
|
||||
content: '×';
|
||||
}
|
||||
|
||||
.todo-list li:hover .destroy {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.todo-list li .edit {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing:last-child {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: #777;
|
||||
padding: 10px 15px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.footer:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
|
||||
0 8px 0 -3px #f6f6f6,
|
||||
0 9px 1px -3px rgba(0, 0, 0, 0.2),
|
||||
0 16px 0 -6px #f6f6f6,
|
||||
0 17px 2px -6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.todo-count {
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.todo-count strong {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.filters {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.filters li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.filters li a {
|
||||
color: inherit;
|
||||
margin: 3px;
|
||||
padding: 3px 7px;
|
||||
text-decoration: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.filters li a:hover {
|
||||
border-color: rgba(175, 47, 47, 0.1);
|
||||
}
|
||||
|
||||
.filters li a.selected {
|
||||
border-color: rgba(175, 47, 47, 0.2);
|
||||
}
|
||||
|
||||
.clear-completed,
|
||||
html .clear-completed:active {
|
||||
float: right;
|
||||
position: relative;
|
||||
line-height: 20px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.clear-completed:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin: 65px auto 0;
|
||||
color: #bfbfbf;
|
||||
font-size: 10px;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info p {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.info a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.info a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*
|
||||
Hack to remove background from Mobile Safari.
|
||||
Can't use it globally since it destroys checkboxes in Firefox
|
||||
*/
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
.toggle-all,
|
||||
.todo-list li .toggle {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.footer {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 20px 0;
|
||||
border: 0;
|
||||
border-top: 1px dashed #c5c5c5;
|
||||
border-bottom: 1px dashed #f7f7f7;
|
||||
}
|
||||
|
||||
.learn a {
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
color: #b83f45;
|
||||
}
|
||||
|
||||
.learn a:hover {
|
||||
text-decoration: underline;
|
||||
color: #787e7e;
|
||||
}
|
||||
|
||||
.learn h3,
|
||||
.learn h4,
|
||||
.learn h5 {
|
||||
margin: 10px 0;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.learn h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.learn h4 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.learn h5 {
|
||||
margin-bottom: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.learn ul {
|
||||
padding: 0;
|
||||
margin: 0 0 30px 25px;
|
||||
}
|
||||
|
||||
.learn li {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.learn p {
|
||||
font-size: 15px;
|
||||
font-weight: 300;
|
||||
line-height: 1.3;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#issue-count {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.quote {
|
||||
border: none;
|
||||
margin: 20px 0 60px 0;
|
||||
}
|
||||
|
||||
.quote p {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.quote p:before {
|
||||
content: '“';
|
||||
font-size: 50px;
|
||||
opacity: .15;
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
.quote p:after {
|
||||
content: '”';
|
||||
font-size: 50px;
|
||||
opacity: .15;
|
||||
position: absolute;
|
||||
bottom: -42px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.quote footer {
|
||||
position: absolute;
|
||||
bottom: -40px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.quote footer img {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.quote footer a {
|
||||
margin-left: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.speech-bubble {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
background: rgba(0, 0, 0, .04);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.speech-bubble:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 30px;
|
||||
border: 13px solid transparent;
|
||||
border-top-color: rgba(0, 0, 0, .04);
|
||||
}
|
||||
|
||||
.learn-bar > .learn {
|
||||
position: absolute;
|
||||
width: 272px;
|
||||
top: 8px;
|
||||
left: -300px;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: rgba(255, 255, 255, .6);
|
||||
transition-property: left;
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
@media (min-width: 899px) {
|
||||
.learn-bar {
|
||||
width: auto;
|
||||
padding-left: 300px;
|
||||
}
|
||||
|
||||
.learn-bar > .learn {
|
||||
left: 8px;
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
[package]
|
||||
name = "counter_std_web"
|
||||
version = "0.1.1"
|
||||
authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
stdweb = "0.4.20"
|
||||
yew = { path = "../../..", features = ["services", "std_web"] }
|
||||
@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
yew::start_app::<counter_std_web::Model>();
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "file_upload_std_web"
|
||||
version = "0.1.0"
|
||||
authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../../..", features = ["std_web"] }
|
||||
@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
yew::start_app::<file_upload_std_web::Model>();
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
[package]
|
||||
name = "js_callback_std_web"
|
||||
version = "0.1.0"
|
||||
authors = ["Scott Steele <scottlsteele@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../../..", features = ["std_web"] }
|
||||
stdweb = "^0.4.20"
|
||||
|
||||
[target.'cfg(all(target_arch = "wasm32", not(cargo_web)))'.dependencies]
|
||||
wasm-bindgen = "0.2.60"
|
||||
@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
yew::start_app::<js_callback_std_web::Model>();
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
fn main() {
|
||||
web_logger::init();
|
||||
yew::start_app::<multi_thread_std_web::Model>();
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
../../../target/wasm32-unknown-unknown/release
|
||||
@ -1,9 +0,0 @@
|
||||
[package]
|
||||
name = "node_refs_std_web"
|
||||
version = "0.1.0"
|
||||
authors = ["Justin Starry <justin.starry@icloud.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../../..", features = ["std_web"] }
|
||||
stdweb = "0.4.20"
|
||||
@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
yew::start_app::<node_refs_std_web::Model>();
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
yew::start_app::<npm_and_rest_std_web::Model>();
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
[package]
|
||||
name = "todomvc_std_web"
|
||||
version = "0.1.0"
|
||||
authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
strum = "0.13"
|
||||
strum_macros = "0.13"
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
yew = { path = "../../..", features = ["std_web"] }
|
||||
@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
yew::start_app::<todomvc_std_web::Model>();
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
[package]
|
||||
name = "two_apps_std_web"
|
||||
version = "0.1.0"
|
||||
authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
stdweb = "0.4.20"
|
||||
yew = { path = "../../..", features = ["std_web"] }
|
||||
@ -1,10 +0,0 @@
|
||||
[package]
|
||||
name = "webgl_std_web"
|
||||
version = "0.1.0"
|
||||
authors = ["Miklós Tusz <mdtusz@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
stdweb = "0.4.20"
|
||||
yew = { path = "../../..", features = [ "std_web" ] }
|
||||
webgl_stdweb = "0.3.0"
|
||||
@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
yew::start_app::<webgl_std_web::Model>();
|
||||
}
|
||||
@ -5,7 +5,7 @@ authors = ["Andrew Straw <strawman@astraw.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../.." }
|
||||
yew = { path = "../../yew" }
|
||||
|
||||
[features]
|
||||
std_web = ["yew/std_web"]
|
||||
|
||||
@ -5,7 +5,7 @@ authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
yew = { path = "../.." }
|
||||
yew = { path = "../../yew" }
|
||||
|
||||
[features]
|
||||
std_web = ["yew/std_web"]
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "todomvc_web_sys"
|
||||
name = "todomvc"
|
||||
version = "0.1.0"
|
||||
authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
edition = "2018"
|
||||
@ -12,4 +12,4 @@ strum = "0.13"
|
||||
strum_macros = "0.13"
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
yew = { path = "../../..", features = ["web_sys"] }
|
||||
yew = { path = "../../yew" }
|
||||
@ -8,7 +8,7 @@ use yew::format::Json;
|
||||
use yew::services::storage::{Area, StorageService};
|
||||
use yew::{html, Component, ComponentLink, Href, Html, InputData, ShouldRender};
|
||||
|
||||
const KEY: &'static str = "yew.todomvc.self";
|
||||
const KEY: &str = "yew.todomvc.self";
|
||||
|
||||
pub struct Model {
|
||||
link: ComponentLink<Self>,
|
||||
3
examples/todomvc/src/main.rs
Normal file
3
examples/todomvc/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
yew::start_app::<todomvc::Model>();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user