Add _NavigationLinkStyle for sidebar lists
This commit is contained in:
parent
4b05fd8523
commit
cb6359431d
|
@ -79,8 +79,49 @@ public extension ForEach where Data == Range<Int>, ID == Int {
|
|||
|
||||
extension ForEach: ParentView {
|
||||
public var children: [AnyView] {
|
||||
data.map { AnyView(content($0)) }
|
||||
data.map { AnyView(IDView(content($0), id: $0[keyPath: id])) }
|
||||
}
|
||||
}
|
||||
|
||||
extension ForEach: GroupView {}
|
||||
|
||||
struct _IDKey: EnvironmentKey {
|
||||
static let defaultValue: AnyHashable? = nil
|
||||
}
|
||||
|
||||
extension EnvironmentValues {
|
||||
public var _id: AnyHashable? {
|
||||
get {
|
||||
self[_IDKey.self]
|
||||
}
|
||||
set {
|
||||
self[_IDKey.self] = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public protocol _AnyIDView {
|
||||
var anyId: AnyHashable { get }
|
||||
}
|
||||
|
||||
struct IDView<Content, ID>: View, _AnyIDView where Content: View, ID: Hashable {
|
||||
let content: Content
|
||||
let id: ID
|
||||
var anyId: AnyHashable { AnyHashable(id) }
|
||||
|
||||
init(_ content: Content, id: ID) {
|
||||
self.content = content
|
||||
self.id = id
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
content
|
||||
.environment(\._id, AnyHashable(id))
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
public func id<ID>(_ id: ID) -> some View where ID: Hashable {
|
||||
IDView(self, id: id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,24 @@
|
|||
// Created by Jed Fox on 06/30/2020.
|
||||
//
|
||||
|
||||
import OpenCombine
|
||||
|
||||
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 {
|
||||
let destination: Destination
|
||||
@State var destination: NavigationLinkDestination
|
||||
let label: Label
|
||||
|
||||
@Environment(\.navigationDestination) var navigationContext
|
||||
@EnvironmentObject var navigationContext: NavigationContext
|
||||
@Environment(\._navigationLinkStyle) var style
|
||||
|
||||
public init(destination: Destination, @ViewBuilder label: () -> Label) {
|
||||
self.destination = destination
|
||||
_destination = State(wrappedValue: NavigationLinkDestination(destination))
|
||||
self.label = label()
|
||||
}
|
||||
|
||||
|
@ -69,7 +78,9 @@ extension NavigationLink where Label == Text {
|
|||
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 init(_ subject: NavigationLink<Label, Destination>) {
|
||||
self.subject = subject
|
||||
}
|
||||
|
||||
public var label: AnyView {
|
||||
subject.style.makeBody(configuration: .init(body: AnyView(subject.label),
|
||||
|
@ -78,10 +89,10 @@ public struct _NavigationLinkProxy<Label, Destination> where Label: View, Destin
|
|||
|
||||
public var style: _AnyNavigationLinkStyle { subject.style }
|
||||
public var isSelected: Bool {
|
||||
true
|
||||
ObjectIdentifier(subject.destination) == ObjectIdentifier(subject.navigationContext.destination)
|
||||
}
|
||||
|
||||
public func activate() {
|
||||
subject.navigationContext!.wrappedValue = AnyView(subject.destination)
|
||||
subject.navigationContext.destination = subject.destination
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,14 @@
|
|||
// Created by Jed Fox on 06/30/2020.
|
||||
//
|
||||
|
||||
final class NavigationContext: ObservableObject {
|
||||
@Published var destination = NavigationLinkDestination(EmptyView())
|
||||
}
|
||||
|
||||
public struct NavigationView<Content>: View where Content: View {
|
||||
let content: Content
|
||||
|
||||
@State var destination = AnyView(EmptyView())
|
||||
@ObservedObject var context = NavigationContext()
|
||||
|
||||
public init(@ViewBuilder content: () -> Content) {
|
||||
self.content = content()
|
||||
|
@ -39,8 +43,9 @@ public struct _NavigationViewProxy<Content: View>: View {
|
|||
public var body: some View {
|
||||
HStack {
|
||||
content
|
||||
subject.destination
|
||||
}.environment(\.navigationDestination, subject.$destination)
|
||||
subject.context.destination.view
|
||||
}
|
||||
.environmentObject(subject.context)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,17 @@
|
|||
import TokamakCore
|
||||
|
||||
private extension DOMViewModifier {
|
||||
func unwrapToStyle<T>(_ key: KeyPath<Self, T?>, property: String) -> String {
|
||||
func unwrapToStyle<T>(_ key: KeyPath<Self, T?>,
|
||||
property: String? = nil,
|
||||
defaultValue: String = "") -> String {
|
||||
if let val = self[keyPath: key] {
|
||||
if let property = property {
|
||||
return "\(property): \(val)px;"
|
||||
} else {
|
||||
return ""
|
||||
return "\(val)px;"
|
||||
}
|
||||
} else {
|
||||
return defaultValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,12 +46,14 @@ extension _FrameLayout: DOMViewModifier {
|
|||
|
||||
extension _FlexFrameLayout: DOMViewModifier {
|
||||
public var attributes: [String: String] {
|
||||
["style": """
|
||||
let flexibleWidth = minWidth == 0 && maxWidth == .infinity
|
||||
let flexibleHeight = minHeight == 0 && maxHeight == .infinity
|
||||
return ["style": """
|
||||
\(unwrapToStyle(\.minWidth, property: "min-width"))
|
||||
\(unwrapToStyle(\.idealWidth, property: "width"))
|
||||
width: \(unwrapToStyle(\.idealWidth, defaultValue: flexibleWidth ? "100%" : "auto"));
|
||||
\(unwrapToStyle(\.maxWidth, property: "max-width"))
|
||||
\(unwrapToStyle(\.minHeight, property: "min-height"))
|
||||
\(unwrapToStyle(\.idealHeight, property: "height"))
|
||||
height: \(unwrapToStyle(\.idealHeight, defaultValue: flexibleHeight ? "100%" : "auto"));
|
||||
\(unwrapToStyle(\.maxHeight, property: "max-height"))
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
|
|
@ -91,7 +91,7 @@ extension InsetGroupedListStyle: ListStyleDeferredToRenderer {
|
|||
|
||||
extension SidebarListStyle: ListStyleDeferredToRenderer {
|
||||
public func listRow<Row>(_ row: Row) -> AnyView where Row: View {
|
||||
AnyView(row)
|
||||
AnyView(row.frame(minWidth: 0, maxWidth: .infinity))
|
||||
}
|
||||
|
||||
public func listBody<ListBody>(_ content: ListBody) -> AnyView where ListBody: View {
|
||||
|
|
Loading…
Reference in New Issue