david-swift 461f9070c9
Some checks failed
Deploy Docs / publish (push) Failing after 39m36s
SwiftLint / SwiftLint (push) Has been cancelled
Add support for bottom actions
2025-01-31 19:17:37 +01:00

82 lines
2.5 KiB
Swift

//
// List.swift
// MacBackend
//
// Created by david-swift on 23.11.2024.
//
import SwiftUI
/// A list widget.
public struct List<Element>: SwiftUIWidget where Element: Identifiable {
/// The elements.
var elements: [Element]
/// The selected element.
var selection: Meta.Binding<Element.ID?>
/// The content for an element.
var content: (Element) -> Body
/// The action at the bottom.
var bottomAction: ((String, Icon), () -> Void)?
/// The wrapped views.
public var wrappedViews: [String: any Meta.AnyView] {
elements.reduce(into: [:]) { partialResult, element in
partialResult["\(element.id)"] = content(element)
}
}
/// Initialize a list widget.
/// - Parameters:
/// - elements: The elements.
/// - selection: The selected element.
/// - content: The content for an element.
public init(
_ elements: [Element],
selection: Meta.Binding<Element.ID?>,
@Meta.ViewBuilder content: @escaping (Element) -> Body
) {
self.elements = elements
self.content = content
self.selection = selection
}
/// Get the SwiftUI view.
/// - Parameter properties: The widget data.
/// - Returns: The SwiftUI view.
public static func view(properties: Self) -> some SwiftUI.View {
SwiftUI.List(properties.elements, selection: properties.selection.swiftUI) { element in
MacBackendView("\(element.id)")
}
.safeAreaInset(edge: .bottom, alignment: .leading) {
if let action = properties.bottomAction {
SwiftUI.Button {
action.1()
} label: {
SwiftUI.Label {
SwiftUI.Text(action.0.0)
} icon: {
action.0.1.image
}
}
.buttonStyle(.plain)
.foregroundStyle(.secondary)
.symbolVariant(.circle)
.padding([.bottom, .leading], 7)
}
}
}
/// Add a button to the bottom of the list.
/// - Parameters:
/// - label: The button's label.
/// - icon: The button's icon.
/// - visible: Whether the button is visible.
/// - handler: The handler.
/// - Returns: The list.
public func bottomAction(_ label: String, icon: Icon, visible: Bool = true, handler: @escaping () -> Void) -> Self {
modify { $0.bottomAction = visible ? ((label, icon), handler) : nil }
}
}