From ab781b7920eab50b8e744fe4499aa00f7a59901c Mon Sep 17 00:00:00 2001
From: MrGVSV <gino.valente.code@gmail.com>
Date: Thu, 3 Feb 2022 15:53:23 -0800
Subject: [PATCH] Removed need for derivative on widget props

---
 kayak_core/src/children.rs              | 31 ++++++++++++++++
 kayak_core/src/fragment.rs              | 12 ++----
 kayak_core/src/lib.rs                   | 21 ++---------
 kayak_core/src/on_event.rs              | 49 +++++++++++++++++++++++++
 kayak_core/src/vec.rs                   | 17 +++------
 kayak_core/src/widget.rs                |  6 +--
 kayak_render_macros/src/children.rs     |  8 ++--
 kayak_render_macros/src/lib.rs          |  2 +-
 kayak_render_macros/src/widget_props.rs | 40 +++++---------------
 rfcs/widget-restructure-rfc-1.md        | 20 +++++-----
 src/widgets/app.rs                      | 19 +++++-----
 src/widgets/background.rs               | 19 +++++-----
 src/widgets/button.rs                   | 19 +++++-----
 src/widgets/clip.rs                     | 15 ++++----
 src/widgets/element.rs                  | 19 +++++-----
 src/widgets/fold.rs                     | 19 +++++-----
 src/widgets/if_element.rs               | 19 +++++-----
 src/widgets/image.rs                    | 19 +++++-----
 src/widgets/inspector.rs                |  2 +-
 src/widgets/nine_patch.rs               | 19 +++++-----
 src/widgets/text.rs                     | 13 +++----
 src/widgets/text_box.rs                 | 19 +++++-----
 src/widgets/tooltip.rs                  | 30 +++++++--------
 src/widgets/window.rs                   | 19 +++++-----
 24 files changed, 237 insertions(+), 219 deletions(-)
 create mode 100644 kayak_core/src/children.rs
 create mode 100644 kayak_core/src/on_event.rs

diff --git a/kayak_core/src/children.rs b/kayak_core/src/children.rs
new file mode 100644
index 0000000..69941dc
--- /dev/null
+++ b/kayak_core/src/children.rs
@@ -0,0 +1,31 @@
+use std::fmt::{Debug, Formatter};
+use std::sync::Arc;
+use crate::{Index, KayakContextRef};
+
+type ChildrenBuilder = Arc<dyn Fn(Option<Index>, &mut KayakContextRef) + Send + Sync>;
+
+/// A container for a function that generates child widgets
+#[derive(Clone)]
+pub struct Children(ChildrenBuilder);
+
+impl Children {
+    pub fn new(builder: ChildrenBuilder) -> Self {
+        Self(builder)
+    }
+    pub fn build(&self, id: Option<Index>, context: &mut KayakContextRef) {
+        self.0(id, context);
+    }
+}
+
+impl Debug for Children {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("Children").finish()
+    }
+}
+
+impl PartialEq for Children {
+    fn eq(&self, _: &Self) -> bool {
+        // Never prevent "==" for being true because of this struct
+        true
+    }
+}
\ No newline at end of file
diff --git a/kayak_core/src/fragment.rs b/kayak_core/src/fragment.rs
index 535d528..939f18f 100644
--- a/kayak_core/src/fragment.rs
+++ b/kayak_core/src/fragment.rs
@@ -1,13 +1,9 @@
-use derivative::*;
-
 use crate::{context_ref::KayakContextRef, styles::Style, Index, Widget, WidgetProps, Children, OnEvent};
 
-#[derive(Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(Default, Debug, PartialEq, Clone)]
 pub struct FragmentProps {
     pub styles: Option<Style>,
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: crate::Children,
+    pub children: Option<crate::Children>,
 }
 
 #[derive(Default, Debug, PartialEq, Clone)]
