fix: tests
This commit is contained in:
parent
e2a6454527
commit
bd341f5571
|
@ -19,7 +19,8 @@ jobs:
|
|||
max-parallel: 2
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: [
|
||||
target:
|
||||
[
|
||||
i686-pc-windows-gnu,
|
||||
i686-pc-windows-msvc,
|
||||
x86_64-pc-windows-gnu,
|
||||
|
@ -62,7 +63,7 @@ jobs:
|
|||
rustc -Vv
|
||||
cargo -V
|
||||
set RUST_BACKTRACE=1
|
||||
cargo build
|
||||
cargo build --features "desktop, ssr, router"
|
||||
shell: cmd
|
||||
|
||||
- name: test
|
||||
|
|
|
@ -89,8 +89,8 @@ fn app(cx: Scope) -> Element {
|
|||
|
||||
#[derive(Props)]
|
||||
struct ActionButtonProps<'a> {
|
||||
name: &'static str,
|
||||
id: &'static str,
|
||||
name: &'a str,
|
||||
id: &'a str,
|
||||
onclick: &'a dyn Fn(),
|
||||
}
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ fn app(cx: Scope) -> Element {
|
|||
r#type: "{field}",
|
||||
value: "{value}",
|
||||
// checked: "false",
|
||||
oninput: move |evt: Arc<FormEvent>| {
|
||||
oninput: move |evt: FormEvent| {
|
||||
println!("{:?}", evt);
|
||||
},
|
||||
}
|
||||
|
|
|
@ -35,5 +35,5 @@ fn main() {
|
|||
|
||||
let app: Component = |cx| cx.render(rsx!(div { "some app" }));
|
||||
|
||||
dioxus_desktop::launch_core(app, (), |c| c.with_edits(edits));
|
||||
dioxus_desktop::launch_with_props(app, (), |c| c.with_edits(edits));
|
||||
}
|
||||
|
|
|
@ -116,8 +116,8 @@ fn app(cx: Scope) -> Element {
|
|||
|
||||
#[derive(Props)]
|
||||
struct CalculatorKeyProps<'a> {
|
||||
name: &'static str,
|
||||
onclick: &'a dyn Fn(Arc<MouseEvent>),
|
||||
name: &'a str,
|
||||
onclick: &'a dyn Fn(MouseEvent),
|
||||
children: Element<'a>,
|
||||
}
|
||||
|
||||
|
@ -211,7 +211,7 @@ impl Calculator {
|
|||
self.cur_val = self.display_value.parse::<f64>().unwrap();
|
||||
self.waiting_for_operand = true;
|
||||
}
|
||||
fn handle_keydown(&mut self, evt: Arc<KeyboardEvent>) {
|
||||
fn handle_keydown(&mut self, evt: KeyboardEvent) {
|
||||
match evt.key_code {
|
||||
KeyCode::Backspace => self.backspace(),
|
||||
KeyCode::Num0 => self.input_digit(0),
|
||||
|
|
|
@ -1,64 +1,53 @@
|
|||
#![allow(non_snake_case)]
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_router::{use_router, Link};
|
||||
use dioxus::router::{Link, Route, Router};
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum Route {
|
||||
// #[at("/")]
|
||||
Home,
|
||||
|
||||
// #[at("/:id")]
|
||||
AllUsers { page: u32 },
|
||||
|
||||
// #[at("/:id")]
|
||||
User { id: u32 },
|
||||
|
||||
// #[at("/:id")]
|
||||
BlogList { page: u32 },
|
||||
|
||||
// #[at("/:id")]
|
||||
BlogPost { post_id: u32 },
|
||||
|
||||
// #[at("/404")]
|
||||
// #[not_found]
|
||||
NotFound,
|
||||
fn main() {
|
||||
dioxus::desktop::launch(app);
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let route = use_router(&cx, Route::parse);
|
||||
|
||||
cx.render(rsx! {
|
||||
nav {
|
||||
Link { to: Route::Home, "Go home!" }
|
||||
Link { to: Route::AllUsers { page: 0 }, "List all users" }
|
||||
Link { to: Route::BlogList { page: 0 }, "Blog posts" }
|
||||
Router {
|
||||
ul {
|
||||
Link { to: "/", li { "Go home!" } }
|
||||
Link { to: "users", li { "List all users" } }
|
||||
Link { to: "blog", li { "Blog posts" } }
|
||||
}
|
||||
match route {
|
||||
Route::Home => rsx!("Home"),
|
||||
Route::AllUsers { page } => rsx!("All users - page {page}"),
|
||||
Route::User { id } => rsx!("User - id: {id}"),
|
||||
Route::BlogList { page } => rsx!("Blog posts - page {page}"),
|
||||
Route::BlogPost { post_id } => rsx!("Blog post - post {post_id}"),
|
||||
Route::NotFound => rsx!("Not found"),
|
||||
Route { to: "/", "Home" }
|
||||
Route { to: "users",
|
||||
Route { to: "/", "User list" }
|
||||
Route { to: ":name", BlogPost {} }
|
||||
}
|
||||
Route { to: "blog"
|
||||
Route { to: "/", "Blog list" }
|
||||
Route { to: ":post", BlogPost {} }
|
||||
}
|
||||
Route { to: "", "Err 404 Route Not Found" }
|
||||
}
|
||||
footer {}
|
||||
})
|
||||
}
|
||||
|
||||
impl Route {
|
||||
// Generate the appropriate route from the "tail" end of the URL
|
||||
fn parse(url: &str) -> Self {
|
||||
use Route::*;
|
||||
match url {
|
||||
"/" => Home,
|
||||
"/users" => AllUsers { page: 1 },
|
||||
"/users/:page" => AllUsers { page: 1 },
|
||||
"/users/:page/:id" => User { id: 1 },
|
||||
"/blog" => BlogList { page: 1 },
|
||||
"/blog/:page" => BlogList { page: 1 },
|
||||
"/blog/:page/:id" => BlogPost { post_id: 1 },
|
||||
_ => NotFound,
|
||||
}
|
||||
fn BlogPost(cx: Scope) -> Element {
|
||||
let post = dioxus::router::use_route(&cx).last_segment()?;
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 { "Reading blog post: {post}" }
|
||||
p { "example blog post" }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn User(cx: Scope) -> Element {
|
||||
let post = dioxus::router::use_route(&cx).last_segment()?;
|
||||
let bold = dioxus::router::use_route(&cx).param::<bool>("bold");
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 { "Reading blog post: {post}" }
|
||||
p { "example blog post" }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -187,9 +187,13 @@ impl Parse for ComponentField {
|
|||
}
|
||||
|
||||
if input.peek(LitStr) && input.peek2(Token![,]) {
|
||||
let t: LitStr = input.fork().parse()?;
|
||||
|
||||
if is_literal_foramtted(&t) {
|
||||
let content = ContentField::Formatted(input.parse()?);
|
||||
return Ok(Self { name, content });
|
||||
}
|
||||
}
|
||||
|
||||
if input.peek(LitStr) && input.peek2(LitStr) {
|
||||
let item = input.parse::<LitStr>().unwrap();
|
||||
|
@ -209,3 +213,19 @@ impl ToTokens for ComponentField {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn is_literal_foramtted(lit: &LitStr) -> bool {
|
||||
let s = lit.value();
|
||||
let mut chars = s.chars();
|
||||
|
||||
while let Some(next) = chars.next() {
|
||||
if next == '{' {
|
||||
let nen = chars.next();
|
||||
if nen == Some('{') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//! This is all kinda WIP, but the bones are there.
|
||||
|
||||
use crate::{ElementId, ScopeId};
|
||||
use std::{any::Any, cell::Cell, rc::Rc, sync::Arc};
|
||||
use std::{any::Any, cell::Cell, fmt::Debug, rc::Rc, sync::Arc};
|
||||
|
||||
pub(crate) struct BubbleState {
|
||||
pub canceled: Cell<bool>,
|
||||
|
@ -143,6 +143,12 @@ pub struct UiEvent<T> {
|
|||
bubble_state: Rc<BubbleState>,
|
||||
}
|
||||
|
||||
impl<T: Debug> std::fmt::Debug for UiEvent<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("UiEvent").field("data", &self.data).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for UiEvent<T> {
|
||||
type Target = T;
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@ use tao::{
|
|||
event::{Event, StartCause, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
|
||||
keyboard::{KeyCode, ModifiersState},
|
||||
menu::{MenuBar, MenuItem},
|
||||
window::{Window, WindowId},
|
||||
};
|
||||
pub use wry;
|
||||
|
|
|
@ -38,7 +38,7 @@ pub struct LinkProps<'a> {
|
|||
}
|
||||
|
||||
pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element {
|
||||
let service = cx.consume_context::<RouterService>().unwrap();
|
||||
let service = cx.consume_context::<RouterService>()?;
|
||||
cx.render(rsx! {
|
||||
a {
|
||||
href: "{cx.props.to}",
|
||||
|
|
|
@ -15,7 +15,7 @@ impl<'a> UseRoute<'a> {
|
|||
todo!()
|
||||
}
|
||||
|
||||
pub fn last_segment(&self) -> Option<&str> {
|
||||
pub fn last_segment(&self) -> Option<&'a str> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,6 @@ impl<'a> UseRoute<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn use_route(cx: &ScopeState) -> UseRoute {
|
||||
pub fn use_route<'a>(cx: &'a ScopeState) -> UseRoute<'a> {
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ dioxus-core = { path = "../core", version = "^0.1.6", features = ["serialize"] }
|
|||
[dev-dependencies]
|
||||
dioxus-hooks = { path = "../hooks" }
|
||||
dioxus-html = { path = "../html" }
|
||||
dioxus-core-macro = { path = "../core-macro" }
|
||||
thiserror = "1.0.23"
|
||||
log = "0.4.13"
|
||||
fern = { version = "0.6.0", features = ["colored"] }
|
||||
|
@ -27,4 +28,3 @@ argh = "0.1.4"
|
|||
serde = "1.0.120"
|
||||
serde_json = "1.0.61"
|
||||
fs_extra = "1.2.0"
|
||||
dioxus-core-macro = { path = "../core-macro" }
|
||||
|
|
|
@ -17,7 +17,7 @@ This crate is a part of the broader Dioxus ecosystem. For more resources about D
|
|||
|
||||
Dioxus SSR provides utilities to render Dioxus components to valid HTML. Once rendered, the HTML can be rehydrated client side or served from your web-server of choice.
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
let app: Component = |cx| cx.render(rsx!(div {"hello world!"}));
|
||||
|
||||
let mut vdom = VirtualDom::new(app);
|
||||
|
@ -32,7 +32,7 @@ assert_eq!(text, "<div>hello world!</div>")
|
|||
|
||||
The simplest example is to simply render some `rsx!` nodes to html. This can be done with the [`render_lazy`] api.
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
let content = dioxus::ssr::render(rsx!{
|
||||
div {
|
||||
(0..5).map(|i| rsx!(
|
||||
|
@ -44,7 +44,7 @@ let content = dioxus::ssr::render(rsx!{
|
|||
|
||||
## Rendering a VirtualDom
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let _ = dom.rebuild();
|
||||
|
||||
|
@ -54,7 +54,7 @@ let content = dioxus::ssr::render_vdom(&dom);
|
|||
## Configuring output
|
||||
It's possible to configure the output of the generated HTML.
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
let content = dioxus::ssr::render_vdom(&dom, |config| config.pretty(true).prerender(true));
|
||||
```
|
||||
|
||||
|
@ -62,7 +62,7 @@ let content = dioxus::ssr::render_vdom(&dom, |config| config.pretty(true).preren
|
|||
|
||||
We provide the basic `SsrFormatter` object that implements `Display`, so you can integrate SSR into an existing string, or write directly to a file.
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
use std::fmt::{Error, Write};
|
||||
|
||||
let mut buf = String::new();
|
||||
|
@ -92,7 +92,7 @@ With pre-rendering enabled, this crate will generate element nodes with Element
|
|||
|
||||
To enable pre-rendering, simply configure the `SsrConfig` with pre-rendering enabled.
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
let dom = VirtualDom::new(App);
|
||||
|
||||
let text = dioxus::ssr::render_vdom(App, |cfg| cfg.pre_render(true));
|
||||
|
@ -102,7 +102,7 @@ let text = dioxus::ssr::render_vdom(App, |cfg| cfg.pre_render(true));
|
|||
|
||||
Dioxus SSR can also be to render on the server. Obviously, you can just render the VirtualDOM to a string and send that down.
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
let text = dioxus::ssr::render_vdom(&vdom);
|
||||
assert_eq!(text, "<div>hello world!</div>")
|
||||
```
|
||||
|
@ -113,7 +113,7 @@ The rest of the space - IE doing this more efficiently, caching the virtualdom,
|
|||
|
||||
Dioxus SSR needs an arena to allocate from - whether it be the VirtualDom or a dedicated Bump allocator. To render `rsx!` directly to a string, you'll want to create an `SsrRenderer` and call `render_lazy`.
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
let text = dioxus::ssr::SsrRenderer::new().render_lazy(rsx!{
|
||||
div { "hello world" }
|
||||
});
|
||||
|
@ -122,7 +122,7 @@ assert_eq!(text, "<div>hello world!</div>")
|
|||
|
||||
This can be automated with the `render_lazy!` macro:
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
let text = render_lazy!(rsx!( div { "hello world" } ));
|
||||
```
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
asd
|
||||
<div title="About W3Schools"><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 0</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 1</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 2</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 3</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 4</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 5</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 6</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 7</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 8</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 9</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 10</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 11</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 12</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 13</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 14</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 15</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 16</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 17</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 18</p></div><div title="About W3Schools" style="color:blue;text-align:center" class="About W3Schools"><p title="About W3Schools">Hello world!: 19</p></div></div>
|
|
@ -2,13 +2,15 @@
|
|||
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use dioxus_core::exports::bumpalo;
|
||||
use dioxus_core::exports::bumpalo::Bump;
|
||||
use dioxus_core::IntoVNode;
|
||||
use dioxus_core::*;
|
||||
|
||||
fn app(_cx: Scope) -> Element {
|
||||
None
|
||||
}
|
||||
|
||||
pub struct SsrRenderer {
|
||||
inner: bumpalo::Bump,
|
||||
vdom: VirtualDom,
|
||||
cfg: SsrConfig,
|
||||
}
|
||||
|
||||
|
@ -16,21 +18,14 @@ impl SsrRenderer {
|
|||
pub fn new(cfg: impl FnOnce(SsrConfig) -> SsrConfig) -> Self {
|
||||
Self {
|
||||
cfg: cfg(SsrConfig::default()),
|
||||
inner: bumpalo::Bump::new(),
|
||||
vdom: VirtualDom::new(app),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_lazy<'a>(&'a mut self, f: LazyNodes<'a, '_>) -> String {
|
||||
let bump = &mut self.inner as *mut _;
|
||||
let s = self.render_inner(f);
|
||||
let scope = self.vdom.base_scope();
|
||||
let factory = NodeFactory::new(&scope);
|
||||
|
||||
// reuse the bump's memory
|
||||
unsafe { (&mut *bump as &mut bumpalo::Bump).reset() };
|
||||
s
|
||||
}
|
||||
|
||||
fn render_inner<'a>(&'a self, f: LazyNodes<'a, '_>) -> String {
|
||||
let factory = NodeFactory::new(&self.inner);
|
||||
let root = f.into_vnode(factory);
|
||||
format!(
|
||||
"{:}",
|
||||
|
@ -44,8 +39,8 @@ impl SsrRenderer {
|
|||
}
|
||||
|
||||
pub fn render_lazy<'a>(f: LazyNodes<'a, '_>) -> String {
|
||||
let bump = bumpalo::Bump::new();
|
||||
let borrowed = ≎
|
||||
let vdom = VirtualDom::new(app);
|
||||
let scope: *const ScopeState = vdom.base_scope();
|
||||
|
||||
// Safety
|
||||
//
|
||||
|
@ -57,9 +52,9 @@ pub fn render_lazy<'a>(f: LazyNodes<'a, '_>) -> String {
|
|||
//
|
||||
// Therefore, we cast our local bump alloactor into right lifetime. This is okay because our usage of the bump arena
|
||||
// is *definitely* shorter than the <'a> lifetime, and we return *owned* data - not borrowed data.
|
||||
let scope = unsafe { &*scope };
|
||||
|
||||
let _b = unsafe { std::mem::transmute::<&Bump, &'a Bump>(borrowed) };
|
||||
let root = f.into_vnode(NodeFactory::new(_b));
|
||||
let root = f.into_vnode(NodeFactory::new(&scope));
|
||||
|
||||
format!(
|
||||
"{:}",
|
||||
|
@ -282,154 +277,3 @@ impl SsrConfig {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
static SIMPLE_APP: Component = |cx| {
|
||||
cx.render(rsx!(div {
|
||||
"hello world!"
|
||||
}))
|
||||
};
|
||||
|
||||
static SLIGHTLY_MORE_COMPLEX: Component = |cx| {
|
||||
cx.render(rsx! {
|
||||
div { title: "About W3Schools",
|
||||
(0..20).map(|f| rsx!{
|
||||
div {
|
||||
title: "About W3Schools",
|
||||
style: "color:blue;text-align:center",
|
||||
class: "About W3Schools",
|
||||
p {
|
||||
title: "About W3Schools",
|
||||
"Hello world!: {f}"
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
static NESTED_APP: Component = |cx| {
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
SIMPLE_APP {}
|
||||
}
|
||||
))
|
||||
};
|
||||
static FRAGMENT_APP: Component = |cx| {
|
||||
cx.render(rsx!(
|
||||
div { "f1" }
|
||||
div { "f2" }
|
||||
div { "f3" }
|
||||
div { "f4" }
|
||||
))
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn to_string_works() {
|
||||
let mut dom = VirtualDom::new(SIMPLE_APP);
|
||||
dom.rebuild();
|
||||
dbg!(render_vdom(&dom));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hydration() {
|
||||
let mut dom = VirtualDom::new(NESTED_APP);
|
||||
dom.rebuild();
|
||||
dbg!(render_vdom_cfg(&dom, |c| c.pre_render(true)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested() {
|
||||
let mut dom = VirtualDom::new(NESTED_APP);
|
||||
dom.rebuild();
|
||||
dbg!(render_vdom(&dom));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fragment_app() {
|
||||
let mut dom = VirtualDom::new(FRAGMENT_APP);
|
||||
dom.rebuild();
|
||||
dbg!(render_vdom(&dom));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_to_file() {
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
let mut file = File::create("index.html").unwrap();
|
||||
|
||||
let mut dom = VirtualDom::new(SLIGHTLY_MORE_COMPLEX);
|
||||
dom.rebuild();
|
||||
|
||||
file.write_fmt(format_args!(
|
||||
"{}",
|
||||
TextRenderer::from_vdom(&dom, SsrConfig::default())
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn styles() {
|
||||
static STLYE_APP: Component = |cx| {
|
||||
cx.render(rsx! {
|
||||
div { color: "blue", font_size: "46px" }
|
||||
})
|
||||
};
|
||||
|
||||
let mut dom = VirtualDom::new(STLYE_APP);
|
||||
dom.rebuild();
|
||||
dbg!(render_vdom(&dom));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lazy() {
|
||||
let p1 = SsrRenderer::new(|c| c).render_lazy(rsx! {
|
||||
div { "ello" }
|
||||
});
|
||||
|
||||
let p2 = render_lazy(rsx! {
|
||||
div {
|
||||
"ello"
|
||||
}
|
||||
});
|
||||
assert_eq!(p1, p2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn big_lazy() {
|
||||
let s = render_lazy(rsx! {
|
||||
div {
|
||||
div {
|
||||
div {
|
||||
h1 { "ello world" }
|
||||
h1 { "ello world" }
|
||||
h1 { "ello world" }
|
||||
h1 { "ello world" }
|
||||
h1 { "ello world" }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dbg!(s);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inner_html() {
|
||||
let s = render_lazy(rsx! {
|
||||
div {
|
||||
dangerous_inner_html: "<div> ack </div>"
|
||||
}
|
||||
});
|
||||
|
||||
dbg!(s);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_ssr::{render_lazy, render_vdom, render_vdom_cfg, SsrConfig, SsrRenderer, TextRenderer};
|
||||
|
||||
static SIMPLE_APP: Component = |cx| {
|
||||
cx.render(rsx!(div {
|
||||
"hello world!"
|
||||
}))
|
||||
};
|
||||
|
||||
static SLIGHTLY_MORE_COMPLEX: Component = |cx| {
|
||||
cx.render(rsx! {
|
||||
div { title: "About W3Schools",
|
||||
(0..20).map(|f| rsx!{
|
||||
div {
|
||||
title: "About W3Schools",
|
||||
style: "color:blue;text-align:center",
|
||||
class: "About W3Schools",
|
||||
p {
|
||||
title: "About W3Schools",
|
||||
"Hello world!: {f}"
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
static NESTED_APP: Component = |cx| {
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
SIMPLE_APP {}
|
||||
}
|
||||
))
|
||||
};
|
||||
static FRAGMENT_APP: Component = |cx| {
|
||||
cx.render(rsx!(
|
||||
div { "f1" }
|
||||
div { "f2" }
|
||||
div { "f3" }
|
||||
div { "f4" }
|
||||
))
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn to_string_works() {
|
||||
let mut dom = VirtualDom::new(SIMPLE_APP);
|
||||
dom.rebuild();
|
||||
dbg!(render_vdom(&dom));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hydration() {
|
||||
let mut dom = VirtualDom::new(NESTED_APP);
|
||||
dom.rebuild();
|
||||
dbg!(render_vdom_cfg(&dom, |c| c.pre_render(true)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested() {
|
||||
let mut dom = VirtualDom::new(NESTED_APP);
|
||||
dom.rebuild();
|
||||
dbg!(render_vdom(&dom));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fragment_app() {
|
||||
let mut dom = VirtualDom::new(FRAGMENT_APP);
|
||||
dom.rebuild();
|
||||
dbg!(render_vdom(&dom));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_to_file() {
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
let mut file = File::create("index.html").unwrap();
|
||||
|
||||
let mut dom = VirtualDom::new(SLIGHTLY_MORE_COMPLEX);
|
||||
dom.rebuild();
|
||||
|
||||
file.write_fmt(format_args!(
|
||||
"{}",
|
||||
TextRenderer::from_vdom(&dom, SsrConfig::default())
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn styles() {
|
||||
static STLYE_APP: Component = |cx| {
|
||||
cx.render(rsx! {
|
||||
div { color: "blue", font_size: "46px" }
|
||||
})
|
||||
};
|
||||
|
||||
let mut dom = VirtualDom::new(STLYE_APP);
|
||||
dom.rebuild();
|
||||
dbg!(render_vdom(&dom));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lazy() {
|
||||
let p1 = SsrRenderer::new(|c| c).render_lazy(rsx! {
|
||||
div { "ello" }
|
||||
});
|
||||
|
||||
let p2 = render_lazy(rsx! {
|
||||
div {
|
||||
"ello"
|
||||
}
|
||||
});
|
||||
assert_eq!(p1, p2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn big_lazy() {
|
||||
let s = render_lazy(rsx! {
|
||||
div {
|
||||
div {
|
||||
div {
|
||||
h1 { "ello world" }
|
||||
h1 { "ello world" }
|
||||
h1 { "ello world" }
|
||||
h1 { "ello world" }
|
||||
h1 { "ello world" }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dbg!(s);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inner_html() {
|
||||
let s = render_lazy(rsx! {
|
||||
div {
|
||||
dangerous_inner_html: "<div> ack </div>"
|
||||
}
|
||||
});
|
||||
|
||||
dbg!(s);
|
||||
}
|
30
src/lib.rs
30
src/lib.rs
|
@ -39,7 +39,7 @@
|
|||
//!
|
||||
//! To launch an app, we use the `launch` method for the specific renderer we want to use. In the launch function, we pass the app's `Component`.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! use dioxus::prelude::*;
|
||||
//!
|
||||
//! fn main() {
|
||||
|
@ -62,7 +62,7 @@
|
|||
//! consistency, we force all attributes and listeners to be listed *before*
|
||||
//! children.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! let value = "123";
|
||||
//!
|
||||
//! rsx!(
|
||||
|
@ -78,7 +78,7 @@
|
|||
//! of the body as child elements and rust expressions. Any rust expression that
|
||||
//! implements `IntoIterator<Item = impl IntoVNode>` will be parsed as a child.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! rsx!(
|
||||
//! div {
|
||||
//! (0..10).map(|_| rsx!(span { "hello world" }))
|
||||
|
@ -94,7 +94,7 @@
|
|||
//! `cx` as the first argument of rsx. This is sometimes useful when we need to
|
||||
//! render nodes in match statements.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! fn example(cx: Scope) -> Element {
|
||||
//!
|
||||
//! // both of these are equivalent
|
||||
|
@ -107,7 +107,7 @@
|
|||
//! Putting everything together, we can write a simple component that a list of
|
||||
//! elements:
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! fn app(cx: Scope) -> Element {
|
||||
//! let name = "dave";
|
||||
//! cx.render(rsx!(
|
||||
|
@ -135,7 +135,7 @@
|
|||
//!
|
||||
//! In Dioxus, all properties are memoized by default!
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! fn App(cx: Scope) -> Element {
|
||||
//! cx.render(rsx!(
|
||||
//! Header {
|
||||
|
@ -149,7 +149,7 @@
|
|||
//! Our `Header` component takes in a `title` and a `color` property, which we
|
||||
//! delcare on an explicit `HeaderProps` struct.
|
||||
//!
|
||||
//! ```
|
||||
//! ```rust, ignore
|
||||
//! // The `Props` derive macro lets us add additional functionality to how props are interpreted.
|
||||
//! #[derive(Props, PartialEq)]
|
||||
//! struct HeaderProps {
|
||||
|
@ -170,7 +170,7 @@
|
|||
//! Components may use the `inline_props` macro to completely inline the props
|
||||
//! definition into the function arguments.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! #[inline_props]
|
||||
//! fn Header(cx: Scope, title: String, color: String) -> Element {
|
||||
//! cx.render(rsx!(
|
||||
|
@ -186,7 +186,7 @@
|
|||
//! attach some lifetimes to the props struct.
|
||||
//! > Note: we don't need to derive `PartialEq` for borrowed props since they cannot be memoized.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! #[derive(Props)]
|
||||
//! struct HeaderProps<'a> {
|
||||
//! title: &'a str,
|
||||
|
@ -206,7 +206,7 @@
|
|||
//! Components that beging with an uppercase letter may be called through
|
||||
//! traditional curly-brace syntax like so:
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! rsx!(
|
||||
//! Header { title: "My App" }
|
||||
//! )
|
||||
|
@ -215,7 +215,7 @@
|
|||
//! Alternatively, if your components begin with a lowercase letter, you can use
|
||||
//! the function call syntax:
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! rsx!(
|
||||
//! header( title: "My App" )
|
||||
//! )
|
||||
|
@ -230,7 +230,7 @@
|
|||
//! By convention, all hooks are functions that should start with `use_`. We can
|
||||
//! use hooks to define state and modify it from within listeners.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! fn app(cx: Scope) -> Element {
|
||||
//! let name = use_state(&cx, || "world");
|
||||
//!
|
||||
|
@ -250,7 +250,7 @@
|
|||
//!
|
||||
//! Most hooks you'll write are simply composition of other hooks:
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! fn use_username(cx: &ScopeState, id: Uuid) -> bool {
|
||||
//! let users = use_context::<Users>(cx);
|
||||
//! users.get(&id).map(|user| user.logged_in).ok_or(false)
|
||||
|
@ -259,7 +259,7 @@
|
|||
//!
|
||||
//! To create entirely new foundational hooks, we can use the `use_hook` method on ScopeState.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! fn use_mut_string(cx: &ScopeState) -> &mut String {
|
||||
//! cx.use_hook(|_| "Hello".to_string())
|
||||
//! }
|
||||
|
@ -271,7 +271,7 @@
|
|||
//!
|
||||
//! Using components, templates, and hooks, we can build a simple app.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust, ignore
|
||||
//! use dioxus::prelude::*;
|
||||
//!
|
||||
//! fn main() {
|
||||
|
|
Loading…
Reference in New Issue