Skip to content

Commit

Permalink
Split lifecycle
Browse files Browse the repository at this point in the history
  • Loading branch information
TimLariviere committed Jun 30, 2024
1 parent 6eaa99a commit fbc9b1f
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 67 deletions.
66 changes: 66 additions & 0 deletions src/Fabulous/Attributes.Components.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,72 @@ open Fabulous
open Fabulous.ScalarAttributeDefinitions

module ComponentAttributes =
/// Define an attribute storing a collection of Widget for a List<T> property
let inline defineListWidgetCollection<'itemType> name ([<InlineIfLambda>] 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<Widget> 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 ([<InlineIfLambda>] getEvent: obj -> IEvent<EventHandler, EventArgs>) : SimpleScalarAttributeDefinition<unit -> unit> =
let key =
Expand Down
66 changes: 66 additions & 0 deletions src/Fabulous/Attributes.Mvu.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,72 @@ type SimpleScalarAttributeDefinitionExtensions() =

module MvuAttributes =

/// Define an attribute storing a collection of Widget for a List<T> property
let inline defineListWidgetCollection<'itemType> name ([<InlineIfLambda>] 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<Widget> 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 ([<InlineIfLambda>] getEvent: obj -> IEvent<EventHandler, EventArgs>) : SimpleScalarAttributeDefinition<MsgValue> =
let key =
Expand Down
66 changes: 0 additions & 66 deletions src/Fabulous/Attributes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -197,72 +197,6 @@ module Attributes =

defineWidget name applyDiff updateNode

/// Define an attribute storing a collection of Widget for a List<T> property
let inline defineListWidgetCollection<'itemType> name ([<InlineIfLambda>] 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<Widget> 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
Expand Down
16 changes: 15 additions & 1 deletion src/Fabulous/Lifecycle.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace Fabulous

open Fabulous.ScalarAttributeDefinitions

module Lifecycle =
module MvuLifecycle =
let inline private createAttribute name : SimpleScalarAttributeDefinition<obj> =
let key =
SimpleScalarAttributeDefinition.CreateAttributeData((fun _ _ -> ScalarAttributeComparison.Identical), (fun _oldValueOpt _newValueOpt _node -> ()))
Expand All @@ -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 -> 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"

0 comments on commit fbc9b1f

Please sign in to comment.