macbackend/Sources/Core/View/Alert.swift
david-swift b17f05a6a0
All checks were successful
Deploy Docs / publish (push) Successful in 3m39s
SwiftLint / SwiftLint (push) Successful in 5s
Add support for ForEach
2024-12-31 09:55:02 +01:00

162 lines
4.8 KiB
Swift

//
// Alert.swift
// MacBackend
//
// Created by david-swift on 01.12.2024.
//
import SwiftUI
/// The alert view.
public struct Alert: SwiftUIWidget {
/// The alert's title.
var title: String
/// The alert's description.
var description: String
/// Whether the alert is presented.
var isPresented: Meta.Binding<Bool>
/// The alert's actions.
var actions: [Action] = []
/// The wrapped view.
var child: Meta.AnyView
/// The wrapped views.
public var wrappedViews: [String: Meta.AnyView] {
[.mainContent: child]
}
/// Initialize the alert.
/// - Parameters:
/// - title: The alert's title.
/// - description: The alert's description.
/// - isPresented: Whether the alert is presented.
/// - child: The wrapped view.
public init(title: String, description: String, isPresented: Meta.Binding<Bool>, child: Meta.AnyView) {
self.title = title
self.description = description
self.isPresented = isPresented
self.child = child
}
/// An alert action.
enum Action {
/// A regular button.
case button(button: Button)
/// A cancel button.
case cancel(button: Button)
/// A destructive button.
case destructive(button: Button)
/// Get the SwiftUI button.
@SwiftUI.ViewBuilder var button: some SwiftUI.View {
switch self {
case let .button(button):
button.button()
case let .cancel(button):
button.button(cancel: true)
case let .destructive(button):
button.button(destructive: true)
}
}
}
/// The button.
struct Button {
/// The button's label.
var label: String
/// The button's action.
var action: () -> Void
/// Whether it is the default action.
var defaultAction: Bool
/// Get the SwiftUI button.
/// - Parameters:
/// - cancel: Whether it is the cancel action.
/// - destructive: Whether it is a destructive action.
/// - Returns: The SwiftUI view.
@SwiftUI.ViewBuilder
func button(cancel: Bool = false, destructive: Bool = false) -> some SwiftUI.View {
let button = SwiftUI.Button(
label,
role: cancel ? .cancel : (destructive ? .destructive : nil),
action: action
)
if defaultAction {
button
.keyboardShortcut(.defaultAction)
} else {
button
}
}
}
/// Get the SwiftUI view.
/// - Parameter properties: The widget data.
/// - Returns: The SwiftUI view.
public static func view(properties: Self) -> some SwiftUI.View {
MacBackendView(.mainContent)
.alert(properties.title, isPresented: properties.isPresented.swiftUI) {
SwiftUI.ForEach(Array(properties.actions.enumerated()), id: \.offset) { action in
action.element.button
}
} message: {
SwiftUI.Text(properties.description)
}
}
/// Add a button to the alert.
/// - Parameters:
/// - label: The button's label.
/// - defaultAction: Whether it is a default action.
/// - action: The handler.
/// - Returns: The alert.
public func button(
_ label: String,
default defaultAction: Bool = false,
action: @escaping () -> Void
) -> Self {
modify { alert in
alert.actions.append(.button(button: .init(label: label, action: action, defaultAction: defaultAction)))
}
}
/// Add a cancel button to the alert.
/// - Parameters:
/// - label: The button's label.
/// - defaultAction: Whether it is a default action.
/// - action: The handler.
/// - Returns: The alert.
public func cancelButton(
_ label: String,
default defaultAction: Bool = false,
action: @escaping () -> Void
) -> Self {
modify { alert in
alert.actions.append(.cancel(button: .init(label: label, action: action, defaultAction: defaultAction)))
}
}
/// Add a destructive button to the alert.
/// - Parameters:
/// - label: The button's label.
/// - defaultAction: Whether it is a default action.
/// - action: The handler.
/// - Returns: The alert.
public func destructiveButton(
_ label: String,
default defaultAction: Bool = false,
action: @escaping () -> Void
) -> Self {
modify { alert in
alert.actions
.append(.destructive(button: .init(label: label, action: action, defaultAction: defaultAction)))
}
}
}