mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-26 22:20:19 +00:00
fix desktop hot reloading
This commit is contained in:
parent
0c5025ffa0
commit
2c1c147828
15 changed files with 130 additions and 115 deletions
|
@ -48,7 +48,7 @@ fn BlogList(cx: Scope) -> Element {
|
||||||
|
|
||||||
fn BlogPost(cx: Scope) -> Element {
|
fn BlogPost(cx: Scope) -> Element {
|
||||||
let Some(id) = use_route(cx).segment("id") else {
|
let Some(id) = use_route(cx).segment("id") else {
|
||||||
return cx.render(rsx! { div { "No blog post id" } })
|
return cx.render(rsx! { div { "No blog post id" } });
|
||||||
};
|
};
|
||||||
|
|
||||||
log::debug!("rendering blog post {}", id);
|
log::debug!("rendering blog post {}", id);
|
||||||
|
|
|
@ -364,6 +364,7 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result<BuildResul
|
||||||
.display()
|
.display()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
println!("build desktop done");
|
||||||
|
|
||||||
Ok(BuildResult {
|
Ok(BuildResult {
|
||||||
warnings: vec![],
|
warnings: vec![],
|
||||||
|
|
|
@ -57,21 +57,7 @@ impl Serve {
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
cfg::Platform::Desktop => {
|
cfg::Platform::Desktop => {
|
||||||
crate::builder::build_desktop(&crate_config, true)?;
|
server::desktop::startup(crate_config.clone()).await?;
|
||||||
|
|
||||||
match &crate_config.executable {
|
|
||||||
crate::ExecutableType::Binary(name)
|
|
||||||
| crate::ExecutableType::Lib(name)
|
|
||||||
| crate::ExecutableType::Example(name) => {
|
|
||||||
let mut file = crate_config.out_dir.join(name);
|
|
||||||
if cfg!(windows) {
|
|
||||||
file.set_extension("exe");
|
|
||||||
}
|
|
||||||
Command::new(file.to_str().unwrap())
|
|
||||||
.stdout(Stdio::inherit())
|
|
||||||
.output()?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
serve::Serve,
|
serve::Serve,
|
||||||
server::{
|
server::{
|
||||||
output::{print_console_info, PrettierOptions, WebServerInfo},
|
output::{print_console_info, PrettierOptions, WebServerInfo},
|
||||||
setup_file_watcher, setup_file_watcher_hot_reload, BuildManager,
|
setup_file_watcher, setup_file_watcher_hot_reload,
|
||||||
},
|
},
|
||||||
BuildResult, CrateConfig, Result,
|
BuildResult, CrateConfig, Result,
|
||||||
};
|
};
|
||||||
|
@ -72,7 +72,15 @@ pub async fn serve_default(config: CrateConfig) -> Result<()> {
|
||||||
|
|
||||||
// We got to own watcher so that it exists for the duration of serve
|
// We got to own watcher so that it exists for the duration of serve
|
||||||
// Otherwise full reload won't work.
|
// Otherwise full reload won't work.
|
||||||
let _watcher = setup_file_watcher(crate::cfg::Platform::Desktop, &config, None, None).await?;
|
let _watcher = setup_file_watcher(
|
||||||
|
{
|
||||||
|
let config = config.clone();
|
||||||
|
move || start_desktop(&config)
|
||||||
|
},
|
||||||
|
&config,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Print serve info
|
// Print serve info
|
||||||
print_console_info(
|
print_console_info(
|
||||||
|
@ -107,15 +115,13 @@ pub async fn serve_hot_reload(config: CrateConfig) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_map = Arc::new(Mutex::new(map));
|
let file_map = Arc::new(Mutex::new(map));
|
||||||
let build_manager = Arc::new(BuildManager {
|
|
||||||
platform: crate::cfg::Platform::Web,
|
|
||||||
config: config.clone(),
|
|
||||||
reload_tx: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let (hot_reload_tx, mut hot_reload_rx) = broadcast::channel(100);
|
let (hot_reload_tx, mut hot_reload_rx) = broadcast::channel(100);
|
||||||
|
|
||||||
// States
|
// States
|
||||||
|
// The open interprocess sockets
|
||||||
|
let channels = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
|
||||||
// Setup file watcher
|
// Setup file watcher
|
||||||
// We got to own watcher so that it exists for the duration of serve
|
// We got to own watcher so that it exists for the duration of serve
|
||||||
// Otherwise hot reload won't work.
|
// Otherwise hot reload won't work.
|
||||||
|
@ -123,7 +129,17 @@ pub async fn serve_hot_reload(config: CrateConfig) -> Result<()> {
|
||||||
&config,
|
&config,
|
||||||
hot_reload_tx,
|
hot_reload_tx,
|
||||||
file_map.clone(),
|
file_map.clone(),
|
||||||
build_manager,
|
{
|
||||||
|
let config = config.clone();
|
||||||
|
|
||||||
|
let channels = channels.clone();
|
||||||
|
move || {
|
||||||
|
for channel in &mut *channels.lock().unwrap() {
|
||||||
|
send_msg(HotReloadMsg::Shutdown, channel);
|
||||||
|
}
|
||||||
|
start_desktop(&config)
|
||||||
|
}
|
||||||
|
},
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -153,8 +169,6 @@ pub async fn serve_hot_reload(config: CrateConfig) -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let channels = Arc::new(Mutex::new(Vec::new()));
|
|
||||||
|
|
||||||
match LocalSocketListener::bind("@dioxusin") {
|
match LocalSocketListener::bind("@dioxusin") {
|
||||||
Ok(local_socket_stream) => {
|
Ok(local_socket_stream) => {
|
||||||
let aborted = Arc::new(Mutex::new(false));
|
let aborted = Arc::new(Mutex::new(false));
|
||||||
|
@ -196,10 +210,6 @@ pub async fn serve_hot_reload(config: CrateConfig) -> Result<()> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// for channel in &mut *channels.lock().unwrap() {
|
|
||||||
// send_msg(HotReloadMsg::Shutdown, channel);
|
|
||||||
// }
|
|
||||||
|
|
||||||
while let Ok(template) = hot_reload_rx.recv().await {
|
while let Ok(template) = hot_reload_rx.recv().await {
|
||||||
let channels = &mut *channels.lock().unwrap();
|
let channels = &mut *channels.lock().unwrap();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
|
@ -39,18 +39,11 @@ pub mod desktop;
|
||||||
pub mod web;
|
pub mod web;
|
||||||
|
|
||||||
/// Sets up a file watcher
|
/// Sets up a file watcher
|
||||||
async fn setup_file_watcher(
|
async fn setup_file_watcher<F: Fn() -> Result<BuildResult> + Send + 'static>(
|
||||||
platform: Platform,
|
build_with: F,
|
||||||
config: &CrateConfig,
|
config: &CrateConfig,
|
||||||
reload_tx: Option<Sender<()>>,
|
|
||||||
web_info: Option<WebServerInfo>,
|
web_info: Option<WebServerInfo>,
|
||||||
) -> Result<RecommendedWatcher> {
|
) -> Result<RecommendedWatcher> {
|
||||||
let build_manager = BuildManager {
|
|
||||||
platform,
|
|
||||||
config: config.clone(),
|
|
||||||
reload_tx,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut last_update_time = chrono::Local::now().timestamp();
|
let mut last_update_time = chrono::Local::now().timestamp();
|
||||||
|
|
||||||
// file watcher: check file change
|
// file watcher: check file change
|
||||||
|
@ -67,7 +60,7 @@ async fn setup_file_watcher(
|
||||||
let config = watcher_config.clone();
|
let config = watcher_config.clone();
|
||||||
if let Ok(e) = info {
|
if let Ok(e) = info {
|
||||||
if chrono::Local::now().timestamp() > last_update_time {
|
if chrono::Local::now().timestamp() > last_update_time {
|
||||||
match build_manager.rebuild() {
|
match build_with() {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
last_update_time = chrono::Local::now().timestamp();
|
last_update_time = chrono::Local::now().timestamp();
|
||||||
|
|
||||||
|
@ -108,11 +101,11 @@ async fn setup_file_watcher(
|
||||||
|
|
||||||
// Todo: reduce duplication and merge with setup_file_watcher()
|
// Todo: reduce duplication and merge with setup_file_watcher()
|
||||||
/// Sets up a file watcher with hot reload
|
/// Sets up a file watcher with hot reload
|
||||||
async fn setup_file_watcher_hot_reload(
|
async fn setup_file_watcher_hot_reload<F: Fn() -> Result<BuildResult> + Send + 'static>(
|
||||||
config: &CrateConfig,
|
config: &CrateConfig,
|
||||||
hot_reload_tx: Sender<Template<'static>>,
|
hot_reload_tx: Sender<Template<'static>>,
|
||||||
file_map: Arc<Mutex<FileMap<HtmlCtx>>>,
|
file_map: Arc<Mutex<FileMap<HtmlCtx>>>,
|
||||||
build_manager: Arc<BuildManager>,
|
build_with: F,
|
||||||
web_info: Option<WebServerInfo>,
|
web_info: Option<WebServerInfo>,
|
||||||
) -> Result<RecommendedWatcher> {
|
) -> Result<RecommendedWatcher> {
|
||||||
// file watcher: check file change
|
// file watcher: check file change
|
||||||
|
@ -138,7 +131,7 @@ async fn setup_file_watcher_hot_reload(
|
||||||
for path in evt.paths.clone() {
|
for path in evt.paths.clone() {
|
||||||
// if this is not a rust file, rebuild the whole project
|
// if this is not a rust file, rebuild the whole project
|
||||||
if path.extension().and_then(|p| p.to_str()) != Some("rs") {
|
if path.extension().and_then(|p| p.to_str()) != Some("rs") {
|
||||||
match build_manager.rebuild() {
|
match build_with() {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
print_console_info(
|
print_console_info(
|
||||||
&config,
|
&config,
|
||||||
|
@ -164,7 +157,7 @@ async fn setup_file_watcher_hot_reload(
|
||||||
messages.extend(msgs);
|
messages.extend(msgs);
|
||||||
}
|
}
|
||||||
Ok(UpdateResult::NeedsRebuild) => {
|
Ok(UpdateResult::NeedsRebuild) => {
|
||||||
match build_manager.rebuild() {
|
match build_with() {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
print_console_info(
|
print_console_info(
|
||||||
&config,
|
&config,
|
||||||
|
@ -209,35 +202,3 @@ async fn setup_file_watcher_hot_reload(
|
||||||
|
|
||||||
Ok(watcher)
|
Ok(watcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BuildManager {
|
|
||||||
platform: Platform,
|
|
||||||
config: CrateConfig,
|
|
||||||
reload_tx: Option<broadcast::Sender<()>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BuildManager {
|
|
||||||
fn rebuild(&self) -> Result<BuildResult> {
|
|
||||||
log::info!("🪁 Rebuild project");
|
|
||||||
match self.platform {
|
|
||||||
Platform::Web => {
|
|
||||||
let result = builder::build(&self.config, true)?;
|
|
||||||
// change the websocket reload state to true;
|
|
||||||
// the page will auto-reload.
|
|
||||||
if self
|
|
||||||
.config
|
|
||||||
.dioxus_config
|
|
||||||
.web
|
|
||||||
.watcher
|
|
||||||
.reload_html
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
let _ = Serve::regen_dev_page(&self.config);
|
|
||||||
}
|
|
||||||
let _ = self.reload_tx.as_ref().map(|tx| tx.send(()));
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
Platform::Desktop => start_desktop(&self.config),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,12 +10,10 @@ use dioxus_html::HtmlCtx;
|
||||||
use dioxus_rsx::hot_reload::FileMap;
|
use dioxus_rsx::hot_reload::FileMap;
|
||||||
use tokio::sync::broadcast;
|
use tokio::sync::broadcast;
|
||||||
|
|
||||||
use super::BuildManager;
|
|
||||||
use crate::CrateConfig;
|
use crate::CrateConfig;
|
||||||
|
|
||||||
pub struct HotReloadState {
|
pub struct HotReloadState {
|
||||||
pub messages: broadcast::Sender<Template<'static>>,
|
pub messages: broadcast::Sender<Template<'static>>,
|
||||||
pub build_manager: Arc<BuildManager>,
|
|
||||||
pub file_map: Arc<Mutex<FileMap<HtmlCtx>>>,
|
pub file_map: Arc<Mutex<FileMap<HtmlCtx>>>,
|
||||||
pub watcher_config: CrateConfig,
|
pub watcher_config: CrateConfig,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
serve::Serve,
|
serve::Serve,
|
||||||
server::{
|
server::{
|
||||||
output::{print_console_info, PrettierOptions, WebServerInfo},
|
output::{print_console_info, PrettierOptions, WebServerInfo},
|
||||||
setup_file_watcher, setup_file_watcher_hot_reload, BuildManager,
|
setup_file_watcher, setup_file_watcher_hot_reload,
|
||||||
},
|
},
|
||||||
BuildResult, CrateConfig, Result,
|
BuildResult, CrateConfig, Result,
|
||||||
};
|
};
|
||||||
|
@ -86,9 +86,12 @@ pub async fn serve_default(
|
||||||
// We got to own watcher so that it exists for the duration of serve
|
// We got to own watcher so that it exists for the duration of serve
|
||||||
// Otherwise full reload won't work.
|
// Otherwise full reload won't work.
|
||||||
let _watcher = setup_file_watcher(
|
let _watcher = setup_file_watcher(
|
||||||
crate::cfg::Platform::Web,
|
{
|
||||||
|
let config = config.clone();
|
||||||
|
let reload_tx = reload_tx.clone();
|
||||||
|
move || build(&config, &reload_tx)
|
||||||
|
},
|
||||||
&config,
|
&config,
|
||||||
Some(reload_tx.clone()),
|
|
||||||
Some(WebServerInfo {
|
Some(WebServerInfo {
|
||||||
ip: ip.clone(),
|
ip: ip.clone(),
|
||||||
port,
|
port,
|
||||||
|
@ -148,18 +151,12 @@ pub async fn serve_hot_reload(
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_map = Arc::new(Mutex::new(map));
|
let file_map = Arc::new(Mutex::new(map));
|
||||||
let build_manager = Arc::new(BuildManager {
|
|
||||||
platform: crate::cfg::Platform::Web,
|
|
||||||
config: config.clone(),
|
|
||||||
reload_tx: Some(reload_tx.clone()),
|
|
||||||
});
|
|
||||||
|
|
||||||
let hot_reload_tx = broadcast::channel(100).0;
|
let hot_reload_tx = broadcast::channel(100).0;
|
||||||
|
|
||||||
// States
|
// States
|
||||||
let hot_reload_state = Arc::new(HotReloadState {
|
let hot_reload_state = Arc::new(HotReloadState {
|
||||||
messages: hot_reload_tx.clone(),
|
messages: hot_reload_tx.clone(),
|
||||||
build_manager: build_manager.clone(),
|
|
||||||
file_map: file_map.clone(),
|
file_map: file_map.clone(),
|
||||||
watcher_config: config.clone(),
|
watcher_config: config.clone(),
|
||||||
});
|
});
|
||||||
|
@ -175,7 +172,11 @@ pub async fn serve_hot_reload(
|
||||||
&config,
|
&config,
|
||||||
hot_reload_tx,
|
hot_reload_tx,
|
||||||
file_map,
|
file_map,
|
||||||
build_manager,
|
{
|
||||||
|
let config = config.clone();
|
||||||
|
let reload_tx = reload_tx.clone();
|
||||||
|
move || build(&config, &reload_tx)
|
||||||
|
},
|
||||||
Some(WebServerInfo {
|
Some(WebServerInfo {
|
||||||
ip: ip.clone(),
|
ip: ip.clone(),
|
||||||
port,
|
port,
|
||||||
|
@ -473,3 +474,20 @@ async fn ws_handler(
|
||||||
reload_watcher.await.unwrap();
|
reload_watcher.await.unwrap();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build(config: &CrateConfig, reload_tx: &Sender<()>) -> Result<BuildResult> {
|
||||||
|
let result = builder::build(&config, true)?;
|
||||||
|
// change the websocket reload state to true;
|
||||||
|
// the page will auto-reload.
|
||||||
|
if config
|
||||||
|
.dioxus_config
|
||||||
|
.web
|
||||||
|
.watcher
|
||||||
|
.reload_html
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
let _ = Serve::regen_dev_page(&config);
|
||||||
|
}
|
||||||
|
let _ = reload_tx.send(());
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
|
@ -378,7 +378,7 @@ impl ServerFnHandler {
|
||||||
.to_vec()
|
.to_vec()
|
||||||
.into();
|
.into();
|
||||||
let body = hyper::body::to_bytes(req.body_mut().unwrap()).await;
|
let body = hyper::body::to_bytes(req.body_mut().unwrap()).await;
|
||||||
let Ok(body)=body else {
|
let Ok(body) = body else {
|
||||||
handle_error(body.err().unwrap(), res);
|
handle_error(body.err().unwrap(), res);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
@ -56,10 +56,9 @@ where
|
||||||
{
|
{
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
let Ok(file_engine) =
|
let Ok(file_engine) = SerializedFileEngine::deserialize(deserializer) else {
|
||||||
SerializedFileEngine::deserialize(deserializer) else{
|
return Ok(None);
|
||||||
return Ok(None);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let file_engine = std::sync::Arc::new(file_engine);
|
let file_engine = std::sync::Arc::new(file_engine);
|
||||||
Ok(Some(file_engine))
|
Ok(Some(file_engine))
|
||||||
|
|
|
@ -82,7 +82,9 @@ impl Button {
|
||||||
fn write_value(&self, rdom: &mut RealDom) {
|
fn write_value(&self, rdom: &mut RealDom) {
|
||||||
if let Some(mut text) = rdom.get_mut(self.text_id) {
|
if let Some(mut text) = rdom.get_mut(self.text_id) {
|
||||||
let node_type = text.node_type_mut();
|
let node_type = text.node_type_mut();
|
||||||
let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Text(mut text) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
*text.text_mut() = self.value.clone();
|
*text.text_mut() = self.value.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +113,9 @@ impl CustomElement for Button {
|
||||||
|
|
||||||
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
||||||
let node_type = root.node_type();
|
let node_type = root.node_type();
|
||||||
let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
|
let NodeType::Element(el) = &*node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
|
|
||||||
let value = el
|
let value = el
|
||||||
.attributes
|
.attributes
|
||||||
|
@ -146,7 +150,9 @@ impl CustomElement for Button {
|
||||||
AttributeMask::All => {
|
AttributeMask::All => {
|
||||||
{
|
{
|
||||||
let node_type = root.node_type_mut();
|
let node_type = root.node_type_mut();
|
||||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Element(mut el) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
self.update_value_attr(&el);
|
self.update_value_attr(&el);
|
||||||
self.update_size_attr(&mut el);
|
self.update_size_attr(&mut el);
|
||||||
}
|
}
|
||||||
|
@ -155,7 +161,9 @@ impl CustomElement for Button {
|
||||||
AttributeMask::Some(attrs) => {
|
AttributeMask::Some(attrs) => {
|
||||||
{
|
{
|
||||||
let node_type = root.node_type_mut();
|
let node_type = root.node_type_mut();
|
||||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Element(mut el) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
if attrs.contains("width") || attrs.contains("height") {
|
if attrs.contains("width") || attrs.contains("height") {
|
||||||
self.update_size_attr(&mut el);
|
self.update_size_attr(&mut el);
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,14 +94,18 @@ impl CheckBox {
|
||||||
fn write_value(&self, mut root: NodeMut) {
|
fn write_value(&self, mut root: NodeMut) {
|
||||||
let single_char = {
|
let single_char = {
|
||||||
let node_type = root.node_type_mut();
|
let node_type = root.node_type_mut();
|
||||||
let NodeTypeMut::Element( el) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Element(el) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
Self::width(&el) == "1px" || Self::height(&el) == "1px"
|
Self::width(&el) == "1px" || Self::height(&el) == "1px"
|
||||||
};
|
};
|
||||||
let rdom = root.real_dom_mut();
|
let rdom = root.real_dom_mut();
|
||||||
|
|
||||||
if let Some(mut text) = rdom.get_mut(self.text_id) {
|
if let Some(mut text) = rdom.get_mut(self.text_id) {
|
||||||
let node_type = text.node_type_mut();
|
let node_type = text.node_type_mut();
|
||||||
let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Text(mut text) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
let value = if single_char {
|
let value = if single_char {
|
||||||
if self.checked {
|
if self.checked {
|
||||||
"☑"
|
"☑"
|
||||||
|
@ -156,7 +160,9 @@ impl CustomElement for CheckBox {
|
||||||
|
|
||||||
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
||||||
let node_type = root.node_type();
|
let node_type = root.node_type();
|
||||||
let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
|
let NodeType::Element(el) = &*node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
|
|
||||||
let value = el
|
let value = el
|
||||||
.attributes
|
.attributes
|
||||||
|
@ -197,7 +203,9 @@ impl CustomElement for CheckBox {
|
||||||
AttributeMask::All => {
|
AttributeMask::All => {
|
||||||
{
|
{
|
||||||
let node_type = root.node_type_mut();
|
let node_type = root.node_type_mut();
|
||||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Element(mut el) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
self.update_value_attr(&el);
|
self.update_value_attr(&el);
|
||||||
self.update_size_attr(&mut el);
|
self.update_size_attr(&mut el);
|
||||||
self.update_checked_attr(&el);
|
self.update_checked_attr(&el);
|
||||||
|
@ -207,7 +215,9 @@ impl CustomElement for CheckBox {
|
||||||
AttributeMask::Some(attrs) => {
|
AttributeMask::Some(attrs) => {
|
||||||
{
|
{
|
||||||
let node_type = root.node_type_mut();
|
let node_type = root.node_type_mut();
|
||||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Element(mut el) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
if attrs.contains("width") || attrs.contains("height") {
|
if attrs.contains("width") || attrs.contains("height") {
|
||||||
self.update_size_attr(&mut el);
|
self.update_size_attr(&mut el);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,9 @@ impl CustomElement for Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
let node_type = root.node_type();
|
let node_type = root.node_type();
|
||||||
let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
|
let NodeType::Element(el) = &*node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
let input_type = el
|
let input_type = el
|
||||||
.attributes
|
.attributes
|
||||||
.get(&OwnedAttributeDiscription {
|
.get(&OwnedAttributeDiscription {
|
||||||
|
|
|
@ -163,7 +163,9 @@ impl Slider {
|
||||||
|
|
||||||
if let Some(mut div) = rdom.get_mut(self.pre_cursor_div) {
|
if let Some(mut div) = rdom.get_mut(self.pre_cursor_div) {
|
||||||
let node_type = div.node_type_mut();
|
let node_type = div.node_type_mut();
|
||||||
let NodeTypeMut::Element(mut element) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Element(mut element) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
element.set_attribute(
|
element.set_attribute(
|
||||||
OwnedAttributeDiscription {
|
OwnedAttributeDiscription {
|
||||||
name: "width".to_string(),
|
name: "width".to_string(),
|
||||||
|
@ -175,7 +177,9 @@ impl Slider {
|
||||||
|
|
||||||
if let Some(mut div) = rdom.get_mut(self.post_cursor_div) {
|
if let Some(mut div) = rdom.get_mut(self.post_cursor_div) {
|
||||||
let node_type = div.node_type_mut();
|
let node_type = div.node_type_mut();
|
||||||
let NodeTypeMut::Element(mut element) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Element(mut element) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
element.set_attribute(
|
element.set_attribute(
|
||||||
OwnedAttributeDiscription {
|
OwnedAttributeDiscription {
|
||||||
name: "width".to_string(),
|
name: "width".to_string(),
|
||||||
|
@ -259,7 +263,9 @@ impl CustomElement for Slider {
|
||||||
|
|
||||||
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
||||||
let node_type = root.node_type();
|
let node_type = root.node_type();
|
||||||
let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
|
let NodeType::Element(el) = &*node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
|
|
||||||
let value = el.attributes.get(&OwnedAttributeDiscription {
|
let value = el.attributes.get(&OwnedAttributeDiscription {
|
||||||
name: "value".to_string(),
|
name: "value".to_string(),
|
||||||
|
@ -390,7 +396,9 @@ impl CustomElement for Slider {
|
||||||
AttributeMask::All => {
|
AttributeMask::All => {
|
||||||
{
|
{
|
||||||
let node_type = root.node_type_mut();
|
let node_type = root.node_type_mut();
|
||||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Element(mut el) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
self.update_value_attr(&el);
|
self.update_value_attr(&el);
|
||||||
self.update_size_attr(&mut el);
|
self.update_size_attr(&mut el);
|
||||||
self.update_max_attr(&el);
|
self.update_max_attr(&el);
|
||||||
|
@ -403,7 +411,9 @@ impl CustomElement for Slider {
|
||||||
AttributeMask::Some(attrs) => {
|
AttributeMask::Some(attrs) => {
|
||||||
{
|
{
|
||||||
let node_type = root.node_type_mut();
|
let node_type = root.node_type_mut();
|
||||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Element(mut el) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
if attrs.contains("width") || attrs.contains("height") {
|
if attrs.contains("width") || attrs.contains("height") {
|
||||||
self.update_size_attr(&mut el);
|
self.update_size_attr(&mut el);
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,19 +143,25 @@ impl<C: TextLikeController> TextLike<C> {
|
||||||
|
|
||||||
if let Some(mut text) = rdom.get_mut(self.pre_cursor_text) {
|
if let Some(mut text) = rdom.get_mut(self.pre_cursor_text) {
|
||||||
let node_type = text.node_type_mut();
|
let node_type = text.node_type_mut();
|
||||||
let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Text(mut text) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
*text.text_mut() = self.controller.display_text(text_before_first_cursor);
|
*text.text_mut() = self.controller.display_text(text_before_first_cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut text) = rdom.get_mut(self.highlighted_text) {
|
if let Some(mut text) = rdom.get_mut(self.highlighted_text) {
|
||||||
let node_type = text.node_type_mut();
|
let node_type = text.node_type_mut();
|
||||||
let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Text(mut text) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
*text.text_mut() = self.controller.display_text(text_highlighted);
|
*text.text_mut() = self.controller.display_text(text_highlighted);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut text) = rdom.get_mut(self.post_cursor_text) {
|
if let Some(mut text) = rdom.get_mut(self.post_cursor_text) {
|
||||||
let node_type = text.node_type_mut();
|
let node_type = text.node_type_mut();
|
||||||
let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Text(mut text) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
*text.text_mut() = self.controller.display_text(text_after_second_cursor);
|
*text.text_mut() = self.controller.display_text(text_after_second_cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +294,9 @@ impl<C: TextLikeController + Send + Sync + Default + 'static> CustomElement for
|
||||||
|
|
||||||
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
||||||
let node_type = root.node_type();
|
let node_type = root.node_type();
|
||||||
let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
|
let NodeType::Element(el) = &*node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
|
|
||||||
let value = el
|
let value = el
|
||||||
.attributes
|
.attributes
|
||||||
|
@ -370,7 +378,9 @@ impl<C: TextLikeController + Send + Sync + Default + 'static> CustomElement for
|
||||||
AttributeMask::All => {
|
AttributeMask::All => {
|
||||||
{
|
{
|
||||||
let node_type = root.node_type_mut();
|
let node_type = root.node_type_mut();
|
||||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Element(mut el) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
self.update_value_attr(&el);
|
self.update_value_attr(&el);
|
||||||
self.update_size_attr(&mut el);
|
self.update_size_attr(&mut el);
|
||||||
self.update_max_width_attr(&el);
|
self.update_max_width_attr(&el);
|
||||||
|
@ -381,7 +391,9 @@ impl<C: TextLikeController + Send + Sync + Default + 'static> CustomElement for
|
||||||
AttributeMask::Some(attrs) => {
|
AttributeMask::Some(attrs) => {
|
||||||
{
|
{
|
||||||
let node_type = root.node_type_mut();
|
let node_type = root.node_type_mut();
|
||||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
let NodeTypeMut::Element(mut el) = node_type else {
|
||||||
|
panic!("input must be an element")
|
||||||
|
};
|
||||||
if attrs.contains("width") || attrs.contains("height") {
|
if attrs.contains("width") || attrs.contains("height") {
|
||||||
self.update_size_attr(&mut el);
|
self.update_size_attr(&mut el);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ fn BlogList(cx: Scope) -> Element {
|
||||||
|
|
||||||
fn BlogPost(cx: Scope) -> Element {
|
fn BlogPost(cx: Scope) -> Element {
|
||||||
let Some(id) = use_route(cx).segment("id") else {
|
let Some(id) = use_route(cx).segment("id") else {
|
||||||
return cx.render(rsx! { div { "No blog post id" } })
|
return cx.render(rsx! { div { "No blog post id" } });
|
||||||
};
|
};
|
||||||
|
|
||||||
log::trace!("rendering blog post {}", id);
|
log::trace!("rendering blog post {}", id);
|
||||||
|
|
Loading…
Reference in a new issue