diff --git a/CHANGELOG.md b/CHANGELOG.md index 41102f73e..1a803b317 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 _No unreleased changes_ +## [2.5.0-pre5] - 2024-01-20 + +### Added +- Add support for Component in frameworks requiring AttachView (like Fabulous.Avalonia) by @TimLariviere (https://github.com/fabulous-dev/Fabulous/pull/1059) + ## [2.5.0-pre4] - 2024-01-18 ### Changed @@ -70,7 +75,8 @@ _No unreleased changes_ ### Changed - Fabulous.XamarinForms & Fabulous.MauiControls have been moved been out of the Fabulous repository. Find them in their own repositories: [https://github.com/fabulous-dev/Fabulous.XamarinForms](https://github.com/fabulous-dev/Fabulous.XamarinForms) / [https://github.com/fabulous-dev/Fabulous.MauiControls](https://github.com/fabulous-dev/Fabulous.MauiControls) -[unreleased]: https://github.com/fabulous-dev/Fabulous/compare/2.5.0-pre4...HEAD +[unreleased]: https://github.com/fabulous-dev/Fabulous/compare/2.5.0-pre5...HEAD +[2.5.0-pre5]: https://github.com/fabulous-dev/Fabulous/releases/tag/2.5.0-pre5 [2.5.0-pre4]: https://github.com/fabulous-dev/Fabulous/releases/tag/2.5.0-pre4 [2.5.0-pre3]: https://github.com/fabulous-dev/Fabulous/releases/tag/2.5.0-pre3 [2.5.0-pre2]: https://github.com/fabulous-dev/Fabulous/releases/tag/2.5.0-pre2 diff --git a/src/Fabulous/Component.fs b/src/Fabulous/Component.fs index 3780bb7d0..cfb5ee574 100644 --- a/src/Fabulous/Component.fs +++ b/src/Fabulous/Component.fs @@ -281,6 +281,32 @@ type Component(treeContext: ViewTreeContext, body: ComponentBody, context: Compo struct (node, view) + member this.AttachView(componentWidget: Widget, view: obj) = + let struct (context, rootWidget) = _body.Invoke(_context) + _widget <- rootWidget + _context <- context + + let struct (scalars, widgets, widgetColls) = + this.MergeAttributes(rootWidget, ValueSome componentWidget) + + let rootWidget: Widget = + { Key = rootWidget.Key +#if DEBUG + DebugName = rootWidget.DebugName +#endif + ScalarAttributes = scalars + WidgetAttributes = widgets + WidgetCollectionAttributes = widgetColls } + + // Attach the widget to the existing view + let widgetDef = WidgetDefinitionStore.get rootWidget.Key + let node = widgetDef.AttachView(rootWidget, treeContext, ValueNone, view) + + _view <- view + _contextSubscription <- _context.RenderNeeded.Subscribe(this.Render) + + node + member this.Render() = let prevRootWidget = _widget let prevContext = _context @@ -304,7 +330,6 @@ module Component = { Key = key Name = "Component" TargetType = typeof - AttachView = fun _ -> failwith "Component widget cannot be attached" CreateView = fun (widget, treeContext, _) -> match widget.ScalarAttributes with @@ -321,7 +346,24 @@ module Component = // TODO: Attach component to view so component is not discarded by GC - struct (node, view) } + struct (node, view) + AttachView = + fun (widget, treeContext, _, view) -> + match widget.ScalarAttributes with + | ValueNone -> failwith "Component widget must have a body" + | ValueSome attrs -> + let data = + match Array.tryHead attrs with + | Some attr -> attr.Value :?> ComponentData + | None -> failwith "Component widget must have a body" + + let ctx = ComponentContext() + let comp = new Component(treeContext, data.Body, ctx) + let node = comp.AttachView(widget, view) + + // TODO: Attach component to view so component is not discarded by GC + + node } WidgetDefinitionStore.set key definition key diff --git a/src/Fabulous/MvuComponent.fs b/src/Fabulous/MvuComponent.fs index e534649bd..d4d8fdc63 100644 --- a/src/Fabulous/MvuComponent.fs +++ b/src/Fabulous/MvuComponent.fs @@ -16,7 +16,6 @@ module MvuComponent = { Key = key Name = "MvuComponent" TargetType = typeof - AttachView = fun _ -> failwith "Component widget cannot be attached" CreateView = fun (widget, treeContext, _) -> match widget.ScalarAttributes with @@ -44,7 +43,35 @@ module MvuComponent = // TODO: Attach component to view so component is not discarded by GC - struct (node, view) } + struct (node, view) + AttachView = + fun (widget, treeContext, _, view) -> + match widget.ScalarAttributes with + | ValueNone -> failwith "Component widget must have a body" + | ValueSome attrs -> + let data = + match Array.tryHead attrs with + | Some attr -> attr.Value :?> MvuComponentData + | None -> failwith "Component widget must have a body" + + let ctx = ComponentContext(1) + + let runner = + Runner((fun () -> ctx.TryGetValue(0).Value), (fun v -> ctx.SetValue(0, v)), data.Program) + + runner.Start(data.Arg) + + // Redirect messages to runner + let treeContext = + { treeContext with + Dispatch = runner.Dispatch } + + let comp = new Component(treeContext, data.Body, ctx) + let node = comp.AttachView(widget, view) + + // TODO: Attach component to view so component is not discarded by GC + + node } WidgetDefinitionStore.set key definition key