OnHoverModifier.swift 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. extension View {
  2. /// Adds an action to perform when the user's pointer enters/leaves this
  3. /// view.
  4. ///
  5. /// - Parameter action: The action to perform when the hover state changes.
  6. /// Receives a `Bool` parameter indicated whether the pointer entered or
  7. /// left the view.
  8. public func onHover(
  9. perform action: @escaping (_ hovering: Bool) -> Void
  10. ) -> some View {
  11. OnHoverModifier(body: TupleView1(self), action: action)
  12. }
  13. }
  14. struct OnHoverModifier<Content: View>: TypeSafeView {
  15. typealias Children = TupleView1<Content>.Children
  16. var body: TupleView1<Content>
  17. var action: (Bool) -> Void
  18. func children<Backend: BaseAppBackend>(
  19. backend: Backend,
  20. snapshots: [ViewGraphSnapshotter.NodeSnapshot]?,
  21. environment: EnvironmentValues
  22. ) -> Children {
  23. body.children(
  24. backend: backend,
  25. snapshots: snapshots,
  26. environment: environment
  27. )
  28. }
  29. func asWidget<Backend: BaseAppBackend>(
  30. _ children: Children,
  31. backend: Backend
  32. ) -> Backend.Widget {
  33. func castBackend_inner<NewBackend: BaseAppBackend & BackendFeatures.HoverGestures>(_ backend: NewBackend) -> NewBackend.Widget {
  34. return backend.createHoverTarget(wrapping: children.child0.widget.into())
  35. }
  36. guard let castedBackend = backend as? any (BaseAppBackend & BackendFeatures.HoverGestures) else {
  37. fatalError("Backend does not implement BackendFeatures.HoverGestures")
  38. }
  39. return castBackend_inner(castedBackend) as! Backend.Widget
  40. }
  41. func computeLayout<Backend: BaseAppBackend>(
  42. _ widget: Backend.Widget,
  43. children: Children,
  44. proposedSize: ProposedViewSize,
  45. environment: EnvironmentValues,
  46. backend: Backend
  47. ) -> ViewLayoutResult {
  48. children.child0.computeLayout(
  49. with: body.view0,
  50. proposedSize: proposedSize,
  51. environment: environment
  52. )
  53. }
  54. func commit<Backend: BaseAppBackend>(
  55. _ widget: Backend.Widget,
  56. children: Children,
  57. layout: ViewLayoutResult,
  58. environment: EnvironmentValues,
  59. backend: Backend
  60. ) {
  61. func castBackend_inner<NewBackend: BaseAppBackend & BackendFeatures.HoverGestures>(_ backend: NewBackend) {
  62. let widget = widget as! NewBackend.Widget
  63. let size = children.child0.commit().size.vector
  64. backend.setSize(of: widget, to: size)
  65. backend.updateHoverTarget(
  66. widget,
  67. environment: environment,
  68. action: action
  69. )
  70. }
  71. guard let castedBackend = backend as? any (BaseAppBackend & BackendFeatures.HoverGestures) else {
  72. fatalError("Backend does not implement BackendFeatures.HoverGestures")
  73. }
  74. castBackend_inner(castedBackend)
  75. }
  76. }