import SwiftUI extension EnvironmentValues { /// Set on a list shown as a `NavigationSplitView` sidebar: what it /// selects opens in the detail column's stack. Nil in a plain stack. @Entry var sidebarSelection: Binding? /// Appends a route to the enclosing stack's path. Screens that push /// from a button use it instead of `navigationDestination(item:)`, /// which puts any later value-link push underneath the pushed screen. @Entry var pushRoute: (any Hashable) -> Void = { _ in } } extension View { /// Lets screens in this stack push onto `path` with `pushRoute`. func pushesRoutes(into path: Binding) -> some View { environment(\.pushRoute) { path.wrappedValue.append($0) } } } /// A `List` whose rows select into `sidebarSelection` when there is one. /// A value-based link in a sidebar only reaches the detail column's stack /// through the list's selection. struct RoutingList: View { @ViewBuilder let content: () -> Content @Environment(\.sidebarSelection) private var selection var body: some View { if let selection { List(selection: selection) { content() } } else { List { content() } } } } /// A `NavigationLink` in a stack; in a sidebar, a button that opens the /// route in the detail column. For links outside the list, such as /// toolbar items, which the list's selection does not cover. struct RouteLink: View { let value: Value @ViewBuilder let label: () -> Label @Environment(\.sidebarSelection) private var selection var body: some View { if let selection { Button { selection.wrappedValue = AnyHashable(value) } label: { label() } } else { NavigationLink(value: value) { label() } } } }