From fbc9b1fcdae151bdb64a8f444b03d2d8f7494aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9=20Larivi=C3=A8re?= Date: Sun, 30 Jun 2024 19:22:34 +0200 Subject: [PATCH] Split lifecycle --- src/Fabulous/Attributes.Components.fs | 66 +++++++++++++++++++++++++++ src/Fabulous/Attributes.Mvu.fs | 66 +++++++++++++++++++++++++++ src/Fabulous/Attributes.fs | 66 --------------------------- src/Fabulous/Lifecycle.fs | 16 ++++++- 4 files changed, 147 insertions(+), 67 deletions(-) diff --git a/src/Fabulous/Attributes.Components.fs b/src/Fabulous/Attributes.Components.fs index ff46d311f..16f13bc04 100644 --- a/src/Fabulous/Attributes.Components.fs +++ b/src/Fabulous/Attributes.Components.fs @@ -5,6 +5,72 @@ open Fabulous open Fabulous.ScalarAttributeDefinitions module ComponentAttributes = + /// Define an attribute storing a collection of Widget for a List property + let inline defineListWidgetCollection<'itemType> name ([] getCollection: obj -> System.Collections.Generic.IList<'itemType>) = + let applyDiff _ (diffs: WidgetCollectionItemChanges) (node: IViewNode) = + let targetColl = getCollection node.Target + + for diff in diffs do + match diff with + | WidgetCollectionItemChange.Remove(index, widget) -> + let itemNode = node.TreeContext.GetViewNode(box targetColl[index]) + + // Trigger the unmounted event + // TODO: Trigger Unmounted function for all children - Dispatcher.dispatchEventForAllChildren itemNode widget Lifecycle.Unmounted + itemNode.Dispose() + + // Remove the child from the UI tree + targetColl.RemoveAt(index) + + | _ -> () + + for diff in diffs do + match diff with + | WidgetCollectionItemChange.Insert(index, widget) -> + let struct (itemNode, view) = Helpers.createViewForWidget node widget + + // Insert the new child into the UI tree + targetColl.Insert(index, unbox view) + + // Trigger the mounted event + // TODO: Trigger Mounted function for all children - Dispatcher.dispatchEventForAllChildren itemNode widget Lifecycle.Mounted + + | WidgetCollectionItemChange.Update(index, widgetDiff) -> + let childNode = node.TreeContext.GetViewNode(box targetColl[index]) + + childNode.ApplyDiff(&widgetDiff) + + | WidgetCollectionItemChange.Replace(index, oldWidget, newWidget) -> + let prevItemNode = node.TreeContext.GetViewNode(box targetColl[index]) + + let struct (nextItemNode, view) = Helpers.createViewForWidget node newWidget + + // Trigger the unmounted event for the old child + // TODO: Trigger Unmounted function for all children - Dispatcher.dispatchEventForAllChildren prevItemNode oldWidget Lifecycle.Unmounted + prevItemNode.Dispose() + + // Replace the existing child in the UI tree at the index with the new one + targetColl[index] <- unbox view + + // Trigger the mounted event for the new child + // TODO: Trigger Mounted function for all children - Dispatcher.dispatchEventForAllChildren nextItemNode newWidget Lifecycle.Mounted + + | _ -> () + + let updateNode _ (newValueOpt: ArraySlice voption) (node: IViewNode) = + let targetColl = getCollection node.Target + targetColl.Clear() + + match newValueOpt with + | ValueNone -> () + | ValueSome widgets -> + for widget in ArraySlice.toSpan widgets do + let struct (_, view) = Helpers.createViewForWidget node widget + + targetColl.Add(unbox view) + + Attributes.defineWidgetCollection name applyDiff updateNode + /// Define an attribute for EventHandler let inline defineEventNoArg name ([] getEvent: obj -> IEvent) : SimpleScalarAttributeDefinition unit> = let key = diff --git a/src/Fabulous/Attributes.Mvu.fs b/src/Fabulous/Attributes.Mvu.fs index 972ac0a23..c7403c42c 100644 --- a/src/Fabulous/Attributes.Mvu.fs +++ b/src/Fabulous/Attributes.Mvu.fs @@ -15,6 +15,72 @@ type SimpleScalarAttributeDefinitionExtensions() = module MvuAttributes = + /// Define an attribute storing a collection of Widget for a List property + let inline defineListWidgetCollection<'itemType> name ([] getCollection: obj -> System.Collections.Generic.IList<'itemType>) = + let applyDiff _ (diffs: WidgetCollectionItemChanges) (node: IViewNode) = + let targetColl = getCollection node.Target + + for diff in diffs do + match diff with + | WidgetCollectionItemChange.Remove(index, widget) -> + let itemNode = node.TreeContext.GetViewNode(box targetColl[index]) + + // Trigger the unmounted event + Dispatcher.dispatchEventForAllChildren itemNode widget MvuLifecycle.Unmounted + itemNode.Dispose() + + // Remove the child from the UI tree + targetColl.RemoveAt(index) + + | _ -> () + + for diff in diffs do + match diff with + | WidgetCollectionItemChange.Insert(index, widget) -> + let struct (itemNode, view) = Helpers.createViewForWidget node widget + + // Insert the new child into the UI tree + targetColl.Insert(index, unbox view) + + // Trigger the mounted event + Dispatcher.dispatchEventForAllChildren itemNode widget MvuLifecycle.Mounted + + | WidgetCollectionItemChange.Update(index, widgetDiff) -> + let childNode = node.TreeContext.GetViewNode(box targetColl[index]) + + childNode.ApplyDiff(&widgetDiff) + + | WidgetCollectionItemChange.Replace(index, oldWidget, newWidget) -> + let prevItemNode = node.TreeContext.GetViewNode(box targetColl[index]) + + let struct (nextItemNode, view) = Helpers.createViewForWidget node newWidget + + // Trigger the unmounted event for the old child + Dispatcher.dispatchEventForAllChildren prevItemNode oldWidget MvuLifecycle.Unmounted + prevItemNode.Dispose() + + // Replace the existing child in the UI tree at the index with the new one + targetColl[index] <- unbox view + + // Trigger the mounted event for the new child + Dispatcher.dispatchEventForAllChildren nextItemNode newWidget MvuLifecycle.Mounted + + | _ -> () + + let updateNode _ (newValueOpt: ArraySlice voption) (node: IViewNode) = + let targetColl = getCollection node.Target + targetColl.Clear() + + match newValueOpt with + | ValueNone -> () + | ValueSome widgets -> + for widget in ArraySlice.toSpan widgets do + let struct (_, view) = Helpers.createViewForWidget node widget + + targetColl.Add(unbox view) + + Attributes.defineWidgetCollection name applyDiff updateNode + /// Define an attribute for EventHandler let inline defineEventNoArg name ([] getEvent: obj -> IEvent) : SimpleScalarAttributeDefinition = let key = diff --git a/src/Fabulous/Attributes.fs b/src/Fabulous/Attributes.fs index 5209f03ad..4374e64f3 100644 --- a/src/Fabulous/Attributes.fs +++ b/src/Fabulous/Attributes.fs @@ -197,72 +197,6 @@ module Attributes = defineWidget name applyDiff updateNode - /// Define an attribute storing a collection of Widget for a List property - let inline defineListWidgetCollection<'itemType> name ([] getCollection: obj -> System.Collections.Generic.IList<'itemType>) = - let applyDiff _ (diffs: WidgetCollectionItemChanges) (node: IViewNode) = - let targetColl = getCollection node.Target - - for diff in diffs do - match diff with - | WidgetCollectionItemChange.Remove(index, widget) -> - let itemNode = node.TreeContext.GetViewNode(box targetColl[index]) - - // Trigger the unmounted event - Dispatcher.dispatchEventForAllChildren itemNode widget Lifecycle.Unmounted - itemNode.Dispose() - - // Remove the child from the UI tree - targetColl.RemoveAt(index) - - | _ -> () - - for diff in diffs do - match diff with - | WidgetCollectionItemChange.Insert(index, widget) -> - let struct (itemNode, view) = Helpers.createViewForWidget node widget - - // Insert the new child into the UI tree - targetColl.Insert(index, unbox view) - - // Trigger the mounted event - Dispatcher.dispatchEventForAllChildren itemNode widget Lifecycle.Mounted - - | WidgetCollectionItemChange.Update(index, widgetDiff) -> - let childNode = node.TreeContext.GetViewNode(box targetColl[index]) - - childNode.ApplyDiff(&widgetDiff) - - | WidgetCollectionItemChange.Replace(index, oldWidget, newWidget) -> - let prevItemNode = node.TreeContext.GetViewNode(box targetColl[index]) - - let struct (nextItemNode, view) = Helpers.createViewForWidget node newWidget - - // Trigger the unmounted event for the old child - Dispatcher.dispatchEventForAllChildren prevItemNode oldWidget Lifecycle.Unmounted - prevItemNode.Dispose() - - // Replace the existing child in the UI tree at the index with the new one - targetColl[index] <- unbox view - - // Trigger the mounted event for the new child - Dispatcher.dispatchEventForAllChildren nextItemNode newWidget Lifecycle.Mounted - - | _ -> () - - let updateNode _ (newValueOpt: ArraySlice voption) (node: IViewNode) = - let targetColl = getCollection node.Target - targetColl.Clear() - - match newValueOpt with - | ValueNone -> () - | ValueSome widgets -> - for widget in ArraySlice.toSpan widgets do - let struct (_, view) = Helpers.createViewForWidget node widget - - targetColl.Add(unbox view) - - defineWidgetCollection name applyDiff updateNode - /// Define an attribute for a value supporting equality comparison let inline defineSimpleScalarWithEquality<'T when 'T: equality> name diff --git a/src/Fabulous/Lifecycle.fs b/src/Fabulous/Lifecycle.fs index 64d1092e0..d9c2ab131 100644 --- a/src/Fabulous/Lifecycle.fs +++ b/src/Fabulous/Lifecycle.fs @@ -2,7 +2,7 @@ namespace Fabulous open Fabulous.ScalarAttributeDefinitions -module Lifecycle = +module MvuLifecycle = let inline private createAttribute name : SimpleScalarAttributeDefinition = let key = SimpleScalarAttributeDefinition.CreateAttributeData((fun _ _ -> ScalarAttributeComparison.Identical), (fun _oldValueOpt _newValueOpt _node -> ())) @@ -15,3 +15,17 @@ module Lifecycle = /// Store an event that will be triggered when a Widget has been unmounted from the UI tree let Unmounted = createAttribute "Unmounted" + +module ComponentLifecycle = + let inline private createAttribute name : SimpleScalarAttributeDefinition unit> = + let key = + SimpleScalarAttributeDefinition.CreateAttributeData((fun _ _ -> ScalarAttributeComparison.Identical), (fun _oldValueOpt _newValueOpt _node -> ())) + |> AttributeDefinitionStore.registerScalar + + { Key = key; Name = name } + + /// Store an event that will be triggered when a Widget has been mounted in the UI tree + let Mounted = createAttribute "Mounted" + + /// Store an event that will be triggered when a Widget has been unmounted from the UI tree + let Unmounted = createAttribute "Unmounted" \ No newline at end of file