gitbay/Views/Shared/SidebarRouting.swift

v1.10.0
gitbay-ios/gitbay/Views/Shared/SidebarRouting.swift history · blame · raw

52 lines · 1875 bytes

 1import SwiftUI
 2
 3extension EnvironmentValues {
 4    /// Set on a list shown as a `NavigationSplitView` sidebar: what it
 5    /// selects opens in the detail column's stack. Nil in a plain stack.
 6    @Entry var sidebarSelection: Binding<AnyHashable?>?
 7
 8    /// Appends a route to the enclosing stack's path. Screens that push
 9    /// from a button use it instead of `navigationDestination(item:)`,
10    /// which puts any later value-link push underneath the pushed screen.
11    @Entry var pushRoute: (any Hashable) -> Void = { _ in }
12}
13
14extension View {
15    /// Lets screens in this stack push onto `path` with `pushRoute`.
16    func pushesRoutes(into path: Binding<NavigationPath>) -> some View {
17        environment(\.pushRoute) { path.wrappedValue.append($0) }
18    }
19}
20
21/// A `List` whose rows select into `sidebarSelection` when there is one.
22/// A value-based link in a sidebar only reaches the detail column's stack
23/// through the list's selection.
24struct RoutingList<Content: View>: View {
25    @ViewBuilder let content: () -> Content
26    @Environment(\.sidebarSelection) private var selection
27
28    var body: some View {
29        if let selection {
30            List(selection: selection) { content() }
31        } else {
32            List { content() }
33        }
34    }
35}
36
37/// A `NavigationLink` in a stack; in a sidebar, a button that opens the
38/// route in the detail column. For links outside the list, such as
39/// toolbar items, which the list's selection does not cover.
40struct RouteLink<Value: Hashable, Label: View>: View {
41    let value: Value
42    @ViewBuilder let label: () -> Label
43    @Environment(\.sidebarSelection) private var selection
44
45    var body: some View {
46        if let selection {
47            Button { selection.wrappedValue = AnyHashable(value) } label: { label() }
48        } else {
49            NavigationLink(value: value) { label() }
50        }
51    }
52}