Merge branch 'main' of github.com:TokamakUI/Tokamak into fiber/view-support
This commit is contained in:
commit
8aca895422
|
@ -3,7 +3,7 @@ name: Bug report
|
|||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: MaxDesiatov
|
||||
assignees: carson-katri
|
||||
|
||||
---
|
||||
|
||||
|
@ -28,17 +28,17 @@ A clear and concise description of what you expected to happen.
|
|||
If this is a layout/rendering issue, please provide screenshots for both Tokamak and SwiftUI that highlight the difference.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. macOS]
|
||||
- OS: [e.g. macOS 12.4]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version of the browser [e.g. 22]
|
||||
- Version of Tokamak [e.g. 0.6.1]
|
||||
- Version of Tokamak [e.g. 0.10.1]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Device: [e.g. iPhone 6]
|
||||
- OS: [e.g. iOS15.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version of the browser [e.g. 22]
|
||||
- Version of Tokamak [e.g. 0.6.1]
|
||||
- Version of Tokamak [e.g. 0.10.1]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
|
|
@ -27,8 +27,8 @@ jobs:
|
|||
matrix:
|
||||
include:
|
||||
- { toolchain: wasm-5.6.0-RELEASE }
|
||||
- { toolchain: wasm-5.7-SNAPSHOT-2022-06-01-a }
|
||||
- { toolchain: wasm-DEVELOPMENT-SNAPSHOT-2022-06-23-a }
|
||||
- { toolchain: wasm-5.7-SNAPSHOT-2022-07-27-a }
|
||||
- { toolchain: wasm-DEVELOPMENT-SNAPSHOT-2022-07-23-a }
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -76,25 +76,26 @@ jobs:
|
|||
name: Failed snapshots
|
||||
path: '*Tests'
|
||||
|
||||
gtk_macos_build:
|
||||
runs-on: macos-12
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build the GTK renderer on macOS
|
||||
shell: bash
|
||||
run: |
|
||||
set -ex
|
||||
sudo xcode-select --switch /Applications/Xcode_13.4.app/Contents/Developer/
|
||||
|
||||
brew install gtk+3
|
||||
|
||||
make build
|
||||
# FIXME: disabled due to build errors, to be investigated
|
||||
# gtk_macos_build:
|
||||
# runs-on: macos-12
|
||||
#
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
# - name: Build the GTK renderer on macOS
|
||||
# shell: bash
|
||||
# run: |
|
||||
# set -ex
|
||||
# sudo xcode-select --switch /Applications/Xcode_13.4.1.app/Contents/Developer/
|
||||
#
|
||||
# brew install gtk+3
|
||||
#
|
||||
# make build
|
||||
|
||||
gtk_ubuntu_18_04_build:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: swiftlang/swift:nightly-bionic
|
||||
image: swiftlang/swift:nightly-5.7-bionic
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -109,7 +110,7 @@ jobs:
|
|||
gtk_ubuntu_20_04_build:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: swiftlang/swift:nightly-focal
|
||||
image: swiftlang/swift:nightly-5.7-focal
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
|
@ -8,26 +8,26 @@ on:
|
|||
jobs:
|
||||
codecov:
|
||||
container:
|
||||
image: swiftlang/swift:nightly-focal
|
||||
image: swiftlang/swift:nightly-5.7-focal
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y gtk+-3.0 libgtk+-3.0
|
||||
- name: Checkout Branch
|
||||
uses: actions/checkout@v2
|
||||
- name: Build Test Target
|
||||
run: swift build -Xswiftc -profile-coverage-mapping -Xswiftc -profile-generate --product TokamakPackageTests
|
||||
- name: Run Tests
|
||||
run: swift test --enable-code-coverage --skip-build
|
||||
- name: Generate Branch Coverage Report
|
||||
uses: mattpolzin/swift-codecov-action@0.7.1
|
||||
id: cov
|
||||
with:
|
||||
MINIMUM_COVERAGE: 15
|
||||
- name: Post Positive Results
|
||||
if: ${{ success() }}
|
||||
run: |
|
||||
echo "::warning file=Package.swift,line=1,col=1::The current code coverage percentage is passing with ${{ steps.cov.outputs.codecov }} (minimum allowed: ${{ steps.cov.outputs.minimum_coverage }}%)."
|
||||
- name: Post Negative Results
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
echo "::error file=Package.swift,line=1,col=1::The current code coverage percentage is failing with ${{ steps.cov.outputs.codecov }} (minimum allowed: ${{ steps.cov.outputs.minimum_coverage }}%)."
|
||||
- run: apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y gtk+-3.0 libgtk+-3.0
|
||||
- name: Checkout Branch
|
||||
uses: actions/checkout@v2
|
||||
- name: Build Test Target
|
||||
run: swift build -Xswiftc -profile-coverage-mapping -Xswiftc -profile-generate --product TokamakPackageTests
|
||||
- name: Run Tests
|
||||
run: swift test --enable-code-coverage --skip-build
|
||||
- name: Generate Branch Coverage Report
|
||||
uses: mattpolzin/swift-codecov-action@0.7.1
|
||||
id: cov
|
||||
with:
|
||||
MINIMUM_COVERAGE: 15
|
||||
- name: Post Positive Results
|
||||
if: ${{ success() }}
|
||||
run: |
|
||||
echo "::warning file=Package.swift,line=1,col=1::The current code coverage percentage is passing with ${{ steps.cov.outputs.codecov }} (minimum allowed: ${{ steps.cov.outputs.minimum_coverage }}%)."
|
||||
- name: Post Negative Results
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
echo "::error file=Package.swift,line=1,col=1::The current code coverage percentage is failing with ${{ steps.cov.outputs.codecov }} (minimum allowed: ${{ steps.cov.outputs.minimum_coverage }}%)."
|
||||
|
|
10
README.md
10
README.md
|
@ -241,6 +241,9 @@ carton dev
|
|||
You can also clone this repository and run `carton dev --product TokamakDemo` in its root
|
||||
directory. This will build the demo app that shows almost all of the currently implemented APIs.
|
||||
|
||||
If you have any questions, pleaes check out the [FAQ](docs/FAQ.md) document, and/or join the
|
||||
#tokamak channel on [the SwiftWasm Discord server](https://discord.gg/ashJW8T8yp).
|
||||
|
||||
## Security
|
||||
|
||||
By default, the DOM renderer will escape HTML control characters in `Text` views. If you wish
|
||||
|
@ -322,9 +325,10 @@ appreciated and helps in maintaining the project.
|
|||
## Maintainers
|
||||
|
||||
In alphabetical order: [Carson Katri](https://github.com/carson-katri),
|
||||
[David Hunt](https://github.com/foscomputerservices), [Ezra Berch](https://github.com/ezraberch),
|
||||
[Jed Fox](https://jedfox.com), [Max Desiatov](https://desiatov.com),
|
||||
[Morten Bek Ditlevsen](https://github.com/mortenbekditlevsen/), [Yuta Saito](https://github.com/kateinoigakukun/).
|
||||
[Ezra Berch](https://github.com/ezraberch),
|
||||
[Jed Fox](https://jedfox.com),
|
||||
[Morten Bek Ditlevsen](https://github.com/mortenbekditlevsen/),
|
||||
[Yuta Saito](https://github.com/kateinoigakukun/).
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
public struct Transaction {
|
||||
/// The overriden transaction for a state change in a `withTransaction` block.
|
||||
/// The overridden transaction for a state change in a `withTransaction` block.
|
||||
/// Is always set back to `nil` when the block exits.
|
||||
static var _active: Self?
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import Foundation
|
|||
public protocol _AnimationSolver {
|
||||
/// Solve value at a specific point in time.
|
||||
func solve(at t: Double) -> Double
|
||||
/// Calculates the duration of the animation to a specific presision.
|
||||
/// Calculates the duration of the animation to a specific precision.
|
||||
func restingPoint(precision y: Double) -> Double
|
||||
}
|
||||
|
||||
|
|
|
@ -261,30 +261,8 @@ extension VStack: StackLayout {
|
|||
public var _alignment: Alignment { .init(horizontal: alignment, vertical: .center) }
|
||||
}
|
||||
|
||||
public extension VStack where Content == EmptyView {
|
||||
init(
|
||||
alignment: HorizontalAlignment = .center,
|
||||
spacing: CGFloat? = nil
|
||||
) {
|
||||
self.alignment = alignment
|
||||
self.spacing = spacing
|
||||
content = EmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
@_spi(TokamakCore)
|
||||
extension HStack: StackLayout {
|
||||
public static var orientation: Axis { .horizontal }
|
||||
public var _alignment: Alignment { .init(horizontal: .center, vertical: alignment) }
|
||||
}
|
||||
|
||||
public extension HStack where Content == EmptyView {
|
||||
init(
|
||||
alignment: VerticalAlignment = .center,
|
||||
spacing: CGFloat? = nil
|
||||
) {
|
||||
self.alignment = alignment
|
||||
self.spacing = spacing
|
||||
content = EmptyView()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
#if canImport(CoreGraphics)
|
||||
import CoreGraphics
|
||||
#endif
|
||||
|
||||
public struct StrokeStyle: Equatable {
|
||||
public var lineWidth: CGFloat
|
||||
public var lineCap: CGLineCap
|
||||
|
|
|
@ -103,7 +103,7 @@ public struct CGAffineTransform: Equatable {
|
|||
/// Returns an affine transformation matrix constructed from a rotation value you provide.
|
||||
/// - Parameters:
|
||||
/// - angle: The angle, in radians, by which this matrix rotates the coordinate system axes.
|
||||
/// A positive value specifies clockwise rotation and anegative value specifies
|
||||
/// A positive value specifies clockwise rotation and a negative value specifies
|
||||
/// counterclockwise rotation.
|
||||
public init(rotationAngle angle: CGFloat) {
|
||||
self.init(a: cos(angle), b: sin(angle), c: -sin(angle), d: cos(angle), tx: 0, ty: 0)
|
||||
|
|
|
@ -39,46 +39,48 @@ public struct List<SelectionValue, Content>: View
|
|||
self.content = content()
|
||||
}
|
||||
|
||||
var listStack: some View {
|
||||
VStack(alignment: .leading, spacing: 0) { () -> AnyView in
|
||||
if let contentContainer = content as? ParentView {
|
||||
var sections = [AnyView]()
|
||||
var currentSection = [AnyView]()
|
||||
for child in contentContainer.children {
|
||||
if child.view is SectionView {
|
||||
if currentSection.count > 0 {
|
||||
sections.append(AnyView(Section {
|
||||
ForEach(Array(currentSection.enumerated()), id: \.offset) { _, view in view }
|
||||
}))
|
||||
currentSection = []
|
||||
}
|
||||
sections.append(child)
|
||||
func stackContent() -> AnyView {
|
||||
if let contentContainer = content as? ParentView {
|
||||
var sections = [AnyView]()
|
||||
var currentSection = [AnyView]()
|
||||
for child in contentContainer.children {
|
||||
if child.view is SectionView {
|
||||
if currentSection.count > 0 {
|
||||
sections.append(AnyView(Section {
|
||||
ForEach(Array(currentSection.enumerated()), id: \.offset) { _, view in view }
|
||||
}))
|
||||
currentSection = []
|
||||
}
|
||||
sections.append(child)
|
||||
} else {
|
||||
if child.children.count > 0 {
|
||||
currentSection.append(contentsOf: child.children)
|
||||
} else {
|
||||
if child.children.count > 0 {
|
||||
currentSection.append(contentsOf: child.children)
|
||||
} else {
|
||||
currentSection.append(child)
|
||||
}
|
||||
currentSection.append(child)
|
||||
}
|
||||
}
|
||||
if currentSection.count > 0 {
|
||||
sections.append(AnyView(Section {
|
||||
ForEach(Array(currentSection.enumerated()), id: \.offset) { _, view in view }
|
||||
}))
|
||||
}
|
||||
return AnyView(_ListRow.buildItems(sections) { view, isLast in
|
||||
if let section = view.view as? SectionView {
|
||||
section.listRow(style)
|
||||
} else {
|
||||
_ListRow.listRow(view, style, isLast: isLast)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return AnyView(content)
|
||||
}
|
||||
if currentSection.count > 0 {
|
||||
sections.append(AnyView(Section {
|
||||
ForEach(Array(currentSection.enumerated()), id: \.offset) { _, view in view }
|
||||
}))
|
||||
}
|
||||
return AnyView(_ListRow.buildItems(sections) { view, isLast in
|
||||
if let section = view.view as? SectionView {
|
||||
section.listRow(style)
|
||||
} else {
|
||||
_ListRow.listRow(view, style, isLast: isLast)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return AnyView(content)
|
||||
}
|
||||
}
|
||||
|
||||
var listStack: some View {
|
||||
VStack(alignment: .leading, spacing: 0, content: stackContent)
|
||||
}
|
||||
|
||||
@_spi(TokamakCore)
|
||||
public var body: some View {
|
||||
if let style = style as? ListStyleDeferredToRenderer {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import JavaScriptEventLoop
|
||||
import JavaScriptKit
|
||||
import OpenCombineJS
|
||||
import OpenCombineShim
|
||||
|
@ -97,6 +98,10 @@ public struct DOMFiberRenderer: FiberRenderer {
|
|||
}
|
||||
|
||||
public init(_ rootSelector: String, useDynamicLayout: Bool = true) {
|
||||
if #available(macOS 10.15, *) {
|
||||
JavaScriptEventLoop.installGlobalExecutor()
|
||||
}
|
||||
|
||||
guard let reference = document.querySelector!(rootSelector).object else {
|
||||
fatalError("""
|
||||
The root element with selector '\(rootSelector)' could not be found. \
|
||||
|
|
|
@ -162,7 +162,7 @@ extension InsetGroupedListStyle: ListStyleDeferredToRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Make sections collabsible (see Section.swift for more impl. details)
|
||||
// TODO: Make sections collapsible (see Section.swift for more impl. details)
|
||||
extension SidebarListStyle: ListStyleDeferredToRenderer {
|
||||
public func sectionHeader<Header>(_ header: Header) -> AnyView where Header: View {
|
||||
AnyView(
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
# Frequently Asked Questions
|
||||
|
||||
## Why does Tokamak use HTML/CSS for rendering in the browser?
|
||||
|
||||
HTML/CSS has a benefit of built-in accessibility support. Other rendering systems in the browser (such as Canvas or WebGL/WebGPU)
|
||||
that bypass HTML/CSS would have to reimplement accessibility from scratch, with all the downsides of increased binary
|
||||
size and performance overhead. With HTML/CSS we can rely on what's already included in the browser and has been tested and polished
|
||||
by hundreds of engineers over the decades of browser development.
|
||||
|
||||
Additionally, we can rely on optimized CSS layout algorithms where possible. This also unlocks more use-cases for Tokamak, such as
|
||||
[static HTML generation](https://github.com/TokamakUI/TokamakPublish) and [server-side rendering](https://github.com/TokamakUI/TokamakVapor).
|
||||
|
||||
At the same time, Tokamak has [a new layout system in development](https://github.com/TokamakUI/Tokamak/pull/472) that accesses
|
||||
DOM directly for layout calculations, bypassing CSS for a lot (or potentially all) of its algorithms.
|
||||
|
||||
## Does the word Tokamak mean anything? Why is it called this?
|
||||
|
||||
The project was originally inspired by [React](https://reactjs.org), which utilizes a model of an atom in its logo,
|
||||
apparently as a reference to nuclear reactors. [Токамак](https://en.wikipedia.org/wiki/Tokamak) is a nuclear fusion reactor, and
|
||||
the word itself is roughly an abbreviation of "**to**roidal **cha**mber with **ma**gnetic **c**oils".
|
||||
|
||||
## What's the history behind it?
|
||||
|
||||
The first commit to this project was made in September 2018, 9 months before SwiftUI was publicly announced. The original maintainer of
|
||||
it had a feeling it would be beneficial to replace UIKit and AppKit with a declarative UI framework. It originally started
|
||||
as a port of the [React API](https://reactjs.org/) to Swift. The opinion of the original maintainer was that React was a pretty good
|
||||
solution at that time and was adopted widely enough for people to be acquainted with the general idea. The architecture of React
|
||||
was quite modular, and it had a well-documented reconciler algorithm that worked independently from platform-specific renderers.
|
||||
|
||||
The plan was to build something similar to the React API in Swift with renderers for macOS and iOS, and then potentially for
|
||||
WebAssembly, Android, and Windows. Shortly after a short series of [0.1 releases with the React
|
||||
API](https://github.com/swiftwasm/Tokamak/blob/0.1.2/README.md), Tokamak for iOS/macOS was [sherlocked](https://en.wikipedia.org/wiki/Sherlock_(software)#Sherlocked_as_a_term) by
|
||||
SwiftUI at WWDC 2019. It no longer made sense to continue developing it in that form for Apple's platforms, even though it could
|
||||
still be useful for other platforms. The original maintainer thought it would be hard to convince Swift developers to use something
|
||||
that doesn't look like SwiftUI, at least as long as the majority of Swift developers target Apple's platforms.
|
||||
|
||||
In addition to SwiftUI and React, we'd like to credit [SwiftWebUI](https://github.com/SwiftWebUI/SwiftWebUI) for reverse-engineering
|
||||
some of the bits of SwiftUI and kickstarting the front-end Swift ecosystem for the web. [Render](https://github.com/alexdrone/Render),
|
||||
[ReSwift](https://github.com/ReSwift/ReSwift), [Katana UI](https://github.com/BendingSpoons/katana-ui-swift), and
|
||||
[Komponents](https://github.com/freshOS/Komponents) declarative UI frameworks served as additional inspiration for the project.
|
Loading…
Reference in New Issue