Revert "improved documentation and refactored naming to be more self-explanatory"

This reverts commit adfbb6c380.
This commit is contained in:
Pascal committed 2023-12-07 17:11:56 +01:00
1 parent adfbb6c380
commit 906c466e78
91 files changed
+1553 -1663

No files matched your search

+7 -8
View File
@@ -43,15 +43,14 @@ const RECT_STYLE: &str = r#"
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let events = use_ref(cx, std::collections::VecDeque::new); let events = use_ref(cx, std::collections::VecDeque::new);
let log_event = let log_event = move |event: Event| {
move |event: Event| { let mut events = events.write();
let mut events = events.write();
if events.len() >= MAX_EVENTS { if events.len() >= MAX_EVENTS {
events.pop_front(); events.pop_front();
} }
events.push_back(event); events.push_back(event);
}; };
cx.render(rsx! ( cx.render(rsx! (
div { div {
+9 -10
View File
@@ -5,17 +5,16 @@ fn main() {
} }
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let login = let login = use_callback!(cx, move |_| async move {
use_callback!(cx, move |_| async move { let res = reqwest::get("https://dog.ceo/api/breeds/list/all")
let res = reqwest::get("https://dog.ceo/api/breeds/list/all") .await
.await .unwrap()
.unwrap() .text()
.text() .await
.await .unwrap();
.unwrap();
println!("{res:#?}, "); println!("{res:#?}, ");
}); });
cx.render(rsx! { cx.render(rsx! {
button { onclick: login, "Click me!" } button { onclick: login, "Click me!" }
+7 -8
View File
@@ -12,15 +12,14 @@ fn app(cx: Scope) -> Element {
let window = use_window(cx); let window = use_window(cx);
let emails_sent = use_ref(cx, Vec::new); let emails_sent = use_ref(cx, Vec::new);
let tx = let tx = use_coroutine(cx, |mut rx: UnboundedReceiver<String>| {
use_coroutine(cx, |mut rx: UnboundedReceiver<String>| { to_owned![emails_sent];
to_owned![emails_sent]; async move {
async move { while let Some(message) = rx.next().await {
while let Some(message) = rx.next().await { emails_sent.write().push(message);
emails_sent.write().push(message);
}
} }
}); }
});
cx.render(rsx! { cx.render(rsx! {
div { div {
+4 -5
View File
@@ -8,11 +8,10 @@ fn main() {
fn App(cx: Scope) -> Element { fn App(cx: Scope) -> Element {
let val = use_state(cx, || "0.0001"); let val = use_state(cx, || "0.0001");
let num = let num = match val.parse::<f32>() {
match val.parse::<f32>() { Err(_) => return cx.render(rsx!("Parsing failed")),
Err(_) => return cx.render(rsx!("Parsing failed")), Ok(num) => num,
Ok(num) => num, };
};
cx.render(rsx! { cx.render(rsx! {
h1 { "The parsed value is {num}" } h1 { "The parsed value is {num}" }
+13 -14
View File
@@ -7,26 +7,25 @@ fn main() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let eval_provider = use_eval(cx); let eval_provider = use_eval(cx);
let future = let future = use_future(cx, (), |_| {
use_future(cx, (), |_| { to_owned![eval_provider];
to_owned![eval_provider]; async move {
async move { let eval = eval_provider(
let eval = eval_provider( r#"
r#"
dioxus.send("Hi from JS!"); dioxus.send("Hi from JS!");
let msg = await dioxus.recv(); let msg = await dioxus.recv();
console.log(msg); console.log(msg);
return "hello world"; return "hello world";
"#, "#,
) )
.unwrap(); .unwrap();
eval.send("Hi from Rust!".into()).unwrap(); eval.send("Hi from Rust!".into()).unwrap();
let res = eval.recv().await.unwrap(); let res = eval.recv().await.unwrap();
println!("{:?}", eval.await); println!("{:?}", eval.await);
res res
} }
}); });
match future.value() { match future.value() {
Some(v) => cx.render(rsx!( Some(v) => cx.render(rsx!(
+5 -6
View File
@@ -73,12 +73,11 @@ struct Files {
impl Files { impl Files {
fn new() -> Self { fn new() -> Self {
let mut files = let mut files = Self {
Self { path_stack: vec!["./".to_string()],
path_stack: vec!["./".to_string()], path_names: vec![],
path_names: vec![], err: None,
err: None, };
};
files.reload_path_list(); files.reload_path_list();
+27 -28
View File
@@ -112,34 +112,33 @@ fn ActionButton<'a>(cx: Scope<'a, ActionButtonProps<'a>>) -> Element {
}) })
} }
static ADJECTIVES: &[&str] = static ADJECTIVES: &[&str] = &[
&[ "pretty",
"pretty", "large",
"large", "big",
"big", "small",
"small", "tall",
"tall", "short",
"short", "long",
"long", "handsome",
"handsome", "plain",
"plain", "quaint",
"quaint", "clean",
"clean", "elegant",
"elegant", "easy",
"easy", "angry",
"angry", "crazy",
"crazy", "helpful",
"helpful", "mushy",
"mushy", "odd",
"odd", "unsightly",
"unsightly", "adorable",
"adorable", "important",
"important", "inexpensive",
"inexpensive", "cheap",
"cheap", "expensive",
"expensive", "fancy",
"fancy", ];
];
static COLOURS: &[&str] = &[ static COLOURS: &[&str] = &[
"red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
+19 -23
View File
@@ -8,32 +8,28 @@ fn main() {
} }
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let onsubmit = let onsubmit = move |evt: FormEvent| {
move |evt: FormEvent| { cx.spawn(async move {
cx.spawn(async move { let resp = reqwest::Client::new()
let resp = .post("http://localhost:8080/login")
reqwest::Client::new() .form(&[
.post("http://localhost:8080/login") ("username", &evt.values["username"]),
.form(&[ ("password", &evt.values["password"]),
("username", &evt.values["username"]), ])
("password", &evt.values["password"]), .send()
]) .await;
.send()
.await;
match resp { match resp {
// Parse data from here, such as storing a response token // Parse data from here, such as storing a response token
Ok(_data) => println!("Login successful!"), Ok(_data) => println!("Login successful!"),
//Handle any errors from the fetch here //Handle any errors from the fetch here
Err(_err) => { Err(_err) => {
println!( println!("Login failed - you need a login server running on localhost:8080.")
"Login failed - you need a login server running on localhost:8080."
)
}
} }
}); }
}; });
};
cx.render(rsx! { cx.render(rsx! {
h1 { "Login" } h1 { "Login" }
+5 -6
View File
@@ -112,12 +112,11 @@ pub async fn exchange_refresh_token(
pub async fn log_out_url(id_token_hint: CoreIdToken) -> Result<Url, crate::errors::Error> { pub async fn log_out_url(id_token_hint: CoreIdToken) -> Result<Url, crate::errors::Error> {
let provider_metadata = init_provider_metadata().await?; let provider_metadata = init_provider_metadata().await?;
let end_session_url = let end_session_url = provider_metadata
provider_metadata .additional_metadata()
.additional_metadata() .clone()
.clone() .end_session_endpoint
.end_session_endpoint .unwrap();
.unwrap();
let logout_request: LogoutRequest = LogoutRequest::from(end_session_url); let logout_request: LogoutRequest = LogoutRequest::from(end_session_url);
Ok(logout_request Ok(logout_request
.set_client_id(ClientId::new(DIOXUS_FRONT_CLIENT_ID.to_string())) .set_client_id(ClientId::new(DIOXUS_FRONT_CLIENT_ID.to_string()))
@@ -22,31 +22,29 @@ pub fn LogOut(cx: Scope<ClientProps>) -> Element {
Some(fermi_auth_token_read) => match fermi_auth_token_read.id_token.clone() { Some(fermi_auth_token_read) => match fermi_auth_token_read.id_token.clone() {
Some(id_token) => match log_out_url_state.get() { Some(id_token) => match log_out_url_state.get() {
Some(log_out_url_result) => match log_out_url_result { Some(log_out_url_result) => match log_out_url_result {
Some(uri) => { Some(uri) => match uri {
match uri { Ok(uri) => {
Ok(uri) => { rsx! {
rsx! { Link {
Link { onclick: move |_| {
onclick: move |_| { {
{ AuthTokenState::persistent_set(
AuthTokenState::persistent_set( fermi_auth_token,
fermi_auth_token, Some(AuthTokenState::default()),
Some(AuthTokenState::default()), );
); }
} },
}, to: uri.to_string(),
to: uri.to_string(), "Log out"
"Log out"
}
}
}
Err(error) => {
rsx! {
div { format!{"Failed to load disconnection url: {:?}", error} }
} }
} }
} }
} Err(error) => {
rsx! {
div { format!{"Failed to load disconnection url: {:?}", error} }
}
}
},
None => { None => {
rsx! { div { "Loading... Please wait" } } rsx! { div { "Loading... Please wait" } }
} }
+12 -14
View File
@@ -13,21 +13,19 @@ fn main() {
} }
fn example(cx: Scope) -> Element { fn example(cx: Scope) -> Element {
let items = let items = use_state(cx, || {
use_state(cx, || { vec![Thing {
vec![Thing { a: "asd".to_string(),
a: "asd".to_string(), b: 10,
b: 10, }]
}] });
});
let things = let things = use_ref(cx, || {
use_ref(cx, || { vec![Thing {
vec![Thing { a: "asd".to_string(),
a: "asd".to_string(), b: 10,
b: 10, }]
}] });
});
let things_list = things.read(); let things_list = things.read();
let mything = use_ref(cx, || Some(String::from("asd"))); let mything = use_ref(cx, || Some(String::from("asd")));
+15 -15
View File
@@ -63,23 +63,23 @@ pub fn Die<'a>(cx: Scope<'a, DieProps<'a>>) -> Element {
let active_dots = &DOTS_FOR_VALUE[(value - 1) as usize]; let active_dots = &DOTS_FOR_VALUE[(value - 1) as usize];
let fill = if keep { HELD_COLOR } else { UNHELD_COLOR }; let fill = if keep { HELD_COLOR } else { UNHELD_COLOR };
let dots = let dots = DOTS
DOTS.iter() .iter()
.zip(active_dots.iter()) .zip(active_dots.iter())
.filter(|(_, &active)| active) .filter(|(_, &active)| active)
.map(|((x, y), _)| { .map(|((x, y), _)| {
let dcx = x * OFFSET; let dcx = x * OFFSET;
let dcy = y * OFFSET; let dcy = y * OFFSET;
rsx! { rsx! {
circle { circle {
cx: "{dcx}", cx: "{dcx}",
cy: "{dcy}", cy: "{dcy}",
r: "{DOT_RADIUS}", r: "{DOT_RADIUS}",
fill: "#333" fill: "#333"
}
} }
}); }
});
cx.render(rsx! { cx.render(rsx! {
svg { svg {
+7 -8
View File
@@ -202,14 +202,13 @@ pub fn ListFooter<'a>(cx: Scope<'a, ListFooterProps<'a>>) -> Element {
let active_todo_count = cx.props.active_todo_count; let active_todo_count = cx.props.active_todo_count;
let active_todo_text = cx.props.active_todo_text; let active_todo_text = cx.props.active_todo_text;
let selected = let selected = |state| {
|state| { if *cx.props.filter == state {
if *cx.props.filter == state { "selected"
"selected" } else {
} else { "false"
"false" }
} };
};
cx.render(rsx! { cx.render(rsx! {
footer { class: "footer", footer { class: "footer",
+7 -8
View File
@@ -34,14 +34,13 @@ impl Writer<'_> {
for (id, line) in self.src[start.line..end.line].iter().enumerate() { for (id, line) in self.src[start.line..end.line].iter().enumerate() {
writeln!(self.out)?; writeln!(self.out)?;
// check if this is the last line // check if this is the last line
let line = let line = {
{ if id == (end.line - start.line) - 1 {
if id == (end.line - start.line) - 1 { &line[..end.column]
&line[..end.column] } else {
} else { line
line }
} };
};
// trim the leading whitespace // trim the leading whitespace
let previous_indent = crate::leading_whitespaces(line) / 4; let previous_indent = crate::leading_whitespaces(line) / 4;
+54 -55
View File
@@ -67,21 +67,19 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
cmd.arg("--quiet") cmd.arg("--quiet")
}; };
let cmd = let cmd = if config.custom_profile.is_some() {
if config.custom_profile.is_some() { let custom_profile = config.custom_profile.as_ref().unwrap();
let custom_profile = config.custom_profile.as_ref().unwrap(); cmd.arg("--profile").arg(custom_profile)
cmd.arg("--profile").arg(custom_profile) } else {
} else { cmd
cmd };
};
let cmd = let cmd = if config.features.is_some() {
if config.features.is_some() { let features_str = config.features.as_ref().unwrap().join(" ");
let features_str = config.features.as_ref().unwrap().join(" "); cmd.arg("--features").arg(features_str)
cmd.arg("--features").arg(features_str) } else {
} else { cmd
cmd };
};
let cmd = match executable { let cmd = match executable {
ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), ExecutableType::Binary(name) => cmd.arg("--bin").arg(name),
@@ -94,14 +92,13 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
// [2] Establish the output directory structure // [2] Establish the output directory structure
let bindgen_outdir = out_dir.join("assets").join("dioxus"); let bindgen_outdir = out_dir.join("assets").join("dioxus");
let build_profile = let build_profile = if config.custom_profile.is_some() {
if config.custom_profile.is_some() { config.custom_profile.as_ref().unwrap()
config.custom_profile.as_ref().unwrap() } else if config.release {
} else if config.release { "release"
"release" } else {
} else { "debug"
"debug" };
};
let input_path = match executable { let input_path = match executable {
ExecutableType::Binary(name) | ExecutableType::Lib(name) => target_dir ExecutableType::Binary(name) | ExecutableType::Lib(name) => target_dir
@@ -210,15 +207,14 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
} }
// this code will copy all public file to the output dir // this code will copy all public file to the output dir
let copy_options = let copy_options = fs_extra::dir::CopyOptions {
fs_extra::dir::CopyOptions { overwrite: true,
overwrite: true, skip_exist: false,
skip_exist: false, buffer_size: 64000,
buffer_size: 64000, copy_inside: false,
copy_inside: false, content_only: false,
content_only: false, depth: 0,
depth: 0, };
};
if asset_dir.is_dir() { if asset_dir.is_dir() {
for entry in std::fs::read_dir(asset_dir)? { for entry in std::fs::read_dir(asset_dir)? {
let path = entry?.path(); let path = entry?.path();
@@ -291,21 +287,20 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result<BuildResul
}; };
let file_name: String; let file_name: String;
let mut res_path = let mut res_path = match &config.executable {
match &config.executable { crate::ExecutableType::Binary(name) | crate::ExecutableType::Lib(name) => {
crate::ExecutableType::Binary(name) | crate::ExecutableType::Lib(name) => { file_name = name.clone();
file_name = name.clone(); config.target_dir.join(release_type).join(name)
config.target_dir.join(release_type).join(name) }
} crate::ExecutableType::Example(name) => {
crate::ExecutableType::Example(name) => { file_name = name.clone();
file_name = name.clone(); config
config .target_dir
.target_dir .join(release_type)
.join(release_type) .join("examples")
.join("examples") .join(name)
.join(name) }
} };
};
let target_file = if cfg!(windows) { let target_file = if cfg!(windows) {
res_path.set_extension("exe"); res_path.set_extension("exe");
@@ -401,7 +396,9 @@ fn prettier_build(cmd: subprocess::Exec) -> anyhow::Result<Vec<Diagnostic>> {
match message.level { match message.level {
cargo_metadata::diagnostic::DiagnosticLevel::Error => { cargo_metadata::diagnostic::DiagnosticLevel::Error => {
return { return {
Err(anyhow::anyhow!(message.rendered.unwrap_or("Unknown".into()))) Err(anyhow::anyhow!(message
.rendered
.unwrap_or("Unknown".into())))
}; };
} }
cargo_metadata::diagnostic::DiagnosticLevel::Warning => { cargo_metadata::diagnostic::DiagnosticLevel::Warning => {
@@ -478,7 +475,10 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String {
let mut script_str = String::new(); let mut script_str = String::new();
for script in script_list { for script in script_list {
script_str.push_str(&format!("<script src=\"{}\"></script>\n", &script.to_str().unwrap(),)) script_str.push_str(&format!(
"<script src=\"{}\"></script>\n",
&script.to_str().unwrap(),
))
} }
replace_or_insert_before("{script_include}", &script_str, "</body", &mut html); replace_or_insert_before("{script_include}", &script_str, "</body", &mut html);
@@ -502,11 +502,10 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String {
html = html.replace("{base_path}", base_path); html = html.replace("{base_path}", base_path);
} else { } else {
// If not, insert the script // If not, insert the script
html = html = html.replace(
html.replace( "</body",
"</body", &format!(
&format!( r#"<script type="module">
r#"<script type="module">
import init from "/{base_path}/assets/dioxus/{app_name}.js"; import init from "/{base_path}/assets/dioxus/{app_name}.js";
init("/{base_path}/assets/dioxus/{app_name}_bg.wasm").then(wasm => {{ init("/{base_path}/assets/dioxus/{app_name}_bg.wasm").then(wasm => {{
if (wasm.__wbindgen_start == undefined) {{ if (wasm.__wbindgen_start == undefined) {{
@@ -515,8 +514,8 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String {
}}); }});
</script> </script>
</body"# </body"#
), ),
); );
} }
let title = config let title = config
+3 -3
View File
@@ -34,9 +34,9 @@ pub fn crate_root() -> Result<PathBuf> {
} }
None None
}) })
.ok_or_else( .ok_or_else(|| {
|| Error::CargoError("Failed to find directory containing Cargo.toml".to_string()) Error::CargoError("Failed to find directory containing Cargo.toml".to_string())
) })
} }
/// Checks if the directory contains `Cargo.toml` /// Checks if the directory contains `Cargo.toml`
+37 -38
View File
@@ -93,49 +93,48 @@ async fn autoformat_project(check: bool) -> Result<()> {
let mut files_to_format = vec![]; let mut files_to_format = vec![];
collect_rs_files(&crate_config.crate_dir, &mut files_to_format); collect_rs_files(&crate_config.crate_dir, &mut files_to_format);
let counts = let counts = files_to_format
files_to_format .into_iter()
.into_iter() .filter(|file| {
.filter(|file| { if file.components().any(|f| f.as_os_str() == "target") {
if file.components().any(|f| f.as_os_str() == "target") { return false;
return false; }
true
})
.map(|path| async {
let _path = path.clone();
let res = tokio::spawn(async move {
let contents = tokio::fs::read_to_string(&path).await?;
let edits = dioxus_autofmt::fmt_file(&contents);
let len = edits.len();
if !edits.is_empty() {
let out = dioxus_autofmt::apply_formats(&contents, edits);
tokio::fs::write(&path, out).await?;
} }
true Ok(len) as Result<usize, tokio::io::Error>
}) })
.map(|path| async {
let _path = path.clone();
let res = tokio::spawn(async move {
let contents = tokio::fs::read_to_string(&path).await?;
let edits = dioxus_autofmt::fmt_file(&contents);
let len = edits.len();
if !edits.is_empty() {
let out = dioxus_autofmt::apply_formats(&contents, edits);
tokio::fs::write(&path, out).await?;
}
Ok(len) as Result<usize, tokio::io::Error>
})
.await;
match res {
Err(err) => {
eprintln!("error formatting file: {}\n{err}", _path.display());
None
}
Ok(Err(err)) => {
eprintln!("error formatting file: {}\n{err}", _path.display());
None
}
Ok(Ok(res)) => Some(res),
}
})
.collect::<FuturesUnordered<_>>()
.collect::<Vec<_>>()
.await; .await;
match res {
Err(err) => {
eprintln!("error formatting file: {}\n{err}", _path.display());
None
}
Ok(Err(err)) => {
eprintln!("error formatting file: {}\n{err}", _path.display());
None
}
Ok(Ok(res)) => Some(res),
}
})
.collect::<FuturesUnordered<_>>()
.collect::<Vec<_>>()
.await;
let files_formatted: usize = counts let files_formatted: usize = counts
.into_iter() .into_iter()
.map(|f| match f { .map(|f| match f {
+7 -8
View File
@@ -35,14 +35,13 @@ impl Create {
let toml_paths = [path.join("Cargo.toml"), path.join("Dioxus.toml")]; let toml_paths = [path.join("Cargo.toml"), path.join("Dioxus.toml")];
for toml_path in &toml_paths { for toml_path in &toml_paths {
let toml = std::fs::read_to_string(toml_path)?; let toml = std::fs::read_to_string(toml_path)?;
let mut toml = let mut toml = toml.parse::<toml_edit::Document>().map_err(|e| {
toml.parse::<toml_edit::Document>().map_err(|e| { anyhow::anyhow!(
anyhow::anyhow!( "failed to parse toml at {}: {}",
"failed to parse toml at {}: {}", toml_path.display(),
toml_path.display(), e.to_string()
e.to_string() )
) })?;
})?;
toml.as_table_mut().fmt(); toml.as_table_mut().fmt();
+5 -6
View File
@@ -67,12 +67,11 @@ impl UserData for PluginFileSystem {
let file = PathBuf::from(args.0); let file = PathBuf::from(args.0);
let target = PathBuf::from(args.1); let target = PathBuf::from(args.1);
let tar_gz = let tar_gz = if let Ok(v) = File::open(file) {
if let Ok(v) = File::open(file) { v
v } else {
} else { return Ok(false);
return Ok(false); };
};
let tar = GzDecoder::new(tar_gz); let tar = GzDecoder::new(tar_gz);
let mut archive = Archive::new(tar); let mut archive = Archive::new(tar);
+5 -6
View File
@@ -317,12 +317,11 @@ impl PluginManager {
let name = i.get::<_, String>("name").unwrap(); let name = i.get::<_, String>("name").unwrap();
let loader = i.get::<_, bool>("loader").unwrap(); let loader = i.get::<_, bool>("loader").unwrap();
let text = let text = if loader {
if loader { format!("{name} [:loader]")
format!("{name} [:loader]") } else {
} else { name
name };
};
res.push(text); res.push(text);
} }
} }
+17 -19
View File
@@ -22,13 +22,12 @@ pub fn print_console_info(
options: PrettierOptions, options: PrettierOptions,
web_info: Option<WebServerInfo>, web_info: Option<WebServerInfo>,
) { ) {
if let Ok(native_clearseq) = if let Ok(native_clearseq) = Command::new(if cfg!(target_os = "windows") {
Command::new(if cfg!(target_os = "windows") { "cls"
"cls" } else {
} else { "clear"
"clear" })
}) .output()
.output()
{ {
print!("{}", String::from_utf8_lossy(&native_clearseq.stdout)); print!("{}", String::from_utf8_lossy(&native_clearseq.stdout));
} else { } else {
@@ -47,18 +46,17 @@ pub fn print_console_info(
} else { } else {
"Default" "Default"
}; };
let url_rewrite = let url_rewrite = if config
if config .dioxus_config
.dioxus_config .web
.web .watcher
.watcher .index_on_404
.index_on_404 .unwrap_or(false)
.unwrap_or(false) {
{ "True"
"True" } else {
} else { "False"
"False" };
};
let proxies = config.dioxus_config.web.proxy.as_ref(); let proxies = config.dioxus_config.web.proxy.as_ref();
+7 -6
View File
@@ -165,7 +165,9 @@ async fn get_rustls(config: &CrateConfig) -> Result<Option<RustlsConfig>> {
get_rustls_without_mkcert(web_config)? get_rustls_without_mkcert(web_config)?
}; };
Ok(Some(RustlsConfig::from_pem_file(cert_path, key_path).await?)) Ok(Some(
RustlsConfig::from_pem_file(cert_path, key_path).await?,
))
} }
fn get_rustls_with_mkcert(web_config: &WebHttpsConfig) -> Result<(String, String)> { fn get_rustls_with_mkcert(web_config: &WebHttpsConfig) -> Result<(String, String)> {
@@ -312,11 +314,10 @@ async fn setup_router(
)); ));
// Setup routes // Setup routes
router = router = router
router .route("/_dioxus/hot_reload", get(hot_reload_handler))
.route("/_dioxus/hot_reload", get(hot_reload_handler)) .layer(cors)
.layer(cors) .layer(Extension(ws_reload));
.layer(Extension(ws_reload));
if let Some(hot_reload) = hot_reload { if let Some(hot_reload) = hot_reload {
router = router.layer(Extension(hot_reload)) router = router.layer(Extension(hot_reload))
+24 -26
View File
@@ -162,11 +162,10 @@ impl Tool {
) )
} }
Self::Tailwind => { Self::Tailwind => {
let windows_extension = let windows_extension = match self.target_platform() {
match self.target_platform() { "windows" => ".exe",
"windows" => ".exe", _ => "",
_ => "", };
};
format!( format!(
"https://github.com/tailwindlabs/tailwindcss/releases/download/{version}/tailwindcss-{target}-x64{optional_ext}", "https://github.com/tailwindlabs/tailwindcss/releases/download/{version}/tailwindcss-{target}-x64{optional_ext}",
version = self.tool_version(), version = self.tool_version(),
@@ -281,30 +280,29 @@ impl Tool {
pub fn call(&self, command: &str, args: Vec<&str>) -> anyhow::Result<Vec<u8>> { pub fn call(&self, command: &str, args: Vec<&str>) -> anyhow::Result<Vec<u8>> {
let bin_path = tools_path().join(self.name()).join(self.bin_path()); let bin_path = tools_path().join(self.name()).join(self.bin_path());
let command_file = let command_file = match self {
match self { Tool::Binaryen => {
Tool::Binaryen => { if cfg!(target_os = "windows") {
if cfg!(target_os = "windows") { format!("{}.exe", command)
format!("{}.exe", command) } else {
} else { command.to_string()
command.to_string()
}
} }
Tool::Sass => { }
if cfg!(target_os = "windows") { Tool::Sass => {
format!("{}.bat", command) if cfg!(target_os = "windows") {
} else { format!("{}.bat", command)
command.to_string() } else {
} command.to_string()
} }
Tool::Tailwind => { }
if cfg!(target_os = "windows") { Tool::Tailwind => {
format!("{}.exe", command) if cfg!(target_os = "windows") {
} else { format!("{}.exe", command)
command.to_string() } else {
} command.to_string()
} }
}; }
};
if !bin_path.join(&command_file).is_file() { if !bin_path.join(&command_file).is_file() {
return Err(anyhow::anyhow!("Command file not found.")); return Err(anyhow::anyhow!("Command file not found."));
@@ -67,12 +67,11 @@ fn get_props_struct(component_body: &ComponentBody) -> ItemStruct {
let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span()); let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span());
let first_lifetime = let first_lifetime = if let Some(GenericParam::Lifetime(lt)) = generics.params.first() {
if let Some(GenericParam::Lifetime(lt)) = generics.params.first() { Some(lt)
Some(lt) } else {
} else { None
None };
};
let struct_attrs = if first_lifetime.is_some() { let struct_attrs = if first_lifetime.is_some() {
quote! { #[derive(Props)] } quote! { #[derive(Props)] }
@@ -251,18 +250,16 @@ fn get_function(component_body: &ComponentBody) -> ItemFn {
let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span()); let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span());
// Skip first arg since that's the context // Skip first arg since that's the context
let struct_field_names = let struct_field_names = inputs.iter().skip(1).filter_map(|f| match f {
inputs.iter().skip(1).filter_map(|f| match f { FnArg::Receiver(_) => unreachable!(), // ComponentBody prohibits receiver parameters.
FnArg::Receiver(_) => unreachable!(), // ComponentBody prohibits receiver parameters. FnArg::Typed(pt) => Some(&pt.pat),
FnArg::Typed(pt) => Some(&pt.pat), });
});
let first_lifetime = let first_lifetime = if let Some(GenericParam::Lifetime(lt)) = generics.params.first() {
if let Some(GenericParam::Lifetime(lt)) = generics.params.first() { Some(lt)
Some(lt) } else {
} else { None
None };
};
let (scope_lifetime, fn_generics) = if let Some(lt) = first_lifetime { let (scope_lifetime, fn_generics) = if let Some(lt) = first_lifetime {
(quote! { #lt, }, generics.clone()) (quote! { #lt, }, generics.clone())
+110 -107
View File
@@ -41,10 +41,16 @@ pub fn impl_my_derive(ast: &syn::DeriveInput) -> Result<TokenStream, Error> {
} }
} }
syn::Fields::Unnamed(_) => { syn::Fields::Unnamed(_) => {
return Err(Error::new(ast.span(), "Props is not supported for tuple structs")) return Err(Error::new(
ast.span(),
"Props is not supported for tuple structs",
))
} }
syn::Fields::Unit => { syn::Fields::Unit => {
return Err(Error::new(ast.span(), "Props is not supported for unit structs")) return Err(Error::new(
ast.span(),
"Props is not supported for unit structs",
))
} }
}, },
syn::Data::Enum(_) => { syn::Data::Enum(_) => {
@@ -328,9 +334,10 @@ mod field_info {
} }
Ok(()) Ok(())
} }
_ => { _ => Err(Error::new_spanned(
Err(Error::new_spanned(&assign, format!("Unknown parameter {name:?}"))) &assign,
} format!("Unknown parameter {name:?}"),
)),
} }
} }
@@ -445,13 +452,12 @@ fn type_from_inside_option(ty: &syn::Type, check_option_name: bool) -> Option<&s
if check_option_name && segment.ident != "Option" { if check_option_name && segment.ident != "Option" {
return None; return None;
} }
let generic_params = if let syn::PathArguments::AngleBracketed(generic_params) = let generic_params =
&segment.arguments if let syn::PathArguments::AngleBracketed(generic_params) = &segment.arguments {
{ generic_params
generic_params } else {
} else { return None;
return None; };
};
if let syn::GenericArgument::Type(ty) = generic_params.args.first()? { if let syn::GenericArgument::Type(ty) = generic_params.args.first()? {
Some(ty) Some(ty)
} else { } else {
@@ -556,38 +562,37 @@ mod struct_info {
} }
syn::GenericParam::Const(_cnst) => None, syn::GenericParam::Const(_cnst) => None,
}); });
let builder_method_doc = let builder_method_doc = match self.builder_attr.builder_method_doc {
match self.builder_attr.builder_method_doc { Some(ref doc) => quote!(#doc),
Some(ref doc) => quote!(#doc), None => {
None => { let doc = format!(
let doc = format!( "
"
Create a builder for building `{name}`. Create a builder for building `{name}`.
On the builder, call {setters} to set the values of the fields. On the builder, call {setters} to set the values of the fields.
Finally, call `.build()` to create the instance of `{name}`. Finally, call `.build()` to create the instance of `{name}`.
", ",
name = self.name, name = self.name,
setters = { setters = {
let mut result = String::new(); let mut result = String::new();
let mut is_first = true; let mut is_first = true;
for field in self.included_fields() { for field in self.included_fields() {
use std::fmt::Write; use std::fmt::Write;
if is_first { if is_first {
is_first = false; is_first = false;
} else { } else {
write!(&mut result, ", ").unwrap(); write!(&mut result, ", ").unwrap();
} }
write!(&mut result, "`.{}(...)`", field.name).unwrap(); write!(&mut result, "`.{}(...)`", field.name).unwrap();
if field.builder_attr.default.is_some() { if field.builder_attr.default.is_some() {
write!(&mut result, "(optional)").unwrap(); write!(&mut result, "(optional)").unwrap();
}
} }
result
} }
); result
quote!(#doc) }
} );
}; quote!(#doc)
}
};
let builder_type_doc = if self.builder_attr.doc { let builder_type_doc = if self.builder_attr.doc {
match self.builder_attr.builder_type_doc { match self.builder_attr.builder_type_doc {
Some(ref doc) => quote!(#[doc = #doc]), Some(ref doc) => quote!(#[doc = #doc]),
@@ -618,11 +623,10 @@ Finally, call `.build()` to create the instance of `{name}`.
false => quote! { self == other }, false => quote! { self == other },
}; };
let is_static = let is_static = match are_there_generics {
match are_there_generics { true => quote! { false },
true => quote! { false }, false => quote! { true },
false => quote! { true }, };
};
Ok(quote! { Ok(quote! {
impl #impl_generics #name #ty_generics #where_clause { impl #impl_generics #name #ty_generics #where_clause {
@@ -707,15 +711,14 @@ Finally, call `.build()` to create the instance of `{name}`.
ref builder_name, .. ref builder_name, ..
} = *self; } = *self;
let descructuring = let descructuring = self.included_fields().map(|f| {
self.included_fields().map(|f| { if f.ordinal == field.ordinal {
if f.ordinal == field.ordinal { quote!(_)
quote!(_) } else {
} else { let name = f.name;
let name = f.name; quote!(#name)
quote!(#name) }
} });
});
let reconstructing = self.included_fields().map(|f| f.name); let reconstructing = self.included_fields().map(|f| f.name);
let mut ty_generics: Vec<syn::GenericArgument> = self let mut ty_generics: Vec<syn::GenericArgument> = self
@@ -782,17 +785,16 @@ Finally, call `.build()` to create the instance of `{name}`.
// NOTE: both auto_into and strip_option affect `arg_type` and `arg_expr`, but the order of // NOTE: both auto_into and strip_option affect `arg_type` and `arg_expr`, but the order of
// nesting is different so we have to do this little dance. // nesting is different so we have to do this little dance.
let arg_type = let arg_type = if field.builder_attr.strip_option {
if field.builder_attr.strip_option { field.type_from_inside_option(false).ok_or_else(|| {
field.type_from_inside_option(false).ok_or_else(|| { Error::new_spanned(
Error::new_spanned( field_type,
field_type, "can't `strip_option` - field is not `Option<...>`",
"can't `strip_option` - field is not `Option<...>`", )
) })?
})? } else {
} else { field_type
field_type };
};
let (arg_type, arg_expr) = if field.builder_attr.auto_into { let (arg_type, arg_expr) = if field.builder_attr.auto_into {
( (
quote!(impl ::core::convert::Into<#arg_type>), quote!(impl ::core::convert::Into<#arg_type>),
@@ -878,45 +880,44 @@ Finally, call `.build()` to create the instance of `{name}`.
}) })
.collect(); .collect();
let mut builder_generics_tuple = empty_type_tuple(); let mut builder_generics_tuple = empty_type_tuple();
let generics = let generics = self.modify_generics(|g| {
self.modify_generics(|g| { let index_after_lifetime_in_generics = g
let index_after_lifetime_in_generics = g .params
.params .iter()
.iter() .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_)))
.filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_))) .count();
.count(); for f in self.included_fields() {
for f in self.included_fields() { if f.builder_attr.default.is_some() {
if f.builder_attr.default.is_some() { // `f` is not mandatory - it does not have it's own fake `build` method, so `field` will need
// `f` is not mandatory - it does not have it's own fake `build` method, so `field` will need // to warn about missing `field` whether or not `f` is set.
// to warn about missing `field` whether or not `f` is set. assert!(
assert!( f.ordinal != field.ordinal,
f.ordinal != field.ordinal, "`required_field_impl` called for optional field {}",
"`required_field_impl` called for optional field {}", field.name
field.name );
); g.params
g.params .insert(index_after_lifetime_in_generics, f.generic_ty_param());
.insert(index_after_lifetime_in_generics, f.generic_ty_param()); builder_generics_tuple.elems.push_value(f.type_ident());
builder_generics_tuple.elems.push_value(f.type_ident()); } else if f.ordinal < field.ordinal {
} else if f.ordinal < field.ordinal { // Only add a `build` method that warns about missing `field` if `f` is set. If `f` is not set,
// Only add a `build` method that warns about missing `field` if `f` is set. If `f` is not set, // `f`'s `build` method will warn, since it appears earlier in the argument list.
// `f`'s `build` method will warn, since it appears earlier in the argument list. builder_generics_tuple
builder_generics_tuple .elems
.elems .push_value(f.tuplized_type_ty_param());
.push_value(f.tuplized_type_ty_param()); } else if f.ordinal == field.ordinal {
} else if f.ordinal == field.ordinal { builder_generics_tuple.elems.push_value(empty_type());
builder_generics_tuple.elems.push_value(empty_type()); } else {
} else { // `f` appears later in the argument list after `field`, so if they are both missing we will
// `f` appears later in the argument list after `field`, so if they are both missing we will // show a warning for `field` and not for `f` - which means this warning should appear whether
// show a warning for `field` and not for `f` - which means this warning should appear whether // or not `f` is set.
// or not `f` is set. g.params
g.params .insert(index_after_lifetime_in_generics, f.generic_ty_param());
.insert(index_after_lifetime_in_generics, f.generic_ty_param()); builder_generics_tuple.elems.push_value(f.type_ident());
builder_generics_tuple.elems.push_value(f.type_ident());
}
builder_generics_tuple.elems.push_punct(Default::default());
} }
});
builder_generics_tuple.elems.push_punct(Default::default());
}
});
let index_after_lifetime_in_generics = builder_generics let index_after_lifetime_in_generics = builder_generics
.iter() .iter()
@@ -1138,9 +1139,10 @@ Finally, call `.build()` to create the instance of `{name}`.
self.doc = true; self.doc = true;
Ok(()) Ok(())
} }
_ => { _ => Err(Error::new_spanned(
Err(Error::new_spanned(&assign, format!("Unknown parameter {name:?}"))) &assign,
} format!("Unknown parameter {name:?}"),
)),
} }
} }
syn::Expr::Path(path) => { syn::Expr::Path(path) => {
@@ -1151,9 +1153,10 @@ Finally, call `.build()` to create the instance of `{name}`.
self.doc = true; self.doc = true;
Ok(()) Ok(())
} }
_ => { _ => Err(Error::new_spanned(
Err(Error::new_spanned(&path, format!("Unknown parameter {name:?}"))) &path,
} format!("Unknown parameter {name:?}"),
)),
} }
} }
syn::Expr::Call(call) => { syn::Expr::Call(call) => {
+7 -4
View File
@@ -31,9 +31,9 @@ pub fn format_type_string(ty: &Type) -> String {
// This should always be valid syntax. // This should always be valid syntax.
// Not Rust code, but syntax, which is the only thing that `syn` cares about. // Not Rust code, but syntax, which is the only thing that `syn` cares about.
let Ok(file_unformatted) = let Ok(file_unformatted) = syn::parse_file(&format!(
syn::parse_file(&format!("{FORMATTED_TYPE_START}{ty_unformatted}{FORMATTED_TYPE_END}")) "{FORMATTED_TYPE_START}{ty_unformatted}{FORMATTED_TYPE_END}"
else { )) else {
return ty_unformatted.to_string(); return ty_unformatted.to_string();
}; };
@@ -60,7 +60,10 @@ impl DeprecatedAttribute {
/// Returns `None` if the given attribute was not a valid form of the `#[deprecated]` attribute. /// Returns `None` if the given attribute was not a valid form of the `#[deprecated]` attribute.
pub fn from_meta(meta: &Meta) -> syn::Result<Self> { pub fn from_meta(meta: &Meta) -> syn::Result<Self> {
if meta.path() != &parse_quote!(deprecated) { if meta.path() != &parse_quote!(deprecated) {
return Err(syn::Error::new(meta.span(), "attribute path is not `deprecated`")); return Err(syn::Error::new(
meta.span(),
"attribute path is not `deprecated`",
));
} }
match &meta { match &meta {
+7 -8
View File
@@ -36,14 +36,13 @@ fn sort_bfs(paths: &[&'static [u8]]) -> Vec<(usize, &'static [u8])> {
#[test] #[test]
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
fn sorting() { fn sorting() {
let r: [(usize, &[u8]); 5] = let r: [(usize, &[u8]); 5] = [
[ (0, &[0, 1]),
(0, &[0, 1]), (1, &[0, 2]),
(1, &[0, 2]), (2, &[1, 0]),
(2, &[1, 0]), (3, &[1, 0, 1]),
(3, &[1, 0, 1]), (4, &[1, 2]),
(4, &[1, 2]), ];
];
assert_eq!( assert_eq!(
sort_bfs(&[&[0, 1,], &[0, 2,], &[1, 0,], &[1, 0, 1,], &[1, 2,],]), sort_bfs(&[&[0, 1,], &[0, 2,], &[1, 0,], &[1, 0, 1,], &[1, 2,],]),
r r
+3 -3
View File
@@ -531,9 +531,9 @@ impl<'a> From<&'a AttributeValue<'a>> for BorrowedAttributeValue<'a> {
} }
AttributeValue::Any(value) => { AttributeValue::Any(value) => {
let value = value.borrow(); let value = value.borrow();
BorrowedAttributeValue::Any( BorrowedAttributeValue::Any(std::cell::Ref::map(value, |value| {
std::cell::Ref::map(value, |value| &**value.as_ref().unwrap()) &**value.as_ref().unwrap()
) }))
} }
AttributeValue::None => BorrowedAttributeValue::None, AttributeValue::None => BorrowedAttributeValue::None,
} }
+4 -5
View File
@@ -267,11 +267,10 @@ impl VirtualDom {
suspended_scopes: Default::default(), suspended_scopes: Default::default(),
}; };
let root = let root = dom.new_scope(
dom.new_scope( Box::new(VProps::new(root, |_, _| unreachable!(), root_props)),
Box::new(VProps::new(root, |_, _| unreachable!(), root_props)), "app",
"app", );
);
// Unlike react, we provide a default error boundary that just renders the error as a string // Unlike react, we provide a default error boundary that just renders the error as a string
root.provide_context(Rc::new(ErrorBoundary::new(ScopeId::ROOT))); root.provide_context(Rc::new(ErrorBoundary::new(ScopeId::ROOT)));
+13 -16
View File
@@ -9,23 +9,20 @@ use dioxus_core::BorrowedAttributeValue;
#[test] #[test]
fn attrs_cycle() { fn attrs_cycle() {
let mut dom = let mut dom = VirtualDom::new(|cx| {
VirtualDom::new(|cx| { let id = cx.generation();
let id = cx.generation(); match cx.generation() % 2 {
match cx.generation() % 2 { 0 => cx.render(rsx! {
0 => { div {}
cx.render(rsx! { }),
div {} 1 => cx.render(rsx! {
}) div {
h1 { class: "{id}", id: "{id}" }
} }
1 => cx.render(rsx! { }),
div { _ => unreachable!(),
h1 { class: "{id}", id: "{id}" } }
} });
}),
_ => unreachable!(),
}
});
let bump = Bump::new(); let bump = Bump::new();
+5 -6
View File
@@ -3,12 +3,11 @@
use dioxus::prelude::*; use dioxus::prelude::*;
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let raw = let raw = match cx.generation() % 2 {
match cx.generation() % 2 { 0 => "123.123",
0 => "123.123", 1 => "123.123.123",
1 => "123.123.123", _ => unreachable!(),
_ => unreachable!(), };
};
let value = raw.parse::<f32>().unwrap_or(123.123); let value = raw.parse::<f32>().unwrap_or(123.123);
+22 -25
View File
@@ -11,16 +11,15 @@ use dioxus_core::ElementId;
#[test] #[test]
fn test_original_diff() { fn test_original_diff() {
let mut dom = let mut dom = VirtualDom::new(|cx| {
VirtualDom::new(|cx| { cx.render(rsx! {
cx.render(rsx! { div {
div { div {
div { "Hello, world!"
"Hello, world!"
}
} }
}) }
}); })
});
let edits = dom.rebuild().santize(); let edits = dom.rebuild().santize();
@@ -83,12 +82,11 @@ fn create() {
#[test] #[test]
fn create_list() { fn create_list() {
let mut dom = let mut dom = VirtualDom::new(|cx| {
VirtualDom::new(|cx| { cx.render(rsx! {
cx.render(rsx! { (0..3).map(|f| rsx!( div { "hello" } ))
(0..3).map(|f| rsx!( div { "hello" } )) })
}) });
});
let _edits = dom.rebuild().santize(); let _edits = dom.rebuild().santize();
@@ -162,17 +160,16 @@ fn create_components() {
#[test] #[test]
fn anchors() { fn anchors() {
let mut dom = let mut dom = VirtualDom::new(|cx| {
VirtualDom::new(|cx| { cx.render(rsx! {
cx.render(rsx! { if true {
if true { rsx!( div { "hello" } )
rsx!( div { "hello" } ) }
} if false {
if false { rsx!( div { "goodbye" } )
rsx!( div { "goodbye" } ) }
} })
}) });
});
// note that the template under "false" doesn't show up since it's not loaded // note that the template under "false" doesn't show up since it's not loaded
let edits = dom.rebuild().santize(); let edits = dom.rebuild().santize();
+6 -7
View File
@@ -24,13 +24,12 @@ fn empty_fragment_creates_nothing() {
#[test] #[test]
fn root_fragments_work() { fn root_fragments_work() {
let mut vdom = let mut vdom = VirtualDom::new(|cx| {
VirtualDom::new(|cx| { cx.render(rsx!(
cx.render(rsx!( div { "hello" }
div { "hello" } div { "goodbye" }
div { "goodbye" } ))
)) });
});
assert_eq!( assert_eq!(
vdom.rebuild().edits.last().unwrap(), vdom.rebuild().edits.last().unwrap(),
+30 -33
View File
@@ -4,18 +4,17 @@ use pretty_assertions::assert_eq;
#[test] #[test]
fn list_creates_one_by_one() { fn list_creates_one_by_one() {
let mut dom = let mut dom = VirtualDom::new(|cx| {
VirtualDom::new(|cx| { let gen = cx.generation();
let gen = cx.generation();
cx.render(rsx! { cx.render(rsx! {
div { div {
(0..gen).map(|i| rsx! { (0..gen).map(|i| rsx! {
div { "{i}" } div { "{i}" }
}) })
} }
}) })
}); });
// load the div and then assign the empty fragment as a placeholder // load the div and then assign the empty fragment as a placeholder
assert_eq!( assert_eq!(
@@ -74,18 +73,17 @@ fn list_creates_one_by_one() {
#[test] #[test]
fn removes_one_by_one() { fn removes_one_by_one() {
let mut dom = let mut dom = VirtualDom::new(|cx| {
VirtualDom::new(|cx| { let gen = 3 - cx.generation() % 4;
let gen = 3 - cx.generation() % 4;
cx.render(rsx! { cx.render(rsx! {
div { div {
(0..gen).map(|i| rsx! { (0..gen).map(|i| rsx! {
div { "{i}" } div { "{i}" }
}) })
} }
}) })
}); });
// load the div and then assign the empty fragment as a placeholder // load the div and then assign the empty fragment as a placeholder
assert_eq!( assert_eq!(
@@ -152,17 +150,16 @@ fn removes_one_by_one() {
#[test] #[test]
fn list_shrink_multiroot() { fn list_shrink_multiroot() {
let mut dom = let mut dom = VirtualDom::new(|cx| {
VirtualDom::new(|cx| { cx.render(rsx! {
cx.render(rsx! { div {
div { (0..cx.generation()).map(|i| rsx! {
(0..cx.generation()).map(|i| rsx! { div { "{i}" }
div { "{i}" } div { "{i}" }
div { "{i}" } })
}) }
} })
}) });
});
assert_eq!( assert_eq!(
dom.rebuild().santize().edits, dom.rebuild().santize().edits,
+54 -59
View File
@@ -8,7 +8,9 @@ fn random_ns() -> Option<&'static str> {
let namespace = rand::random::<u8>() % 2; let namespace = rand::random::<u8>() % 2;
match namespace { match namespace {
0 => None, 0 => None,
1 => Some(Box::leak(format!("ns{}", rand::random::<usize>()).into_boxed_str())), 1 => Some(Box::leak(
format!("ns{}", rand::random::<usize>()).into_boxed_str(),
)),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -20,15 +22,13 @@ fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute<'static> {
value: Box::leak(format!("value{}", rand::random::<usize>()).into_boxed_str()), value: Box::leak(format!("value{}", rand::random::<usize>()).into_boxed_str()),
namespace: random_ns(), namespace: random_ns(),
}, },
1 => { 1 => TemplateAttribute::Dynamic {
TemplateAttribute::Dynamic { id: {
id: { let old_idx = *attr_idx;
let old_idx = *attr_idx; *attr_idx += 1;
*attr_idx += 1; old_idx
old_idx },
}, },
}
}
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -73,26 +73,22 @@ fn create_random_template_node(
1 => TemplateNode::Text { 1 => TemplateNode::Text {
text: Box::leak(format!("{}", rand::random::<usize>()).into_boxed_str()), text: Box::leak(format!("{}", rand::random::<usize>()).into_boxed_str()),
}, },
2 => { 2 => TemplateNode::DynamicText {
TemplateNode::DynamicText { id: {
id: { let old_idx = *template_idx;
let old_idx = *template_idx; *template_idx += 1;
*template_idx += 1; dynamic_node_types.push(DynamicNodeType::Text);
dynamic_node_types.push(DynamicNodeType::Text); old_idx
old_idx },
}, },
} 3 => TemplateNode::Dynamic {
} id: {
3 => { let old_idx = *template_idx;
TemplateNode::Dynamic { *template_idx += 1;
id: { dynamic_node_types.push(DynamicNodeType::Other);
let old_idx = *template_idx; old_idx
*template_idx += 1; },
dynamic_node_types.push(DynamicNodeType::Other); },
old_idx
},
}
}
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -211,9 +207,9 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode {
fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute { fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute {
let value = match rand::random::<u8>() % 7 { let value = match rand::random::<u8>() % 7 {
0 => { 0 => AttributeValue::Text(Box::leak(
AttributeValue::Text(Box::leak(format!("{}", rand::random::<usize>()).into_boxed_str())) format!("{}", rand::random::<usize>()).into_boxed_str(),
} )),
1 => AttributeValue::Float(rand::random()), 1 => AttributeValue::Float(rand::random()),
2 => AttributeValue::Int(rand::random()), 2 => AttributeValue::Int(rand::random()),
3 => AttributeValue::Bool(rand::random()), 3 => AttributeValue::Bool(rand::random()),
@@ -276,32 +272,31 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
.into_boxed_str(), .into_boxed_str(),
)); ));
// println!("{template:#?}"); // println!("{template:#?}");
let node = let node = VNode {
VNode { key: None,
key: None, parent: None,
parent: None, template: Cell::new(template),
template: Cell::new(template), root_ids: bumpalo::collections::Vec::new_in(cx.bump()).into(),
root_ids: bumpalo::collections::Vec::new_in(cx.bump()).into(), dynamic_nodes: {
dynamic_nodes: { let dynamic_nodes: Vec<_> = dynamic_node_types
let dynamic_nodes: Vec<_> = dynamic_node_types .iter()
.iter() .map(|ty| match ty {
.map(|ty| match ty { DynamicNodeType::Text => DynamicNode::Text(VText::new(Box::leak(
DynamicNodeType::Text => DynamicNode::Text(VText::new(Box::leak( format!("{}", rand::random::<usize>()).into_boxed_str(),
format!("{}", rand::random::<usize>()).into_boxed_str(), ))),
))), DynamicNodeType::Other => {
DynamicNodeType::Other => { create_random_dynamic_node(cx, cx.props.depth + 1)
create_random_dynamic_node(cx, cx.props.depth + 1) }
} })
}) .collect();
.collect(); cx.bump().alloc(dynamic_nodes)
cx.bump().alloc(dynamic_nodes) },
}, dynamic_attrs: cx.bump().alloc(
dynamic_attrs: cx.bump().alloc( (0..template.attr_paths.len())
(0..template.attr_paths.len()) .map(|_| create_random_dynamic_attr(cx))
.map(|_| create_random_dynamic_attr(cx)) .collect::<Vec<_>>(),
.collect::<Vec<_>>(), ),
), };
};
Some(node) Some(node)
} }
_ => None, _ => None,
+5 -6
View File
@@ -34,13 +34,12 @@ fn use_inner_html(cx: &ScopeState, id: &'static str) -> Option<String> {
to_owned![value, eval_provider]; to_owned![value, eval_provider];
async move { async move {
tokio::time::sleep(std::time::Duration::from_millis(100)).await; tokio::time::sleep(std::time::Duration::from_millis(100)).await;
let html = let html = eval_provider(&format!(
eval_provider(&format!( r#"let element = document.getElementById('{}');
r#"let element = document.getElementById('{}');
return element.innerHTML"#, return element.innerHTML"#,
id id
)) ))
.unwrap(); .unwrap();
if let Ok(serde_json::Value::String(html)) = html.await { if let Ok(serde_json::Value::String(html)) = html.await {
println!("html: {}", html); println!("html: {}", html);
value.set(Some(html)); value.set(Some(html));
+5 -7
View File
@@ -36,7 +36,7 @@ pub struct Config {
pub(crate) root_name: String, pub(crate) root_name: String,
pub(crate) background_color: Option<(u8, u8, u8, u8)>, pub(crate) background_color: Option<(u8, u8, u8, u8)>,
pub(crate) last_window_close_behaviour: WindowCloseBehaviour, pub(crate) last_window_close_behaviour: WindowCloseBehaviour,
pub(crate) enable_default_menu_bar: bool, pub(crate) disable_default_menu_bar: bool,
} }
type DropHandler = Box<dyn Fn(&Window, FileDropEvent) -> bool>; type DropHandler = Box<dyn Fn(&Window, FileDropEvent) -> bool>;
@@ -66,15 +66,13 @@ impl Config {
root_name: "main".to_string(), root_name: "main".to_string(),
background_color: None, background_color: None,
last_window_close_behaviour: WindowCloseBehaviour::LastWindowExitsApp, last_window_close_behaviour: WindowCloseBehaviour::LastWindowExitsApp,
enable_default_menu_bar: true, disable_default_menu_bar: false,
} }
} }
/// Set whether the default menu bar should be enabled. /// Set whether the default menu bar should be disabled.
/// pub fn with_disable_default_menu_bar(mut self, disable: bool) -> Self {
/// > Note: `enable` is `true` by default. To disable the default menu bar pass `false`. self.disable_default_menu_bar = disable;
pub fn with_default_menu_bar(mut self, enable: bool) -> Self {
self.enable_default_menu_bar = enable;
self self
} }
+9 -11
View File
@@ -240,20 +240,18 @@ pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, cfg: Config)
Event::UserEvent(event) => match event.0 { Event::UserEvent(event) => match event.0 {
#[cfg(all(feature = "hot-reload", debug_assertions))] #[cfg(all(feature = "hot-reload", debug_assertions))]
EventData::HotReloadEvent(msg) => { EventData::HotReloadEvent(msg) => match msg {
match msg { dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => {
dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => { for webview in webviews.values_mut() {
for webview in webviews.values_mut() { webview.dom.replace_template(template);
webview.dom.replace_template(template);
poll_vdom(webview); poll_vdom(webview);
}
}
dioxus_hot_reload::HotReloadMsg::Shutdown => {
*control_flow = ControlFlow::Exit;
} }
} }
} dioxus_hot_reload::HotReloadMsg::Shutdown => {
*control_flow = ControlFlow::Exit;
}
},
EventData::CloseWindow => { EventData::CloseWindow => {
webviews.remove(&event.1); webviews.remove(&event.1);
+4 -8
View File
@@ -19,8 +19,8 @@ pub fn build(
let index_file = cfg.custom_index.clone(); let index_file = cfg.custom_index.clone();
let root_name = cfg.root_name.clone(); let root_name = cfg.root_name.clone();
if cfg.enable_default_menu_bar { if !cfg.disable_default_menu_bar {
builder = builder.with_menu(build_default_menu_bar()); builder = builder.with_menu(create_default_menu_bar());
} }
let window = builder.with_visible(false).build(event_loop).unwrap(); let window = builder.with_visible(false).build(event_loop).unwrap();
@@ -103,12 +103,8 @@ pub fn build(
(webview.build().unwrap(), web_context) (webview.build().unwrap(), web_context)
} }
/// Builds a standard menu bar depending on the users platform. It may be used as a starting point /// Creates a standard menu bar depending on the platform
/// to further customize the menu bar and pass it to a [`WindowBuilder`](tao::window::WindowBuilder). fn create_default_menu_bar() -> MenuBar {
/// > Note: The default menu bar enables macOS shortcuts like cut/copy/paste.
/// > The menu bar differs per platform because of constraints introduced
/// > by [`MenuItem`](tao::menu::MenuItem).
pub fn build_default_menu_bar() -> MenuBar {
let mut menu_bar = MenuBar::new(); let mut menu_bar = MenuBar::new();
// since it is uncommon on windows to have an "application menu" // since it is uncommon on windows to have an "application menu"
@@ -40,10 +40,9 @@ fn app(cx: Scope) -> Element {
rsx!(p { "{trimmed}" }) rsx!(p { "{trimmed}" })
}); });
let log_event = let log_event = move |event: Event| {
move |event: Event| { events.write().push(event);
events.write().push(event); };
};
cx.render(rsx! { cx.render(rsx! {
div { div {
+27 -28
View File
@@ -87,34 +87,33 @@ impl Label {
} }
} }
static ADJECTIVES: &[&str] = static ADJECTIVES: &[&str] = &[
&[ "pretty",
"pretty", "large",
"large", "big",
"big", "small",
"small", "tall",
"tall", "short",
"short", "long",
"long", "handsome",
"handsome", "plain",
"plain", "quaint",
"quaint", "clean",
"clean", "elegant",
"elegant", "easy",
"easy", "angry",
"angry", "crazy",
"crazy", "helpful",
"helpful", "mushy",
"mushy", "odd",
"odd", "unsightly",
"unsightly", "adorable",
"adorable", "important",
"important", "inexpensive",
"inexpensive", "cheap",
"cheap", "expensive",
"expensive", "fancy",
"fancy", ];
];
static COLOURS: &[&str] = &[ static COLOURS: &[&str] = &[
"red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
+27 -28
View File
@@ -62,34 +62,33 @@ impl Label {
} }
} }
static ADJECTIVES: &[&str] = static ADJECTIVES: &[&str] = &[
&[ "pretty",
"pretty", "large",
"large", "big",
"big", "small",
"small", "tall",
"tall", "short",
"short", "long",
"long", "handsome",
"handsome", "plain",
"plain", "quaint",
"quaint", "clean",
"clean", "elegant",
"elegant", "easy",
"easy", "angry",
"angry", "crazy",
"crazy", "helpful",
"helpful", "mushy",
"mushy", "odd",
"odd", "unsightly",
"unsightly", "adorable",
"adorable", "important",
"important", "inexpensive",
"inexpensive", "cheap",
"cheap", "expensive",
"expensive", "fancy",
"fancy", ];
];
static COLOURS: &[&str] = &[ static COLOURS: &[&str] = &[
"red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
@@ -37,13 +37,12 @@ fn main() {
//To enable Private cookies for integrity, and authenticity please check the next Example. //To enable Private cookies for integrity, and authenticity please check the next Example.
let session_config = SessionConfig::default().with_table_name("test_table"); let session_config = SessionConfig::default().with_table_name("test_table");
let auth_config = AuthConfig::<i64>::default().with_anonymous_user_id(Some(1)); let auth_config = AuthConfig::<i64>::default().with_anonymous_user_id(Some(1));
let session_store = let session_store = SessionStore::<SessionSqlitePool>::new(
SessionStore::<SessionSqlitePool>::new( Some(pool.clone().into()),
Some(pool.clone().into()), session_config,
session_config, )
) .await
.await .unwrap();
.unwrap();
//Create the Database table for storing our Session Data. //Create the Database table for storing our Session Data.
session_store.initiate().await.unwrap(); session_store.initiate().await.unwrap();
@@ -16,9 +16,9 @@ use serde::{Deserialize, Serialize};
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
pre_cache_static_routes_with_props( pre_cache_static_routes_with_props(
&ServeConfigBuilder::new_with_router( &ServeConfigBuilder::new_with_router(dioxus_fullstack::router::FullstackRouterConfig::<
dioxus_fullstack::router::FullstackRouterConfig::<Route>::default() Route,
) >::default())
.assets_path("docs") .assets_path("docs")
.incremental(IncrementalRendererConfig::default().static_dir("docs")) .incremental(IncrementalRendererConfig::default().static_dir("docs"))
.build(), .build(),
@@ -280,13 +280,12 @@ where
let assets_path = assets_path.into(); let assets_path = assets_path.into();
// Serve all files in dist folder except index.html // Serve all files in dist folder except index.html
let dir = let dir = std::fs::read_dir(&assets_path).unwrap_or_else(|e| {
std::fs::read_dir(&assets_path).unwrap_or_else(|e| { panic!(
panic!( "Couldn't read assets directory at {:?}: {}",
"Couldn't read assets directory at {:?}: {}", &assets_path, e
&assets_path, e )
) });
});
for entry in dir.flatten() { for entry in dir.flatten() {
let path = entry.path(); let path = entry.path();
@@ -298,9 +297,9 @@ where
.unwrap() .unwrap()
.iter() .iter()
.map(|segment| { .map(|segment| {
segment.to_str().unwrap_or_else( segment.to_str().unwrap_or_else(|| {
|| panic!("Failed to convert path segment {:?} to string", segment) panic!("Failed to convert path segment {:?} to string", segment)
) })
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("/"); .join("/");
@@ -244,13 +244,12 @@ impl DioxusRouterExt for Router {
let assets_path = assets_path.into(); let assets_path = assets_path.into();
// Serve all files in dist folder except index.html // Serve all files in dist folder except index.html
let dir = let dir = std::fs::read_dir(&assets_path).unwrap_or_else(|e| {
std::fs::read_dir(&assets_path).unwrap_or_else(|e| { panic!(
panic!( "Couldn't read assets directory at {:?}: {}",
"Couldn't read assets directory at {:?}: {}", &assets_path, e
&assets_path, e )
) });
});
for entry in dir.flatten() { for entry in dir.flatten() {
let path = entry.path(); let path = entry.path();
@@ -262,9 +261,9 @@ impl DioxusRouterExt for Router {
.unwrap() .unwrap()
.iter() .iter()
.map(|segment| { .map(|segment| {
segment.to_str().unwrap_or_else( segment.to_str().unwrap_or_else(|| {
|| panic!("Failed to convert path segment {:?} to string", segment) panic!("Failed to convert path segment {:?} to string", segment)
) })
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("/"); .join("/");
@@ -7,14 +7,13 @@ use super::HTMLDataCursor;
#[allow(unused)] #[allow(unused)]
pub(crate) fn serde_from_bytes<T: DeserializeOwned>(string: &[u8]) -> Option<T> { pub(crate) fn serde_from_bytes<T: DeserializeOwned>(string: &[u8]) -> Option<T> {
let decompressed = let decompressed = match STANDARD.decode(string) {
match STANDARD.decode(string) { Ok(bytes) => bytes,
Ok(bytes) => bytes, Err(err) => {
Err(err) => { tracing::error!("Failed to decode base64: {}", err);
tracing::error!("Failed to decode base64: {}", err); return None;
return None; }
} };
};
match postcard::from_bytes(&decompressed) { match postcard::from_bytes(&decompressed) {
Ok(data) => Some(data), Ok(data) => Some(data),
+5 -3
View File
@@ -46,9 +46,11 @@ where
> + Send, > + Send,
>, >,
> { > {
let fut = self.call(req).instrument( let fut = self.call(req).instrument(tracing::trace_span!(
tracing::trace_span!("service", "{}", std::any::type_name::<S>()) "service",
); "{}",
std::any::type_name::<S>()
));
Box::pin(async move { fut.await.map_err(|err| err.into()) }) Box::pin(async move { fut.await.map_err(|err| err.into()) })
} }
} }
+4 -5
View File
@@ -91,11 +91,10 @@ impl SsrRendererPool {
Ok((freshness, html)) Ok((freshness, html))
} }
Self::Incremental(pool) => { Self::Incremental(pool) => {
let mut renderer = pool let mut renderer =
.write() pool.write().unwrap().pop().unwrap_or_else(|| {
.unwrap() incremental_pre_renderer(cfg.incremental.as_ref().unwrap())
.pop() });
.unwrap_or_else(|| incremental_pre_renderer(cfg.incremental.as_ref().unwrap()));
let (tx, rx) = tokio::sync::oneshot::channel(); let (tx, rx) = tokio::sync::oneshot::channel();
+7 -9
View File
@@ -122,16 +122,14 @@ fn load_index_html(path: PathBuf, root_id: &'static str) -> IndexHtml {
let (pre_main, post_main) = contents.split_once(&format!("id=\"{root_id}\"")).unwrap_or_else(|| panic!("Failed to find id=\"{root_id}\" in index.html. The id is used to inject the application into the page.")); let (pre_main, post_main) = contents.split_once(&format!("id=\"{root_id}\"")).unwrap_or_else(|| panic!("Failed to find id=\"{root_id}\" in index.html. The id is used to inject the application into the page."));
let post_main = let post_main = post_main.split_once('>').unwrap_or_else(|| {
post_main.split_once('>').unwrap_or_else( panic!("Failed to find closing > after id=\"{root_id}\" in index.html.")
|| panic!("Failed to find closing > after id=\"{root_id}\" in index.html.") });
);
let (pre_main, post_main) = let (pre_main, post_main) = (
( pre_main.to_string() + &format!("id=\"{root_id}\"") + post_main.0 + ">",
pre_main.to_string() + &format!("id=\"{root_id}\"") + post_main.0 + ">", post_main.1.to_string(),
post_main.1.to_string(), );
);
IndexHtml { IndexHtml {
pre_main, pre_main,
+9 -9
View File
@@ -22,9 +22,9 @@ impl Default for DioxusServerContext {
fn default() -> Self { fn default() -> Self {
Self { Self {
shared_context: std::sync::Arc::new(std::sync::RwLock::new(anymap::Map::new())), shared_context: std::sync::Arc::new(std::sync::RwLock::new(anymap::Map::new())),
response_parts: std::sync::Arc::new( response_parts: std::sync::Arc::new(RwLock::new(
RwLock::new(http::response::Response::new(()).into_parts().0) http::response::Response::new(()).into_parts().0,
), )),
parts: std::sync::Arc::new(RwLock::new(http::request::Request::new(()).into_parts().0)), parts: std::sync::Arc::new(RwLock::new(http::request::Request::new(()).into_parts().0)),
html_data: Arc::new(RwLock::new(HTMLData::default())), html_data: Arc::new(RwLock::new(HTMLData::default())),
} }
@@ -45,9 +45,9 @@ mod server_fn_impl {
Self { Self {
parts: parts.into(), parts: parts.into(),
shared_context: Arc::new(RwLock::new(SendSyncAnyMap::new())), shared_context: Arc::new(RwLock::new(SendSyncAnyMap::new())),
response_parts: std::sync::Arc::new( response_parts: std::sync::Arc::new(RwLock::new(
RwLock::new(http::response::Response::new(()).into_parts().0) http::response::Response::new(()).into_parts().0,
), )),
html_data: Arc::new(RwLock::new(HTMLData::default())), html_data: Arc::new(RwLock::new(HTMLData::default())),
} }
} }
@@ -221,9 +221,9 @@ impl<T: Send + Sync + Clone + 'static> FromServerContext for FromContext<T> {
type Rejection = NotFoundInServerContext<T>; type Rejection = NotFoundInServerContext<T>;
async fn from_request(req: &DioxusServerContext) -> Result<Self, Self::Rejection> { async fn from_request(req: &DioxusServerContext) -> Result<Self, Self::Rejection> {
Ok(Self(req.clone().get::<T>().ok_or_else( Ok(Self(req.clone().get::<T>().ok_or_else(|| {
|| NotFoundInServerContext::<T>(std::marker::PhantomData::<T>) NotFoundInServerContext::<T>(std::marker::PhantomData::<T>)
)?)) })?))
} }
} }
+5 -6
View File
@@ -129,12 +129,11 @@ mod tests {
use futures_util::StreamExt; use futures_util::StreamExt;
fn app(cx: Scope, name: String) -> Element { fn app(cx: Scope, name: String) -> Element {
let task = let task = use_coroutine(cx, |mut rx: UnboundedReceiver<i32>| async move {
use_coroutine(cx, |mut rx: UnboundedReceiver<i32>| async move { while let Some(msg) = rx.next().await {
while let Some(msg) = rx.next().await { println!("got message: {msg}");
println!("got message: {msg}"); }
} });
});
let task2 = use_coroutine(cx, view_task); let task2 = use_coroutine(cx, view_task);
+18 -25
View File
@@ -226,12 +226,10 @@ impl<T> UseSharedState<T> {
pub fn read(&self) -> Ref<'_, T> { pub fn read(&self) -> Ref<'_, T> {
match self.try_read() { match self.try_read() {
Ok(value) => value, Ok(value) => value,
Err(message) => { Err(message) => panic!(
panic!( "Reading the shared state failed: {}\n({:?})",
"Reading the shared state failed: {}\n({:?})", message, message
message, message ),
)
}
} }
} }
@@ -260,12 +258,10 @@ impl<T> UseSharedState<T> {
pub fn write(&self) -> RefMut<'_, T> { pub fn write(&self) -> RefMut<'_, T> {
match self.try_write() { match self.try_write() {
Ok(value) => value, Ok(value) => value,
Err(message) => { Err(message) => panic!(
panic!( "Writing to shared state failed: {}\n({:?})",
"Writing to shared state failed: {}\n({:?})", message, message
message, message ),
)
}
} }
} }
@@ -288,12 +284,10 @@ impl<T> UseSharedState<T> {
pub fn write_silent(&self) -> RefMut<'_, T> { pub fn write_silent(&self) -> RefMut<'_, T> {
match self.try_write_silent() { match self.try_write_silent() {
Ok(value) => value, Ok(value) => value,
Err(message) => { Err(message) => panic!(
panic!( "Writing to shared state silently failed: {}\n({:?})",
"Writing to shared state silently failed: {}\n({:?})", message, message
message, message ),
)
}
} }
} }
@@ -369,13 +363,12 @@ impl<T> PartialEq for UseSharedState<T> {
/// ``` /// ```
pub fn use_shared_state_provider<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) { pub fn use_shared_state_provider<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) {
cx.use_hook(|| { cx.use_hook(|| {
let state: ProvidedState<T> = let state: ProvidedState<T> = Rc::new(RefCell::new(ProvidedStateInner {
Rc::new(RefCell::new(ProvidedStateInner { value: f(),
value: f(), notify_any: cx.schedule_update_any(),
notify_any: cx.schedule_update_any(), consumers: HashSet::new(),
consumers: HashSet::new(), gen: 0,
gen: 0, }));
}));
cx.provide_context(state); cx.provide_context(state);
}); });
+24 -25
View File
@@ -35,37 +35,36 @@ pub fn use_state<T: 'static>(
cx: &ScopeState, cx: &ScopeState,
initial_state_fn: impl FnOnce() -> T, initial_state_fn: impl FnOnce() -> T,
) -> &UseState<T> { ) -> &UseState<T> {
let hook = let hook = cx.use_hook(move || {
cx.use_hook(move || { let current_val = Rc::new(initial_state_fn());
let current_val = Rc::new(initial_state_fn()); let update_callback = cx.schedule_update();
let update_callback = cx.schedule_update(); let slot = Rc::new(RefCell::new(current_val.clone()));
let slot = Rc::new(RefCell::new(current_val.clone())); let setter = Rc::new({
let setter = Rc::new({ to_owned![update_callback, slot];
to_owned![update_callback, slot]; move |new| {
move |new| { {
{ let mut slot = slot.borrow_mut();
let mut slot = slot.borrow_mut();
// if there's only one reference (weak or otherwise), we can just swap the values // if there's only one reference (weak or otherwise), we can just swap the values
// Typically happens when the state is set multiple times - we don't want to create a new Rc for each new value // Typically happens when the state is set multiple times - we don't want to create a new Rc for each new value
if let Some(val) = Rc::get_mut(&mut slot) { if let Some(val) = Rc::get_mut(&mut slot) {
*val = new; *val = new;
} else { } else {
*slot = Rc::new(new); *slot = Rc::new(new);
}
} }
update_callback();
} }
}); update_callback();
UseState {
current_val,
update_callback,
setter,
slot,
} }
}); });
UseState {
current_val,
update_callback,
setter,
slot,
}
});
hook.current_val = hook.slot.borrow().clone(); hook.current_val = hook.slot.borrow().clone();
hook hook
+3 -3
View File
@@ -37,9 +37,9 @@ async fn main() {
.route( .route(
"/", "/",
get(move || async move { get(move || async move {
index_page_with_glue( index_page_with_glue(&dioxus_liveview::interpreter_glue(&format!(
&dioxus_liveview::interpreter_glue(&format!("ws://{addr}/ws")) "ws://{addr}/ws"
) )))
}), }),
) )
.route( .route(
+7 -8
View File
@@ -112,14 +112,13 @@ impl<S> LiveViewSocket for S where
/// You might need to transform the error types of the web backend into the LiveView error type. /// You might need to transform the error types of the web backend into the LiveView error type.
pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), LiveViewError> { pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), LiveViewError> {
#[cfg(all(feature = "hot-reload", debug_assertions))] #[cfg(all(feature = "hot-reload", debug_assertions))]
let mut hot_reload_rx = let mut hot_reload_rx = {
{ let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); dioxus_hot_reload::connect(move |template| {
dioxus_hot_reload::connect(move |template| { let _ = tx.send(template);
let _ = tx.send(template); });
}); rx
rx };
};
// Create the a proxy for query engine // Create the a proxy for query engine
let (query_tx, mut query_rx) = tokio::sync::mpsc::unbounded_channel(); let (query_tx, mut query_rx) = tokio::sync::mpsc::unbounded_channel();
+41 -50
View File
@@ -66,13 +66,12 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream {
Some(tuple) => { Some(tuple) => {
let mut parent_dependencies = Vec::new(); let mut parent_dependencies = Vec::new();
for type_ in &tuple.elems { for type_ in &tuple.elems {
let mut type_ = let mut type_ = extract_type_path(type_).unwrap_or_else(|| {
extract_type_path(type_).unwrap_or_else(|| { panic!(
panic!( "ParentDependencies must be a tuple of type paths, found {}",
"ParentDependencies must be a tuple of type paths, found {}", quote!(#type_)
quote!(#type_) )
) });
});
if type_ == self_path { if type_ == self_path {
type_ = this_type.clone(); type_ = this_type.clone();
} }
@@ -81,24 +80,21 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream {
} }
parent_dependencies parent_dependencies
} }
_ => { _ => panic!(
panic!( "ParentDependencies must be a tuple, found {}",
"ParentDependencies must be a tuple, found {}", quote!(#parent_dependencies)
quote!(#parent_dependencies) ),
)
}
}; };
let child_dependencies = match extract_tuple(child_dependencies) { let child_dependencies = match extract_tuple(child_dependencies) {
Some(tuple) => { Some(tuple) => {
let mut child_dependencies = Vec::new(); let mut child_dependencies = Vec::new();
for type_ in &tuple.elems { for type_ in &tuple.elems {
let mut type_ = let mut type_ = extract_type_path(type_).unwrap_or_else(|| {
extract_type_path(type_).unwrap_or_else(|| { panic!(
panic!( "ChildDependencies must be a tuple of type paths, found {}",
"ChildDependencies must be a tuple of type paths, found {}", quote!(#type_)
quote!(#type_) )
) });
});
if type_ == self_path { if type_ == self_path {
type_ = this_type.clone(); type_ = this_type.clone();
} }
@@ -107,39 +103,34 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream {
} }
child_dependencies child_dependencies
} }
_ => { _ => panic!(
panic!( "ChildDependencies must be a tuple, found {}",
"ChildDependencies must be a tuple, found {}", quote!(#child_dependencies)
quote!(#child_dependencies) ),
)
}
}; };
let node_dependencies = let node_dependencies = match extract_tuple(node_dependencies) {
match extract_tuple(node_dependencies) { Some(tuple) => {
Some(tuple) => { let mut node_dependencies = Vec::new();
let mut node_dependencies = Vec::new(); for type_ in &tuple.elems {
for type_ in &tuple.elems { let mut type_ = extract_type_path(type_).unwrap_or_else(|| {
let mut type_ = extract_type_path(type_).unwrap_or_else(|| { panic!(
panic!( "NodeDependencies must be a tuple of type paths, found {}",
"NodeDependencies must be a tuple of type paths, found {}", quote!(#type_)
quote!(#type_) )
) });
}); if type_ == self_path {
if type_ == self_path { type_ = this_type.clone();
type_ = this_type.clone();
}
combined_dependencies.insert(type_.clone());
node_dependencies.push(type_);
} }
node_dependencies combined_dependencies.insert(type_.clone());
node_dependencies.push(type_);
} }
_ => { node_dependencies
panic!( }
"NodeDependencies must be a tuple, found {}", _ => panic!(
quote!(#node_dependencies) "NodeDependencies must be a tuple, found {}",
) quote!(#node_dependencies)
} ),
}; };
combined_dependencies.insert(this_type.clone()); combined_dependencies.insert(this_type.clone());
let combined_dependencies: Vec<_> = combined_dependencies.into_iter().collect(); let combined_dependencies: Vec<_> = combined_dependencies.into_iter().collect();
+6 -7
View File
@@ -160,13 +160,12 @@ impl State<X> for Border {
_context: &SendAnyMap, _context: &SendAnyMap,
) -> bool { ) -> bool {
// check if the node contians a border attribute // check if the node contians a border attribute
let new = let new = Self(
Self( node_view
node_view .attributes()
.attributes() .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border"))
.and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) .is_some(),
.is_some(), );
);
// check if the member has changed // check if the member has changed
let changed = new != *self; let changed = new != *self;
*self = new; *self = new;
+6 -7
View File
@@ -151,13 +151,12 @@ impl State for Border {
_context: &SendAnyMap, _context: &SendAnyMap,
) -> bool { ) -> bool {
// check if the node contians a border attribute // check if the node contians a border attribute
let new = let new = Self(
Self( node_view
node_view .attributes()
.attributes() .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border"))
.and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) .is_some(),
.is_some(), );
);
// check if the member has changed // check if the member has changed
let changed = new != *self; let changed = new != *self;
*self = new; *self = new;
@@ -152,13 +152,12 @@ impl State for Border {
_context: &SendAnyMap, _context: &SendAnyMap,
) -> bool { ) -> bool {
// check if the node contians a border attribute // check if the node contians a border attribute
let new = let new = Self(
Self( node_view
node_view .attributes()
.attributes() .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border"))
.and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) .is_some(),
.is_some(), );
);
// check if the member has changed // check if the member has changed
let changed = new != *self; let changed = new != *self;
*self = new; *self = new;
+24 -27
View File
@@ -340,27 +340,26 @@ pub fn apply_layout_attributes_cfg(
} }
Property::JustifyContent(justify, _) => { Property::JustifyContent(justify, _) => {
use AlignContent::*; use AlignContent::*;
style.justify_content = style.justify_content = match justify {
match justify { align::JustifyContent::ContentDistribution(distribution) => {
align::JustifyContent::ContentDistribution(distribution) => { match distribution {
match distribution { align::ContentDistribution::SpaceBetween => Some(SpaceBetween),
align::ContentDistribution::SpaceBetween => Some(SpaceBetween), align::ContentDistribution::SpaceAround => Some(SpaceAround),
align::ContentDistribution::SpaceAround => Some(SpaceAround), align::ContentDistribution::SpaceEvenly => Some(SpaceEvenly),
align::ContentDistribution::SpaceEvenly => Some(SpaceEvenly), _ => return,
_ => return,
}
} }
align::JustifyContent::ContentPosition { }
value: position, .. align::JustifyContent::ContentPosition {
} => match position { value: position, ..
align::ContentPosition::Center => Some(Center), } => match position {
align::ContentPosition::Start => Some(Start), align::ContentPosition::Center => Some(Center),
align::ContentPosition::FlexStart => Some(FlexStart), align::ContentPosition::Start => Some(Start),
align::ContentPosition::End => Some(End), align::ContentPosition::FlexStart => Some(FlexStart),
align::ContentPosition::FlexEnd => Some(FlexEnd), align::ContentPosition::End => Some(End),
}, align::ContentPosition::FlexEnd => Some(FlexEnd),
_ => return, },
}; _ => return,
};
} }
Property::AlignSelf(align, _) => { Property::AlignSelf(align, _) => {
use AlignItems::*; use AlignItems::*;
@@ -586,13 +585,11 @@ fn convert_grid_track_size(input: grid::TrackSize) -> NonRepeatedTrackSizingFunc
convert_track_breadth_min(&min), convert_track_breadth_min(&min),
convert_track_breadth_max(&max), convert_track_breadth_max(&max),
), ),
grid::TrackSize::FitContent(limit) => { grid::TrackSize::FitContent(limit) => match limit {
match limit { DimensionPercentage::Dimension(LengthValue::Px(len)) => minmax(auto(), points(len)),
DimensionPercentage::Dimension(LengthValue::Px(len)) => minmax(auto(), points(len)), DimensionPercentage::Percentage(Percentage(pct)) => minmax(auto(), percent(pct)),
DimensionPercentage::Percentage(Percentage(pct)) => minmax(auto(), percent(pct)), _ => unimplemented!(),
_ => unimplemented!(), },
}
}
} }
} }
@@ -488,5 +488,8 @@ fn persist_instertions_after() {
)); ));
let text = "hello world".to_string(); let text = "hello world".to_string();
let idx = iter.next(&rdom).id(); let idx = iter.next(&rdom).id();
assert!(matches!(&*rdom.get(idx).unwrap().node_type(), NodeType::Text(text))); assert!(matches!(
&*rdom.get(idx).unwrap().node_type(),
NodeType::Text(text)
));
} }
+29 -33
View File
@@ -9,7 +9,9 @@ fn random_ns() -> Option<&'static str> {
let namespace = rand::random::<u8>() % 2; let namespace = rand::random::<u8>() % 2;
match namespace { match namespace {
0 => None, 0 => None,
1 => Some(Box::leak(format!("ns{}", rand::random::<usize>()).into_boxed_str())), 1 => Some(Box::leak(
format!("ns{}", rand::random::<usize>()).into_boxed_str(),
)),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -21,15 +23,13 @@ fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute<'static> {
value: Box::leak(format!("value{}", rand::random::<usize>()).into_boxed_str()), value: Box::leak(format!("value{}", rand::random::<usize>()).into_boxed_str()),
namespace: random_ns(), namespace: random_ns(),
}, },
1 => { 1 => TemplateAttribute::Dynamic {
TemplateAttribute::Dynamic { id: {
id: { let old_idx = *attr_idx;
let old_idx = *attr_idx; *attr_idx += 1;
*attr_idx += 1; old_idx
old_idx },
}, },
}
}
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -74,26 +74,22 @@ fn create_random_template_node(
1 => TemplateNode::Text { 1 => TemplateNode::Text {
text: Box::leak(format!("{}", rand::random::<usize>()).into_boxed_str()), text: Box::leak(format!("{}", rand::random::<usize>()).into_boxed_str()),
}, },
2 => { 2 => TemplateNode::DynamicText {
TemplateNode::DynamicText { id: {
id: { let old_idx = *template_idx;
let old_idx = *template_idx; *template_idx += 1;
*template_idx += 1; dynamic_node_types.push(DynamicNodeType::Text);
dynamic_node_types.push(DynamicNodeType::Text); old_idx
old_idx },
}, },
} 3 => TemplateNode::Dynamic {
} id: {
3 => { let old_idx = *template_idx;
TemplateNode::Dynamic { *template_idx += 1;
id: { dynamic_node_types.push(DynamicNodeType::Other);
let old_idx = *template_idx; old_idx
*template_idx += 1; },
dynamic_node_types.push(DynamicNodeType::Other); },
old_idx
},
}
}
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -210,9 +206,9 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode {
fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute { fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute {
let value = match rand::random::<u8>() % 6 { let value = match rand::random::<u8>() % 6 {
0 => { 0 => AttributeValue::Text(Box::leak(
AttributeValue::Text(Box::leak(format!("{}", rand::random::<usize>()).into_boxed_str())) format!("{}", rand::random::<usize>()).into_boxed_str(),
} )),
1 => AttributeValue::Float(rand::random()), 1 => AttributeValue::Float(rand::random()),
2 => AttributeValue::Int(rand::random()), 2 => AttributeValue::Int(rand::random()),
3 => AttributeValue::Bool(rand::random()), 3 => AttributeValue::Bool(rand::random()),
+25 -26
View File
@@ -83,37 +83,36 @@ impl State for Focus {
_: &SendAnyMap, _: &SendAnyMap,
) -> bool { ) -> bool {
let new = Focus { let new = Focus {
level: level: if let Some(a) = node_view
if let Some(a) = node_view .attributes()
.attributes() .and_then(|mut a| a.find(|a| a.attribute.name == "tabindex"))
.and_then(|mut a| a.find(|a| a.attribute.name == "tabindex")) {
if let Some(index) = a
.value
.as_int()
.or_else(|| a.value.as_text().and_then(|v| v.parse::<i64>().ok()))
{ {
if let Some(index) = a match index.cmp(&0) {
.value Ordering::Less => FocusLevel::Unfocusable,
.as_int() Ordering::Equal => FocusLevel::Focusable,
.or_else(|| a.value.as_text().and_then(|v| v.parse::<i64>().ok())) Ordering::Greater => {
{ FocusLevel::Ordered(NonZeroU16::new(index as u16).unwrap())
match index.cmp(&0) {
Ordering::Less => FocusLevel::Unfocusable,
Ordering::Equal => FocusLevel::Focusable,
Ordering::Greater => {
FocusLevel::Ordered(NonZeroU16::new(index as u16).unwrap())
}
} }
} else {
FocusLevel::Unfocusable
} }
} else if node_view
.listeners()
.and_then(
|mut listeners| listeners.any(|l| FOCUS_EVENTS.contains(&l)).then_some(())
)
.is_some()
{
FocusLevel::Focusable
} else { } else {
FocusLevel::Unfocusable FocusLevel::Unfocusable
}, }
} else if node_view
.listeners()
.and_then(|mut listeners| {
listeners.any(|l| FOCUS_EVENTS.contains(&l)).then_some(())
})
.is_some()
{
FocusLevel::Focusable
} else {
FocusLevel::Unfocusable
},
}; };
if *self != new { if *self != new {
*self = new; *self = new;
+44 -46
View File
@@ -585,14 +585,13 @@ impl RinkInputHandler {
let queued_events = Rc::new(RefCell::new(Vec::new())); let queued_events = Rc::new(RefCell::new(Vec::new()));
let queued_events2 = Rc::downgrade(&queued_events); let queued_events2 = Rc::downgrade(&queued_events);
let regester_event = let regester_event = move |evt: crossterm::event::Event| {
move |evt: crossterm::event::Event| { if let Some(evt) = get_event(evt) {
if let Some(evt) = get_event(evt) { if let Some(v) = queued_events2.upgrade() {
if let Some(v) = queued_events2.upgrade() { (*v).borrow_mut().push(evt);
(*v).borrow_mut().push(evt);
}
} }
}; }
};
let state = Rc::new(RefCell::new(InnerInputState::create(rdom))); let state = Rc::new(RefCell::new(InnerInputState::create(rdom)));
@@ -681,49 +680,48 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> {
let ctrl = m.modifiers.contains(KeyModifiers::CONTROL); let ctrl = m.modifiers.contains(KeyModifiers::CONTROL);
let meta = false; let meta = false;
let get_mouse_data = let get_mouse_data = |crossterm_button: Option<MouseButton>| {
|crossterm_button: Option<MouseButton>| { let button = crossterm_button.map(|b| match b {
let button = crossterm_button.map(|b| match b { MouseButton::Left => DioxusMouseButton::Primary,
MouseButton::Left => DioxusMouseButton::Primary, MouseButton::Right => DioxusMouseButton::Secondary,
MouseButton::Right => DioxusMouseButton::Secondary, MouseButton::Middle => DioxusMouseButton::Auxiliary,
MouseButton::Middle => DioxusMouseButton::Auxiliary, });
});
// from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent // from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
// The `page` and `screen` coordinates are inconsistent with the MDN definition, as they are relative to the viewport (client), not the target element/page/screen, respectively. // The `page` and `screen` coordinates are inconsistent with the MDN definition, as they are relative to the viewport (client), not the target element/page/screen, respectively.
// todo? // todo?
// But then, MDN defines them in terms of pixels, yet crossterm provides only row/column, and it might not be possible to get pixels. So we can't get 100% consistency anyway. // But then, MDN defines them in terms of pixels, yet crossterm provides only row/column, and it might not be possible to get pixels. So we can't get 100% consistency anyway.
let coordinates = Coordinates::new( let coordinates = Coordinates::new(
ScreenPoint::new(x, y), ScreenPoint::new(x, y),
ClientPoint::new(x, y), ClientPoint::new(x, y),
// offset x/y are set when the origin of the event is assigned to an element // offset x/y are set when the origin of the event is assigned to an element
ElementPoint::new(0., 0.), ElementPoint::new(0., 0.),
PagePoint::new(x, y), PagePoint::new(x, y),
); );
let mut modifiers = Modifiers::empty(); let mut modifiers = Modifiers::empty();
if shift { if shift {
modifiers.insert(Modifiers::SHIFT); modifiers.insert(Modifiers::SHIFT);
} }
if ctrl { if ctrl {
modifiers.insert(Modifiers::CONTROL); modifiers.insert(Modifiers::CONTROL);
} }
if meta { if meta {
modifiers.insert(Modifiers::META); modifiers.insert(Modifiers::META);
} }
if alt { if alt {
modifiers.insert(Modifiers::ALT); modifiers.insert(Modifiers::ALT);
} }
// held mouse buttons get set later by maintaining state, as crossterm does not provide them // held mouse buttons get set later by maintaining state, as crossterm does not provide them
EventData::Mouse(MouseData::new( EventData::Mouse(MouseData::new(
coordinates, coordinates,
button, button,
DioxusMouseButtons::empty(), DioxusMouseButtons::empty(),
modifiers, modifiers,
)) ))
}; };
let get_wheel_data = |up| { let get_wheel_data = |up| {
let y = if up { -1.0 } else { 1.0 }; let y = if up { -1.0 } else { 1.0 };
+5 -6
View File
@@ -195,12 +195,11 @@ impl State for TaffyLayout {
taffy.set_children(n, &child_layout).unwrap(); taffy.set_children(n, &child_layout).unwrap();
} }
} else { } else {
self.node = self.node = PossiblyUninitalized::Initialized(
PossiblyUninitalized::Initialized( taffy
taffy .new_with_children(scaled_style, &child_layout)
.new_with_children(scaled_style, &child_layout) .unwrap(),
.unwrap(), );
);
changed = true; changed = true;
} }
} }
+21 -22
View File
@@ -43,28 +43,27 @@ impl State for PreventDefault {
_: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>, _: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
_: &SendAnyMap, _: &SendAnyMap,
) -> bool { ) -> bool {
let new = let new = match node_view.attributes().and_then(|mut attrs| {
match node_view.attributes().and_then(|mut attrs| { attrs
attrs .find(|a| a.attribute.name == "dioxus-prevent-default")
.find(|a| a.attribute.name == "dioxus-prevent-default") .and_then(|a| a.value.as_text())
.and_then(|a| a.value.as_text()) }) {
}) { Some("onfocus") => PreventDefault::Focus,
Some("onfocus") => PreventDefault::Focus, Some("onkeypress") => PreventDefault::KeyPress,
Some("onkeypress") => PreventDefault::KeyPress, Some("onkeyrelease") => PreventDefault::KeyRelease,
Some("onkeyrelease") => PreventDefault::KeyRelease, Some("onkeydown") => PreventDefault::KeyDown,
Some("onkeydown") => PreventDefault::KeyDown, Some("onkeyup") => PreventDefault::KeyUp,
Some("onkeyup") => PreventDefault::KeyUp, Some("onclick") => PreventDefault::Click,
Some("onclick") => PreventDefault::Click, Some("onmousedown") => PreventDefault::MouseDown,
Some("onmousedown") => PreventDefault::MouseDown, Some("onmouseup") => PreventDefault::MouseUp,
Some("onmouseup") => PreventDefault::MouseUp, Some("onmouseenter") => PreventDefault::MouseEnter,
Some("onmouseenter") => PreventDefault::MouseEnter, Some("onmouseover") => PreventDefault::MouseOver,
Some("onmouseover") => PreventDefault::MouseOver, Some("onmouseleave") => PreventDefault::MouseLeave,
Some("onmouseleave") => PreventDefault::MouseLeave, Some("onmouseout") => PreventDefault::MouseOut,
Some("onmouseout") => PreventDefault::MouseOut, Some("onwheel") => PreventDefault::Wheel,
Some("onwheel") => PreventDefault::Wheel, Some("oncontextmenu") => PreventDefault::ContextMenu,
Some("oncontextmenu") => PreventDefault::ContextMenu, _ => return false,
_ => return false, };
};
if new == *self { if new == *self {
false false
} else { } else {
+16 -18
View File
@@ -350,26 +350,24 @@ pub fn convert(mode: RenderingMode, c: Color) -> Color {
let rgb = to_rgb(c); let rgb = to_rgb(c);
Color::Rgb(rgb[0], rgb[1], rgb[2]) Color::Rgb(rgb[0], rgb[1], rgb[2])
} }
crate::RenderingMode::Ansi => { crate::RenderingMode::Ansi => match c {
match c { Color::Indexed(_) => c,
Color::Indexed(_) => c, _ => {
_ => { let rgb = to_rgb(c);
let rgb = to_rgb(c); // 16-231: 6 × 6 × 6 color cube
// 16-231: 6 × 6 × 6 color cube // 232-255: 23 step grayscale
// 232-255: 23 step grayscale if rgb[0] == rgb[1] && rgb[1] == rgb[2] {
if rgb[0] == rgb[1] && rgb[1] == rgb[2] { let idx = 232 + (rgb[0] as u16 * 23 / 255) as u8;
let idx = 232 + (rgb[0] as u16 * 23 / 255) as u8; Color::Indexed(idx)
Color::Indexed(idx) } else {
} else { let r = (rgb[0] as u16 * 5) / 255;
let r = (rgb[0] as u16 * 5) / 255; let g = (rgb[1] as u16 * 5) / 255;
let g = (rgb[1] as u16 * 5) / 255; let b = (rgb[2] as u16 * 5) / 255;
let b = (rgb[2] as u16 * 5) / 255; let idx = 16 + r * 36 + g * 6 + b;
let idx = 16 + r * 36 + g * 6 + b; Color::Indexed(idx as u8)
Color::Indexed(idx as u8)
}
} }
} }
} },
} }
} }
} }
+5 -6
View File
@@ -90,12 +90,11 @@ impl Button {
} }
fn switch(&mut self, ctx: &WidgetContext, node: NodeMut) { fn switch(&mut self, ctx: &WidgetContext, node: NodeMut) {
let data = let data = FormData {
FormData { value: self.value.to_string(),
value: self.value.to_string(), values: HashMap::new(),
values: HashMap::new(), files: None,
files: None, };
};
ctx.send(crate::Event { ctx.send(crate::Event {
id: node.id(), id: node.id(),
name: "input", name: "input",
+13 -16
View File
@@ -236,11 +236,10 @@ impl Slider {
let id = root.id(); let id = root.id();
let rdom = root.real_dom_mut(); let rdom = root.real_dom_mut();
let world = rdom.raw_world_mut(); let world = rdom.raw_world_mut();
let taffy = let taffy = {
{ let query: UniqueView<Query> = world.borrow().unwrap();
let query: UniqueView<Query> = world.borrow().unwrap(); query.stretch.clone()
query.stretch.clone() };
};
let taffy = taffy.lock().unwrap(); let taffy = taffy.lock().unwrap();
@@ -268,11 +267,10 @@ impl CustomElement for Slider {
panic!("input must be an element") panic!("input must be an element")
}; };
let value = let value = el.attributes.get(&OwnedAttributeDiscription {
el.attributes.get(&OwnedAttributeDiscription { name: "value".to_string(),
name: "value".to_string(), namespace: None,
namespace: None, });
});
let value = value let value = value
.and_then(|value| match value { .and_then(|value| match value {
OwnedAttributeValue::Text(text) => text.as_str().parse().ok(), OwnedAttributeValue::Text(text) => text.as_str().parse().ok(),
@@ -303,12 +301,11 @@ impl CustomElement for Slider {
let cursor_text = rdom.create_node("|".to_string()); let cursor_text = rdom.create_node("|".to_string());
let cursor_text_id = cursor_text.id(); let cursor_text_id = cursor_text.id();
let mut cursor_span = let mut cursor_span = rdom.create_node(NodeType::Element(ElementNode {
rdom.create_node(NodeType::Element(ElementNode { tag: "div".to_string(),
tag: "div".to_string(), attributes: [].into_iter().collect(),
attributes: [].into_iter().collect(), ..Default::default()
..Default::default() }));
}));
cursor_span.add_child(cursor_text_id); cursor_span.add_child(cursor_text_id);
let cursor_span_id = cursor_span.id(); let cursor_span_id = cursor_span.id();
+11 -13
View File
@@ -144,14 +144,13 @@ impl Route {
_ => Vec::new(), _ => Vec::new(),
}; };
let (route_segments, query) = let (route_segments, query) = {
{ parse_route_segments(
parse_route_segments( variant.ident.span(),
variant.ident.span(), fields.iter().map(|f| (&f.0, &f.1)),
fields.iter().map(|f| (&f.0, &f.1)), &route,
&route, )?
)? };
};
Ok(Self { Ok(Self {
ty, ty,
@@ -324,11 +323,10 @@ impl Route {
pub fn error_type(&self) -> TokenStream2 { pub fn error_type(&self) -> TokenStream2 {
let error_name = self.error_ident(); let error_name = self.error_ident();
let child_type = let child_type = match &self.ty {
match &self.ty { RouteType::Child(field) => Some(&field.ty),
RouteType::Child(field) => Some(&field.ty), RouteType::Leaf { .. } => None,
RouteType::Leaf { .. } => None, };
};
create_error_type(error_name, &self.segments, child_type) create_error_type(error_name, &self.segments, child_type)
} }
+17 -20
View File
@@ -135,11 +135,10 @@ pub fn parse_route_segments<'a>(
) -> syn::Result<(Vec<RouteSegment>, Option<QuerySegment>)> { ) -> syn::Result<(Vec<RouteSegment>, Option<QuerySegment>)> {
let mut route_segments = Vec::new(); let mut route_segments = Vec::new();
let (route_string, query) = let (route_string, query) = match route.rsplit_once('?') {
match route.rsplit_once('?') { Some((route, query)) => (route, Some(query)),
Some((route, query)) => (route, Some(query)), None => (route, None),
None => (route, None), };
};
let mut iterator = route_string.split('/'); let mut iterator = route_string.split('/');
// skip the first empty segment // skip the first empty segment
@@ -158,12 +157,11 @@ pub fn parse_route_segments<'a>(
if let Some(segment) = segment.strip_prefix(':') { if let Some(segment) = segment.strip_prefix(':') {
let spread = segment.starts_with(".."); let spread = segment.starts_with("..");
let ident = let ident = if spread {
if spread { segment[2..].to_string()
segment[2..].to_string() } else {
} else { segment.to_string()
segment.to_string() };
};
let field = fields.find(|(name, _)| **name == ident); let field = fields.find(|(name, _)| **name == ident);
@@ -207,15 +205,14 @@ pub fn parse_route_segments<'a>(
let query_ident = Ident::new(query, Span::call_site()); let query_ident = Ident::new(query, Span::call_site());
let field = fields.find(|(name, _)| *name == &query_ident); let field = fields.find(|(name, _)| *name == &query_ident);
let ty = let ty = if let Some((_, ty)) = field {
if let Some((_, ty)) = field { ty.clone()
ty.clone() } else {
} else { return Err(syn::Error::new(
return Err(syn::Error::new( route_span,
route_span, format!("Could not find a field with the name '{}'", query_ident),
format!("Could not find a field with the name '{}'", query_ident), ));
)); };
};
Some(QuerySegment { Some(QuerySegment {
ident: query_ident, ident: query_ident,
+11 -12
View File
@@ -77,18 +77,17 @@ where
self.routes.retain(|&lhs, _| lhs <= last_visited); self.routes.retain(|&lhs, _| lhs <= last_visited);
} }
}; };
let state = let state = match state {
match state { Some(state) => {
Some(state) => { self.current_index = state.index;
self.current_index = state.index; state
state }
} None => {
None => { let index = depth - 1;
let index = depth - 1; self.current_index = index;
self.current_index = index; State { index }
State { index } }
} };
};
self.routes.insert(state.index, route); self.routes.insert(state.index, route);
state state
} }
+16 -18
View File
@@ -302,16 +302,15 @@ where
let s = self.listener_animation_frame.clone(); let s = self.listener_animation_frame.clone();
let d = self.do_scroll_restoration; let d = self.do_scroll_restoration;
self.listener_navigation = self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| {
Some(EventListener::new(&self.window, "popstate", move |_| { (*callback)();
(*callback)(); if d {
if d { let mut s = s.lock().expect("unpoisoned scroll mutex");
let mut s = s.lock().expect("unpoisoned scroll mutex"); if let Some(current_state) = get_current::<WebHistoryState<R>>(&h) {
if let Some(current_state) = get_current::<WebHistoryState<R>>(&h) { *s = Some(current_state.scroll.scroll_to(w.clone()));
*s = Some(current_state.scroll.scroll_to(w.clone()));
}
} }
})); }
}));
} }
} }
@@ -378,15 +377,14 @@ where
let s = self.listener_animation_frame.clone(); let s = self.listener_animation_frame.clone();
let d = self.do_scroll_restoration; let d = self.do_scroll_restoration;
self.listener_navigation = self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| {
Some(EventListener::new(&self.window, "popstate", move |_| { (*callback)();
(*callback)(); if d {
if d { let mut s = s.lock().expect("unpoisoned scroll mutex");
let mut s = s.lock().expect("unpoisoned scroll mutex"); if let Some([x, y]) = get_current(&h) {
if let Some([x, y]) = get_current(&h) { *s = Some(ScrollPosition { x, y }.scroll_to(w.clone()));
*s = Some(ScrollPosition { x, y }.scroll_to(w.clone()));
}
} }
})); }
}));
} }
} }
+5 -3
View File
@@ -114,9 +114,11 @@ impl<R: Routable> FromStr for NavigationTarget<R> {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
match Url::parse(s) { match Url::parse(s) {
Ok(_) => Ok(Self::External(s.to_string())), Ok(_) => Ok(Self::External(s.to_string())),
Err(ParseError::RelativeUrlWithoutBase) => Ok(Self::Internal( Err(ParseError::RelativeUrlWithoutBase) => {
R::from_str(s).map_err(|e| NavigationTargetParseError::InvalidInternalURL(e))?, Ok(Self::Internal(R::from_str(s).map_err(|e| {
)), NavigationTargetParseError::InvalidInternalURL(e)
})?))
}
Err(e) => Err(NavigationTargetParseError::InvalidUrl(e)), Err(e) => Err(NavigationTargetParseError::InvalidUrl(e)),
} }
} }
+5 -6
View File
@@ -134,12 +134,11 @@ impl<I: std::iter::FromIterator<String>> FromRouteSegments for I {
/// A flattened version of [`Routable::SITE_MAP`]. /// A flattened version of [`Routable::SITE_MAP`].
/// This essentially represents a `Vec<Vec<SegmentType>>`, which you can collect it into. /// This essentially represents a `Vec<Vec<SegmentType>>`, which you can collect it into.
type SiteMapFlattened<'a> = type SiteMapFlattened<'a> = FlatMap<
FlatMap< Iter<'a, SiteMapSegment>,
Iter<'a, SiteMapSegment>, Vec<Vec<SegmentType>>,
Vec<Vec<SegmentType>>, fn(&SiteMapSegment) -> Vec<Vec<SegmentType>>,
fn(&SiteMapSegment) -> Vec<Vec<SegmentType>>, >;
>;
fn seg_strs_to_route<T>(segs_maybe: &Option<Vec<&str>>) -> Option<T> fn seg_strs_to_route<T>(segs_maybe: &Option<Vec<&str>>) -> Option<T>
where where
@@ -11,15 +11,14 @@ use crate::prelude::*;
/// - [`None`], when the current component isn't a descendant of a [`Link`] component. /// - [`None`], when the current component isn't a descendant of a [`Link`] component.
/// - Otherwise [`Some`]. /// - Otherwise [`Some`].
pub(crate) fn use_router_internal(cx: &ScopeState) -> &Option<RouterContext> { pub(crate) fn use_router_internal(cx: &ScopeState) -> &Option<RouterContext> {
let inner = let inner = cx.use_hook(|| {
cx.use_hook(|| { let router = cx.consume_context::<RouterContext>()?;
let router = cx.consume_context::<RouterContext>()?;
let id = cx.scope_id(); let id = cx.scope_id();
router.subscribe(id); router.subscribe(id);
Some(Subscription { router, id }) Some(Subscription { router, id })
}); });
cx.use_hook(|| inner.as_ref().map(|s| s.router.clone())) cx.use_hook(|| inner.as_ref().map(|s| s.router.clone()))
} }
+2 -3
View File
@@ -36,8 +36,7 @@ fn simple_elements() {
#[test] #[test]
fn deeply_nested() { fn deeply_nested() {
let html = let html = r#"
r#"
<div> <div>
<div class="asd"> <div class="asd">
<div class="asd"> <div class="asd">
@@ -49,7 +48,7 @@ fn deeply_nested() {
</div> </div>
</div> </div>
"# "#
.trim(); .trim();
let dom = Dom::parse(html).unwrap(); let dom = Dom::parse(html).unwrap();
+8 -10
View File
@@ -162,11 +162,10 @@ impl ToTokens for Component {
} }
if !self.children.is_empty() { if !self.children.is_empty() {
let renderer: TemplateRenderer = let renderer: TemplateRenderer = TemplateRenderer {
TemplateRenderer { roots: &self.children,
roots: &self.children, location: None,
location: None, };
};
toks.append_all(quote! { toks.append_all(quote! {
.children( .children(
@@ -184,11 +183,10 @@ impl ToTokens for Component {
let fn_name = self.name.segments.last().unwrap().ident.to_string(); let fn_name = self.name.segments.last().unwrap().ident.to_string();
let gen_name = let gen_name = match &self.prop_gen_args {
match &self.prop_gen_args { Some(gen) => quote! { #name #gen },
Some(gen) => quote! { #name #gen }, None => quote! { #name },
None => quote! { #name }, };
};
tokens.append_all(quote! { tokens.append_all(quote! {
__cx.component( __cx.component(
+48 -49
View File
@@ -332,60 +332,59 @@ impl ToTokens for ElementAttrNamed {
} }
}; };
let attribute = let attribute = match attr {
match attr { ElementAttr::AttrText { name, value } => {
ElementAttr::AttrText { name, value } => { let ns = ns(name);
let ns = ns(name); let volitile = volitile(name);
let volitile = volitile(name); let attribute = attribute(name);
let attribute = attribute(name); quote! {
quote! { __cx.attr(
__cx.attr( #attribute,
#attribute, #value,
#value, #ns,
#ns, #volitile
#volitile )
)
}
} }
ElementAttr::AttrExpression { name, value } => { }
let ns = ns(name); ElementAttr::AttrExpression { name, value } => {
let volitile = volitile(name); let ns = ns(name);
let attribute = attribute(name); let volitile = volitile(name);
quote! { let attribute = attribute(name);
__cx.attr( quote! {
#attribute, __cx.attr(
#value, #attribute,
#ns, #value,
#volitile #ns,
) #volitile
} )
} }
ElementAttr::CustomAttrText { name, value } => { }
quote! { ElementAttr::CustomAttrText { name, value } => {
__cx.attr( quote! {
#name, __cx.attr(
#value, #name,
None, #value,
false None,
) false
} )
} }
ElementAttr::CustomAttrExpression { name, value } => { }
quote! { ElementAttr::CustomAttrExpression { name, value } => {
__cx.attr( quote! {
#name, __cx.attr(
#value, #name,
None, #value,
false None,
) false
} )
} }
ElementAttr::EventTokens { name, tokens } => { }
quote! { ElementAttr::EventTokens { name, tokens } => {
dioxus_elements::events::#name(__cx, #tokens) quote! {
} dioxus_elements::events::#name(__cx, #tokens)
} }
}; }
};
tokens.append_all(attribute); tokens.append_all(attribute);
} }
@@ -77,12 +77,11 @@ impl<Ctx: HotReloadingContext> FileMap<Ctx> {
} }
let FileMapSearchResult { map, errors } = find_rs_files(path, &mut filter)?; let FileMapSearchResult { map, errors } = find_rs_files(path, &mut filter)?;
let result = let result = Self {
Self { map,
map, in_workspace: HashMap::new(),
in_workspace: HashMap::new(), phantom: std::marker::PhantomData,
phantom: std::marker::PhantomData, };
};
Ok(FileMapBuildResult { Ok(FileMapBuildResult {
map: result, map: result,
errors, errors,
+19 -16
View File
@@ -99,9 +99,10 @@ impl FromStr for IfmtInput {
current_literal.push(c); current_literal.push(c);
continue; continue;
} else { } else {
return Err( return Err(Error::new(
Error::new(Span::call_site(), "unmatched closing '}' in format string") Span::call_site(),
); "unmatched closing '}' in format string",
));
} }
} }
current_literal.push(c); current_literal.push(c);
@@ -146,18 +147,17 @@ impl ToTokens for IfmtInput {
} }
} }
let positional_args = let positional_args = self.segments.iter().filter_map(|seg| {
self.segments.iter().filter_map(|seg| { if let Segment::Formatted(FormattedSegment {
if let Segment::Formatted(FormattedSegment { segment: FormattedSegmentType::Expr(expr),
segment: FormattedSegmentType::Expr(expr), ..
.. }) = seg
}) = seg {
{ Some(expr)
Some(expr) } else {
} else { None
None }
} });
});
// remove duplicate idents // remove duplicate idents
let named_args_idents: HashSet<_> = self let named_args_idents: HashSet<_> = self
@@ -228,7 +228,10 @@ impl FormattedSegmentType {
if let Ok(expr) = parse_str(input) { if let Ok(expr) = parse_str(input) {
Ok(Self::Expr(Box::new(expr))) Ok(Self::Expr(Box::new(expr)))
} else { } else {
Err(Error::new(Span::call_site(), "Expected Ident or Expression")) Err(Error::new(
Span::call_site(),
"Expected Ident or Expression",
))
} }
} }
} }
+10 -12
View File
@@ -199,11 +199,10 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
_ => None, _ => None,
}; };
let key_tokens = let key_tokens = match key {
match key { Some(tok) => quote! { Some( __cx.raw_text(#tok) ) },
Some(tok) => quote! { Some( __cx.raw_text(#tok) ) }, None => quote! { None },
None => quote! { None }, };
};
let spndbg = format!("{:?}", self.roots[0].span()); let spndbg = format!("{:?}", self.roots[0].span());
let root_col = spndbg let root_col = spndbg
@@ -519,13 +518,12 @@ impl<'a> DynamicContext<'a> {
let attrs = quote! { #(#static_attrs),*}; let attrs = quote! { #(#static_attrs),*};
let children = let children = el.children.iter().enumerate().map(|(idx, root)| {
el.children.iter().enumerate().map(|(idx, root)| { self.current_path.push(idx as u8);
self.current_path.push(idx as u8); let out = self.render_static_node(root);
let out = self.render_static_node(root); self.current_path.pop();
self.current_path.pop(); out
out });
});
let _opt = el.children.len() == 1; let _opt = el.children.len() == 1;
let children = quote! { #(#children),* }; let children = quote! { #(#children),* };
+4 -5
View File
@@ -65,11 +65,10 @@ use syn::{
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream { pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
// before we pass this off to the server function macro, we apply extractors and middleware // before we pass this off to the server function macro, we apply extractors and middleware
let mut function: syn::ItemFn = let mut function: syn::ItemFn = match syn::parse(s).map_err(|e| e.to_compile_error()) {
match syn::parse(s).map_err(|e| e.to_compile_error()) { Ok(f) => f,
Ok(f) => f, Err(e) => return e.into(),
Err(e) => return e.into(), };
};
// extract all #[middleware] attributes // extract all #[middleware] attributes
let mut middlewares: Vec<Middleware> = vec![]; let mut middlewares: Vec<Middleware> = vec![];
+5 -6
View File
@@ -87,12 +87,11 @@ impl Effect {
/// ///
/// The signal will be owned by the current component and will be dropped when the component is dropped. /// The signal will be owned by the current component and will be dropped when the component is dropped.
pub fn new(callback: impl FnMut() + 'static) -> Self { pub fn new(callback: impl FnMut() + 'static) -> Self {
let myself = let myself = Self {
Self { source: current_scope_id().expect("in a virtual dom"),
source: current_scope_id().expect("in a virtual dom"), callback: CopyValue::new(Box::new(callback)),
callback: CopyValue::new(Box::new(callback)), effect_stack: get_effect_stack(),
effect_stack: get_effect_stack(), };
};
myself.try_run(); myself.try_run();
+3 -4
View File
@@ -72,10 +72,9 @@ where
/// ///
/// Selectors can be used to efficiently compute derived data from signals. /// Selectors can be used to efficiently compute derived data from signals.
pub fn selector<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> ReadOnlySignal<R> { pub fn selector<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> ReadOnlySignal<R> {
let state = let state = Signal::<R> {
Signal::<R> { inner: CopyValue::invalid(),
inner: CopyValue::invalid(), };
};
let effect = Effect { let effect = Effect {
source: current_scope_id().expect("in a virtual dom"), source: current_scope_id().expect("in a virtual dom"),
callback: CopyValue::invalid(), callback: CopyValue::invalid(),
+20 -23
View File
@@ -6,14 +6,13 @@ use dioxus_signals::*;
#[test] #[test]
fn create_signals_global() { fn create_signals_global() {
let mut dom = let mut dom = VirtualDom::new(|cx| {
VirtualDom::new(|cx| { render! {
render! { for _ in 0..10 {
for _ in 0..10 { Child {}
Child {}
}
} }
}); }
});
fn Child(cx: Scope) -> Element { fn Child(cx: Scope) -> Element {
let signal = create_without_cx(); let signal = create_without_cx();
@@ -32,14 +31,13 @@ fn create_signals_global() {
#[test] #[test]
fn deref_signal() { fn deref_signal() {
let mut dom = let mut dom = VirtualDom::new(|cx| {
VirtualDom::new(|cx| { render! {
render! { for _ in 0..10 {
for _ in 0..10 { Child {}
Child {}
}
} }
}); }
});
fn Child(cx: Scope) -> Element { fn Child(cx: Scope) -> Element {
let signal = Signal::new("hello world".to_string()); let signal = Signal::new("hello world".to_string());
@@ -57,17 +55,16 @@ fn deref_signal() {
#[test] #[test]
fn drop_signals() { fn drop_signals() {
let mut dom = let mut dom = VirtualDom::new(|cx| {
VirtualDom::new(|cx| { let generation = cx.generation();
let generation = cx.generation();
let count = if generation % 2 == 0 { 10 } else { 0 }; let count = if generation % 2 == 0 { 10 } else { 0 };
render! { render! {
for _ in 0..count { for _ in 0..count {
Child {} Child {}
}
} }
}); }
});
fn Child(cx: Scope) -> Element { fn Child(cx: Scope) -> Element {
let signal = create_without_cx(); let signal = create_without_cx();
+8 -9
View File
@@ -100,15 +100,14 @@ fn memos_prevents_component_rerun() {
let signal = cx.props.signal; let signal = cx.props.signal;
counter.borrow_mut().component += 1; counter.borrow_mut().component += 1;
let memo = let memo = cx.use_hook(move || {
cx.use_hook(move || { to_owned![counter];
to_owned![counter]; selector(move || {
selector(move || { counter.borrow_mut().effect += 1;
counter.borrow_mut().effect += 1; println!("Signal: {:?}", signal);
println!("Signal: {:?}", signal); signal.value()
signal.value() })
}) });
});
match cx.generation() { match cx.generation() {
0 => { 0 => {
assert_eq!(memo.value(), 0); assert_eq!(memo.value(), 0);
+300 -301
View File
@@ -1,301 +1,300 @@
pub static BUILTIN_INTERNED_STRINGS: &[&str] = pub static BUILTIN_INTERNED_STRINGS: &[&str] = &[
&[ // Important tags to dioxus
// Important tags to dioxus "dioxus-id",
"dioxus-id", "dioxus",
"dioxus", "dioxus-event-click", // todo: more events
"dioxus-event-click", // todo: more events "click",
"click", // All the HTML Tags
// All the HTML Tags "a",
"a", "abbr",
"abbr", "address",
"address", "area",
"area", "article",
"article", "aside",
"aside", "audio",
"audio", "b",
"b", "base",
"base", "bdi",
"bdi", "bdo",
"bdo", "big",
"big", "blockquote",
"blockquote", "body",
"body", "br",
"br", "button",
"button", "canvas",
"canvas", "caption",
"caption", "cite",
"cite", "code",
"code", "col",
"col", "colgroup",
"colgroup", "command",
"command", "data",
"data", "datalist",
"datalist", "dd",
"dd", "del",
"del", "details",
"details", "dfn",
"dfn", "dialog",
"dialog", "div",
"div", "dl",
"dl", "dt",
"dt", "em",
"em", "embed",
"embed", "fieldset",
"fieldset", "figcaption",
"figcaption", "figure",
"figure", "footer",
"footer", "form",
"form", "h1",
"h1", "h2",
"h2", "h3",
"h3", "h4",
"h4", "h5",
"h5", "h6",
"h6", "head",
"head", "header",
"header", "hr",
"hr", "html",
"html", "i",
"i", "iframe",
"iframe", "img",
"img", "input",
"input", "ins",
"ins", "kbd",
"kbd", "keygen",
"keygen", "label",
"label", "legend",
"legend", "li",
"li", "link",
"link", "main",
"main", "map",
"map", "mark",
"mark", "menu",
"menu", "menuitem",
"menuitem", "meta",
"meta", "meter",
"meter", "nav",
"nav", "noscript",
"noscript", "object",
"object", "ol",
"ol", "optgroup",
"optgroup", "option",
"option", "output",
"output", "p",
"p", "param",
"param", "picture",
"picture", "pre",
"pre", "progress",
"progress", "q",
"q", "rp",
"rp", "rt",
"rt", "ruby",
"ruby", "s",
"s", "samp",
"samp", "script",
"script", "section",
"section", "select",
"select", "small",
"small", "source",
"source", "span",
"span", "strong",
"strong", "style",
"style", "sub",
"sub", "summary",
"summary", "sup",
"sup", "table",
"table", "tbody",
"tbody", "td",
"td", "textarea",
"textarea", "tfoot",
"tfoot", "th",
"th", "thead",
"thead", "time",
"time", "title",
"title", "tr",
"tr", "track",
"track", "u",
"u", "ul",
"ul", "var",
"var", "video",
"video", "wbr",
"wbr", // All the event handlers
// All the event handlers "Attribute",
"Attribute", "accept",
"accept", "accept-charset",
"accept-charset", "accesskey",
"accesskey", "action",
"action", "alt",
"alt", "async",
"async", "autocomplete",
"autocomplete", "autofocus",
"autofocus", "autoplay",
"autoplay", "charset",
"charset", "checked",
"checked", "cite",
"cite", "class",
"class", "cols",
"cols", "colspan",
"colspan", "content",
"content", "contenteditable",
"contenteditable", "controls",
"controls", "coords",
"coords", "data",
"data", "data-*",
"data-*", "datetime",
"datetime", "default",
"default", "defer",
"defer", "dir",
"dir", "dirname",
"dirname", "disabled",
"disabled", "download",
"download", "draggable",
"draggable", "enctype",
"enctype", "for",
"for", "form",
"form", "formaction",
"formaction", "headers",
"headers", "height",
"height", "hidden",
"hidden", "high",
"high", "href",
"href", "hreflang",
"hreflang", "http-equiv",
"http-equiv", "id",
"id", "ismap",
"ismap", "kind",
"kind", "label",
"label", "lang",
"lang", "list",
"list", "loop",
"loop", "low",
"low", "max",
"max", "maxlength",
"maxlength", "media",
"media", "method",
"method", "min",
"min", "multiple",
"multiple", "muted",
"muted", "name",
"name", "novalidate",
"novalidate", "onabort",
"onabort", "onafterprint",
"onafterprint", "onbeforeprint",
"onbeforeprint", "onbeforeunload",
"onbeforeunload", "onblur",
"onblur", "oncanplay",
"oncanplay", "oncanplaythrough",
"oncanplaythrough", "onchange",
"onchange", "onclick",
"onclick", "oncontextmenu",
"oncontextmenu", "oncopy",
"oncopy", "oncuechange",
"oncuechange", "oncut",
"oncut", "ondblclick",
"ondblclick", "ondrag",
"ondrag", "ondragend",
"ondragend", "ondragenter",
"ondragenter", "ondragleave",
"ondragleave", "ondragover",
"ondragover", "ondragstart",
"ondragstart", "ondrop",
"ondrop", "ondurationchange",
"ondurationchange", "onemptied",
"onemptied", "onended",
"onended", "onerror",
"onerror", "onfocus",
"onfocus", "onfocusout",
"onfocusout", "onfocusin",
"onfocusin", "onhashchange",
"onhashchange", "oninput",
"oninput", "oninvalid",
"oninvalid", "onkeydown",
"onkeydown", "onkeypress",
"onkeypress", "onkeyup",
"onkeyup", "onload",
"onload", "onloadeddata",
"onloadeddata", "onloadedmetadata",
"onloadedmetadata", "onloadstart",
"onloadstart", "onmousedown",
"onmousedown", "onmousemove",
"onmousemove", "onmouseout",
"onmouseout", "onmouseover",
"onmouseover", "onmouseup",
"onmouseup", "onmousewheel",
"onmousewheel", "onoffline",
"onoffline", "ononline",
"ononline", "onpageshow",
"onpageshow", "onpaste",
"onpaste", "onpause",
"onpause", "onplay",
"onplay", "onplaying",
"onplaying", "onprogress",
"onprogress", "onratechange",
"onratechange", "onreset",
"onreset", "onresize",
"onresize", "onscroll",
"onscroll", "onsearch",
"onsearch", "onseeked",
"onseeked", "onseeking",
"onseeking", "onselect",
"onselect", "onstalled",
"onstalled", "onsubmit",
"onsubmit", "onsuspend",
"onsuspend", "ontimeupdate",
"ontimeupdate", "ontoggle",
"ontoggle", "onunload",
"onunload", "onvolumechange",
"onvolumechange", "onwaiting",
"onwaiting", "onwheel",
"onwheel", "open",
"open", "optimum",
"optimum", "pattern",
"pattern", "placeholder",
"placeholder", "poster",
"poster", "preload",
"preload", "readonly",
"readonly", "rel",
"rel", "required",
"required", "reversed",
"reversed", "rows",
"rows", "rowspan",
"rowspan", "sandbox",
"sandbox", "scope",
"scope", "selected",
"selected", "shape",
"shape", "size",
"size", "sizes",
"sizes", "span",
"span", "spellcheck",
"spellcheck", "src",
"src", "srcdoc",
"srcdoc", "srclang",
"srclang", "srcset",
"srcset", "start",
"start", "step",
"step", "style",
"style", "tabindex",
"tabindex", "target",
"target", "title",
"title", "translate",
"translate", "type",
"type", "usemap",
"usemap", "value",
"value", "width",
"width", "wrap",
"wrap", "0",
"0", "1",
"1", "2",
"2", "3",
"3", "4",
"4", "5",
"5", "6",
"6", "7",
"7", "8",
"8", "9",
"9", "10",
"10", "11",
"11", "12",
"12", "13",
"13", "14",
"14", ];
];
+6 -7
View File
@@ -80,13 +80,12 @@ impl WebsysDom {
} }
let data = virtual_event_from_websys_event(event.clone(), target); let data = virtual_event_from_websys_event(event.clone(), target);
let _ = let _ = event_channel.unbounded_send(UiEvent {
event_channel.unbounded_send(UiEvent { name,
name, bubbles,
bubbles, element,
element, data,
data, });
});
} }
} }
})); }));
+12 -6
View File
@@ -62,18 +62,24 @@ impl WebEvaluator {
if let Ok(stringified) = js_sys::JSON::stringify(&result) { if let Ok(stringified) = js_sys::JSON::stringify(&result) {
if !stringified.is_undefined() && stringified.is_valid_utf16() { if !stringified.is_undefined() && stringified.is_valid_utf16() {
let string: String = stringified.into(); let string: String = stringified.into();
Value::from_str(&string).map_err( Value::from_str(&string).map_err(|e| {
|e| EvalError::Communication(format!("Failed to parse result - {}", e)) EvalError::Communication(format!("Failed to parse result - {}", e))
)? })?
} else { } else {
return Err(EvalError::Communication("Failed to stringify result".into())); return Err(EvalError::Communication(
"Failed to stringify result".into(),
));
} }
} else { } else {
return Err(EvalError::Communication("Failed to stringify result".into())); return Err(EvalError::Communication(
"Failed to stringify result".into(),
));
} }
} }
Err(err) => { Err(err) => {
return Err(EvalError::InvalidJs(err.as_string().unwrap_or("unknown".to_string()))); return Err(EvalError::InvalidJs(
err.as_string().unwrap_or("unknown".to_string()),
));
} }
}; };