Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid AnyView in the Counter code #168

Merged
merged 8 commits into from
Jul 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ jobs:
run: |
set -ex
sudo xcode-select --switch /Applications/Xcode_12_beta.app/Contents/Developer/
xcodebuild -version
cd "TokamakDemo Native"
xcodebuild -scheme macOS
xcodebuild -scheme iOS -destination 'generic/platform=iOS' \
CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
35 changes: 18 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,16 @@ struct Counter: View {
let limit: Int

var body: some View {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need @ViewBuilder here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I forgot to commit it 🤦‍♂️

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer needed as @ViewBuilder is already on the body declaration of the View protocol.

count < limit ?
AnyView(
VStack {
Button("Increment") { count += 1 }
Text("\(count)")
}
) : AnyView(
VStack { Text("Limit exceeded") }
)
if count < limit {
VStack {
Button("Increment") { count += 1 }
Text("\(count)")
}
.onAppear { print("Counter.VStack onAppear") }
.onDisappear { print("Counter.VStack onDisappear") }
} else {
VStack { Text("Limit exceeded") }
}
}
}
```
Expand Down Expand Up @@ -125,20 +126,20 @@ separate modules for platform-specific renderers. Currently, the only available
is `TokamakDOM`, but we intend to provide other renderers in the future, such as `TokamakHTML`
for static websites and server-side rendering. Tokamak users only need to import a renderer module
they would like to use, while `TokamakCore` is hidden as an "internal" `Tokamak` package target.
Unfortunately, Swift does not allow us to specify that certain symbols in `TokamakCore` are private
Unfortunately, Swift does not allow us to specify that certain symbols in `TokamakCore` are private
to a package, but they need to stay `public` for renderer modules to get access to them. Thus, the
current workaround is to mark those symbols with underscores in their names to indicate this. It
can be formulated as these "rules":

1. If a symbol is restricted to a module and has no `public` access control, no need for an underscore.
2. If a symbol is part of a public renderer module API (e.g. `TokamakDOM`), no need for an underscore,
users may use those symbols directly, and it is re-exported from `TokamakCore` by the renderer module
2. If a symbol is part of a public renderer module API (e.g. `TokamakDOM`), no need for an underscore,
users may use those symbols directly, and it is re-exported from `TokamakCore` by the renderer module
via `public typealias`.
3. If a function or a type have `public` on them only by necessity to make them available in `TokamakDOM`,
but unavailable to users (or not intended for public use), underscore is needed to indicate that.

The benefit of separate modules is that they allow us to provide separate renderers for different platforms.
Users can pick and choose what they want to use, e.g. purely static websites would use only `TokamakHTML`,
Users can pick and choose what they want to use, e.g. purely static websites would use only `TokamakHTML`,
single-page apps would use `TokamakDOM`, maybe in conjuction with `TokamakHTML` for pre-rendering. As we'd
like to try to implement a native renderer for Android at some point, probably in a separate `TokamakAndroid`
module, Android apps would use `TokamakAndroid` with no need to be aware of any of the web modules.
Expand Down Expand Up @@ -193,7 +194,7 @@ unacceptable behavior to conduct@tokamak.dev.

- Thanks to the [Swift community](https://swift.org/community/) for
building one of the best programming languages available!
- Thanks to everyone who developed [React](https://reactjs.org/) with its [reconciler/renderer
- Thanks to everyone who developed [React](https://reactjs.org/) with its [reconciler/renderer
architecture](https://reactjs.org/docs/codebase-overview.html#renderers) that inspired Tokamak
in the first place.
- Thanks to the designers of [the SwiftUI API](https://developer.apple.com/documentation/swiftui)
Expand All @@ -204,13 +205,13 @@ unacceptable behavior to conduct@tokamak.dev.
[ReSwift](https://github.com/ReSwift/ReSwift), [Katana
UI](https://github.com/BendingSpoons/katana-ui-swift) and
[Komponents](https://github.com/freshOS/Komponents) for inspiration!
SwiftUI is a trademark owned by Apple Inc. Software maintained as a part of the Tokamak project

SwiftUI is a trademark owned by Apple Inc. Software maintained as a part of the Tokamak project
is not affiliated with Apple Inc.

## License

Tokamak is available under the Apache 2.0 license.
Tokamak is available under the Apache 2.0 license.
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.
Expand Down
2 changes: 1 addition & 1 deletion Sources/TokamakCore/Views/View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
public protocol View {
associatedtype Body: View

var body: Self.Body { get }
@ViewBuilder var body: Self.Body { get }
}

extension Never: View {
Expand Down
21 changes: 12 additions & 9 deletions Sources/TokamakCore/Views/ViewBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,28 @@ public struct _ConditionalContent<TrueContent, FalseContent>: View

let storage: Storage

@ViewBuilder
public var body: some View {
public var body: Never {
neverBody("_ConditionContent")
}
}

extension _ConditionalContent: GroupView {
public var children: [AnyView] {
switch storage {
case let .trueContent(view):
view
return [AnyView(view)]
case let .falseContent(view):
view
return [AnyView(view)]
}
}
}

// FIXME: Remove type erasure when https://github.com/swiftwasm/swift/issues/1379
// is resolved
extension Optional: View where Wrapped: View {
public var body: AnyView {
public var body: some View {
if let view = self {
return AnyView(view)
view
} else {
return AnyView(EmptyView())
EmptyView()
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions Sources/TokamakDOM/Views/SecureField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ extension SecureField: ViewDeferredToRenderer where Label == Text {
], listeners: [
"keypress": { event in if event.key == "Enter" { proxy.onCommit() } },
"input": { event in
if let newValue = event.target.object?.value.string {
proxy.textBinding.wrappedValue = newValue
}
},
if let newValue = event.target.object?.value.string {
proxy.textBinding.wrappedValue = newValue
}
},
]))
}
}
8 changes: 4 additions & 4 deletions Sources/TokamakDOM/Views/TextField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ extension TextField: ViewDeferredToRenderer where Label == Text {
"blur": { _ in proxy.onEditingChanged(false) },
"keypress": { event in if event.key == "Enter" { proxy.onCommit() } },
"input": { event in
if let newValue = event.target.object?.value.string {
proxy.textBinding.wrappedValue = newValue
}
},
if let newValue = event.target.object?.value.string {
proxy.textBinding.wrappedValue = newValue
}
},
]))
}
}
21 changes: 10 additions & 11 deletions Sources/TokamakDemo/Counter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,15 @@ public struct Counter: View {
let limit: Int

public var body: some View {
MaxDesiatov marked this conversation as resolved.
Show resolved Hide resolved
count < limit ?
AnyView(
VStack {
Button("Increment") { count += 1 }
Text("\(count)")
}
.onAppear { print("Counter.VStack onAppear") }
.onDisappear { print("Counter.VStack onDisappear") }
) : AnyView(
VStack { Text("Limit exceeded") }
)
if count < limit {
VStack {
Button("Increment") { count += 1 }
Text("\(count)")
}
.onAppear { print("Counter.VStack onAppear") }
.onDisappear { print("Counter.VStack onDisappear") }
} else {
VStack { Text("Limit exceeded") }
}
}
}
2 changes: 1 addition & 1 deletion Sources/TokamakDemo/OutlineGroupDemo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct File: Identifiable {
let children: [File]?
}

@available(OSX 10.16, *)
@available(OSX 10.16, iOS 14, *)
struct OutlineGroupDemo: View {
let fs: [File] = [
.init(id: 0, name: "Users", children: [
Expand Down