Merge branch 'master' into pr/atty303/1349
This commit is contained in:
commit
355cd9b19e
20 files changed
+125
-85
No files matched your search
+1
-1
@@ -90,7 +90,7 @@ slab = "0.4.2"
|
||||
futures-channel = "0.3.21"
|
||||
futures-util = { version = "0.3", default-features = false }
|
||||
rustc-hash = "1.1.0"
|
||||
wasm-bindgen = "0.2.87"
|
||||
wasm-bindgen = "0.2.88"
|
||||
html_parser = "0.7.0"
|
||||
thiserror = "1.0.40"
|
||||
prettyplease = { package = "prettier-please", version = "0.2", features = [
|
||||
|
||||
@@ -62,6 +62,7 @@ fn app(cx: Scope) -> Element {
|
||||
div { id: "wrapper",
|
||||
div { class: "app",
|
||||
div { class: "calculator",
|
||||
tabindex: "0",
|
||||
onkeydown: handle_key_down_event,
|
||||
div { class: "calculator-display", val.to_string() }
|
||||
div { class: "calculator-keypad",
|
||||
|
||||
@@ -11,7 +11,7 @@ It handles building, bundling, development and publishing to simplify developmen
|
||||
### Install the stable version (recommended)
|
||||
|
||||
```
|
||||
cargo install dioxus-cli --locked
|
||||
cargo install dioxus-cli
|
||||
```
|
||||
|
||||
### Install the latest development build through git
|
||||
|
||||
@@ -469,7 +469,7 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String {
|
||||
.unwrap_or_default()
|
||||
.contains_key("tailwindcss")
|
||||
{
|
||||
style_str.push_str("<link rel=\"stylesheet\" href=\"tailwind.css\">\n");
|
||||
style_str.push_str("<link rel=\"stylesheet\" href=\"/{base_path}/tailwind.css\">\n");
|
||||
}
|
||||
|
||||
replace_or_insert_before("{style_include}", &style_str, "</head", &mut html);
|
||||
|
||||
@@ -29,6 +29,9 @@ pub enum Error {
|
||||
#[error("Cargo Error: {0}")]
|
||||
CargoError(String),
|
||||
|
||||
#[error("Couldn't retrieve cargo metadata")]
|
||||
CargoMetadata(#[source] cargo_metadata::Error),
|
||||
|
||||
#[error("{0}")]
|
||||
CustomError(String),
|
||||
|
||||
|
||||
+28
-39
@@ -9,42 +9,31 @@ use dioxus_cli::plugin::PluginManager;
|
||||
|
||||
use Commands::*;
|
||||
|
||||
fn get_bin(bin: Option<String>) -> Result<Option<PathBuf>> {
|
||||
const ERR_MESSAGE: &str = "The `--bin` flag has to be ran in a Cargo workspace.";
|
||||
fn get_bin(bin: Option<String>) -> Result<PathBuf> {
|
||||
let metadata = cargo_metadata::MetadataCommand::new()
|
||||
.exec()
|
||||
.map_err(Error::CargoMetadata)?;
|
||||
let package = if let Some(bin) = bin {
|
||||
metadata
|
||||
.workspace_packages()
|
||||
.into_iter()
|
||||
.find(|p| p.name == bin)
|
||||
.ok_or(format!("no such package: {}", bin))
|
||||
.map_err(Error::CargoError)?
|
||||
} else {
|
||||
metadata
|
||||
.root_package()
|
||||
.ok_or("no root package?".into())
|
||||
.map_err(Error::CargoError)?
|
||||
};
|
||||
|
||||
if let Some(ref bin) = bin {
|
||||
let manifest = cargo_toml::Manifest::from_path("./Cargo.toml")
|
||||
.map_err(|_| Error::CargoError(ERR_MESSAGE.to_string()))?;
|
||||
let crate_dir = package
|
||||
.manifest_path
|
||||
.parent()
|
||||
.ok_or("couldn't take parent dir".into())
|
||||
.map_err(Error::CargoError)?;
|
||||
|
||||
if let Some(workspace) = manifest.workspace {
|
||||
for item in workspace.members.iter() {
|
||||
let path = PathBuf::from(item);
|
||||
|
||||
if !path.exists() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !path.is_dir() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if path.ends_with(bin.clone()) {
|
||||
return Ok(Some(path));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(Error::CargoError(ERR_MESSAGE.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
// If the bin exists but we couldn't find it
|
||||
if bin.is_some() {
|
||||
return Err(Error::CargoError(
|
||||
"The specified bin does not exist.".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
Ok(crate_dir.into())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
@@ -55,7 +44,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
let bin = get_bin(args.bin)?;
|
||||
|
||||
let _dioxus_config = DioxusConfig::load(bin.clone())
|
||||
let _dioxus_config = DioxusConfig::load(Some(bin.clone()))
|
||||
.map_err(|e| anyhow!("Failed to load Dioxus config because: {e}"))?
|
||||
.unwrap_or_else(|| {
|
||||
log::warn!("You appear to be creating a Dioxus project from scratch; we will use the default config");
|
||||
@@ -72,15 +61,15 @@ async fn main() -> anyhow::Result<()> {
|
||||
.map_err(|e| anyhow!("🚫 Translation of HTML into RSX failed: {}", e)),
|
||||
|
||||
Build(opts) => opts
|
||||
.build(bin.clone())
|
||||
.build(Some(bin.clone()))
|
||||
.map_err(|e| anyhow!("🚫 Building project failed: {}", e)),
|
||||
|
||||
Clean(opts) => opts
|
||||
.clean(bin.clone())
|
||||
.clean(Some(bin.clone()))
|
||||
.map_err(|e| anyhow!("🚫 Cleaning project failed: {}", e)),
|
||||
|
||||
Serve(opts) => opts
|
||||
.serve(bin.clone())
|
||||
.serve(Some(bin.clone()))
|
||||
.await
|
||||
.map_err(|e| anyhow!("🚫 Serving project failed: {}", e)),
|
||||
|
||||
@@ -93,7 +82,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
.map_err(|e| anyhow!("🚫 Configuring new project failed: {}", e)),
|
||||
|
||||
Bundle(opts) => opts
|
||||
.bundle(bin.clone())
|
||||
.bundle(Some(bin.clone()))
|
||||
.map_err(|e| anyhow!("🚫 Bundling project failed: {}", e)),
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
|
||||
@@ -31,6 +31,7 @@ fn get_out_comp_fn(orig_comp_fn: &ItemFn, cx_pat: &Pat) -> ItemFn {
|
||||
block: parse_quote! {
|
||||
{
|
||||
#[warn(non_snake_case)]
|
||||
#[allow(clippy::inline_always)]
|
||||
#[inline(always)]
|
||||
#inner_comp_fn
|
||||
#inner_comp_ident (#cx_pat)
|
||||
|
||||
@@ -632,18 +632,16 @@ mod struct_info {
|
||||
let generics_with_empty = modify_types_generics_hack(&b_initial_generics, |args| {
|
||||
args.insert(0, syn::GenericArgument::Type(empties_tuple.clone().into()));
|
||||
});
|
||||
let phantom_generics = self.generics.params.iter().map(|param| match param {
|
||||
let phantom_generics = self.generics.params.iter().filter_map(|param| match param {
|
||||
syn::GenericParam::Lifetime(lifetime) => {
|
||||
let lifetime = &lifetime.lifetime;
|
||||
quote!(::core::marker::PhantomData<&#lifetime ()>)
|
||||
Some(quote!(::core::marker::PhantomData<&#lifetime ()>))
|
||||
}
|
||||
syn::GenericParam::Type(ty) => {
|
||||
let ty = &ty.ident;
|
||||
quote!(::core::marker::PhantomData<#ty>)
|
||||
}
|
||||
syn::GenericParam::Const(_cnst) => {
|
||||
quote!()
|
||||
Some(quote!(::core::marker::PhantomData<#ty>))
|
||||
}
|
||||
syn::GenericParam::Const(_cnst) => None,
|
||||
});
|
||||
let builder_method_doc = match self.builder_attr.builder_method_doc {
|
||||
Some(ref doc) => quote!(#doc),
|
||||
@@ -738,7 +736,7 @@ Finally, call `.build()` to create the instance of `{name}`.
|
||||
Ok(quote! {
|
||||
impl #impl_generics #name #ty_generics #where_clause {
|
||||
#[doc = #builder_method_doc]
|
||||
#[allow(dead_code)]
|
||||
#[allow(dead_code, clippy::type_complexity)]
|
||||
#vis fn builder(_cx: & #extend_lifetime ::dioxus::prelude::ScopeState) -> #builder_name #generics_with_empty {
|
||||
#builder_name {
|
||||
#(#extend_fields_value,)*
|
||||
@@ -1073,6 +1071,7 @@ Finally, call `.build()` to create the instance of `{name}`.
|
||||
#[allow(dead_code, non_camel_case_types, missing_docs)]
|
||||
impl #impl_generics #builder_name < #( #ty_generics ),* > #where_clause {
|
||||
#doc
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn #field_name (self, #field_name: #arg_type) -> #builder_name < #( #target_generics ),* > {
|
||||
let #field_name = (#arg_expr,);
|
||||
let ( #(#descructuring,)* ) = self.fields;
|
||||
@@ -1093,6 +1092,7 @@ Finally, call `.build()` to create the instance of `{name}`.
|
||||
#[deprecated(
|
||||
note = #repeated_fields_error_message
|
||||
)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn #field_name (self, _: #repeated_fields_error_type_name) -> #builder_name < #( #target_generics ),* > {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -164,17 +164,11 @@ impl VirtualDom {
|
||||
});
|
||||
|
||||
// Now that all the references are gone, we can safely drop our own references in our listeners.
|
||||
let mut listeners = scope.attributes_to_drop.borrow_mut();
|
||||
let mut listeners = scope.attributes_to_drop_before_render.borrow_mut();
|
||||
listeners.drain(..).for_each(|listener| {
|
||||
let listener = unsafe { &*listener };
|
||||
match &listener.value {
|
||||
AttributeValue::Listener(l) => {
|
||||
_ = l.take();
|
||||
}
|
||||
AttributeValue::Any(a) => {
|
||||
_ = a.take();
|
||||
}
|
||||
_ => (),
|
||||
if let AttributeValue::Listener(l) = &listener.value {
|
||||
_ = l.take();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use crate::nodes::RenderReturn;
|
||||
use crate::{Attribute, AttributeValue};
|
||||
use bumpalo::Bump;
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
|
||||
pub(crate) struct BumpFrame {
|
||||
pub bump: UnsafeCell<Bump>,
|
||||
pub node: Cell<*const RenderReturn<'static>>,
|
||||
pub(crate) attributes_to_drop_before_reset: RefCell<Vec<*const Attribute<'static>>>,
|
||||
}
|
||||
|
||||
impl BumpFrame {
|
||||
@@ -13,6 +16,7 @@ impl BumpFrame {
|
||||
Self {
|
||||
bump: UnsafeCell::new(bump),
|
||||
node: Cell::new(std::ptr::null()),
|
||||
attributes_to_drop_before_reset: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +35,23 @@ impl BumpFrame {
|
||||
unsafe { &*self.bump.get() }
|
||||
}
|
||||
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub(crate) unsafe fn bump_mut(&self) -> &mut Bump {
|
||||
unsafe { &mut *self.bump.get() }
|
||||
pub(crate) fn add_attribute_to_drop(&self, attribute: *const Attribute<'static>) {
|
||||
self.attributes_to_drop_before_reset
|
||||
.borrow_mut()
|
||||
.push(attribute);
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn reset(&self) {
|
||||
let mut attributes = self.attributes_to_drop_before_reset.borrow_mut();
|
||||
attributes.drain(..).for_each(|attribute| {
|
||||
let attribute = unsafe { &*attribute };
|
||||
if let AttributeValue::Any(l) = &attribute.value {
|
||||
_ = l.take();
|
||||
}
|
||||
});
|
||||
unsafe {
|
||||
let bump = &mut *self.bump.get();
|
||||
bump.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,8 +23,37 @@ use crate::{innerlude::VNode, ScopeState};
|
||||
///
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// LazyNodes::new(|f| f.element("div", [], [], [] None))
|
||||
/// LazyNodes::new(|f| {
|
||||
/// static TEMPLATE: dioxus::core::Template = dioxus::core::Template {
|
||||
/// name: "main.rs:5:5:20", // Source location of the template for hot reloading
|
||||
/// roots: &[
|
||||
/// dioxus::core::TemplateNode::Element {
|
||||
/// tag: dioxus_elements::div::TAG_NAME,
|
||||
/// namespace: dioxus_elements::div::NAME_SPACE,
|
||||
/// attrs: &[],
|
||||
/// children: &[],
|
||||
/// },
|
||||
/// ],
|
||||
/// node_paths: &[],
|
||||
/// attr_paths: &[],
|
||||
/// };
|
||||
/// dioxus::core::VNode {
|
||||
/// parent: None,
|
||||
/// key: None,
|
||||
/// template: std::cell::Cell::new(TEMPLATE),
|
||||
/// root_ids: dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(
|
||||
/// 1usize,
|
||||
/// f.bump(),
|
||||
/// )
|
||||
/// .into(),
|
||||
/// dynamic_nodes: f.bump().alloc([]),
|
||||
/// dynamic_attrs: f.bump().alloc([]),
|
||||
/// })
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Find more information about how to construct [`VNode`] at <https://dioxuslabs.com/learn/0.4/contributing/walkthrough_readme#the-rsx-macro>
|
||||
|
||||
pub struct LazyNodes<'a, 'b> {
|
||||
#[cfg(not(miri))]
|
||||
inner: SmallBox<dyn FnMut(&'a ScopeState) -> VNode<'a> + 'b, S16>,
|
||||
@@ -61,7 +90,7 @@ impl<'a, 'b> LazyNodes<'a, 'b> {
|
||||
/// Call the closure with the given factory to produce real [`VNode`].
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// let f = LazyNodes::new(move |f| f.element("div", [], [], [] None));
|
||||
/// let f = LazyNodes::new(/* Closure for creating VNodes */);
|
||||
///
|
||||
/// let node = f.call(cac);
|
||||
/// ```
|
||||
|
||||
@@ -35,7 +35,7 @@ impl VirtualDom {
|
||||
hook_idx: Default::default(),
|
||||
|
||||
borrowed_props: Default::default(),
|
||||
attributes_to_drop: Default::default(),
|
||||
attributes_to_drop_before_render: Default::default(),
|
||||
}));
|
||||
|
||||
let context =
|
||||
@@ -54,7 +54,7 @@ impl VirtualDom {
|
||||
|
||||
let new_nodes = unsafe {
|
||||
let scope = &self.scopes[scope_id.0];
|
||||
scope.previous_frame().bump_mut().reset();
|
||||
scope.previous_frame().reset();
|
||||
|
||||
scope.context().suspended.set(false);
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ pub struct ScopeState {
|
||||
pub(crate) hook_idx: Cell<usize>,
|
||||
|
||||
pub(crate) borrowed_props: RefCell<Vec<*const VComponent<'static>>>,
|
||||
pub(crate) attributes_to_drop: RefCell<Vec<*const Attribute<'static>>>,
|
||||
pub(crate) attributes_to_drop_before_render: RefCell<Vec<*const Attribute<'static>>>,
|
||||
|
||||
pub(crate) props: Option<Box<dyn AnyProps<'static>>>,
|
||||
}
|
||||
@@ -349,12 +349,22 @@ impl<'src> ScopeState {
|
||||
pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> {
|
||||
let element = rsx.call(self);
|
||||
|
||||
let mut listeners = self.attributes_to_drop.borrow_mut();
|
||||
let mut listeners = self.attributes_to_drop_before_render.borrow_mut();
|
||||
for attr in element.dynamic_attrs {
|
||||
attr.ty.for_each(|attr| {
|
||||
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
|
||||
listeners.push(unbounded);
|
||||
})
|
||||
match attr.value {
|
||||
// We need to drop listeners before the next render because they may borrow data from the borrowed props which will be dropped
|
||||
AttributeValue::Listener(_) => {
|
||||
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
|
||||
listeners.push(unbounded);
|
||||
}
|
||||
// We need to drop any values manually to make sure that their drop implementation is called before the next render
|
||||
AttributeValue::Any(_) => {
|
||||
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
|
||||
self.previous_frame().add_attribute_to_drop(unbounded);
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let mut props = self.borrowed_props.borrow_mut();
|
||||
|
||||
@@ -7,6 +7,6 @@ use dioxus_core::ScopeState;
|
||||
pub fn use_atom_root(cx: &ScopeState) -> &Rc<AtomRoot> {
|
||||
cx.use_hook(|| match cx.consume_context::<Rc<AtomRoot>>() {
|
||||
Some(root) => root,
|
||||
None => panic!("No atom root found in context. Did you forget place an AtomRoot component at the top of your app?"),
|
||||
None => panic!("No atom root found in context. Did you forget to call use_init_atom_root at the top of your app?"),
|
||||
})
|
||||
}
|
||||
@@ -86,7 +86,9 @@ impl<T: 'static> AtomState<T> {
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn current(&self) -> Rc<T> {
|
||||
self.value.as_ref().unwrap().clone()
|
||||
let atoms = self.root.atoms.borrow();
|
||||
let slot = atoms.get(&self.id).unwrap();
|
||||
slot.value.clone().downcast().unwrap()
|
||||
}
|
||||
|
||||
/// Get the `setter` function directly without the `AtomState` wrapper.
|
||||
|
||||
@@ -11,7 +11,7 @@ keywords = ["ui", "gui", "react", "ssr", "fullstack"]
|
||||
|
||||
[dependencies]
|
||||
# server functions
|
||||
server_fn = { version = "0.4.6", default-features = false }
|
||||
server_fn = { version = "0.5.2", default-features = false }
|
||||
dioxus_server_macro = { workspace = true }
|
||||
|
||||
# warp
|
||||
|
||||
@@ -53,7 +53,7 @@ fn default_external_navigation_handler() -> fn(Scope) -> Element {
|
||||
dioxus_router::prelude::FailureExternalNavigation
|
||||
}
|
||||
|
||||
/// The configeration for the router
|
||||
/// The configuration for the router
|
||||
#[derive(Props, serde::Serialize, serde::Deserialize)]
|
||||
pub struct FullstackRouterConfig<R>
|
||||
where
|
||||
|
||||
@@ -125,14 +125,6 @@ impl server_fn::ServerFunctionRegistry<()> for DioxusServerFnRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
fn register(
|
||||
url: &'static str,
|
||||
server_function: ServerFunction,
|
||||
encoding: server_fn::Encoding,
|
||||
) -> Result<(), Self::Error> {
|
||||
Self::register_explicit("", url, server_function, encoding)
|
||||
}
|
||||
|
||||
/// Returns the server function registered at the given URL, or `None` if no function is registered at that URL.
|
||||
fn get(url: &str) -> Option<server_fn::ServerFnTraitObj<()>> {
|
||||
REGISTERED_SERVER_FUNCTIONS
|
||||
|
||||
@@ -17,7 +17,7 @@ proc-macro2 = "^1.0.63"
|
||||
quote = "^1.0.26"
|
||||
syn = { version = "2", features = ["full"] }
|
||||
convert_case = "^0.6.0"
|
||||
server_fn_macro = "^0.4.6"
|
||||
server_fn_macro = "^0.5.2"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
@@ -294,7 +294,7 @@ pub fn virtual_event_from_websys_event(event: web_sys::Event, target: Element) -
|
||||
"select" => Rc::new(SelectionData {}),
|
||||
"touchcancel" | "touchend" | "touchmove" | "touchstart" => Rc::new(TouchData::from(event)),
|
||||
|
||||
"scroll" => Rc::new(()),
|
||||
"scroll" => Rc::new(ScrollData {}),
|
||||
"wheel" => Rc::new(WheelData::from(event)),
|
||||
"animationstart" | "animationend" | "animationiteration" => {
|
||||
Rc::new(AnimationData::from(event))
|
||||
|
||||
Reference in new issue
Block a user