macbackend/Sources/Core/View/NavigationStack.swift
david-swift 8391997848
Some checks failed
Deploy Docs / publish (push) Failing after 0s
SwiftLint / SwiftLint (push) Failing after 1s
Add navigation stack
2024-12-15 21:26:38 +01:00

121 lines
3.3 KiB
Swift

//
// NavigationStack.swift
// MacBackend
//
// Created by david-swift on 14.12.2024.
//
import SwiftUI
/// The navigation stack view.
public struct NavigationStack<Component>: SwiftUIWidget where Component: CustomStringConvertible {
/// The current navigation path.
@Meta.Binding var path: NavigationPath
/// The content.
var content: (Component) -> Body
/// The initial view.
var initialView: Body
/// The wrapped views.
public var wrappedViews: [String: Meta.AnyView] {
if let current = path.current {
_ = current
return [.mainContent: initialView, current.description: content(current)]
} else {
return [.mainContent: initialView]
}
}
/// Initialize the navigation stack.
/// - Parameters:
/// - path: The path.
/// - content: The content.
/// - initialView: The initial view.
public init(
path: Meta.Binding<NavigationPath>,
@Meta.ViewBuilder content: @escaping (Component) -> Body,
@Meta.ViewBuilder initialView: () -> Body
) {
self._path = path
self.content = content
self.initialView = initialView()
}
/// The navigation path.
public struct NavigationPath {
/// The path.
var path: [Component] = []
/// The current component.
var current: Component? { path.last }
/// The path as an array of strings.
var hashable: [String] {
get {
path.map { $0.description }
}
set {
if newValue.count < hashable.count {
_ = path.popLast()
}
}
}
/// Initialize a navigation stack.
public init() { }
/// Pop the last element.
public mutating func pop() {
_ = path.popLast()
}
/// Add a new element.
/// - Parameter component: The element.
public mutating func push(_ component: Component) {
path.append(component)
}
}
/// Receive the SwiftUI view.
/// - Parameter properties: The properties.
/// - Returns: The SwiftUI view.
public static func view(properties: Self) -> some SwiftUI.View {
SwiftUINavigationStack(path: properties.$path.swiftUI)
}
}
/// The SwiftUI navigation stack.
struct SwiftUINavigationStack<Component>: SwiftUI.View where Component: CustomStringConvertible {
/// The path.
@SwiftUI.Binding var path: NavigationPath<Component>
/// The views.
@SwiftUI.Environment(\.views)
var views
/// The view's body.
var body: some SwiftUI.View {
SwiftUI.NavigationStack(path: $path.hashable) {
let view = MacBackendView(.mainContent)
if path.current != nil {
view
.navigationDestination(for: String.self) { string in
SwiftUI.VStack {
MacBackendView(string)
.environment(\.views, views)
}
}
} else {
view
}
}
}
}
/// The navigation path.
public typealias NavigationPath<Component: CustomStringConvertible> = NavigationStack<Component>.NavigationPath