mirror of
https://github.com/DioxusLabs/dioxus
synced 2025-02-17 06:08:26 +00:00
Merge branch 'DioxusLabs:master' into events-2
This commit is contained in:
commit
072ca3529b
25 changed files with 191 additions and 106 deletions
|
@ -22,7 +22,7 @@ serde = { version = "1.0.136", features = ["derive"] }
|
||||||
serde_json = "1.0.79"
|
serde_json = "1.0.79"
|
||||||
toml = "0.5.8"
|
toml = "0.5.8"
|
||||||
fs_extra = "1.2.0"
|
fs_extra = "1.2.0"
|
||||||
cargo_toml = "0.11.4"
|
cargo_toml = "0.16.0"
|
||||||
futures = "0.3.21"
|
futures = "0.3.21"
|
||||||
notify = { version = "5.0.0-pre.16", features = ["serde"] }
|
notify = { version = "5.0.0-pre.16", features = ["serde"] }
|
||||||
html_parser = { workspace = true }
|
html_parser = { workspace = true }
|
||||||
|
|
|
@ -132,10 +132,10 @@ impl Bundle {
|
||||||
.project_out_directory(crate_config.out_dir)
|
.project_out_directory(crate_config.out_dir)
|
||||||
.package_settings(PackageSettings {
|
.package_settings(PackageSettings {
|
||||||
product_name: crate_config.dioxus_config.application.name.clone(),
|
product_name: crate_config.dioxus_config.application.name.clone(),
|
||||||
version: package.version,
|
version: package.version().to_string(),
|
||||||
description: package.description.unwrap_or_default(),
|
description: package.description().unwrap_or_default().to_string(),
|
||||||
homepage: package.homepage,
|
homepage: Some(package.homepage().unwrap_or_default().to_string()),
|
||||||
authors: Some(package.authors),
|
authors: Some(Vec::from(package.authors())),
|
||||||
default_run: Some(crate_config.dioxus_config.application.name.clone()),
|
default_run: Some(crate_config.dioxus_config.application.name.clone()),
|
||||||
})
|
})
|
||||||
.binaries(binaries)
|
.binaries(binaries)
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub(crate) mod innerlude {
|
||||||
pub use crate::nodes::RenderReturn;
|
pub use crate::nodes::RenderReturn;
|
||||||
pub use crate::nodes::*;
|
pub use crate::nodes::*;
|
||||||
pub use crate::properties::*;
|
pub use crate::properties::*;
|
||||||
pub use crate::runtime::{in_runtime, override_runtime, Runtime};
|
pub use crate::runtime::{Runtime, RuntimeGuard};
|
||||||
pub use crate::scheduler::*;
|
pub use crate::scheduler::*;
|
||||||
pub use crate::scope_context::*;
|
pub use crate::scope_context::*;
|
||||||
pub use crate::scopes::*;
|
pub use crate::scopes::*;
|
||||||
|
@ -87,11 +87,11 @@ pub use crate::innerlude::{
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::innerlude::{
|
pub use crate::innerlude::{
|
||||||
consume_context, consume_context_from_scope, current_scope_id, fc_to_builder, has_context,
|
consume_context, consume_context_from_scope, current_scope_id, fc_to_builder, has_context,
|
||||||
in_runtime, override_runtime, provide_context, provide_context_to_scope,
|
provide_context, provide_context_to_scope, provide_root_context, push_future,
|
||||||
provide_root_context, push_future, remove_future, schedule_update_any, spawn,
|
remove_future, schedule_update_any, spawn, spawn_forever, suspend, throw, AnyValue,
|
||||||
spawn_forever, suspend, throw, AnyValue, Component, Element, Event, EventHandler, Fragment,
|
Component, Element, Event, EventHandler, Fragment, IntoAttributeValue, LazyNodes,
|
||||||
IntoAttributeValue, LazyNodes, Properties, Runtime, Scope, ScopeId, ScopeState, Scoped,
|
Properties, Runtime, RuntimeGuard, Scope, ScopeId, ScopeState, Scoped, TaskId, Template,
|
||||||
TaskId, Template, TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom,
|
TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,51 +7,6 @@ thread_local! {
|
||||||
static RUNTIMES: RefCell<Vec<Rc<Runtime>>> = RefCell::new(vec![]);
|
static RUNTIMES: RefCell<Vec<Rc<Runtime>>> = RefCell::new(vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run some code within a runtime
|
|
||||||
pub fn in_runtime<R>(runtime: Rc<Runtime>, f: impl FnOnce() -> R) -> R {
|
|
||||||
let _guard = RuntimeGuard::new(runtime);
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Override the current runtime. This must be used to override the current runtime when importing components from a dynamic library that has it's own runtime.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use dioxus::prelude::*;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let virtual_dom = VirtualDom::new(app);
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn app(cx: Scope) -> Element {
|
|
||||||
/// render!{ Component { runtime: Runtime::current().unwrap() } }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// // In a dynamic library
|
|
||||||
/// #[derive(Props)]
|
|
||||||
/// struct ComponentProps {
|
|
||||||
/// runtime: std::rc::Rc<Runtime>,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// impl PartialEq for ComponentProps {
|
|
||||||
/// fn eq(&self, _other: &Self) -> bool {
|
|
||||||
/// true
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn Component(cx: Scope<ComponentProps>) -> Element {
|
|
||||||
/// cx.use_hook(|| override_runtime(cx.props.runtime.clone()));
|
|
||||||
///
|
|
||||||
/// render! { div {} }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn override_runtime(runtime: Rc<Runtime>) {
|
|
||||||
RUNTIMES.with(|stack| {
|
|
||||||
let mut stack = stack.borrow_mut();
|
|
||||||
stack.pop();
|
|
||||||
stack.push(runtime);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pushes a new scope onto the stack
|
/// Pushes a new scope onto the stack
|
||||||
pub(crate) fn push_runtime(runtime: Rc<Runtime>) {
|
pub(crate) fn push_runtime(runtime: Rc<Runtime>) {
|
||||||
RUNTIMES.with(|stack| stack.borrow_mut().push(runtime));
|
RUNTIMES.with(|stack| stack.borrow_mut().push(runtime));
|
||||||
|
@ -143,10 +98,42 @@ impl Runtime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RuntimeGuard(Rc<Runtime>);
|
/// A gaurd for a new runtime. This must be used to override the current runtime when importing components from a dynamic library that has it's own runtime.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dioxus::prelude::*;
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let virtual_dom = VirtualDom::new(app);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn app(cx: Scope) -> Element {
|
||||||
|
/// render!{ Component { runtime: Runtime::current().unwrap() } }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // In a dynamic library
|
||||||
|
/// #[derive(Props)]
|
||||||
|
/// struct ComponentProps {
|
||||||
|
/// runtime: std::rc::Rc<Runtime>,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl PartialEq for ComponentProps {
|
||||||
|
/// fn eq(&self, _other: &Self) -> bool {
|
||||||
|
/// true
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn Component(cx: Scope<ComponentProps>) -> Element {
|
||||||
|
/// cx.use_hook(|| RuntimeGuard::new(cx.props.runtime.clone()));
|
||||||
|
///
|
||||||
|
/// render! { div {} }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub struct RuntimeGuard(Rc<Runtime>);
|
||||||
|
|
||||||
impl RuntimeGuard {
|
impl RuntimeGuard {
|
||||||
pub(crate) fn new(runtime: Rc<Runtime>) -> Self {
|
/// Create a new runtime guard that sets the current Dioxus runtime. The runtime will be reset when the guard is dropped
|
||||||
|
pub fn new(runtime: Rc<Runtime>) -> Self {
|
||||||
push_runtime(runtime.clone());
|
push_runtime(runtime.clone());
|
||||||
Self(runtime)
|
Self(runtime)
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ tokio_runtime = ["tokio"]
|
||||||
fullscreen = ["wry/fullscreen"]
|
fullscreen = ["wry/fullscreen"]
|
||||||
transparent = ["wry/transparent"]
|
transparent = ["wry/transparent"]
|
||||||
devtools = ["wry/devtools"]
|
devtools = ["wry/devtools"]
|
||||||
|
tray = ["wry/tray"]
|
||||||
dox = ["wry/dox"]
|
dox = ["wry/dox"]
|
||||||
hot-reload = ["dioxus-hot-reload"]
|
hot-reload = ["dioxus-hot-reload"]
|
||||||
|
|
||||||
|
|
|
@ -57,32 +57,32 @@ pub mod computed;
|
||||||
mod use_on_unmount;
|
mod use_on_unmount;
|
||||||
pub use use_on_unmount::*;
|
pub use use_on_unmount::*;
|
||||||
|
|
||||||
mod usecontext;
|
mod use_context;
|
||||||
pub use usecontext::*;
|
pub use use_context::*;
|
||||||
|
|
||||||
mod usestate;
|
mod use_state;
|
||||||
pub use usestate::{use_state, UseState};
|
pub use use_state::{use_state, UseState};
|
||||||
|
|
||||||
mod useref;
|
mod use_ref;
|
||||||
pub use useref::*;
|
pub use use_ref::*;
|
||||||
|
|
||||||
mod use_shared_state;
|
mod use_shared_state;
|
||||||
pub use use_shared_state::*;
|
pub use use_shared_state::*;
|
||||||
|
|
||||||
mod usecoroutine;
|
mod use_coroutine;
|
||||||
pub use usecoroutine::*;
|
pub use use_coroutine::*;
|
||||||
|
|
||||||
mod usefuture;
|
mod use_future;
|
||||||
pub use usefuture::*;
|
pub use use_future::*;
|
||||||
|
|
||||||
mod useeffect;
|
mod use_effect;
|
||||||
pub use useeffect::*;
|
pub use use_effect::*;
|
||||||
|
|
||||||
mod usecallback;
|
mod use_callback;
|
||||||
pub use usecallback::*;
|
pub use use_callback::*;
|
||||||
|
|
||||||
mod usememo;
|
mod use_memo;
|
||||||
pub use usememo::*;
|
pub use use_memo::*;
|
||||||
|
|
||||||
mod userootcontext;
|
mod use_root_context;
|
||||||
pub use userootcontext::*;
|
pub use use_root_context::*;
|
||||||
|
|
|
@ -336,6 +336,50 @@ impl<T> PartialEq<UseState<T>> for UseState<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: std::cmp::PartialOrd> PartialOrd<T> for UseState<T> {
|
||||||
|
fn ge(&self, other: &T) -> bool {
|
||||||
|
*self.current_val >= *other
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gt(&self, other: &T) -> bool {
|
||||||
|
*self.current_val > *other
|
||||||
|
}
|
||||||
|
|
||||||
|
fn le(&self, other: &T) -> bool {
|
||||||
|
*self.current_val <= *other
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lt(&self, other: &T) -> bool {
|
||||||
|
*self.current_val < *other
|
||||||
|
}
|
||||||
|
|
||||||
|
fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
|
||||||
|
(*self.current_val).partial_cmp(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: std::cmp::PartialOrd> PartialOrd<UseState<T>> for UseState<T> {
|
||||||
|
fn ge(&self, other: &UseState<T>) -> bool {
|
||||||
|
self.current_val >= other.current_val
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gt(&self, other: &UseState<T>) -> bool {
|
||||||
|
self.current_val > other.current_val
|
||||||
|
}
|
||||||
|
|
||||||
|
fn le(&self, other: &UseState<T>) -> bool {
|
||||||
|
self.current_val <= other.current_val
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lt(&self, other: &UseState<T>) -> bool {
|
||||||
|
self.current_val < other.current_val
|
||||||
|
}
|
||||||
|
|
||||||
|
fn partial_cmp(&self, other: &UseState<T>) -> Option<std::cmp::Ordering> {
|
||||||
|
self.current_val.partial_cmp(&other.current_val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Debug> Debug for UseState<T> {
|
impl<T: Debug> Debug for UseState<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{:?}", self.current_val)
|
write!(f, "{:?}", self.current_val)
|
|
@ -1203,6 +1203,7 @@ builder_constructors! {
|
||||||
value: String DEFAULT,
|
value: String DEFAULT,
|
||||||
|
|
||||||
selected: Bool volatile,
|
selected: Bool volatile,
|
||||||
|
initial_selected: Bool DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Build a
|
/// Build a
|
||||||
|
|
|
@ -54,6 +54,9 @@ export function setAttributeInner(node, field, value, ns) {
|
||||||
case "selected":
|
case "selected":
|
||||||
node.selected = truthy(value);
|
node.selected = truthy(value);
|
||||||
break;
|
break;
|
||||||
|
case "initial_selected":
|
||||||
|
node.defaultSelected = truthy(value);
|
||||||
|
break;
|
||||||
case "dangerous_inner_html":
|
case "dangerous_inner_html":
|
||||||
node.innerHTML = value;
|
node.innerHTML = value;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -83,6 +83,9 @@ mod js {
|
||||||
case "selected":
|
case "selected":
|
||||||
node.selected = truthy(value);
|
node.selected = truthy(value);
|
||||||
break;
|
break;
|
||||||
|
case "initial_selected":
|
||||||
|
node.defaultSelected = truthy(value);
|
||||||
|
break;
|
||||||
case "dangerous_inner_html":
|
case "dangerous_inner_html":
|
||||||
node.innerHTML = value;
|
node.innerHTML = value;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -19,32 +19,43 @@ async fn main() {
|
||||||
let addr: std::net::SocketAddr = ([127, 0, 0, 1], 3030).into();
|
let addr: std::net::SocketAddr = ([127, 0, 0, 1], 3030).into();
|
||||||
|
|
||||||
let view = dioxus_liveview::LiveViewPool::new();
|
let view = dioxus_liveview::LiveViewPool::new();
|
||||||
|
let index_page_with_glue = |glue: &str| {
|
||||||
|
Html(format!(
|
||||||
|
r#"
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head> <title>Dioxus LiveView with axum</title> </head>
|
||||||
|
<body> <div id="main"></div> </body>
|
||||||
|
{glue}
|
||||||
|
</html>
|
||||||
|
"#,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
let app = Router::new()
|
let app =
|
||||||
.route(
|
Router::new()
|
||||||
"/",
|
.route(
|
||||||
get(move || async move {
|
"/",
|
||||||
Html(format!(
|
get(move || async move {
|
||||||
r#"
|
index_page_with_glue(&dioxus_liveview::interpreter_glue(&format!(
|
||||||
<!DOCTYPE html>
|
"ws://{addr}/ws"
|
||||||
<html>
|
)))
|
||||||
<head> <title>Dioxus LiveView with axum</title> </head>
|
}),
|
||||||
<body> <div id="main"></div> </body>
|
)
|
||||||
{glue}
|
.route(
|
||||||
</html>
|
"/as-path",
|
||||||
"#,
|
get(move || async move {
|
||||||
glue = dioxus_liveview::interpreter_glue(&format!("ws://{addr}/ws"))
|
index_page_with_glue(&dioxus_liveview::interpreter_glue("/ws"))
|
||||||
))
|
}),
|
||||||
}),
|
)
|
||||||
)
|
.route(
|
||||||
.route(
|
"/ws",
|
||||||
"/ws",
|
get(move |ws: WebSocketUpgrade| async move {
|
||||||
get(move |ws: WebSocketUpgrade| async move {
|
ws.on_upgrade(move |socket| async move {
|
||||||
ws.on_upgrade(move |socket| async move {
|
_ = view.launch(dioxus_liveview::axum_socket(socket), app).await;
|
||||||
_ = view.launch(dioxus_liveview::axum_socket(socket), app).await;
|
})
|
||||||
})
|
}),
|
||||||
}),
|
);
|
||||||
);
|
|
||||||
|
|
||||||
println!("Listening on http://{addr}");
|
println!("Listening on http://{addr}");
|
||||||
|
|
||||||
|
|
|
@ -94,14 +94,49 @@ static MAIN_JS: &str = include_str!("./main.js");
|
||||||
/// This script that gets injected into your app connects this page to the websocket endpoint
|
/// This script that gets injected into your app connects this page to the websocket endpoint
|
||||||
///
|
///
|
||||||
/// Once the endpoint is connected, it will send the initial state of the app, and then start
|
/// Once the endpoint is connected, it will send the initial state of the app, and then start
|
||||||
/// processing user events and returning edits to the liveview instance
|
/// processing user events and returning edits to the liveview instance.
|
||||||
pub fn interpreter_glue(url: &str) -> String {
|
///
|
||||||
|
/// You can pass a relative path prefixed with "/", or enter a full URL including the protocol
|
||||||
|
/// (`ws:` or `wss:`) as an argument.
|
||||||
|
///
|
||||||
|
/// If you enter a relative path, the web client automatically prefixes the host address in
|
||||||
|
/// `window.location` when creating a web socket to LiveView.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Creates websocket connection to same host as current page
|
||||||
|
/// interpreter_glue("/api/liveview");
|
||||||
|
///
|
||||||
|
/// // Creates websocket connection to specified url
|
||||||
|
/// interpreter_glue("ws://localhost:8080/api/liveview");
|
||||||
|
/// ```
|
||||||
|
pub fn interpreter_glue(url_or_path: &str) -> String {
|
||||||
|
// If the url starts with a `/`, generate glue which reuses current host
|
||||||
|
let get_ws_url = if url_or_path.starts_with('/') {
|
||||||
|
r#"
|
||||||
|
let loc = window.location;
|
||||||
|
let new_url = "";
|
||||||
|
if (loc.protocol === "https:") {{
|
||||||
|
new_url = "wss:";
|
||||||
|
}} else {{
|
||||||
|
new_url = "ws:";
|
||||||
|
}}
|
||||||
|
new_url += "//" + loc.host + path;
|
||||||
|
return new_url;
|
||||||
|
"#
|
||||||
|
} else {
|
||||||
|
"return path;"
|
||||||
|
};
|
||||||
|
|
||||||
let js = &*INTERPRETER_JS;
|
let js = &*INTERPRETER_JS;
|
||||||
let common = &*COMMON_JS;
|
let common = &*COMMON_JS;
|
||||||
format!(
|
format!(
|
||||||
r#"
|
r#"
|
||||||
<script>
|
<script>
|
||||||
var WS_ADDR = "{url}";
|
function __dioxusGetWsUrl(path) {{
|
||||||
|
{get_ws_url}
|
||||||
|
}}
|
||||||
|
|
||||||
|
var WS_ADDR = __dioxusGetWsUrl("{url_or_path}");
|
||||||
{js}
|
{js}
|
||||||
{common}
|
{common}
|
||||||
{MAIN_JS}
|
{MAIN_JS}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use syn::{
|
||||||
Ident, ItemFn, Token,
|
Ident, ItemFn, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Declares that a function is a [server function](dioxus_fullstack). This means that
|
/// Declares that a function is a [server function](https://dioxuslabs.com/learn/0.4/reference/fullstack/server_functions). This means that
|
||||||
/// its body will only run on the server, i.e., when the `ssr` feature is enabled.
|
/// its body will only run on the server, i.e., when the `ssr` feature is enabled.
|
||||||
///
|
///
|
||||||
/// If you call a server function from the client (i.e., when the `csr` or `hydrate` features
|
/// If you call a server function from the client (i.e., when the `csr` or `hydrate` features
|
||||||
|
|
|
@ -90,7 +90,7 @@ module.exports = defineConfig({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cwd: path.join(process.cwd(), 'fullstack'),
|
cwd: path.join(process.cwd(), 'fullstack'),
|
||||||
command: 'cargo run --package dioxus-cli -- build --features web --release\ncargo run --release --features ssr',
|
command: 'cargo run --package dioxus-cli -- build --features web --release && cargo run --release --features ssr',
|
||||||
port: 3333,
|
port: 3333,
|
||||||
timeout: 10 * 60 * 1000,
|
timeout: 10 * 60 * 1000,
|
||||||
reuseExistingServer: !process.env.CI,
|
reuseExistingServer: !process.env.CI,
|
||||||
|
|
Loading…
Add table
Reference in a new issue