@@ -19,23 +19,27 @@ import SwiftUI
1919/// A drop-in replacement `Button` that executes an async action and shows a busy label when in progress.
2020///
2121/// - Parameters:
22- /// - action: The async action to execute.
22+ /// - action: The async action to execute (can be throwing) .
2323/// - label: The label to show when not busy.
2424/// - busyLabel: The label to show when busy. Defaults to an empty view.
25+ /// - onError: Optional closure to handle errors thrown by the action.
2526public struct AsyncButton < Label: View , BusyLabel: View > : View {
26- private let action : ( ) async -> Void
27+ private let action : ( ) async throws -> Void
28+ private let onError : ( ( Error ) -> Void ) ?
2729
2830 @ViewBuilder private let label : Label
2931 @ViewBuilder private let busyLabel : BusyLabel
3032
3133 @State private var isBusy = false
3234
3335 public init (
34- action: @escaping ( ) async -> Void ,
36+ action: @escaping ( ) async throws -> Void ,
3537 @ViewBuilder label: ( ) -> Label ,
36- @ViewBuilder busyLabel: ( ) -> BusyLabel = EmptyView . init
38+ @ViewBuilder busyLabel: ( ) -> BusyLabel = EmptyView . init,
39+ onError: ( ( Error ) -> Void ) ? = nil
3740 ) {
3841 self . action = action
42+ self . onError = onError
3943 self . label = label ( )
4044 self . busyLabel = busyLabel ( )
4145 }
@@ -44,7 +48,11 @@ public struct AsyncButton<Label: View, BusyLabel: View>: View {
4448 Button {
4549 isBusy = true
4650 Task {
47- await action ( )
51+ do {
52+ try await action ( )
53+ } catch {
54+ onError ? ( error)
55+ }
4856 isBusy = false
4957 }
5058 } label: {
0 commit comments