Last active
October 22, 2024 09:22
-
-
Save magnuskahr/1c89ade86410577a2719020f01fcfdf5 to your computer and use it in GitHub Desktop.
Cascading Action system for SwiftUI. Read more about it here: http://www.magnuskahr.dk/posts/2021/12/cascading-environment-actions-in-swiftui/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
extension View { | |
func cascadingAction<ActionInput>(path: CascadingActionNodeModifier<ActionInput>.Path, handler: @escaping (ActionInput) -> Void) -> some View { | |
self.modifier(CascadingActionNodeModifier(path: path, handler: handler)) | |
} | |
func cascadingAction(path: CascadingActionNodeModifier<Void>.Path, handler: @escaping () -> Void) -> some View { | |
self.modifier(CascadingActionNodeModifier(path: path, handler: handler)) | |
} | |
} | |
struct CascadingActionNodeModifier<ActionInput>: ViewModifier { | |
typealias Path = WritableKeyPath<EnvironmentValues, CascadingAction<ActionInput>> | |
@Environment private var parent: CascadingAction<ActionInput> | |
let handler: (ActionInput) -> Void | |
let path: Path | |
init(path: Path, handler: @escaping (ActionInput) -> Void) { | |
self._parent = Environment(path) | |
self.handler = handler | |
self.path = path | |
} | |
func body(content: Content) -> some View { | |
content.environment(path, node) | |
} | |
private var node: CascadingAction<ActionInput> { | |
.node(parent: parent, action: handler) | |
} | |
} | |
indirect enum CascadingAction<Input> { | |
typealias Action = (Input) -> Void | |
case root | |
case node(parent: Self, action: Action) | |
func callAsFunction(_ input: Input) { | |
if case let .node(parent, action) = self { | |
action(input) | |
parent(input) | |
} | |
} | |
} | |
extension CascadingAction where Input == Void { | |
func callAsFunction() { | |
self.callAsFunction(_: ()) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment