implement launch builder for the desktop and web platforms

This commit is contained in:
Evan Almloff committed 2024-01-16 08:42:16 -06:00
1 parent ef553a2cb2
commit 7e4d2debe0
70 files changed
+448 -431

No files matched your search

+7 -5
View File
@@ -13,6 +13,7 @@ mod fragment;
mod global_context;
mod mutations;
mod nodes;
mod platform;
mod properties;
mod runtime;
mod scheduler;
@@ -30,6 +31,7 @@ pub(crate) mod innerlude {
pub use crate::global_context::*;
pub use crate::mutations::*;
pub use crate::nodes::*;
pub use crate::platform::*;
pub use crate::properties::*;
pub use crate::runtime::{Runtime, RuntimeGuard};
pub use crate::scheduler::*;
@@ -73,11 +75,11 @@ pub(crate) mod innerlude {
pub use crate::innerlude::{
fc_to_builder, generation, schedule_update, schedule_update_any, use_hook, vdom_is_rendering,
AnyValue, Attribute, AttributeValue, CapturedError, Component, ComponentFunction, DynamicNode,
Element, ElementId, Event, Fragment, HasAttributes, IntoDynNode, Mutation, Mutations,
NoOpMutations, Properties, RenderReturn, ScopeId, ScopeState, Task, Template,
TemplateAttribute, TemplateNode, VComponent, VNode, VNodeInner, VPlaceholder, VText,
VirtualDom, WriteMutations,
AnyValue, Attribute, AttributeValue, BoxedContext, CapturedError, Component, ComponentFunction,
CrossPlatformConfig, DynamicNode, Element, ElementId, Event, Fragment, HasAttributes,
IntoDynNode, Mutation, Mutations, NoOpMutations, PlatformBuilder, Properties, RenderReturn,
ScopeId, ScopeState, Task, Template, TemplateAttribute, TemplateNode, VComponent, VNode,
VNodeInner, VPlaceholder, VText, VirtualDom, WriteMutations,
};
/// The purpose of this module is to alleviate imports of many common types
+106
View File
@@ -0,0 +1,106 @@
use std::{any::Any, marker::PhantomData};
use crate::{ComponentFunction, VirtualDom};
/// A boxed object that can be injected into a component's context.
pub struct BoxedContext(Box<dyn ClonableAny>);
impl BoxedContext {
/// Create a new boxed context.
pub fn new(value: impl Any + Clone + 'static) -> Self {
Self(Box::new(value))
}
/// Unwrap the boxed context into its inner value.
pub fn into_inner(self) -> Box<dyn Any> {
self.0.into_inner()
}
}
impl Clone for BoxedContext {
fn clone(&self) -> Self {
Self(self.0.clone_box())
}
}
trait ClonableAny: Any {
fn clone_box(&self) -> Box<dyn ClonableAny>;
fn into_inner(self: Box<Self>) -> Box<dyn Any>;
}
impl<T: Any + Clone> ClonableAny for T {
fn clone_box(&self) -> Box<dyn ClonableAny> {
Box::new(self.clone())
}
fn into_inner(self: Box<Self>) -> Box<dyn Any> {
self
}
}
/// The platform-independent part of the config needed to launch an application.
pub struct CrossPlatformConfig<
Component: ComponentFunction<Phantom, Props = Props>,
Props: Clone + 'static,
Phantom: 'static,
> {
/// The root component function.
pub component: Component,
/// The props for the root component.
pub props: Props,
/// The contexts to provide to the root component.
pub root_contexts: Vec<BoxedContext>,
_phantom: PhantomData<Phantom>,
}
impl<
Component: ComponentFunction<Phantom, Props = Props>,
Props: Clone + 'static,
Phantom: 'static,
> CrossPlatformConfig<Component, Props, Phantom>
{
/// Create a new cross-platform config.
pub fn new(component: Component, props: Props, root_contexts: Vec<BoxedContext>) -> Self {
Self {
component,
props,
root_contexts,
_phantom: PhantomData,
}
}
/// Build a virtual dom from the config.
pub fn build_vdom(self) -> VirtualDom {
let mut vdom = VirtualDom::new_with_props(self.component, self.props);
for context in self.root_contexts {
vdom.insert_boxed_root_context(context);
}
vdom
}
}
/// A builder to launch a specific platform.
pub trait PlatformBuilder<Props: Clone + 'static> {
/// The platform-specific config needed to launch an application.
type Config: Default;
/// Launch the app.
fn launch<Component: ComponentFunction<Phantom, Props = Props>, Phantom: 'static>(
config: CrossPlatformConfig<Component, Props, Phantom>,
platform_config: Self::Config,
);
}
impl<Props: Clone + 'static> PlatformBuilder<Props> for () {
type Config = ();
fn launch<Component: ComponentFunction<Phantom, Props = Props>, Phantom: 'static>(
_: CrossPlatformConfig<Component, Props, Phantom>,
_: Self::Config,
) {
panic!("No platform is currently enabled. Please enable a platform feature for the dioxus crate.");
}
}
+1 -2
View File
@@ -309,12 +309,11 @@ impl ScopeContext {
impl Drop for ScopeContext {
fn drop(&mut self) {
// Drop all spawned tasks
with_runtime(|rt| {
_ = with_runtime(|rt| {
for id in self.spawned_tasks.borrow().iter() {
rt.remove_task(*id);
}
})
.expect("Runtime to exist")
}
}
+10 -4
View File
@@ -227,7 +227,7 @@ impl VirtualDom {
///
/// Note: the VirtualDom is not progressed, you must either "run_with_deadline" or use "rebuild" to progress it.
pub fn new(app: fn() -> Element) -> Self {
Self::new_with_props(|app| app(), app)
Self::new_with_props(app, ())
}
/// Create a new virtualdom and build it immediately
@@ -267,7 +267,14 @@ impl VirtualDom {
/// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" });
/// let mutations = dom.rebuild();
/// ```
pub fn new_with_props<P: Clone + 'static>(root: fn(P) -> Element, root_props: P) -> Self {
pub fn new_with_props<
F: crate::ComponentFunction<Phantom, Props = P>,
P: Clone + 'static,
Phantom: 'static,
>(
root: F,
root_props: P,
) -> Self {
let (tx, rx) = futures_channel::mpsc::unbounded();
let mut dom = Self {
@@ -328,11 +335,10 @@ impl VirtualDom {
/// Build the virtualdom with a global context inserted into the base scope
///
/// This method is useful for when you want to provide a context in your app without knowing its type
pub fn with_boxed_root_context(self, context: BoxedContext) -> Self {
pub fn insert_boxed_root_context(&mut self, context: BoxedContext) {
self.base_scope()
.context()
.provide_any_context(context.into_inner());
self
}
/// Manually mark a scope as requiring a re-render