@@ -17,7 +13,7 @@ pub struct Fragment {
 }
 
 impl WidgetProps for FragmentProps {
-    fn get_children(&self) -> Children {
+    fn get_children(&self) -> Option<Children> {
         self.children.clone()
     }
 
@@ -64,7 +60,7 @@ impl Widget for Fragment {
         let parent_id = self.get_id();
         if let Some(children) = self.props.children.take() {
             let mut context = KayakContextRef::new(&mut context.context, Some(parent_id));
-            children(Some(parent_id), &mut context);
+            children.build(Some(parent_id), &mut context);
         } else {
             return;
         }
diff --git a/kayak_core/src/lib.rs b/kayak_core/src/lib.rs
index 94f06d1..2db69fe 100644
--- a/kayak_core/src/lib.rs
+++ b/kayak_core/src/lib.rs
@@ -23,10 +23,13 @@ pub mod tree;
 mod vec;
 pub mod widget;
 pub mod widget_manager;
+mod children;
+mod on_event;
 
 use std::sync::{Arc, RwLock};
 
 pub use binding::*;
+pub use children::Children;
 pub use color::Color;
 pub use context::*;
 pub use context_ref::KayakContextRef;
@@ -38,6 +41,7 @@ pub use generational_arena::{Arena, Index};
 pub use input_event::*;
 pub use keyboard::{KeyboardEvent, KeyboardModifiers};
 pub use keys::KeyCode;
+pub use on_event::OnEvent;
 pub use resources::Resources;
 pub use tree::{Tree, WidgetTree};
 pub use vec::{VecTracker, VecTrackerProps};
@@ -50,23 +54,6 @@ pub mod derivative {
 /// Type alias for dynamic widget objects. We use [BaseWidget] so that we can be object-safe
 type BoxedWidget = Box<dyn BaseWidget>;
 
-pub type Children = Option<Arc<dyn Fn(Option<crate::Index>, &mut KayakContextRef) + Send + Sync>>;
-
-#[derive(Clone)]
-pub struct OnEvent(
-    pub  Arc<
-        RwLock<dyn FnMut(&mut crate::context::KayakContext, &mut Event) + Send + Sync + 'static>,
-    >,
-);
-
-impl OnEvent {
-    pub fn new<F: FnMut(&mut crate::context::KayakContext, &mut Event) + Send + Sync + 'static>(
-        f: F,
-    ) -> OnEvent {
-        OnEvent(Arc::new(RwLock::new(f)))
-    }
-}
-
 #[derive(Clone)]
 pub struct Handler<T = ()>(pub Arc<RwLock<dyn FnMut(T) + Send + Sync + 'static>>);
 
diff --git a/kayak_core/src/on_event.rs b/kayak_core/src/on_event.rs
new file mode 100644
index 0000000..c2fcb26
--- /dev/null
+++ b/kayak_core/src/on_event.rs
@@ -0,0 +1,49 @@
+use std::fmt::{Debug, Formatter};
+use std::sync::{Arc, RwLock};
+use crate::{Event, KayakContext};
+
+/// A container for a function that handles events
+#[derive(Clone)]
+pub struct OnEvent(
+    Arc<
+        RwLock<dyn FnMut(&mut KayakContext, &mut Event) + Send + Sync + 'static>,
+    >,
+);
+
+impl OnEvent {
+    /// Create a new event handler
+    ///
+    /// The handler should be a closure that takes the following arguments:
+    /// 1. The current context
+    /// 2. The event
+    pub fn new<F: FnMut(&mut KayakContext, &mut Event) + Send + Sync + 'static>(
+        f: F,
+    ) -> OnEvent {
+        OnEvent(Arc::new(RwLock::new(f)))
+    }
+
+    /// Call the event handler
+    ///
+    /// Returns true if the handler was successfully invoked.
+    pub fn try_call(&self, context: &mut KayakContext, event: &mut Event) -> bool {
+        if let Ok(mut on_event) = self.0.write() {
+            on_event(context, event);
+            true
+        } else {
+            false
+        }
+    }
+}
+
+impl Debug for OnEvent {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("OnEvent").finish()
+    }
+}
+
+impl PartialEq for OnEvent {
+    fn eq(&self, _: &Self) -> bool {
+        // Never prevent "==" for being true because of this struct
+        true
+    }
+}
\ No newline at end of file
diff --git a/kayak_core/src/vec.rs b/kayak_core/src/vec.rs
index f241347..b25d7e0 100644
--- a/kayak_core/src/vec.rs
+++ b/kayak_core/src/vec.rs
@@ -1,21 +1,14 @@
-use derivative::*;
-
 use crate::{context_ref::KayakContextRef, styles::Style, Index, Widget, Children, OnEvent, WidgetProps};
 
-#[derive(Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(Default, Debug, PartialEq, Clone)]
 pub struct VecTrackerProps<T> {
     pub data: Vec<T>,
-    #[derivative(Default(value = "None"))]
     pub styles: Option<Style>,
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: crate::Children,
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub on_event: Option<crate::OnEvent>,
+    pub children: Option<Children>,
+    pub on_event: Option<OnEvent>,
 }
 
-#[derive(Derivative)]
-#[derivative(Debug, PartialEq, Clone, Default)]
+#[derive(Debug, PartialEq, Clone, Default)]
 pub struct VecTracker<T> {
     pub id: Index,
     pub props: VecTrackerProps<T>,
@@ -50,7 +43,7 @@ impl<T> WidgetProps for VecTrackerProps<T>
     where
         T: Widget, {
 
-    fn get_children(&self) -> Children {
+    fn get_children(&self) -> Option<Children> {
         self.children.clone()
     }
 
diff --git a/kayak_core/src/widget.rs b/kayak_core/src/widget.rs
index 7d6bcae..e418595 100644
--- a/kayak_core/src/widget.rs
+++ b/kayak_core/src/widget.rs
@@ -60,16 +60,14 @@ pub trait Widget: std::fmt::Debug + Clone + Default + PartialEq + AsAny + Send +
     /// Send an event to this widget
     fn on_event(&mut self, context: &mut KayakContext, event: &mut Event) {
         if let Some(on_event) = self.get_props().get_on_event() {
-            if let Ok(mut on_event) = on_event.0.write() {
-                on_event(context, event);
-            }
+            on_event.try_call(context, event);
         }
     }
 }
 
 /// Trait for props passed to a widget
 pub trait WidgetProps: std::fmt::Debug + AsAny + Send + Sync {
-    fn get_children(&self) -> Children;
+    fn get_children(&self) -> Option<Children>;
     fn get_styles(&self) -> Option<Style>;
     fn get_on_event(&self) -> Option<OnEvent>;
     fn get_focusable(&self) -> Option<bool>;
diff --git a/kayak_render_macros/src/children.rs b/kayak_render_macros/src/children.rs
index baa33e1..5870e64 100644
--- a/kayak_render_macros/src/children.rs
+++ b/kayak_render_macros/src/children.rs
@@ -87,11 +87,11 @@ impl Children {
                         );
 
                         quote! {
-                            Some(std::sync::Arc::new(move |parent_id: Option<#kayak_core::Index>, context: &mut #kayak_core::KayakContextRef| {
+                            Some(#kayak_core::Children::new(std::sync::Arc::new(move |parent_id: Option<#kayak_core::Index>, context: &mut #kayak_core::KayakContextRef| {
                                 #cloned_attrs
                                 #children_builder
                                 context.commit();
-                            }))
+                            })))
                         }
                     }
                 };
