diff --git a/Cargo.toml b/Cargo.toml index ce06992c..6ad8a518 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,34 +1,56 @@ [workspace] -# Temporarily disabled to upgrade individual packages to Leptos 0.7. -# members = [ -# "book-examples/*/*", -# "packages/colors", -# "packages/icons/*", -# "packages/primitives/*/*", -# "packages/themes/*", -# "scripts", -# "stories/*", -# ] +# Temporarily disabled subcrates to be upgraded individually to Leptos 0.7. +# Once a crate is ready, uncomment it here. members = [ "book-examples/*/*", "packages/colors", - "packages/icons/*", - "packages/primitives/leptos/accessible-icon", - "packages/primitives/leptos/arrow", - "packages/primitives/leptos/aspect-ratio", - "packages/primitives/leptos/direction", - "packages/primitives/leptos/id", - "packages/primitives/leptos/label", - "packages/primitives/leptos/use-controllable-state", - "packages/primitives/leptos/use-escape-keydown", - "packages/primitives/leptos/use-previous", - "packages/primitives/leptos/use-size", - "packages/primitives/leptos/visually-hidden", + "packages/icons/dioxus", + "packages/icons/yew", + + # -- Leptos Primitives (commented until they're upgraded) -- + # "packages/primitives/leptos/accessible-icon", + # "packages/primitives/leptos/arrow", + # "packages/primitives/leptos/aspect-ratio", + # "packages/primitives/leptos/avatar", + # "packages/primitives/leptos/checkbox", + # "packages/primitives/leptos/collection", + "packages/primitives/leptos/compose-refs", + # "packages/primitives/leptos/direction", + # "packages/primitives/leptos/dismissable-layer", + # "packages/primitives/leptos/dropdown-menu", + # "packages/primitives/leptos/focus-guards", + # "packages/primitives/leptos/focus-scope", + # "packages/primitives/leptos/id", + # "packages/primitives/leptos/label", + # "packages/primitives/leptos/menu", + # "packages/primitives/leptos/popover", + # "packages/primitives/leptos/popper", + # "packages/primitives/leptos/portal", + # "packages/primitives/leptos/presence", + # "packages/primitives/leptos/primitive", + # "packages/primitives/leptos/progress", + # "packages/primitives/leptos/roving-focus", + # "packages/primitives/leptos/select", + # "packages/primitives/leptos/separator", + # "packages/primitives/leptos/slot", + # "packages/primitives/leptos/switch", + # "packages/primitives/leptos/tabs", + # "packages/primitives/leptos/toggle", + # "packages/primitives/leptos/use-controllable-state", + # "packages/primitives/leptos/use-escape-keydown", + # "packages/primitives/leptos/use-previous", + # "packages/primitives/leptos/use-size", + # "packages/primitives/leptos/visually-hidden", + + # -- Yew Primitives -- "packages/primitives/yew/*", + + # -- Themes, Scripts, and Stories -- "packages/themes/yew", "scripts", "stories/*", ] + resolver = "2" [workspace.package] @@ -39,14 +61,17 @@ repository = "https://github.com/RustForWeb/radix" version = "0.0.2" [workspace.dependencies] -console_log = "1.0.0" console_error_panic_hook = "0.1.7" +console_log = "1.0.0" dioxus = "0.6.1" leptos = "0.7.2" leptos_dom = "0.7.2" leptos_router = "0.7.2" leptos-node-ref = "0.0.3" +leptos-maybe-callback = "0.0.3" leptos-style = "0.0.3" +leptos-typed-fallback-show = "0.0.3" +leptos-use = "0.15.2" log = "0.4.22" send_wrapper = "0.6.0" serde = "1.0.198" @@ -58,6 +83,43 @@ yew-router = "0.18.0" yew-struct-component = "0.1.4" yew-style = "0.1.4" +# Subcrate packages (paths remain the same; you can comment out any subcrate not yet upgraded). +# We centralize shared dependencies in [workspace.dependencies] for a single source of truth, +# reducing duplication, preventing version drift, and keeping the Cargo.lock consistent. +#radix-leptos-arrow.path = "./packages/primitives/leptos/arrow" +#radix-leptos-aspect-ratio.path = "./packages/primitives/leptos/aspect-ratio" +#radix-leptos-accessible-icon.path = "./packages/primitives/leptos/accessible-icon" +#radix-leptos-avatar.path = "./packages/primitives/leptos/avatar" +#radix-leptos-checkbox.path = "./packages/primitives/leptos/checkbox" +#radix-leptos-collection.path = "./packages/primitives/leptos/collection" +radix-leptos-compose-refs.path = "./packages/primitives/leptos/compose-refs" +#radix-leptos-direction.path = "./packages/primitives/leptos/direction" +#radix-leptos-dismissable-layer.path = "./packages/primitives/leptos/dismissable-layer" +#radix-leptos-dropdown-menu.path = "./packages/primitives/leptos/dropdown-menu" +#radix-leptos-focus-guards.path = "./packages/primitives/leptos/focus-guards" +#radix-leptos-focus-scope.path = "./packages/primitives/leptos/focus-scope" +#radix-leptos-id.path = "./packages/primitives/leptos/id" +#radix-leptos-label.path = "./packages/primitives/leptos/label" +#radix-leptos-menu.path = "./packages/primitives/leptos/menu" +#radix-leptos-popper.path = "./packages/primitives/leptos/popper" +#radix-leptos-portal.path = "./packages/primitives/leptos/portal" +#radix-leptos-presence.path = "./packages/primitives/leptos/presence" +#radix-leptos-primitive.path = "./packages/primitives/leptos/primitive" +#radix-leptos-progress.path = "./packages/primitives/leptos/progress" +#radix-leptos-roving-focus.path = "./packages/primitives/leptos/roving-focus" +#radix-leptos-select.path = "./packages/primitives/leptos/select" +#radix-leptos-separator.path = "./packages/primitives/leptos/separator" +#radix-leptos-slot.path = "./packages/primitives/leptos/slot" +#radix-leptos-switch.path = "./packages/primitives/leptos/switch" +#radix-leptos-tabs.path = "./packages/primitives/leptos/tabs" +#radix-leptos-toggle.path = "./packages/primitives/leptos/toggle" +#radix-leptos-use-controllable-state.path = "./packages/primitives/leptos/use-controllable-state" +#radix-leptos-use-escape-keydown.path = "./packages/primitives/leptos/use-escape-keydown" +#radix-leptos-use-previous.path = "./packages/primitives/leptos/use-previous" +#radix-leptos-use-size.path = "./packages/primitives/leptos/use-size" +#radix-leptos-visually-hidden.path = "./packages/primitives/leptos/visually-hidden" + [patch.crates-io] yew = { git = "https://github.com/RustForWeb/yew.git", branch = "feature/use-composed-ref" } yew-router = { git = "https://github.com/RustForWeb/yew.git", branch = "feature/use-composed-ref" } +leptos-node-ref = { git = "https://github.com/geoffreygarrett/leptos-utils", branch = "feature/any-node-ref" } diff --git a/packages/primitives/leptos/compose-refs/Cargo.toml b/packages/primitives/leptos/compose-refs/Cargo.toml index e980a089..6771c149 100644 --- a/packages/primitives/leptos/compose-refs/Cargo.toml +++ b/packages/primitives/leptos/compose-refs/Cargo.toml @@ -10,3 +10,4 @@ version.workspace = true [dependencies] leptos.workspace = true +leptos-node-ref.workspace = true \ No newline at end of file diff --git a/packages/primitives/leptos/compose-refs/src/compose_refs.rs b/packages/primitives/leptos/compose-refs/src/compose_refs.rs index 2529cdf0..19a6d9ed 100644 --- a/packages/primitives/leptos/compose-refs/src/compose_refs.rs +++ b/packages/primitives/leptos/compose-refs/src/compose_refs.rs @@ -1,21 +1,255 @@ -use leptos::{html::ElementDescriptor, Effect, NodeRef}; +use leptos::{ + html::{self, ElementType}, + prelude::*, + tachys::html::node_ref::NodeRefContainer, + wasm_bindgen::JsCast, + web_sys::Element, +}; +use leptos_node_ref::prelude::*; +use std::{rc::Rc}; -fn compose_refs(refs: Vec>) -> NodeRef { - let composed_ref = NodeRef::new(); +/// A trait for composable node references that can be combined, +/// while maintaining static dispatch (tuples) and dynamic dispatch (iterables). +pub trait ComposeRefs { + /// Applies the composition to a given DOM node. + fn compose_with(&self, node: &Element); +} + +// ------------------------------------- +// 1. Static Implementations +// ------------------------------------- + +impl ComposeRefs for AnyNodeRef { + #[inline(always)] + fn compose_with(&self, node: &Element) { + >::load(*self, node); + } +} + +impl ComposeRefs for NodeRef +where + T: ElementType, + T::Output: JsCast, +{ + #[inline(always)] + fn compose_with(&self, node: &Element) { + as NodeRefContainer>::load(*self, node); + } +} + +// NOTE: See macro ahead, replaces these. These are +// left for illustration for now. +// impl ComposeRefs for (A, B) +// where +// A: ComposeRefs, +// B: ComposeRefs, +// { +// #[inline(always)] +// fn compose_with(&self, node: &Element) { +// self.0.compose_with(node); +// self.1.compose_with(node); +// } +// } + +// impl ComposeRefs for (A, B, C) +// where +// A: ComposeRefs, +// B: ComposeRefs, +// C: ComposeRefs, +// { +// #[inline(always)] +// fn compose_with(&self, node: &Element) { +// self.0.compose_with(node); +// self.1.compose_with(node); +// self.2.compose_with(node); +// } +// } + +macro_rules! impl_compose_refs_tuple { + ($($idx:tt $type:ident),+) => { + impl<$($type),+> ComposeRefs for ($($type),+) + where + $($type: ComposeRefs),+ + { + #[inline(always)] + fn compose_with(&self, node: &Element) { + $( + self.$idx.compose_with(node); + )+ + } + } + } +} + +impl_compose_refs_tuple!(0 A, 1 B); +impl_compose_refs_tuple!(0 A, 1 B, 2 C); +impl_compose_refs_tuple!(0 A, 1 B, 2 C, 3 D); +impl_compose_refs_tuple!(0 A, 1 B, 2 C, 3 D, 4 E); +impl_compose_refs_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F); + +// ------------------------------------- +// 2. Dynamic Implementations +// ------------------------------------- + +/// Implementation for arrays of any size +impl ComposeRefs for [T; N] { + fn compose_with(&self, node: &Element) { + for item in self.iter() { + item.compose_with(node); + } + } +} + +/// Implementation for slice references +impl ComposeRefs for &[T] { + fn compose_with(&self, node: &Element) { + for item in (*self).iter() { + item.compose_with(node); + } + } +} +/// Implementation for Vec +impl ComposeRefs for Vec { + fn compose_with(&self, node: &Element) { + for item in self.iter() { + item.compose_with(node); + } + } +} + +// ------------------------------------- +// 3. compose_refs + Hook +// ------------------------------------- + +/// Combines multiple node references into a single reference that, when set, +/// updates all input references to point to the same DOM node. +/// +/// - **Static**: Tuples (`(ref1, ref2, ...)`)—no heap allocation. +/// - **Dynamic**: Any iterable (`Vec`, slice, array) of references. +/// +/// # Examples +/// ```rust +/// use leptos::{html::Div, html::Button}; +/// use leptos::prelude::NodeRef; +/// use leptos_node_ref::prelude::*; +/// use radix_leptos_compose_refs::compose_refs; +/// +/// // 1) Static composition (tuples): +/// let div_ref = NodeRef::
::new(); +/// let btn_ref = NodeRef::