101 lines
3.3 KiB
Swift
101 lines
3.3 KiB
Swift
// Copyright 2020 Tokamak contributors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
// Created by Jed Fox on 06/30/2020.
|
|
//
|
|
|
|
final class NavigationLinkDestination {
|
|
let view: AnyView
|
|
init<V: View>(_ destination: V) {
|
|
view = AnyView(destination)
|
|
}
|
|
}
|
|
|
|
public struct NavigationLink<Label, Destination>: View where Label: View, Destination: View {
|
|
@State var destination: NavigationLinkDestination
|
|
let label: Label
|
|
|
|
@EnvironmentObject var navigationContext: NavigationContext
|
|
@Environment(\._navigationLinkStyle) var style
|
|
|
|
public init(destination: Destination, @ViewBuilder label: () -> Label) {
|
|
_destination = State(wrappedValue: NavigationLinkDestination(destination))
|
|
self.label = label()
|
|
}
|
|
|
|
/// Creates an instance that presents `destination` when active.
|
|
// public init(destination: Destination, isActive: Binding<Bool>, @ViewBuilder label: () -> Label)
|
|
|
|
/// Creates an instance that presents `destination` when `selection` is set
|
|
/// to `tag`.
|
|
// public init<V>(
|
|
// destination: Destination,
|
|
// tag: V, selection: Binding<V?>,
|
|
// @ViewBuilder label: () -> Label
|
|
// ) where V : Hashable
|
|
|
|
public var body: Never {
|
|
neverBody("NavigationLink")
|
|
}
|
|
}
|
|
|
|
public extension NavigationLink where Label == Text {
|
|
/// Creates an instance that presents `destination`, with a `Text` label
|
|
/// generated from a title string.
|
|
init<S>(_ title: S, destination: Destination) where S: StringProtocol {
|
|
self.init(destination: destination) { Text(title) }
|
|
}
|
|
|
|
/// Creates an instance that presents `destination` when active, with a
|
|
/// `Text` label generated from a title string.
|
|
// public init<S>(
|
|
// _ title: S, destination: Destination,
|
|
// isActive: Binding<Bool>
|
|
// ) where S : StringProtocol
|
|
|
|
/// Creates an instance that presents `destination` when `selection` is set
|
|
/// to `tag`, with a `Text` label generated from a title string.
|
|
// public init<S, V>(
|
|
// _ title: S, destination: Destination,
|
|
// tag: V, selection: Binding<V?>
|
|
// ) where S : StringProtocol, V : Hashable
|
|
}
|
|
|
|
/// This is a helper class that works around absence of "package private" access control in Swift
|
|
public struct _NavigationLinkProxy<Label, Destination> where Label: View, Destination: View {
|
|
public let subject: NavigationLink<Label, Destination>
|
|
|
|
public init(_ subject: NavigationLink<Label, Destination>) {
|
|
self.subject = subject
|
|
}
|
|
|
|
public var label: AnyView {
|
|
subject.style.makeBody(configuration: .init(
|
|
body: AnyView(subject.label),
|
|
isSelected: isSelected
|
|
))
|
|
}
|
|
|
|
public var style: _AnyNavigationLinkStyle { subject.style }
|
|
public var isSelected: Bool {
|
|
subject.destination === subject.navigationContext.destination
|
|
}
|
|
|
|
public func activate() {
|
|
if !isSelected {
|
|
subject.navigationContext.destination = subject.destination
|
|
}
|
|
}
|
|
}
|