@@ -149,10 +149,10 @@ impl Children {
                 }
 
                 quote! {
-                    Some(std::sync::Arc::new(move |parent_id: Option<#kayak_core::Index>, context: &mut #kayak_core::KayakContextRef| {
+                    Some(#kayak_core::Children::new(std::sync::Arc::new(move |parent_id: Option<#kayak_core::Index>, context: &mut #kayak_core::KayakContextRef| {
                         #(#output)*
                         context.commit();
-                    }))
+                    })))
                 }
             }
         }
diff --git a/kayak_render_macros/src/lib.rs b/kayak_render_macros/src/lib.rs
index 761726d..120dc86 100644
--- a/kayak_render_macros/src/lib.rs
+++ b/kayak_render_macros/src/lib.rs
@@ -75,7 +75,7 @@ pub fn widget(args: TokenStream, item: TokenStream) -> TokenStream {
     function_component::create_function_widget(f, widget_args)
 }
 
-#[proc_macro_derive(WidgetProps, attributes(props, widget_props))]
+#[proc_macro_derive(WidgetProps, attributes(prop_field))]
 #[proc_macro_error]
 pub fn derive_widget_props(item: TokenStream) -> TokenStream {
     impl_widget_props(item)
diff --git a/kayak_render_macros/src/widget_props.rs b/kayak_render_macros/src/widget_props.rs
index 46dbb2c..b223ef8 100644
--- a/kayak_render_macros/src/widget_props.rs
+++ b/kayak_render_macros/src/widget_props.rs
@@ -1,41 +1,19 @@
 use proc_macro::TokenStream;
 
-use proc_macro2::Ident;
+use proc_macro2::{Ident};
 use proc_macro_error::{emit_error, emit_warning};
 use quote::quote;
-use syn::{Data, DeriveInput, Field, Meta, NestedMeta, parse_macro_input, spanned::Spanned};
+use syn::{AttributeArgs, Data, DeriveInput, Field, Fields, ItemStruct, Meta, NestedMeta, parse_macro_input, spanned::Spanned};
+use crate::attribute::Attribute;
 
 use crate::get_core_crate;
 
-/// The ident for the props helper attribute (`#[props(Children)]`)
-const PROPS_HELPER_1: &str = "props";
-/// An alternate for the props helper attribute in case more specificity is needed to
-/// prevent conflicts with other crates (`#[widget_props(Children)]`)
-const PROPS_HELPER_2: &str = "widget_props";
+/// The ident for the props helper attribute (`#[prop_field(Children)]`)
+const PROPS_HELPER_IDENT: &str = "prop_field";
 
-
-/// Usage:
-/// ```
-/// #[props(Children)]
-/// ```
 const PROP_CHILDREN: &str = "Children";
-
-/// Usage:
-/// ```
-/// #[props(Styles)]
-/// ```
 const PROP_STYLE: &str = "Styles";
-
-/// Usage:
-/// ```
-/// #[props(OnEvent)]
-/// ```
 const PROP_ON_EVENT: &str = "OnEvent";
-
-/// Usage:
-/// ```
-/// #[props(Focusable)]
-/// ```
 const PROP_FOCUSABLE: &str = "Focusable";
 
 #[derive(Default)]
@@ -64,15 +42,15 @@ pub(crate) fn impl_widget_props(input: TokenStream) -> TokenStream {
     let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
     let output = quote! {
         impl #impl_generics #kayak_core::WidgetProps for #ident #ty_generics #where_clause {
-            fn get_children(&self) -> kayak_core::Children {
+            fn get_children(&self) -> Option<#kayak_core::Children> {
                 #children_return
             }
 
-            fn get_styles(&self) -> Option<kayak_core::styles::Style> {
+            fn get_styles(&self) -> Option<#kayak_core::styles::Style> {
                 #styles_return
             }
 
-            fn get_on_event(&self) -> Option<kayak_core::OnEvent> {
+            fn get_on_event(&self) -> Option<#kayak_core::OnEvent> {
                 #on_event_return
             }
 
@@ -126,7 +104,7 @@ fn process_field(field: Field, props: &mut PropsHelpers) {
     for attr in field.attrs {
         if let Ok(meta) = attr.parse_meta() {
             if let Meta::List(meta) = meta {
-                if !meta.path.is_ident(PROPS_HELPER_1) && !meta.path.is_ident(PROPS_HELPER_2) {
+                if !meta.path.is_ident(PROPS_HELPER_IDENT) {
                     continue;
                 }
 
diff --git a/rfcs/widget-restructure-rfc-1.md b/rfcs/widget-restructure-rfc-1.md
index f071c8c..10efd91 100644
--- a/rfcs/widget-restructure-rfc-1.md
+++ b/rfcs/widget-restructure-rfc-1.md
@@ -142,10 +142,10 @@ One additional feature for `WidgetProps` this RFC would like to propose is the a
 
 The derive macro would have some associated macros, which will be used to mark certain fields for use in the implementation. These are:
 
-* `#[props(OnEvent)]` - Used to mark a field as the `OnEvent` prop
-* `#[props(Styles)]` - Used to mark a field as the `Styles` prop
-* `#[props(Focusable)]` - Used to mark a field as the `Focusable` prop
-* `#[props(Children)]` - Used to mark a field as the `Children` prop
+* `#[prop_field(OnEvent)]` - Used to mark a field as the `OnEvent` prop
+* `#[prop_field(Styles)]` - Used to mark a field as the `Styles` prop
+* `#[prop_field(Focusable)]` - Used to mark a field as the `Focusable` prop
+* `#[prop_field(Children)]` - Used to mark a field as the `Children` prop
 
 There may be more added to this list in the future, but for now this is the main assortment.
 
@@ -158,11 +158,11 @@ Additionally, they should be allowed to be specified as `Optional`.
 ```rust
 #[derive(WidgetProps)]
 struct MyWidgetProps {
-  #[props(OnEvent)]
+  #[prop_field(OnEvent)]
   event_handler: OnEvent
-  #[props(Focusable)]
+  #[prop_field(Focusable)]
   focusable: Optional<bool>,
-  #[props(Children)]
+  #[prop_field(Children)]
   children: Children,
   // Defined without the marker attribute:
   styles: Styles,
@@ -237,11 +237,11 @@ For now though we can create our props struct and derive `WidgetProps` as explai
 #[derive(Debug, WidgetProps)]
 struct MyButtonProps {
   // Kayak Props
-  #[props(OnEvent)]
+  #[prop_field(OnEvent)]
   event_handler: Option<OnEvent>,
-  #[props(Styles)]
+  #[prop_field(Styles)]
   styles: Option<Style>,
-  #[props(Focusable)]
+  #[prop_field(Focusable)]
   focusable: bool,
   
   // Widget Props
diff --git a/src/widgets/app.rs b/src/widgets/app.rs
index bfa99d9..03216d9 100644
--- a/src/widgets/app.rs
+++ b/src/widgets/app.rs
@@ -8,19 +8,18 @@ use crate::core::{
 
 use crate::widgets::Clip;
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct AppProps {
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
-    #[props(Focusable)]
-    #[derivative(Default(value = "None"), PartialEq = "ignore")]
+    #[prop_field(Focusable)]
+
     pub focusable: Option<bool>,
 }
 
diff --git a/src/widgets/background.rs b/src/widgets/background.rs
index b43034e..be08aac 100644
--- a/src/widgets/background.rs
+++ b/src/widgets/background.rs
@@ -6,19 +6,18 @@ use crate::core::{
     widget, Children, Fragment,
 };
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct BackgroundProps {
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
-    #[props(Focusable)]
-    #[derivative(Default(value = "None"), PartialEq = "ignore")]
+    #[prop_field(Focusable)]
+
     pub focusable: Option<bool>,
 }
 
diff --git a/src/widgets/button.rs b/src/widgets/button.rs
index 02f311b..7c790d2 100644
--- a/src/widgets/button.rs
+++ b/src/widgets/button.rs
@@ -6,19 +6,18 @@ use crate::core::{
     widget, Children, Fragment,
 };
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct ButtonProps {
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
-    #[props(Focusable)]
-    #[derivative(Default(value = "Some(true)"), PartialEq = "ignore")]
+    #[prop_field(Focusable)]
+
     pub focusable: Option<bool>,
 }
 
diff --git a/src/widgets/clip.rs b/src/widgets/clip.rs
index a064606..d710339 100644
--- a/src/widgets/clip.rs
+++ b/src/widgets/clip.rs
@@ -6,16 +6,15 @@ use crate::core::{
     widget, Children, Fragment,
 };
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct ClipProps {
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
 }
 
diff --git a/src/widgets/element.rs b/src/widgets/element.rs
index 40ccd50..6d0a4ca 100644
--- a/src/widgets/element.rs
+++ b/src/widgets/element.rs
@@ -6,19 +6,18 @@ use crate::core::{
     widget, Children, Fragment,
 };
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct ElementProps {
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
-    #[props(Focusable)]
-    #[derivative(Default(value = "None"), PartialEq = "ignore")]
+    #[prop_field(Focusable)]
+
     pub focusable: Option<bool>,
 }
 
diff --git a/src/widgets/fold.rs b/src/widgets/fold.rs
index f4d99d5..c9a2b40 100644
--- a/src/widgets/fold.rs
+++ b/src/widgets/fold.rs
@@ -8,23 +8,22 @@ use crate::core::{
 
 use crate::widgets::{Background, Clip, If, Text};
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct FoldProps {
     pub label: String,
     pub open: Option<bool>,
     pub on_change: Option<Handler<bool>>,
     pub default_open: bool,
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
-    #[props(Focusable)]
-    #[derivative(Default(value = "Some(true)"), PartialEq = "ignore")]
+    #[prop_field(Focusable)]
+
     pub focusable: Option<bool>,
 }
 
diff --git a/src/widgets/if_element.rs b/src/widgets/if_element.rs
index 6997ef9..3fdb090 100644
--- a/src/widgets/if_element.rs
+++ b/src/widgets/if_element.rs
@@ -6,20 +6,19 @@ use crate::core::{
     widget, Children, Fragment,
 };
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct IfProps {
     pub condition: bool,
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
-    #[props(Focusable)]
-    #[derivative(Default(value = "None"), PartialEq = "ignore")]
+    #[prop_field(Focusable)]
+
     pub focusable: Option<bool>,
 }
 
diff --git a/src/widgets/image.rs b/src/widgets/image.rs
index 854e10d..79d421c 100644
--- a/src/widgets/image.rs
+++ b/src/widgets/image.rs
@@ -6,20 +6,19 @@ use crate::core::{
     widget, Children, Fragment,
 };
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct ImageProps {
     pub handle: u16,
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
-    #[props(Focusable)]
-    #[derivative(Default(value = "None"), PartialEq = "ignore")]
+    #[prop_field(Focusable)]
+
     pub focusable: Option<bool>,
 }
 
diff --git a/src/widgets/inspector.rs b/src/widgets/inspector.rs
index bee6cd1..2b5cb7f 100644
--- a/src/widgets/inspector.rs
+++ b/src/widgets/inspector.rs
@@ -15,7 +15,7 @@ pub enum InspectData {
 
 #[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct InspectorProps {
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
 }
 
diff --git a/src/widgets/nine_patch.rs b/src/widgets/nine_patch.rs
index 31a7c1c..830c61e 100644
--- a/src/widgets/nine_patch.rs
+++ b/src/widgets/nine_patch.rs
@@ -7,21 +7,20 @@ use crate::core::{
     widget, Children, Fragment,
 };
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct NinePatchProps {
     pub handle: u16,
     pub border: Space,
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
-    #[props(Focusable)]
-    #[derivative(Default(value = "None"), PartialEq = "ignore")]
+    #[prop_field(Focusable)]
+
     pub focusable: Option<bool>,
 }
 
diff --git a/src/widgets/text.rs b/src/widgets/text.rs
index 1a18142..b1845c5 100644
--- a/src/widgets/text.rs
+++ b/src/widgets/text.rs
@@ -9,20 +9,19 @@ use crate::core::{
     widget, Children, Fragment,
 };
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct TextProps {
     pub content: String,
     pub font: Option<String>,
     pub line_height: Option<f32>,
     pub size: f32,
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
-    #[props(Focusable)]
-    #[derivative(Default(value = "None"), PartialEq = "ignore")]
+    #[prop_field(Focusable)]
+
     pub focusable: Option<bool>,
 }
 
diff --git a/src/widgets/text_box.rs b/src/widgets/text_box.rs
index a5a2d8d..14aa3e3 100644
--- a/src/widgets/text_box.rs
+++ b/src/widgets/text_box.rs
@@ -9,22 +9,21 @@ use std::sync::{Arc, RwLock};
 
 use crate::widgets::{Background, Clip, Text};
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct TextBoxProps {
     pub value: String,
     pub on_change: Option<OnChange>,
     pub placeholder: Option<String>,
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
-    #[props(Focusable)]
-    #[derivative(Default(value = "Some(true)"), PartialEq = "ignore")]
+    #[prop_field(Focusable)]
+
     pub focusable: Option<bool>,
 }
 
diff --git a/src/widgets/tooltip.rs b/src/widgets/tooltip.rs
index 0fea0ac..ccdff94 100644
--- a/src/widgets/tooltip.rs
+++ b/src/widgets/tooltip.rs
@@ -21,34 +21,32 @@ pub struct TooltipData {
     pub visible: bool,
 }
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct TooltipProviderProps {
     pub position: (f32, f32),
     pub size: (f32, f32),
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
 }
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct TooltipConsumerProps {
     pub anchor: Option<(f32, f32)>,
     pub size: Option<(f32, f32)>,
     pub text: String,
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
 }
 
diff --git a/src/widgets/window.rs b/src/widgets/window.rs
index 84ca262..c6366e8 100644
--- a/src/widgets/window.rs
+++ b/src/widgets/window.rs
@@ -9,23 +9,22 @@ use crate::core::{
 
 use crate::widgets::{Background, Clip, Element, Text};
 
-#[derive(WidgetProps, Derivative)]
-#[derivative(Default, Debug, PartialEq, Clone)]
+#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
 pub struct WindowProps {
     pub draggable: bool,
     pub position: (f32, f32),
     pub size: (f32, f32),
     pub title: String,
-    #[props(Styles)]
+    #[prop_field(Styles)]
     pub styles: Option<Style>,
-    #[props(Children)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
-    pub children: Children,
-    #[props(OnEvent)]
-    #[derivative(Default(value = "None"), Debug = "ignore", PartialEq = "ignore")]
+    #[prop_field(Children)]
+
+    pub children: Option<Children>,
+    #[prop_field(OnEvent)]
+
     pub on_event: Option<OnEvent>,
-    #[props(Focusable)]
-    #[derivative(Default(value = "None"), PartialEq = "ignore")]
+    #[prop_field(Focusable)]
+
     pub focusable: Option<bool>,
 }
 
-- 
GitLab