fix: tests

This commit is contained in:
Jonathan Kelley 2022-01-05 17:30:12 -05:00
parent e2a6454527
commit bd341f5571
17 changed files with 305 additions and 300 deletions

View File

@ -19,52 +19,53 @@ jobs:
max-parallel: 2
fail-fast: false
matrix:
target: [
i686-pc-windows-gnu,
i686-pc-windows-msvc,
x86_64-pc-windows-gnu,
x86_64-pc-windows-msvc,
]
target:
[
i686-pc-windows-gnu,
i686-pc-windows-msvc,
x86_64-pc-windows-gnu,
x86_64-pc-windows-msvc,
]
cfg_release_channel: [nightly, stable]
steps:
# The Windows runners have autocrlf enabled by default
# which causes failures for some of rustfmt's line-ending sensitive tests
- name: disable git eol translation
run: git config --global core.autocrlf false
- name: checkout
uses: actions/checkout@v2
# The Windows runners have autocrlf enabled by default
# which causes failures for some of rustfmt's line-ending sensitive tests
- name: disable git eol translation
run: git config --global core.autocrlf false
- name: checkout
uses: actions/checkout@v2
# Run build
- name: Install Rustup using win.rustup.rs
run: |
# Disable the download progress bar which can cause perf issues
$ProgressPreference = "SilentlyContinue"
Invoke-WebRequest https://win.rustup.rs/ -OutFile rustup-init.exe
.\rustup-init.exe -y --default-host=x86_64-pc-windows-msvc --default-toolchain=none
del rustup-init.exe
rustup target add ${{ matrix.target }}
shell: powershell
# Run build
- name: Install Rustup using win.rustup.rs
run: |
# Disable the download progress bar which can cause perf issues
$ProgressPreference = "SilentlyContinue"
Invoke-WebRequest https://win.rustup.rs/ -OutFile rustup-init.exe
.\rustup-init.exe -y --default-host=x86_64-pc-windows-msvc --default-toolchain=none
del rustup-init.exe
rustup target add ${{ matrix.target }}
shell: powershell
- name: Add mingw32 to path for i686-gnu
run: |
echo "C:\msys64\mingw32\bin" >> $GITHUB_PATH
if: matrix.target == 'i686-pc-windows-gnu' && matrix.channel == 'nightly'
shell: bash
- name: Add mingw32 to path for i686-gnu
run: |
echo "C:\msys64\mingw32\bin" >> $GITHUB_PATH
if: matrix.target == 'i686-pc-windows-gnu' && matrix.channel == 'nightly'
shell: bash
- name: Add mingw64 to path for x86_64-gnu
run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH
if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly'
shell: bash
- name: Add mingw64 to path for x86_64-gnu
run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH
if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly'
shell: bash
- name: build
run: |
rustc -Vv
cargo -V
set RUST_BACKTRACE=1
cargo build
shell: cmd
- name: build
run: |
rustc -Vv
cargo -V
set RUST_BACKTRACE=1
cargo build --features "desktop, ssr, router"
shell: cmd
- name: test
run: cargo test
shell: cmd
- name: test
run: cargo test
shell: cmd

View File

@ -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(),
}

View File

@ -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);
},
}

View File

@ -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));
}

View File

@ -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),

View File

@ -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" } }
}
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" }
}
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"),
}
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" }
}
})
}

View File

@ -187,8 +187,12 @@ impl Parse for ComponentField {
}
if input.peek(LitStr) && input.peek2(Token![,]) {
let content = ContentField::Formatted(input.parse()?);
return Ok(Self { name, content });
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) {
@ -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
}

View File

@ -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;

View File

@ -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;

View File

@ -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}",

View File

@ -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!()
}

View File

@ -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" }

View File

@ -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" } ));
```

View File

@ -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>

View File

@ -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 = &bump;
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);
}
}

View File

@ -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);
}

View File

@ -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() {