extension View { /// Adds an action to perform when the user's pointer enters/leaves this /// view. /// /// - Parameter action: The action to perform when the hover state changes. /// Receives a `Bool` parameter indicated whether the pointer entered or /// left the view. public func onHover( perform action: @escaping (_ hovering: Bool) -> Void ) -> some View { OnHoverModifier(body: TupleView1(self), action: action) } } struct OnHoverModifier: TypeSafeView { typealias Children = TupleView1.Children var body: TupleView1 var action: (Bool) -> Void func children( backend: Backend, snapshots: [ViewGraphSnapshotter.NodeSnapshot]?, environment: EnvironmentValues ) -> Children { body.children( backend: backend, snapshots: snapshots, environment: environment ) } func asWidget( _ children: Children, backend: Backend ) -> Backend.Widget { func castBackend_inner(_ backend: NewBackend) -> NewBackend.Widget { return backend.createHoverTarget(wrapping: children.child0.widget.into()) } guard let castedBackend = backend as? any (BaseAppBackend & BackendFeatures.HoverGestures) else { fatalError("Backend does not implement BackendFeatures.HoverGestures") } return castBackend_inner(castedBackend) as! Backend.Widget } func computeLayout( _ widget: Backend.Widget, children: Children, proposedSize: ProposedViewSize, environment: EnvironmentValues, backend: Backend ) -> ViewLayoutResult { children.child0.computeLayout( with: body.view0, proposedSize: proposedSize, environment: environment ) } func commit( _ widget: Backend.Widget, children: Children, layout: ViewLayoutResult, environment: EnvironmentValues, backend: Backend ) { func castBackend_inner(_ backend: NewBackend) { let widget = widget as! NewBackend.Widget let size = children.child0.commit().size.vector backend.setSize(of: widget, to: size) backend.updateHoverTarget( widget, environment: environment, action: action ) } guard let castedBackend = backend as? any (BaseAppBackend & BackendFeatures.HoverGestures) else { fatalError("Backend does not implement BackendFeatures.HoverGestures") } castBackend_inner(castedBackend) } }