From 5240c097a8f1a2aa43608e83c41e495c4977597b Mon Sep 17 00:00:00 2001 From: Filipe Rodrigues Date: Mon, 19 Feb 2024 08:30:18 +0000 Subject: [PATCH] `ObjectDynProp` now receives anything that implements `ToDynProp`. --- Cargo.lock | 1 + dynatos/Cargo.toml | 1 + dynatos/src/lib.rs | 2 +- dynatos/src/object_dyn_prop.rs | 119 ++++++++++++++++++++++++++++++--- examples/Cargo.lock | 1 + 5 files changed, 114 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c10217..0166ed9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,6 +38,7 @@ dependencies = [ "dynatos-context", "dynatos-html", "dynatos-reactive", + "dynatos-router", "dynatos-util", "extend", "js-sys", diff --git a/dynatos/Cargo.toml b/dynatos/Cargo.toml index 5d5b79e..0779211 100644 --- a/dynatos/Cargo.toml +++ b/dynatos/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" dynatos-context = { workspace = true } dynatos-html = { workspace = true } dynatos-reactive = { workspace = true } +dynatos-router = { workspace = true } dynatos-util = { workspace = true } duplicate = { workspace = true } diff --git a/dynatos/src/lib.rs b/dynatos/src/lib.rs index 36f5304..272485c 100644 --- a/dynatos/src/lib.rs +++ b/dynatos/src/lib.rs @@ -18,5 +18,5 @@ pub use self::{ node_dyn_text::{NodeDynText, NodeWithDynText, WithDynText}, object_attach_context::{ObjectAttachContext, ObjectWithContext}, object_attach_effect::{ObjectAttachEffect, ObjectWithEffect}, - object_dyn_prop::{ObjectDynProp, ObjectWithDynProp}, + object_dyn_prop::{ObjectDynProp, ObjectWithDynProp, ToDynProp}, }; diff --git a/dynatos/src/object_dyn_prop.rs b/dynatos/src/object_dyn_prop.rs index 5b415ab..9e40634 100644 --- a/dynatos/src/object_dyn_prop.rs +++ b/dynatos/src/object_dyn_prop.rs @@ -3,7 +3,8 @@ // Imports use { crate::ObjectAttachEffect, - dynatos_reactive::Effect, + dynatos_reactive::{Derived, Effect, Signal, SignalWith, WithDefault}, + dynatos_router::QuerySignal, dynatos_util::{ObjectRemoveProp, ObjectSetProp, TryOrReturnExt, WeakRef}, wasm_bindgen::JsValue, }; @@ -12,11 +13,10 @@ use { #[extend::ext(name = ObjectDynProp)] pub impl js_sys::Object { /// Adds a dynamic property to this object, where only the value is dynamic. - fn add_dyn_prop_value(&self, key: K, f: F) + fn add_dyn_prop_value(&self, key: K, value: V) where - F: Fn() -> Option + 'static, K: AsRef + 'static, - V: Into, + V: ToDynProp + 'static, { // The object we're attaching to // Note: It's important that we only keep a `WeakRef` to the object. @@ -30,8 +30,8 @@ pub impl js_sys::Object { let object = object.get().or_return()?; // Then get the property - let value = f(); let key = key.as_ref(); + let value = value.to_prop(); // And finally set/remove the property match value { @@ -59,13 +59,114 @@ where /// Adds a dynamic property to this object, where only the value is dynamic. /// /// Returns the object, for chaining - fn with_dyn_prop_value(self, key: K, f: F) -> Self + fn with_dyn_prop_value(self, key: K, value: V) -> Self where - F: Fn() -> Option + 'static, K: AsRef + 'static, - V: Into, + V: ToDynProp + 'static, { - self.as_ref().add_dyn_prop_value(key, f); + self.as_ref().add_dyn_prop_value(key, value); self } } + +/// Trait for values accepted by [`ObjectDynProp`]. +/// +/// This allows it to work with the following types: +/// - `impl Fn() -> N` +/// - `impl Fn() -> Option` +/// - `N` +/// - `Option` +/// Where `N` is a dyn prop. +pub trait ToDynProp { + /// Gets the current prop + fn to_prop(&self) -> Option; +} + +impl ToDynProp for F +where + F: Fn() -> T, + T: ToDynProp, +{ + fn to_prop(&self) -> Option { + self().to_prop() + } +} + +impl ToDynProp for Option +where + T: ToDynProp, +{ + fn to_prop(&self) -> Option { + self.as_ref().and_then(T::to_prop) + } +} + +// TODO: Generalize to `impl Into` +#[duplicate::duplicate_item( + Ty; + [&'_ str]; + [&'_ String]; + [bool]; + [f32]; + [f64]; + [i128]; + [i16]; + [i32]; + [i64]; + [i8]; + [isize]; + [u128]; + [u16]; + [u32]; + [u64]; + [u8]; + [usize]; +)] +impl ToDynProp for Ty { + fn to_prop(&self) -> Option { + Some(JsValue::from(*self)) + } +} + +#[duplicate::duplicate_item( + Ty; + [JsValue]; + [String]; +)] +impl ToDynProp for Ty { + fn to_prop(&self) -> Option { + Some(JsValue::from(self)) + } +} + +// TODO: Allow impl for `impl SignalGet` +#[duplicate::duplicate_item( + Sig; + [Signal]; + [Derived]; +)] +impl ToDynProp for Sig +where + T: ToDynProp, +{ + fn to_prop(&self) -> Option { + self.with(|prop| prop.to_prop()) + } +} +impl ToDynProp for QuerySignal +where + T: ToDynProp, +{ + fn to_prop(&self) -> Option { + self.with(|prop| prop.to_prop()) + } +} +impl ToDynProp for WithDefault +where + S: SignalWith>, + T: ToDynProp, +{ + fn to_prop(&self) -> Option { + self.with(|prop| prop.to_prop()) + } +} diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 9304b7c..62580ec 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -66,6 +66,7 @@ dependencies = [ "dynatos-context", "dynatos-html", "dynatos-reactive", + "dynatos-router", "dynatos-util", "extend", "js-sys",