Skip to content

Commit

Permalink
Initial NavigationView implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
j-f1 committed Jun 30, 2020
1 parent 5439933 commit 93456b1
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 21 deletions.
90 changes: 90 additions & 0 deletions Sources/TokamakCore/Views/Navigation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// 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.
//

public struct NavigationView<Content>: View where Content: View {
let content: Content

@State public var selectedId: Double?

public init(@ViewBuilder content: () -> Content) {
self.content = content()
}

public var body: Never {
neverBody("NavigationView")
}
}

public struct NavigationLink<Label, Destination>: View where Label: View, Destination: View {
let destination: Destination
let label: Label

public init(destination: Destination, @ViewBuilder label: () -> Label) {
self.destination = 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")
}
}

extension NavigationLink where Label == Text {
/// Creates an instance that presents `destination`, with a `Text` label
/// generated from a title string.
public init<S>(_ title: S, destination: Destination) where S: StringProtocol {
self.destination = destination
label = 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
}

public func navigationViewContent<Content>(
_ navigationView: NavigationView<Content>
) -> Content {
navigationView.content
}

public func navigationLinkContent<Label, Destination>(
_ navigationLink: NavigationLink<Label, Destination>
) -> Label {
navigationLink.label
}
56 changes: 56 additions & 0 deletions Sources/TokamakDOM/Views/Navigation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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.

import JavaScriptKit
import TokamakCore

public typealias NavigationView = TokamakCore.NavigationView
public typealias NavigationLink = TokamakCore.NavigationLink

extension NavigationView: ViewDeferredToRenderer {
public var deferredBody: AnyView {
AnyView(HTML("div", [
"style": """
display: flex; flex-direction: row; align-items: stretch;
width: 100%; height: 100%;
""",
], listeners: [
"navlink:click": { event in
if let id = event.detail.object?.id.number {
selectedId = id
}
},
]) {
Text("\(selectedId)")
navigationViewContent(self)
})
}
}

extension NavigationLink: ViewDeferredToRenderer {
public var deferredBody: AnyView {
AnyView(HTML("div", listeners: [
"click": { event in
if let customEvent = JSObjectRef.global.CustomEvent.function?.new(
"navlink:click", [
"bubbles": true,
"detail": ["id": 42],
]
), let dispatch = event.target.object?.dispatchEvent.function {
_ = dispatch.apply(this: event.target.object!, arguments: customEvent)
}
},
]) { navigationLinkContent(self) })
}
}
10 changes: 7 additions & 3 deletions Sources/TokamakDemo/SpacerDemo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ import TokamakDOM

struct SpacerDemo: View {
var body: some View {
HStack {
Text("Left side.")
VStack {
HStack {
Text("Left side.")
Spacer()
Text("Right side.")
}
Spacer()
Text("Right side.")
Text("Forced to bottom.")
}
}
}
34 changes: 16 additions & 18 deletions Sources/TokamakDemo/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,28 @@ struct CustomModifier: ViewModifier {

let div = document.createElement!("div").object!
let renderer = DOMRenderer(
ScrollView(showsIndicators: false) {
HStack {
NavigationView {
VStack(alignment: .leading, spacing: 16) {
Spacer()
}
VStack {
Counter(count: 5, limit: 15)
.padding()
.background(Color(red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0))
.border(Color.red, width: 3)
ZStack {
NavigationLink("Counter", destination:
Counter(count: 5, limit: 15)
.padding()
.background(Color(red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0))
.border(Color.red, width: 3)
)

NavigationLink("ZStack", destination: ZStack {
Text("I'm on bottom")
Text("I'm forced to the top")
.zIndex(1)
Text("I'm on top")
}
.padding(20)
ForEachDemo()
TextDemo()
SVGCircle()
.frame(width: 25, height: 25)
TextFieldDemo()
SpacerDemo()
Spacer()
Text("Forced to bottom.")
.padding(20))
NavigationLink("ForEach", destination: ForEachDemo())
NavigationLink("Text", destination: TextDemo())
NavigationLink("SVG", destination: SVGCircle().frame(width: 25, height: 25))
NavigationLink("TextField", destination: TextFieldDemo())
NavigationLink("Spacer", destination: SpacerDemo())
}
},
div
Expand Down

0 comments on commit 93456b1

Please sign in to comment.