Revert "improved documentation and refactored naming to be more self-explanatory"
This reverts commit adfbb6c380.
This commit is contained in:
1 parent
adfbb6c380
commit
906c466e78
91 files changed
+1553
-1663
No files matched your search
@@ -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
@@ -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
@@ -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 {
|
||||||
|
|||||||
@@ -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
@@ -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!(
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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" }
|
||||||
|
|||||||
@@ -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" } }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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",
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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`
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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())
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)));
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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>)
|
||||||
)?))
|
})?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
@@ -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
@@ -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
@@ -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 };
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}));
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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),* };
|
||||||
|
|||||||
@@ -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![];
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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
@@ -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",
|
];
|
||||||
];
|
|
||||||
@@ -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,
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -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()),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user