Merge branch 'main' of github.com:swiftwasm/Tokamak into dark-mode
# Conflicts: # Sources/TokamakCore/Modifiers/FlexFrameLayout.swift # Sources/TokamakCore/Modifiers/ModifiedContent.swift # Sources/TokamakCore/Tokens/Color.swift # Sources/TokamakCore/Views/Text/Text.swift # Sources/TokamakDemo/TokamakDemo.swift # Sources/TokamakStaticHTML/Views/Containers/List.swift
This commit is contained in:
commit
487543d692
|
@ -1,9 +1,12 @@
|
|||
--indent 2
|
||||
--indentcase false
|
||||
--trimwhitespace always
|
||||
--empty tuple
|
||||
--voidtype tuple
|
||||
--nospaceoperators ..<,...
|
||||
--ifdef noindent
|
||||
--stripunusedargs closure-only
|
||||
--maxwidth 100
|
||||
--wraparguments before-first
|
||||
--funcattributes prev-line
|
||||
--disable andOperator
|
||||
--swiftversion 5.2
|
||||
--swiftversion 5.3
|
||||
|
|
|
@ -9,6 +9,7 @@ disabled_rules:
|
|||
- type_name
|
||||
- todo
|
||||
- large_tuple
|
||||
- opening_brace
|
||||
|
||||
line_length: 100
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"editor.formatOnSave": true,
|
||||
"licenser.author": "Tokamak contributors"
|
||||
"licenser.author": "Tokamak contributors",
|
||||
"cSpell.words": [
|
||||
"Tokamak"
|
||||
]
|
||||
}
|
||||
|
|
22
README.md
22
README.md
|
@ -200,18 +200,18 @@ appreciated and helps in maintaining the project.
|
|||
|
||||
### Coding Style
|
||||
|
||||
This project uses [SwiftFormat](https://github.com/nicklockwood/SwiftFormat)
|
||||
and [SwiftLint](https://github.com/realm/SwiftLint) to
|
||||
enforce formatting and coding style. We encourage you to run SwiftFormat within
|
||||
a local clone of the repository in whatever way works best for you either
|
||||
manually or automatically via an [Xcode
|
||||
extension](https://github.com/nicklockwood/SwiftFormat#xcode-source-editor-extension),
|
||||
[build phase](https://github.com/nicklockwood/SwiftFormat#xcode-build-phase) or
|
||||
[git pre-commit
|
||||
hook](https://github.com/nicklockwood/SwiftFormat#git-pre-commit-hook) etc.
|
||||
This project uses [SwiftFormat](https://github.com/nicklockwood/SwiftFormat) and
|
||||
[SwiftLint](https://github.com/realm/SwiftLint) to enforce formatting and coding style. SwiftFormat
|
||||
0.45.3 and SwiftLint 0.39.2 or later versions are recommended. We encourage you to run SwiftFormat
|
||||
and SwiftLint within a local clone of the repository in whatever way works best for you. You can do
|
||||
that either manually, or automatically with VSCode extensions for
|
||||
[SwiftFormat](https://github.com/vknabel/vscode-swiftformat) and
|
||||
[SwiftLint](https://github.com/vknabel/vscode-swiftlint) respectively, or with the [Xcode
|
||||
extension](https://github.com/nicklockwood/SwiftFormat#xcode-source-editor-extension), or [build
|
||||
phase](https://github.com/nicklockwood/SwiftFormat#xcode-build-phase).
|
||||
|
||||
To guarantee that these tools run before you commit your changes on macOS, you're encouraged
|
||||
to run this once to set up the [pre-commit](https://pre-commit.com/) hook:
|
||||
To guarantee that these tools run before you commit your changes on macOS, you're encouraged to run
|
||||
this once to set up the [pre-commit](https://pre-commit.com/) hook:
|
||||
|
||||
```
|
||||
brew bundle # installs SwiftLint, SwiftFormat and pre-commit
|
||||
|
|
|
@ -54,9 +54,9 @@ import CombineShim
|
|||
extension AppStorage: ObservedProperty {}
|
||||
|
||||
extension AppStorage {
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String,
|
||||
store: _StorageProvider? = nil) where Value == Bool {
|
||||
public init(wrappedValue: Value, _ key: String, store: _StorageProvider? = nil)
|
||||
where Value == Bool
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
provider = store
|
||||
|
@ -64,9 +64,9 @@ extension AppStorage {
|
|||
read = { $0.read(key: $1) }
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String,
|
||||
store: _StorageProvider? = nil) where Value == Int {
|
||||
public init(wrappedValue: Value, _ key: String, store: _StorageProvider? = nil)
|
||||
where Value == Int
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
provider = store
|
||||
|
@ -74,9 +74,9 @@ extension AppStorage {
|
|||
read = { $0.read(key: $1) }
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String,
|
||||
store: _StorageProvider? = nil) where Value == Double {
|
||||
public init(wrappedValue: Value, _ key: String, store: _StorageProvider? = nil)
|
||||
where Value == Double
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
provider = store
|
||||
|
@ -84,9 +84,9 @@ extension AppStorage {
|
|||
read = { $0.read(key: $1) }
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String,
|
||||
store: _StorageProvider? = nil) where Value == String {
|
||||
public init(wrappedValue: Value, _ key: String, store: _StorageProvider? = nil)
|
||||
where Value == String
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
provider = store
|
||||
|
@ -94,10 +94,9 @@ extension AppStorage {
|
|||
read = { $0.read(key: $1) }
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String,
|
||||
store: _StorageProvider? = nil)
|
||||
where Value: RawRepresentable, Value.RawValue == Int {
|
||||
public init(wrappedValue: Value, _ key: String, store: _StorageProvider? = nil)
|
||||
where Value: RawRepresentable, Value.RawValue == Int
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
provider = store
|
||||
|
@ -110,10 +109,9 @@ extension AppStorage {
|
|||
}
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String,
|
||||
store: _StorageProvider? = nil)
|
||||
where Value: RawRepresentable, Value.RawValue == String {
|
||||
public init(wrappedValue: Value, _ key: String, store: _StorageProvider? = nil)
|
||||
where Value: RawRepresentable, Value.RawValue == String
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
provider = store
|
||||
|
@ -128,9 +126,9 @@ extension AppStorage {
|
|||
}
|
||||
|
||||
extension AppStorage where Value: ExpressibleByNilLiteral {
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String,
|
||||
store: _StorageProvider? = nil) where Value == Bool? {
|
||||
public init(wrappedValue: Value, _ key: String, store: _StorageProvider? = nil)
|
||||
where Value == Bool?
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
provider = store
|
||||
|
@ -138,9 +136,9 @@ extension AppStorage where Value: ExpressibleByNilLiteral {
|
|||
read = { $0.read(key: $1) }
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String,
|
||||
store: _StorageProvider? = nil) where Value == Int? {
|
||||
public init(wrappedValue: Value, _ key: String, store: _StorageProvider? = nil)
|
||||
where Value == Int?
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
provider = store
|
||||
|
@ -148,9 +146,9 @@ extension AppStorage where Value: ExpressibleByNilLiteral {
|
|||
read = { $0.read(key: $1) }
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String,
|
||||
store: _StorageProvider? = nil) where Value == Double? {
|
||||
public init(wrappedValue: Value, _ key: String, store: _StorageProvider? = nil)
|
||||
where Value == Double?
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
provider = store
|
||||
|
@ -158,9 +156,9 @@ extension AppStorage where Value: ExpressibleByNilLiteral {
|
|||
read = { $0.read(key: $1) }
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String,
|
||||
store: _StorageProvider? = nil) where Value == String? {
|
||||
public init(wrappedValue: Value, _ key: String, store: _StorageProvider? = nil)
|
||||
where Value == String?
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
provider = store
|
||||
|
|
|
@ -22,60 +22,195 @@ public struct SceneBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable line_length
|
||||
// swiftlint:disable large_tuple
|
||||
// swiftlint:disable function_parameter_count
|
||||
|
||||
extension SceneBuilder {
|
||||
public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> some Scene where C0: Scene, C1: Scene {
|
||||
public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> some Scene where C0: Scene,
|
||||
C1: Scene
|
||||
{
|
||||
_TupleScene((c0, c1), children: [_AnyScene(c0), _AnyScene(c1)])
|
||||
}
|
||||
}
|
||||
|
||||
extension SceneBuilder {
|
||||
public static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2) -> some Scene where C0: Scene, C1: Scene, C2: Scene {
|
||||
public static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2) -> some Scene
|
||||
where C0: Scene, C1: Scene, C2: Scene
|
||||
{
|
||||
_TupleScene((c0, c1, c2), children: [_AnyScene(c0), _AnyScene(c1), _AnyScene(c2)])
|
||||
}
|
||||
}
|
||||
|
||||
extension SceneBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene {
|
||||
_TupleScene((c0, c1, c2, c3), children: [_AnyScene(c0), _AnyScene(c1), _AnyScene(c2), _AnyScene(c3)])
|
||||
public static func buildBlock<C0, C1, C2, C3>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3
|
||||
) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene {
|
||||
_TupleScene(
|
||||
(c0, c1, c2, c3),
|
||||
children: [_AnyScene(c0), _AnyScene(c1), _AnyScene(c2), _AnyScene(c3)]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension SceneBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene {
|
||||
_TupleScene((c0, c1, c2, c3, c4), children: [_AnyScene(c0), _AnyScene(c1), _AnyScene(c2), _AnyScene(c3), _AnyScene(c4)])
|
||||
public static func buildBlock<C0, C1, C2, C3, C4>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4
|
||||
) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene {
|
||||
_TupleScene(
|
||||
(c0, c1, c2, c3, c4),
|
||||
children: [_AnyScene(c0), _AnyScene(c1), _AnyScene(c2), _AnyScene(c3), _AnyScene(c4)]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension SceneBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene, C5: Scene {
|
||||
_TupleScene((c0, c1, c2, c3, c4, c5), children: [_AnyScene(c0), _AnyScene(c1), _AnyScene(c2), _AnyScene(c3), _AnyScene(c4), _AnyScene(c5)])
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4,
|
||||
_ c5: C5
|
||||
) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene,
|
||||
C5: Scene
|
||||
{
|
||||
_TupleScene(
|
||||
(c0, c1, c2, c3, c4, c5),
|
||||
children: [
|
||||
_AnyScene(c0),
|
||||
_AnyScene(c1),
|
||||
_AnyScene(c2),
|
||||
_AnyScene(c3),
|
||||
_AnyScene(c4),
|
||||
_AnyScene(c5),
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension SceneBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene, C5: Scene, C6: Scene {
|
||||
_TupleScene((c0, c1, c2, c3, c4, c5, c6), children: [_AnyScene(c0), _AnyScene(c1), _AnyScene(c2), _AnyScene(c3), _AnyScene(c4), _AnyScene(c5), _AnyScene(c6)])
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4,
|
||||
_ c5: C5,
|
||||
_ c6: C6
|
||||
) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene,
|
||||
C4: Scene, C5: Scene, C6: Scene
|
||||
{
|
||||
_TupleScene(
|
||||
(c0, c1, c2, c3, c4, c5, c6),
|
||||
children: [
|
||||
_AnyScene(c0),
|
||||
_AnyScene(c1),
|
||||
_AnyScene(c2),
|
||||
_AnyScene(c3),
|
||||
_AnyScene(c4),
|
||||
_AnyScene(c5),
|
||||
_AnyScene(c6),
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension SceneBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene, C5: Scene, C6: Scene, C7: Scene {
|
||||
_TupleScene((c0, c1, c2, c3, c4, c5, c6, c7), children: [_AnyScene(c0), _AnyScene(c1), _AnyScene(c2), _AnyScene(c3), _AnyScene(c4), _AnyScene(c5), _AnyScene(c6), _AnyScene(c7)])
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4,
|
||||
_ c5: C5,
|
||||
_ c6: C6,
|
||||
_ c7: C7
|
||||
) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene, C5: Scene, C6: Scene,
|
||||
C7: Scene
|
||||
{
|
||||
_TupleScene(
|
||||
(c0, c1, c2, c3, c4, c5, c6, c7),
|
||||
children: [
|
||||
_AnyScene(c0),
|
||||
_AnyScene(c1),
|
||||
_AnyScene(c2),
|
||||
_AnyScene(c3),
|
||||
_AnyScene(c4),
|
||||
_AnyScene(c5),
|
||||
_AnyScene(c6),
|
||||
_AnyScene(c7),
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension SceneBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene, C5: Scene, C6: Scene, C7: Scene, C8: Scene {
|
||||
_TupleScene((c0, c1, c2, c3, c4, c5, c6, c7, c8), children: [_AnyScene(c0), _AnyScene(c1), _AnyScene(c2), _AnyScene(c3), _AnyScene(c4), _AnyScene(c5), _AnyScene(c6), _AnyScene(c7), _AnyScene(c8)])
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4,
|
||||
_ c5: C5,
|
||||
_ c6: C6,
|
||||
_ c7: C7,
|
||||
_ c8: C8
|
||||
) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene, C5: Scene, C6: Scene,
|
||||
C7: Scene, C8: Scene
|
||||
{
|
||||
_TupleScene(
|
||||
(c0, c1, c2, c3, c4, c5, c6, c7, c8),
|
||||
children: [
|
||||
_AnyScene(c0),
|
||||
_AnyScene(c1),
|
||||
_AnyScene(c2),
|
||||
_AnyScene(c3),
|
||||
_AnyScene(c4),
|
||||
_AnyScene(c5),
|
||||
_AnyScene(c6),
|
||||
_AnyScene(c7),
|
||||
_AnyScene(c8),
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension SceneBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8, _ c9: C9) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene, C5: Scene, C6: Scene, C7: Scene, C8: Scene, C9: Scene {
|
||||
_TupleScene((c0, c1, c2, c3, c4, c5, c6, c7, c8, c9), children: [_AnyScene(c0), _AnyScene(c1), _AnyScene(c2), _AnyScene(c3), _AnyScene(c4), _AnyScene(c5), _AnyScene(c6), _AnyScene(c7), _AnyScene(c8), _AnyScene(c9)])
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4,
|
||||
_ c5: C5,
|
||||
_ c6: C6,
|
||||
_ c7: C7,
|
||||
_ c8: C8,
|
||||
_ c9: C9
|
||||
) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene, C5: Scene, C6: Scene,
|
||||
C7: Scene, C8: Scene, C9: Scene
|
||||
{
|
||||
_TupleScene(
|
||||
(c0, c1, c2, c3, c4, c5, c6, c7, c8, c9),
|
||||
children: [
|
||||
_AnyScene(c0),
|
||||
_AnyScene(c1),
|
||||
_AnyScene(c2),
|
||||
_AnyScene(c3),
|
||||
_AnyScene(c4),
|
||||
_AnyScene(c5),
|
||||
_AnyScene(c6),
|
||||
_AnyScene(c7),
|
||||
_AnyScene(c8),
|
||||
_AnyScene(c9),
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,41 +54,37 @@ public enum _DefaultSceneStorageProvider {
|
|||
extension SceneStorage: ObservedProperty {}
|
||||
|
||||
extension SceneStorage {
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String) where Value == Bool {
|
||||
public init(wrappedValue: Value, _ key: String) where Value == Bool {
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
store = { $0.store(key: $1, value: $2) }
|
||||
read = { $0.read(key: $1) }
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String) where Value == Int {
|
||||
public init(wrappedValue: Value, _ key: String) where Value == Int {
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
store = { $0.store(key: $1, value: $2) }
|
||||
read = { $0.read(key: $1) }
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String) where Value == Double {
|
||||
public init(wrappedValue: Value, _ key: String) where Value == Double {
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
store = { $0.store(key: $1, value: $2) }
|
||||
read = { $0.read(key: $1) }
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String) where Value == String {
|
||||
public init(wrappedValue: Value, _ key: String) where Value == String {
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
store = { $0.store(key: $1, value: $2) }
|
||||
read = { $0.read(key: $1) }
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String)
|
||||
where Value: RawRepresentable, Value.RawValue == Int {
|
||||
public init(wrappedValue: Value, _ key: String) where Value: RawRepresentable,
|
||||
Value.RawValue == Int
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
store = { $0.store(key: $1, value: $2.rawValue) }
|
||||
|
@ -100,9 +96,9 @@ extension SceneStorage {
|
|||
}
|
||||
}
|
||||
|
||||
public init(wrappedValue: Value,
|
||||
_ key: String)
|
||||
where Value: RawRepresentable, Value.RawValue == String {
|
||||
public init(wrappedValue: Value, _ key: String)
|
||||
where Value: RawRepresentable, Value.RawValue == String
|
||||
{
|
||||
defaultValue = wrappedValue
|
||||
self.key = key
|
||||
store = { $0.store(key: $1, value: $2.rawValue) }
|
||||
|
|
|
@ -27,18 +27,17 @@ public struct WindowGroup<Content>: Scene, TitledScene where Content: View {
|
|||
self.content = content()
|
||||
}
|
||||
|
||||
@_disfavoredOverload public init(_ title: Text,
|
||||
id: String,
|
||||
@ViewBuilder content: () -> Content) {
|
||||
@_disfavoredOverload
|
||||
public init(_ title: Text, id: String, @ViewBuilder content: () -> Content) {
|
||||
self.id = id
|
||||
self.title = title
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
@_disfavoredOverload public init<S>(_ title: S,
|
||||
id: String,
|
||||
@ViewBuilder content: () -> Content)
|
||||
where S: StringProtocol {
|
||||
@_disfavoredOverload
|
||||
public init<S>(_ title: S, id: String, @ViewBuilder content: () -> Content)
|
||||
where S: StringProtocol
|
||||
{
|
||||
self.id = id
|
||||
self.title = Text(title)
|
||||
self.content = content()
|
||||
|
@ -50,16 +49,15 @@ public struct WindowGroup<Content>: Scene, TitledScene where Content: View {
|
|||
self.content = content()
|
||||
}
|
||||
|
||||
@_disfavoredOverload public init(_ title: Text,
|
||||
@ViewBuilder content: () -> Content) {
|
||||
@_disfavoredOverload
|
||||
public init(_ title: Text, @ViewBuilder content: () -> Content) {
|
||||
id = ""
|
||||
self.title = title
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
@_disfavoredOverload public init<S>(_ title: S,
|
||||
@ViewBuilder content: () -> Content)
|
||||
where S: StringProtocol {
|
||||
@_disfavoredOverload
|
||||
public init<S>(_ title: S, @ViewBuilder content: () -> Content) where S: StringProtocol {
|
||||
id = ""
|
||||
self.title = Text(title)
|
||||
self.content = content()
|
||||
|
|
|
@ -39,8 +39,7 @@ public struct _AnyApp: App {
|
|||
fatalError("`_AnyApp` cannot be initialized without an underlying `App` type.")
|
||||
}
|
||||
|
||||
public static func _launch(_ app: Self,
|
||||
_ rootEnvironment: EnvironmentValues) {
|
||||
public static func _launch(_ app: Self, _ rootEnvironment: EnvironmentValues) {
|
||||
fatalError("`_AnyApp` cannot be launched. Access underlying `app` value.")
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
import CombineShim
|
||||
|
||||
@propertyWrapper public struct EnvironmentObject<ObjectType>: DynamicProperty
|
||||
where ObjectType: ObservableObject {
|
||||
where ObjectType: ObservableObject
|
||||
{
|
||||
@dynamicMemberLookup public struct Wrapper {
|
||||
internal let root: ObjectType
|
||||
public subscript<Subject>(
|
||||
|
|
|
@ -30,7 +30,8 @@ struct _AppearanceActionModifier: ViewModifier {
|
|||
}
|
||||
|
||||
extension ModifiedContent: AppearanceActionType
|
||||
where Content: View, Modifier == _AppearanceActionModifier {
|
||||
where Content: View, Modifier == _AppearanceActionModifier
|
||||
{
|
||||
var appear: (() -> ())? { modifier.appear }
|
||||
var disappear: (() -> ())? { modifier.disappear }
|
||||
}
|
||||
|
|
|
@ -35,12 +35,16 @@ extension View {
|
|||
}
|
||||
|
||||
public func clipped(antialiased: Bool = false) -> some View {
|
||||
clipShape(Rectangle(),
|
||||
style: FillStyle(antialiased: antialiased))
|
||||
clipShape(
|
||||
Rectangle(),
|
||||
style: FillStyle(antialiased: antialiased)
|
||||
)
|
||||
}
|
||||
|
||||
public func cornerRadius(_ radius: CGFloat, antialiased: Bool = true) -> some View {
|
||||
clipShape(RoundedRectangle(cornerRadius: radius),
|
||||
style: FillStyle(antialiased: antialiased))
|
||||
clipShape(
|
||||
RoundedRectangle(cornerRadius: radius),
|
||||
style: FillStyle(antialiased: antialiased)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,13 +31,15 @@ public struct _FlexFrameLayout: ViewModifier {
|
|||
minHeight == 0 && maxHeight == .infinity
|
||||
}
|
||||
|
||||
init(minWidth: CGFloat? = nil,
|
||||
idealWidth: CGFloat? = nil,
|
||||
maxWidth: CGFloat? = nil,
|
||||
minHeight: CGFloat? = nil,
|
||||
idealHeight: CGFloat? = nil,
|
||||
maxHeight: CGFloat? = nil,
|
||||
alignment: Alignment) {
|
||||
init(
|
||||
minWidth: CGFloat? = nil,
|
||||
idealWidth: CGFloat? = nil,
|
||||
maxWidth: CGFloat? = nil,
|
||||
minHeight: CGFloat? = nil,
|
||||
idealHeight: CGFloat? = nil,
|
||||
maxHeight: CGFloat? = nil,
|
||||
alignment: Alignment
|
||||
) {
|
||||
self.minWidth = minWidth
|
||||
self.idealWidth = idealWidth
|
||||
self.maxWidth = maxWidth
|
||||
|
@ -53,13 +55,15 @@ public struct _FlexFrameLayout: ViewModifier {
|
|||
}
|
||||
|
||||
extension View {
|
||||
public func frame(minWidth: CGFloat? = nil,
|
||||
idealWidth: CGFloat? = nil,
|
||||
maxWidth: CGFloat? = nil,
|
||||
minHeight: CGFloat? = nil,
|
||||
idealHeight: CGFloat? = nil,
|
||||
maxHeight: CGFloat? = nil,
|
||||
alignment: Alignment = .center) -> some View {
|
||||
public func frame(
|
||||
minWidth: CGFloat? = nil,
|
||||
idealWidth: CGFloat? = nil,
|
||||
maxWidth: CGFloat? = nil,
|
||||
minHeight: CGFloat? = nil,
|
||||
idealHeight: CGFloat? = nil,
|
||||
maxHeight: CGFloat? = nil,
|
||||
alignment: Alignment = .center
|
||||
) -> some View {
|
||||
func areInNondecreasingOrder(
|
||||
_ min: CGFloat?, _ ideal: CGFloat?, _ max: CGFloat?
|
||||
) -> Bool {
|
||||
|
@ -69,8 +73,9 @@ extension View {
|
|||
return min <= ideal && ideal <= max
|
||||
}
|
||||
|
||||
if !areInNondecreasingOrder(minWidth, idealWidth, maxWidth)
|
||||
|| !areInNondecreasingOrder(minHeight, idealHeight, maxHeight) {
|
||||
if !areInNondecreasingOrder(minWidth, idealWidth, maxWidth) ||
|
||||
!areInNondecreasingOrder(minHeight, idealHeight, maxHeight)
|
||||
{
|
||||
fatalError("Contradictory frame constraints specified.")
|
||||
}
|
||||
|
||||
|
@ -81,6 +86,7 @@ extension View {
|
|||
minHeight: minHeight,
|
||||
idealHeight: idealHeight, maxHeight: maxHeight,
|
||||
alignment: alignment
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,7 @@ public struct _FrameLayout: ViewModifier {
|
|||
public let height: CGFloat?
|
||||
public let alignment: Alignment
|
||||
|
||||
init(width: CGFloat?,
|
||||
height: CGFloat?,
|
||||
alignment: Alignment) {
|
||||
init(width: CGFloat?, height: CGFloat?, alignment: Alignment) {
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.alignment = alignment
|
||||
|
@ -31,9 +29,11 @@ public struct _FrameLayout: ViewModifier {
|
|||
}
|
||||
|
||||
extension View {
|
||||
public func frame(width: CGFloat? = nil,
|
||||
height: CGFloat? = nil,
|
||||
alignment: Alignment = .center) -> some View {
|
||||
public func frame(
|
||||
width: CGFloat? = nil,
|
||||
height: CGFloat? = nil,
|
||||
alignment: Alignment = .center
|
||||
) -> some View {
|
||||
modifier(_FrameLayout(width: width, height: height, alignment: alignment))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
//
|
||||
|
||||
public struct _BackgroundModifier<Background>: ViewModifier, EnvironmentReader
|
||||
where Background: View {
|
||||
where Background: View
|
||||
{
|
||||
public var environment: EnvironmentValues!
|
||||
public var background: Background
|
||||
public var alignment: Alignment
|
||||
|
@ -36,8 +37,10 @@ public struct _BackgroundModifier<Background>: ViewModifier, EnvironmentReader
|
|||
}
|
||||
|
||||
extension _BackgroundModifier: Equatable where Background: Equatable {
|
||||
public static func == (lhs: _BackgroundModifier<Background>,
|
||||
rhs: _BackgroundModifier<Background>) -> Bool {
|
||||
public static func == (
|
||||
lhs: _BackgroundModifier<Background>,
|
||||
rhs: _BackgroundModifier<Background>
|
||||
) -> Bool {
|
||||
lhs.background == rhs.background
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +55,8 @@ extension View {
|
|||
}
|
||||
|
||||
public struct _OverlayModifier<Overlay>: ViewModifier, EnvironmentReader
|
||||
where Overlay: View {
|
||||
where Overlay: View
|
||||
{
|
||||
public var environment: EnvironmentValues!
|
||||
public var overlay: Overlay
|
||||
public var alignment: Alignment
|
||||
|
@ -75,15 +79,15 @@ public struct _OverlayModifier<Overlay>: ViewModifier, EnvironmentReader
|
|||
}
|
||||
|
||||
extension _OverlayModifier: Equatable where Overlay: Equatable {
|
||||
public static func == (lhs: _OverlayModifier<Overlay>,
|
||||
rhs: _OverlayModifier<Overlay>) -> Bool {
|
||||
public static func == (lhs: _OverlayModifier<Overlay>, rhs: _OverlayModifier<Overlay>) -> Bool {
|
||||
lhs.overlay == rhs.overlay
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
public func overlay<Overlay>(_ overlay: Overlay,
|
||||
alignment: Alignment = .center) -> some View where Overlay: View {
|
||||
public func overlay<Overlay>(_ overlay: Overlay, alignment: Alignment = .center) -> some View
|
||||
where Overlay: View
|
||||
{
|
||||
modifier(_OverlayModifier(overlay: overlay, alignment: alignment))
|
||||
}
|
||||
|
||||
|
|
|
@ -40,8 +40,7 @@ class MountedCompositeElement<R: Renderer>: MountedElement<R> {
|
|||
}
|
||||
|
||||
extension MountedCompositeElement: Hashable {
|
||||
static func == (lhs: MountedCompositeElement<R>,
|
||||
rhs: MountedCompositeElement<R>) -> Bool {
|
||||
static func == (lhs: MountedCompositeElement<R>, rhs: MountedCompositeElement<R>) -> Bool {
|
||||
lhs === rhs
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,8 @@ public class MountedElement<R: Renderer> {
|
|||
updateEnvironment()
|
||||
}
|
||||
|
||||
@discardableResult func updateEnvironment() -> TypeInfo {
|
||||
@discardableResult
|
||||
func updateEnvironment() -> TypeInfo {
|
||||
// swiftlint:disable:next force_try
|
||||
let info = try! typeInfo(of: element.type)
|
||||
switch element {
|
||||
|
@ -143,7 +144,8 @@ extension TypeInfo {
|
|||
// swiftlint:disable force_try
|
||||
// Extract the view from the AnyView for modification, apply Environment changes:
|
||||
if genericTypes.contains(where: { $0 is EnvironmentModifier.Type }),
|
||||
let modifier = try! property(named: "modifier").get(from: element) as? EnvironmentModifier {
|
||||
let modifier = try! property(named: "modifier").get(from: element) as? EnvironmentModifier
|
||||
{
|
||||
modifier.modifyEnvironment(&modifiedEnv)
|
||||
}
|
||||
|
||||
|
@ -175,8 +177,7 @@ extension TypeInfo {
|
|||
/// Extract all `DynamicProperty` from a type, recursively.
|
||||
/// This is necessary as a `DynamicProperty` can be nested.
|
||||
/// `EnvironmentValues` can also be injected at this point.
|
||||
func dynamicProperties(_ environment: EnvironmentValues,
|
||||
source: inout Any) -> [PropertyInfo] {
|
||||
func dynamicProperties(_ environment: EnvironmentValues, source: inout Any) -> [PropertyInfo] {
|
||||
var dynamicProps = [PropertyInfo]()
|
||||
for prop in properties where prop.type is DynamicProperty.Type {
|
||||
dynamicProps.append(prop)
|
||||
|
@ -185,8 +186,10 @@ extension TypeInfo {
|
|||
_ = propInfo.injectEnvironment(from: environment, into: &source)
|
||||
var extracted = try! prop.get(from: source)
|
||||
dynamicProps.append(
|
||||
contentsOf: propInfo.dynamicProperties(environment,
|
||||
source: &extracted)
|
||||
contentsOf: propInfo.dynamicProperties(
|
||||
environment,
|
||||
source: &extracted
|
||||
)
|
||||
)
|
||||
// swiftlint:disable:next force_cast
|
||||
var extractedDynamicProp = extracted as! DynamicProperty
|
||||
|
|
|
@ -91,7 +91,8 @@ extension _AnyScene {
|
|||
) -> MountedScene<R> {
|
||||
var title: String?
|
||||
if let titledSelf = scene as? TitledScene,
|
||||
let text = titledSelf.title {
|
||||
let text = titledSelf.title
|
||||
{
|
||||
title = _TextProxy(text).rawText
|
||||
}
|
||||
let children: [MountedElement<R>]
|
||||
|
|
|
@ -86,24 +86,21 @@ public struct Path: Equatable, LosslessStringConvertible {
|
|||
self.init(storage: .rect(rect))
|
||||
}
|
||||
|
||||
public init(roundedRect rect: CGRect,
|
||||
cornerSize: CGSize,
|
||||
style: RoundedCornerStyle = .circular) {
|
||||
self.init(storage: .roundedRect(FixedRoundedRect(
|
||||
rect: rect,
|
||||
cornerSize: cornerSize,
|
||||
style: style
|
||||
)))
|
||||
public init(roundedRect rect: CGRect, cornerSize: CGSize, style: RoundedCornerStyle = .circular) {
|
||||
self.init(
|
||||
storage: .roundedRect(FixedRoundedRect(rect: rect, cornerSize: cornerSize, style: style))
|
||||
)
|
||||
}
|
||||
|
||||
public init(roundedRect rect: CGRect,
|
||||
cornerRadius: CGFloat,
|
||||
style: RoundedCornerStyle = .circular) {
|
||||
public init(
|
||||
roundedRect rect: CGRect,
|
||||
cornerRadius: CGFloat,
|
||||
style: RoundedCornerStyle = .circular
|
||||
) {
|
||||
self.init(
|
||||
storage: .roundedRect(FixedRoundedRect(
|
||||
rect: rect,
|
||||
cornerSize: CGSize(width: cornerRadius,
|
||||
height: cornerRadius),
|
||||
cornerSize: CGSize(width: cornerRadius, height: cornerRadius),
|
||||
style: style
|
||||
))
|
||||
)
|
||||
|
@ -192,55 +189,61 @@ extension Path {
|
|||
|
||||
public mutating func addRect(_ rect: CGRect, transform: CGAffineTransform = .identity) {
|
||||
move(to: rect.origin)
|
||||
addLine(to: CGPoint(x: rect.size.width, y: 0)
|
||||
.offset(by: rect.origin))
|
||||
addLine(to: CGPoint(x: rect.size.width, y: rect.size.height)
|
||||
.offset(by: rect.origin))
|
||||
addLine(to: CGPoint(x: 0, y: rect.size.height)
|
||||
.offset(by: rect.origin))
|
||||
addLine(to: CGPoint(x: rect.size.width, y: 0).offset(by: rect.origin))
|
||||
addLine(to: CGPoint(x: rect.size.width, y: rect.size.height).offset(by: rect.origin))
|
||||
addLine(to: CGPoint(x: 0, y: rect.size.height).offset(by: rect.origin))
|
||||
closeSubpath()
|
||||
}
|
||||
|
||||
public mutating func addRoundedRect(in rect: CGRect,
|
||||
cornerSize: CGSize,
|
||||
style: RoundedCornerStyle = .circular,
|
||||
transform: CGAffineTransform = .identity) {
|
||||
move(to: CGPoint(x: rect.size.width, y: rect.size.height / 2)
|
||||
.offset(by: rect.origin))
|
||||
addLine(to: CGPoint(x: rect.size.width, y: rect.size.height - cornerSize.height)
|
||||
.offset(by: rect.origin))
|
||||
addQuadCurve(to: CGPoint(x: rect.size.width - cornerSize.width, y: rect.size.height)
|
||||
.offset(by: rect.origin),
|
||||
control: CGPoint(x: rect.size.width, y: rect.size.height)
|
||||
.offset(by: rect.origin))
|
||||
addLine(to: CGPoint(x: cornerSize.width, y: rect.size.height)
|
||||
.offset(by: rect.origin))
|
||||
addQuadCurve(to: CGPoint(x: 0, y: rect.size.height - cornerSize.height)
|
||||
.offset(by: rect.origin),
|
||||
control: CGPoint(x: 0, y: rect.size.height)
|
||||
.offset(by: rect.origin))
|
||||
addLine(to: CGPoint(x: 0, y: cornerSize.height)
|
||||
.offset(by: rect.origin))
|
||||
addQuadCurve(to: CGPoint(x: cornerSize.width, y: 0)
|
||||
.offset(by: rect.origin),
|
||||
control: CGPoint.zero
|
||||
.offset(by: rect.origin))
|
||||
addLine(to: CGPoint(x: rect.size.width - cornerSize.width, y: 0)
|
||||
.offset(by: rect.origin))
|
||||
addQuadCurve(to: CGPoint(x: rect.size.width, y: cornerSize.height)
|
||||
.offset(by: rect.origin),
|
||||
control: CGPoint(x: rect.size.width, y: 0)
|
||||
.offset(by: rect.origin))
|
||||
public mutating func addRoundedRect(
|
||||
in rect: CGRect,
|
||||
cornerSize: CGSize,
|
||||
style: RoundedCornerStyle = .circular,
|
||||
transform: CGAffineTransform = .identity
|
||||
) {
|
||||
move(to: CGPoint(x: rect.size.width, y: rect.size.height / 2).offset(by: rect.origin))
|
||||
addLine(
|
||||
to: CGPoint(x: rect.size.width, y: rect.size.height - cornerSize.height)
|
||||
.offset(by: rect.origin)
|
||||
)
|
||||
addQuadCurve(
|
||||
to: CGPoint(x: rect.size.width - cornerSize.width, y: rect.size.height)
|
||||
.offset(by: rect.origin),
|
||||
control: CGPoint(x: rect.size.width, y: rect.size.height)
|
||||
.offset(by: rect.origin)
|
||||
)
|
||||
addLine(to: CGPoint(x: cornerSize.width, y: rect.size.height).offset(by: rect.origin))
|
||||
addQuadCurve(
|
||||
to: CGPoint(x: 0, y: rect.size.height - cornerSize.height)
|
||||
.offset(by: rect.origin),
|
||||
control: CGPoint(x: 0, y: rect.size.height)
|
||||
.offset(by: rect.origin)
|
||||
)
|
||||
addLine(to: CGPoint(x: 0, y: cornerSize.height).offset(by: rect.origin))
|
||||
addQuadCurve(
|
||||
to: CGPoint(x: cornerSize.width, y: 0)
|
||||
.offset(by: rect.origin),
|
||||
control: CGPoint.zero
|
||||
.offset(by: rect.origin)
|
||||
)
|
||||
addLine(to: CGPoint(x: rect.size.width - cornerSize.width, y: 0).offset(by: rect.origin))
|
||||
addQuadCurve(
|
||||
to: CGPoint(x: rect.size.width, y: cornerSize.height)
|
||||
.offset(by: rect.origin),
|
||||
control: CGPoint(x: rect.size.width, y: 0)
|
||||
.offset(by: rect.origin)
|
||||
)
|
||||
closeSubpath()
|
||||
}
|
||||
|
||||
public mutating func addEllipse(in rect: CGRect, transform: CGAffineTransform = .identity) {
|
||||
subpaths.append(.init(path: .init(ellipseIn: .init(origin: rect.origin
|
||||
.offset(by: .init(x: rect.size.width / 2,
|
||||
y: rect.size.height / 2)),
|
||||
size: .init(width: rect.size.width / 2,
|
||||
height: rect.size.height / 2))),
|
||||
transform: transform))
|
||||
subpaths.append(.init(
|
||||
path: .init(ellipseIn: .init(
|
||||
origin: rect.origin.offset(by: .init(x: rect.size.width / 2, y: rect.size.height / 2)),
|
||||
size: .init(width: rect.size.width / 2, height: rect.size.height / 2)
|
||||
)),
|
||||
transform: transform
|
||||
))
|
||||
}
|
||||
|
||||
public mutating func addRects(_ rects: [CGRect], transform: CGAffineTransform = .identity) {
|
||||
|
@ -251,71 +254,93 @@ extension Path {
|
|||
lines.forEach { addLine(to: $0) }
|
||||
}
|
||||
|
||||
public mutating func addRelativeArc(center: CGPoint,
|
||||
radius: CGFloat,
|
||||
startAngle: Angle,
|
||||
delta: Angle,
|
||||
transform: CGAffineTransform = .identity) {
|
||||
addArc(center: center,
|
||||
radius: radius,
|
||||
startAngle: startAngle,
|
||||
endAngle: startAngle + delta,
|
||||
clockwise: false)
|
||||
public mutating func addRelativeArc(
|
||||
center: CGPoint,
|
||||
radius: CGFloat,
|
||||
startAngle: Angle,
|
||||
delta: Angle,
|
||||
transform: CGAffineTransform = .identity
|
||||
) {
|
||||
addArc(
|
||||
center: center,
|
||||
radius: radius,
|
||||
startAngle: startAngle,
|
||||
endAngle: startAngle + delta,
|
||||
clockwise: false
|
||||
)
|
||||
}
|
||||
|
||||
// There's a great article on bezier curves here:
|
||||
// https://pomax.github.io/bezierinfo
|
||||
// FIXME: Handle negative delta
|
||||
public mutating func addArc(center: CGPoint,
|
||||
radius: CGFloat,
|
||||
startAngle: Angle,
|
||||
endAngle: Angle,
|
||||
clockwise: Bool,
|
||||
transform: CGAffineTransform = .identity) {
|
||||
public mutating func addArc(
|
||||
center: CGPoint,
|
||||
radius: CGFloat,
|
||||
startAngle: Angle,
|
||||
endAngle: Angle,
|
||||
clockwise: Bool,
|
||||
transform: CGAffineTransform = .identity
|
||||
) {
|
||||
if clockwise {
|
||||
addArc(center: center,
|
||||
radius: radius,
|
||||
startAngle: endAngle,
|
||||
endAngle: endAngle + (.radians(.pi * 2) - endAngle) + startAngle,
|
||||
clockwise: false)
|
||||
addArc(
|
||||
center: center,
|
||||
radius: radius,
|
||||
startAngle: endAngle,
|
||||
endAngle: endAngle + (.radians(.pi * 2) - endAngle) + startAngle,
|
||||
clockwise: false
|
||||
)
|
||||
} else {
|
||||
let angle = abs(startAngle.radians - endAngle.radians)
|
||||
if angle > .pi / 2 {
|
||||
// Split the angle into 90º chunks
|
||||
let chunk1 = Angle.radians(startAngle.radians + (.pi / 2))
|
||||
addArc(center: center,
|
||||
radius: radius,
|
||||
startAngle: startAngle,
|
||||
endAngle: chunk1,
|
||||
clockwise: clockwise)
|
||||
addArc(center: center,
|
||||
radius: radius,
|
||||
startAngle: chunk1,
|
||||
endAngle: endAngle,
|
||||
clockwise: clockwise)
|
||||
addArc(
|
||||
center: center,
|
||||
radius: radius,
|
||||
startAngle: startAngle,
|
||||
endAngle: chunk1,
|
||||
clockwise: clockwise
|
||||
)
|
||||
addArc(
|
||||
center: center,
|
||||
radius: radius,
|
||||
startAngle: chunk1,
|
||||
endAngle: endAngle,
|
||||
clockwise: clockwise
|
||||
)
|
||||
} else {
|
||||
let startPoint = CGPoint(x: radius + center.x,
|
||||
y: center.y)
|
||||
let endPoint = CGPoint(x: (radius * cos(angle)) + center.x,
|
||||
y: (radius * sin(angle)) + center.y)
|
||||
let startPoint = CGPoint(
|
||||
x: radius + center.x,
|
||||
y: center.y
|
||||
)
|
||||
let endPoint = CGPoint(
|
||||
x: (radius * cos(angle)) + center.x,
|
||||
y: (radius * sin(angle)) + center.y
|
||||
)
|
||||
let l = (4 / 3) * tan(angle / 4)
|
||||
let c1 = CGPoint(x: radius + center.x, y: (l * radius) + center.y)
|
||||
let c2 = CGPoint(x: ((cos(angle) + l * sin(angle)) * radius) + center.x,
|
||||
y: ((sin(angle) - l * cos(angle)) * radius) + center.y)
|
||||
let c2 = CGPoint(
|
||||
x: ((cos(angle) + l * sin(angle)) * radius) + center.x,
|
||||
y: ((sin(angle) - l * cos(angle)) * radius) + center.y
|
||||
)
|
||||
|
||||
move(to: startPoint.rotate(startAngle, around: center))
|
||||
addCurve(to: endPoint.rotate(startAngle, around: center),
|
||||
control1: c1.rotate(startAngle, around: center),
|
||||
control2: c2.rotate(startAngle, around: center))
|
||||
addCurve(
|
||||
to: endPoint.rotate(startAngle, around: center),
|
||||
control1: c1.rotate(startAngle, around: center),
|
||||
control2: c2.rotate(startAngle, around: center)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: How does this arc method work?
|
||||
public mutating func addArc(tangent1End p1: CGPoint,
|
||||
tangent2End p2: CGPoint,
|
||||
radius: CGFloat,
|
||||
transform: CGAffineTransform = .identity) {}
|
||||
public mutating func addArc(
|
||||
tangent1End p1: CGPoint,
|
||||
tangent2End p2: CGPoint,
|
||||
radius: CGFloat,
|
||||
transform: CGAffineTransform = .identity
|
||||
) {}
|
||||
|
||||
public mutating func addPath(_ path: Path, transform: CGAffineTransform = .identity) {
|
||||
subpaths.append(.init(path: path, transform: transform))
|
||||
|
|
|
@ -59,10 +59,16 @@ extension Rectangle: InsettableShape {
|
|||
}
|
||||
|
||||
public func path(in rect: CGRect) -> Path {
|
||||
.init(storage: .rect(CGRect(origin: rect.origin,
|
||||
size: CGSize(width: rect.size.width - (amount / 2),
|
||||
height: rect.size.height - (amount / 2)))),
|
||||
sizing: .flexible)
|
||||
.init(
|
||||
storage: .rect(CGRect(
|
||||
origin: rect.origin,
|
||||
size: CGSize(
|
||||
width: rect.size.width - (amount / 2),
|
||||
height: rect.size.height - (amount / 2)
|
||||
)
|
||||
)),
|
||||
sizing: .flexible
|
||||
)
|
||||
}
|
||||
|
||||
public func inset(by amount: CGFloat) -> Rectangle._Inset {
|
||||
|
|
|
@ -88,8 +88,11 @@ extension Shape {
|
|||
y: CGFloat = 1,
|
||||
anchor: UnitPoint = .center
|
||||
) -> ScaledShape<Self> {
|
||||
ScaledShape(shape: self,
|
||||
scale: CGSize(width: x, height: y), anchor: anchor)
|
||||
ScaledShape(
|
||||
shape: self,
|
||||
scale: CGSize(width: x, height: y),
|
||||
anchor: anchor
|
||||
)
|
||||
}
|
||||
|
||||
public func scale(_ scale: CGFloat, anchor: UnitPoint = .center) -> ScaledShape<Self> {
|
||||
|
|
|
@ -39,13 +39,18 @@ extension InsettableShape {
|
|||
lineWidth: CGFloat = 1,
|
||||
antialiased: Bool = true
|
||||
) -> some View where S: ShapeStyle {
|
||||
strokeBorder(content, style: StrokeStyle(lineWidth: lineWidth),
|
||||
antialiased: antialiased)
|
||||
strokeBorder(
|
||||
content,
|
||||
style: StrokeStyle(lineWidth: lineWidth),
|
||||
antialiased: antialiased
|
||||
)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func strokeBorder(lineWidth: CGFloat = 1, antialiased: Bool = true) -> some View {
|
||||
strokeBorder(style: StrokeStyle(lineWidth: lineWidth),
|
||||
antialiased: antialiased)
|
||||
strokeBorder(
|
||||
style: StrokeStyle(lineWidth: lineWidth),
|
||||
antialiased: antialiased
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,14 @@ public struct StrokeStyle: Equatable {
|
|||
public var dash: [CGFloat]
|
||||
public var dashPhase: CGFloat
|
||||
|
||||
public init(lineWidth: CGFloat = 1,
|
||||
lineCap: CGLineCap = .butt,
|
||||
lineJoin: CGLineJoin = .miter,
|
||||
miterLimit: CGFloat = 10,
|
||||
dash: [CGFloat] = [CGFloat](),
|
||||
dashPhase: CGFloat = 0) {
|
||||
public init(
|
||||
lineWidth: CGFloat = 1,
|
||||
lineCap: CGLineCap = .butt,
|
||||
lineJoin: CGLineJoin = .miter,
|
||||
miterLimit: CGFloat = 10,
|
||||
dash: [CGFloat] = [CGFloat](),
|
||||
dashPhase: CGFloat = 0
|
||||
) {
|
||||
self.lineWidth = lineWidth
|
||||
self.lineCap = lineCap
|
||||
self.lineJoin = lineJoin
|
||||
|
|
|
@ -186,9 +186,11 @@ public final class StackReconciler<R: Renderer> {
|
|||
}.store(in: &mountedApp.subscriptions)
|
||||
}
|
||||
|
||||
func render<T>(compositeElement: MountedCompositeElement<R>,
|
||||
body bodyKeypath: ReferenceWritableKeyPath<MountedCompositeElement<R>, Any>,
|
||||
result: KeyPath<MountedCompositeElement<R>, (Any) -> T>) -> T {
|
||||
func render<T>(
|
||||
compositeElement: MountedCompositeElement<R>,
|
||||
body bodyKeypath: ReferenceWritableKeyPath<MountedCompositeElement<R>, Any>,
|
||||
result: KeyPath<MountedCompositeElement<R>, (Any) -> T>
|
||||
) -> T {
|
||||
let info = compositeElement.updateEnvironment()
|
||||
|
||||
var stateIdx = 0
|
||||
|
|
|
@ -49,5 +49,6 @@ protocol ValueStorage {
|
|||
extension State: ValueStorage {}
|
||||
|
||||
extension State where Value: ExpressibleByNilLiteral {
|
||||
@inlinable public init() { self.init(wrappedValue: nil) }
|
||||
@inlinable
|
||||
public init() { self.init(wrappedValue: nil) }
|
||||
}
|
||||
|
|
|
@ -38,13 +38,17 @@ public struct CGPoint: Equatable {
|
|||
func rotate(_ angle: Angle, around origin: Self) -> Self {
|
||||
let cosAngle = cos(angle.radians)
|
||||
let sinAngle = sin(angle.radians)
|
||||
return .init(x: cosAngle * (x - origin.x) - sinAngle * (y - origin.y) + origin.x,
|
||||
y: sinAngle * (x - origin.x) + cosAngle * (y - origin.y) + origin.y)
|
||||
return .init(
|
||||
x: cosAngle * (x - origin.x) - sinAngle * (y - origin.y) + origin.x,
|
||||
y: sinAngle * (x - origin.x) + cosAngle * (y - origin.y) + origin.y
|
||||
)
|
||||
}
|
||||
|
||||
func offset(by offset: Self) -> Self {
|
||||
.init(x: x + offset.x,
|
||||
y: y + offset.y)
|
||||
.init(
|
||||
x: x + offset.x,
|
||||
y: y + offset.y
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,13 +111,20 @@ public struct CGAffineTransform: Equatable {
|
|||
public var ty: CGFloat
|
||||
|
||||
/// The identity matrix
|
||||
public static let identity: Self = .init(a: 1, b: 0, // 0
|
||||
c: 0, d: 1, // 0
|
||||
tx: 0, ty: 0) // 1
|
||||
public static let identity: Self = .init(
|
||||
a: 1,
|
||||
b: 0, // 0
|
||||
c: 0,
|
||||
d: 1, // 0
|
||||
tx: 0,
|
||||
ty: 0
|
||||
) // 1
|
||||
|
||||
public init(a: CGFloat, b: CGFloat,
|
||||
c: CGFloat, d: CGFloat,
|
||||
tx: CGFloat, ty: CGFloat) {
|
||||
public init(
|
||||
a: CGFloat, b: CGFloat,
|
||||
c: CGFloat, d: CGFloat,
|
||||
tx: CGFloat, ty: CGFloat
|
||||
) {
|
||||
self.a = a
|
||||
self.b = b
|
||||
self.c = c
|
||||
|
@ -135,28 +146,38 @@ public struct CGAffineTransform: Equatable {
|
|||
/// - Parameters:
|
||||
/// - sx: The factor by which to scale the x-axis of the coordinate system.
|
||||
/// - sy: The factor by which to scale the y-axis of the coordinate system.
|
||||
public init(scaleX sx: CGFloat,
|
||||
y sy: CGFloat) {
|
||||
self.init(a: sx, b: 0,
|
||||
c: 0, d: sy,
|
||||
tx: 0, ty: 0)
|
||||
public init(scaleX sx: CGFloat, y sy: CGFloat) {
|
||||
self.init(
|
||||
a: sx,
|
||||
b: 0,
|
||||
c: 0,
|
||||
d: sy,
|
||||
tx: 0,
|
||||
ty: 0
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns an affine transformation matrix constructed from translation values you provide.
|
||||
/// - Parameters:
|
||||
/// - tx: The value by which to move the x-axis of the coordinate system.
|
||||
/// - ty: The value by which to move the y-axis of the coordinate system.
|
||||
public init(translationX tx: CGFloat,
|
||||
y ty: CGFloat) {
|
||||
self.init(a: 1, b: 0,
|
||||
c: 0, d: 1,
|
||||
tx: tx, ty: ty)
|
||||
public init(translationX tx: CGFloat, y ty: CGFloat) {
|
||||
self.init(
|
||||
a: 1,
|
||||
b: 0,
|
||||
c: 0,
|
||||
d: 1,
|
||||
tx: tx,
|
||||
ty: ty
|
||||
)
|
||||
}
|
||||
|
||||
/// Transform the point into the transform's coordinate system.
|
||||
public func transform(point: CGPoint) -> CGPoint {
|
||||
CGPoint(x: (a * point.x) + (c * point.y) + tx,
|
||||
y: (b * point.x) + (d * point.y) + ty)
|
||||
CGPoint(
|
||||
x: (a * point.x) + (c * point.y) + tx,
|
||||
y: (b * point.x) + (d * point.y) + ty
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns an affine transformation matrix constructed by combining two existing affine
|
||||
|
@ -180,9 +201,14 @@ public struct CGAffineTransform: Equatable {
|
|||
}
|
||||
}
|
||||
}
|
||||
return .init(a: res[0][0], b: res[0][1],
|
||||
c: res[1][0], d: res[1][1],
|
||||
tx: res[2][0], ty: res[2][1])
|
||||
return .init(
|
||||
a: res[0][0],
|
||||
b: res[0][1],
|
||||
c: res[1][0],
|
||||
d: res[1][1],
|
||||
tx: res[2][0],
|
||||
ty: res[2][1]
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns an affine transformation matrix constructed by inverting an existing affine transform.
|
||||
|
@ -205,10 +231,9 @@ public struct CGAffineTransform: Equatable {
|
|||
/// - tx: The value by which to move x values with the affine transform.
|
||||
/// - ty: The value by which to move y values with the affine transform.
|
||||
public func translatedBy(x tx: CGFloat,
|
||||
y ty: CGFloat) -> Self {
|
||||
.init(a: a, b: b,
|
||||
c: c, d: d,
|
||||
tx: self.tx + tx, ty: self.ty + ty)
|
||||
y ty: CGFloat) -> Self
|
||||
{
|
||||
.init(a: a, b: b, c: c, d: d, tx: self.tx + tx, ty: self.ty + ty)
|
||||
}
|
||||
|
||||
/// Returns an affine transformation matrix constructed by scaling an existing affine transform.
|
||||
|
@ -216,10 +241,9 @@ public struct CGAffineTransform: Equatable {
|
|||
/// - sx: The value by which to scale x values of the affine transform.
|
||||
/// - sy: The value by which to scale y values of the affine transform.
|
||||
public func scaledBy(x sx: CGFloat,
|
||||
y sy: CGFloat) -> Self {
|
||||
.init(a: a + sx, b: b,
|
||||
c: c, d: d + sy,
|
||||
tx: tx, ty: ty)
|
||||
y sy: CGFloat) -> Self
|
||||
{
|
||||
.init(a: a + sx, b: b, c: c, d: d + sy, tx: tx, ty: ty)
|
||||
}
|
||||
|
||||
public var isIdentity: Bool {
|
||||
|
|
|
@ -34,8 +34,7 @@ public extension ListStyleDeferredToRenderer {
|
|||
}
|
||||
|
||||
func listRow<Row>(_ row: Row) -> AnyView where Row: View {
|
||||
AnyView(row
|
||||
.padding([.trailing, .top, .bottom]))
|
||||
AnyView(row.padding([.trailing, .top, .bottom]))
|
||||
}
|
||||
|
||||
func sectionHeader<Header>(_ header: Header) -> AnyView where Header: View {
|
||||
|
|
|
@ -49,46 +49,31 @@ public struct Color: Hashable, Equatable {
|
|||
self.evaluator = evaluator
|
||||
}
|
||||
|
||||
public init(_ colorSpace: RGBColorSpace = .sRGB,
|
||||
red: Double,
|
||||
green: Double,
|
||||
blue: Double,
|
||||
opacity: Double = 1) {
|
||||
public init(
|
||||
_ colorSpace: RGBColorSpace = .sRGB,
|
||||
red: Double,
|
||||
green: Double,
|
||||
blue: Double,
|
||||
opacity: Double = 1
|
||||
) {
|
||||
self.init { _ in
|
||||
_RGBA(red: red,
|
||||
green: green,
|
||||
blue: blue,
|
||||
opacity: opacity,
|
||||
space: colorSpace)
|
||||
_RGBA(red: red, green: green, blue: blue, opacity: opacity, space: colorSpace)
|
||||
}
|
||||
}
|
||||
|
||||
public init(_ colorSpace: RGBColorSpace = .sRGB,
|
||||
white: Double,
|
||||
opacity: Double = 1) {
|
||||
self.init(colorSpace,
|
||||
red: white,
|
||||
green: white,
|
||||
blue: white,
|
||||
opacity: opacity)
|
||||
public init(_ colorSpace: RGBColorSpace = .sRGB, white: Double, opacity: Double = 1) {
|
||||
self.init(colorSpace, red: white, green: white, blue: white, opacity: opacity)
|
||||
}
|
||||
|
||||
// Source for the formula:
|
||||
// https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative
|
||||
public init(hue: Double,
|
||||
saturation: Double,
|
||||
brightness: Double,
|
||||
opacity: Double = 1) {
|
||||
public init(hue: Double, saturation: Double, brightness: Double, opacity: Double = 1) {
|
||||
let a = saturation * min(brightness / 2, 1 - (brightness / 2))
|
||||
let f = { (n: Int) -> Double in
|
||||
let k = Double((n + Int(hue * 12)) % 12)
|
||||
return brightness - (a * max(-1, min(k - 3, 9 - k, 1)))
|
||||
}
|
||||
self.init(.sRGB,
|
||||
red: f(0),
|
||||
green: f(8),
|
||||
blue: f(4),
|
||||
opacity: opacity)
|
||||
self.init(.sRGB, red: f(0), green: f(8), blue: f(4), opacity: opacity)
|
||||
}
|
||||
|
||||
/// Create a `Color` dependent on the current `ColorScheme`.
|
||||
|
@ -118,17 +103,9 @@ extension Color {
|
|||
public static let primary: Self = .init {
|
||||
switch $0.colorScheme {
|
||||
case .light:
|
||||
return .init(red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
opacity: 1,
|
||||
space: .sRGB)
|
||||
return .init(red: 0, green: 0, blue: 0, opacity: 1, space: .sRGB)
|
||||
case .dark:
|
||||
return .init(red: 1,
|
||||
green: 1,
|
||||
blue: 1,
|
||||
opacity: 1,
|
||||
space: .sRGB)
|
||||
return .init(red: 1, green: 1, blue: 1, opacity: 1, space: .sRGB)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,11 +122,13 @@ extension Color {
|
|||
extension Color: ExpressibleByIntegerLiteral {
|
||||
/// Allows initializing value of `Color` type from hex values
|
||||
public init(integerLiteral bitMask: UInt32) {
|
||||
self.init(.sRGB,
|
||||
red: Double((bitMask & 0xFF0000) >> 16) / 255,
|
||||
green: Double((bitMask & 0x00FF00) >> 8) / 255,
|
||||
blue: Double(bitMask & 0x0000FF) / 255,
|
||||
opacity: 1)
|
||||
self.init(
|
||||
.sRGB,
|
||||
red: Double((bitMask & 0xFF0000) >> 16) / 255,
|
||||
green: Double((bitMask & 0x00FF00) >> 8) / 255,
|
||||
blue: Double(bitMask & 0x0000FF) / 255,
|
||||
opacity: 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,11 +145,13 @@ extension Color {
|
|||
else {
|
||||
return nil
|
||||
}
|
||||
self.init(.sRGB,
|
||||
red: Double(red) / 255,
|
||||
green: Double(green) / 255,
|
||||
blue: Double(blue) / 255,
|
||||
opacity: 1)
|
||||
self.init(
|
||||
.sRGB,
|
||||
red: Double(red) / 255,
|
||||
green: Double(green) / 255,
|
||||
blue: Double(blue) / 255,
|
||||
opacity: 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// swiftlint:disable line_length
|
||||
public struct Font: Hashable {
|
||||
public let _name: String
|
||||
public let _size: CGFloat
|
||||
|
@ -25,11 +24,31 @@ public struct Font: Hashable {
|
|||
public let _leading: Leading
|
||||
|
||||
public func italic() -> Self {
|
||||
.init(_name: _name, _size: _size, _design: _design, _weight: _weight, _smallCaps: _smallCaps, _italic: true, _bold: _bold, _monospaceDigit: _monospaceDigit, _leading: _leading)
|
||||
.init(
|
||||
_name: _name,
|
||||
_size: _size,
|
||||
_design: _design,
|
||||
_weight: _weight,
|
||||
_smallCaps: _smallCaps,
|
||||
_italic: true,
|
||||
_bold: _bold,
|
||||
_monospaceDigit: _monospaceDigit,
|
||||
_leading: _leading
|
||||
)
|
||||
}
|
||||
|
||||
public func smallCaps() -> Self {
|
||||
.init(_name: _name, _size: _size, _design: _design, _weight: _weight, _smallCaps: true, _italic: _italic, _bold: _bold, _monospaceDigit: _monospaceDigit, _leading: _leading)
|
||||
.init(
|
||||
_name: _name,
|
||||
_size: _size,
|
||||
_design: _design,
|
||||
_weight: _weight,
|
||||
_smallCaps: true,
|
||||
_italic: _italic,
|
||||
_bold: _bold,
|
||||
_monospaceDigit: _monospaceDigit,
|
||||
_leading: _leading
|
||||
)
|
||||
}
|
||||
|
||||
public func lowercaseSmallCaps() -> Self {
|
||||
|
@ -41,19 +60,59 @@ public struct Font: Hashable {
|
|||
}
|
||||
|
||||
public func monospacedDigit() -> Self {
|
||||
.init(_name: _name, _size: _size, _design: _design, _weight: _weight, _smallCaps: _smallCaps, _italic: _italic, _bold: _bold, _monospaceDigit: true, _leading: _leading)
|
||||
.init(
|
||||
_name: _name,
|
||||
_size: _size,
|
||||
_design: _design,
|
||||
_weight: _weight,
|
||||
_smallCaps: _smallCaps,
|
||||
_italic: _italic,
|
||||
_bold: _bold,
|
||||
_monospaceDigit: true,
|
||||
_leading: _leading
|
||||
)
|
||||
}
|
||||
|
||||
public func weight(_ weight: Weight) -> Self {
|
||||
.init(_name: _name, _size: _size, _design: _design, _weight: weight, _smallCaps: _smallCaps, _italic: _italic, _bold: _bold, _monospaceDigit: _monospaceDigit, _leading: _leading)
|
||||
.init(
|
||||
_name: _name,
|
||||
_size: _size,
|
||||
_design: _design,
|
||||
_weight: weight,
|
||||
_smallCaps: _smallCaps,
|
||||
_italic: _italic,
|
||||
_bold: _bold,
|
||||
_monospaceDigit: _monospaceDigit,
|
||||
_leading: _leading
|
||||
)
|
||||
}
|
||||
|
||||
public func bold() -> Self {
|
||||
.init(_name: _name, _size: _size, _design: _design, _weight: _weight, _smallCaps: _smallCaps, _italic: _italic, _bold: true, _monospaceDigit: _monospaceDigit, _leading: _leading)
|
||||
.init(
|
||||
_name: _name,
|
||||
_size: _size,
|
||||
_design: _design,
|
||||
_weight: _weight,
|
||||
_smallCaps: _smallCaps,
|
||||
_italic: _italic,
|
||||
_bold: true,
|
||||
_monospaceDigit: _monospaceDigit,
|
||||
_leading: _leading
|
||||
)
|
||||
}
|
||||
|
||||
public func leading(_ leading: Leading) -> Self {
|
||||
.init(_name: _name, _size: _size, _design: _design, _weight: _weight, _smallCaps: _smallCaps, _italic: _italic, _bold: true, _monospaceDigit: _monospaceDigit, _leading: leading)
|
||||
.init(
|
||||
_name: _name,
|
||||
_size: _size,
|
||||
_design: _design,
|
||||
_weight: _weight,
|
||||
_smallCaps: _smallCaps,
|
||||
_italic: _italic,
|
||||
_bold: true,
|
||||
_monospaceDigit: _monospaceDigit,
|
||||
_leading: leading
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,8 +145,20 @@ public enum _FontNames: String, CaseIterable {
|
|||
}
|
||||
|
||||
extension Font {
|
||||
public static func system(size: CGFloat, weight: Weight = .regular, design: Design = .default) -> Self {
|
||||
.init(_name: _FontNames.system.rawValue, _size: size, _design: design, _weight: weight, _smallCaps: false, _italic: false, _bold: false, _monospaceDigit: false, _leading: .standard)
|
||||
public static func system(size: CGFloat, weight: Weight = .regular,
|
||||
design: Design = .default) -> Self
|
||||
{
|
||||
.init(
|
||||
_name: _FontNames.system.rawValue,
|
||||
_size: size,
|
||||
_design: design,
|
||||
_weight: weight,
|
||||
_smallCaps: false,
|
||||
_italic: false,
|
||||
_bold: false,
|
||||
_monospaceDigit: false,
|
||||
_leading: .standard
|
||||
)
|
||||
}
|
||||
|
||||
public enum Design: Hashable {
|
||||
|
|
|
@ -26,9 +26,11 @@ public struct GridItem {
|
|||
public var spacing: CGFloat
|
||||
public var alignment: Alignment
|
||||
|
||||
public init(_ size: GridItem.Size = .flexible(),
|
||||
spacing: CGFloat? = nil,
|
||||
alignment: Alignment? = nil) {
|
||||
public init(
|
||||
_ size: GridItem.Size = .flexible(),
|
||||
spacing: CGFloat? = nil,
|
||||
alignment: Alignment? = nil
|
||||
) {
|
||||
self.size = size
|
||||
self.spacing = spacing ?? 4
|
||||
self.alignment = alignment ?? .center
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
// Created by Carson Katri on 7/3/20.
|
||||
//
|
||||
|
||||
public struct DisclosureGroup<Label, Content>: View
|
||||
where Label: View, Content: View {
|
||||
public struct DisclosureGroup<Label, Content>: View where Label: View, Content: View {
|
||||
@State var isExpanded: Bool = false
|
||||
let isExpandedBinding: Binding<Bool>?
|
||||
|
||||
|
@ -25,16 +24,17 @@ public struct DisclosureGroup<Label, Content>: View
|
|||
let label: Label
|
||||
let content: () -> Content
|
||||
|
||||
public init(@ViewBuilder content: @escaping () -> Content,
|
||||
@ViewBuilder label: () -> Label) {
|
||||
public init(@ViewBuilder content: @escaping () -> Content, @ViewBuilder label: () -> Label) {
|
||||
isExpandedBinding = nil
|
||||
self.label = label()
|
||||
self.content = content
|
||||
}
|
||||
|
||||
public init(isExpanded: Binding<Bool>,
|
||||
@ViewBuilder content: @escaping () -> Content,
|
||||
@ViewBuilder label: () -> Label) {
|
||||
public init(
|
||||
isExpanded: Binding<Bool>,
|
||||
@ViewBuilder content: @escaping () -> Content,
|
||||
@ViewBuilder label: () -> Label
|
||||
) {
|
||||
isExpandedBinding = isExpanded
|
||||
self.label = label()
|
||||
self.content = content
|
||||
|
@ -53,22 +53,26 @@ extension DisclosureGroup where Label == Text {
|
|||
// isExpanded: SwiftUI.Binding<Swift.Bool>,
|
||||
// @SwiftUI.ViewBuilder content: @escaping () -> Content)
|
||||
|
||||
@_disfavoredOverload public init<S>(_ label: S,
|
||||
@ViewBuilder content: @escaping () -> Content)
|
||||
where S: StringProtocol {
|
||||
@_disfavoredOverload
|
||||
public init<S>(_ label: S, @ViewBuilder content: @escaping () -> Content)
|
||||
where S: StringProtocol
|
||||
{
|
||||
self.init(content: content, label: { Text(label) })
|
||||
}
|
||||
|
||||
@_disfavoredOverload public init<S>(_ label: S,
|
||||
isExpanded: Binding<Bool>,
|
||||
@ViewBuilder content: @escaping () -> Content)
|
||||
where S: StringProtocol {
|
||||
@_disfavoredOverload
|
||||
public init<S>(
|
||||
_ label: S,
|
||||
isExpanded: Binding<Bool>,
|
||||
@ViewBuilder content: @escaping () -> Content
|
||||
) where S: StringProtocol {
|
||||
self.init(isExpanded: isExpanded, content: content, label: { Text(label) })
|
||||
}
|
||||
}
|
||||
|
||||
public struct _DisclosureGroupProxy<Label, Content>
|
||||
where Label: View, Content: View {
|
||||
where Label: View, Content: View
|
||||
{
|
||||
public var subject: DisclosureGroup<Label, Content>
|
||||
|
||||
public init(_ subject: DisclosureGroup<Label, Content>) { self.subject = subject }
|
||||
|
|
|
@ -31,8 +31,9 @@ protocol ForEachProtocol: GroupView {
|
|||
/// Text("\($0)")
|
||||
/// }
|
||||
/// }
|
||||
public struct ForEach<Data, ID, Content>: View
|
||||
where Data: RandomAccessCollection, ID: Hashable, Content: View {
|
||||
public struct ForEach<Data, ID, Content>: View where Data: RandomAccessCollection, ID: Hashable,
|
||||
Content: View
|
||||
{
|
||||
let data: Data
|
||||
let id: KeyPath<Data.Element, ID>
|
||||
public let content: (Data.Element) -> Content
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
//
|
||||
|
||||
public struct List<SelectionValue, Content>: View
|
||||
where SelectionValue: Hashable, Content: View {
|
||||
where SelectionValue: Hashable, Content: View
|
||||
{
|
||||
public enum _Selection {
|
||||
case one(Binding<SelectionValue?>?)
|
||||
case many(Binding<Set<SelectionValue>>?)
|
||||
|
@ -46,9 +47,7 @@ public struct List<SelectionValue, Content>: View
|
|||
if child.view is SectionView {
|
||||
if currentSection.count > 0 {
|
||||
sections.append(AnyView(Section {
|
||||
ForEach(Array(currentSection.enumerated()), id: \.offset) { _, view in
|
||||
view
|
||||
}
|
||||
ForEach(Array(currentSection.enumerated()), id: \.offset) { _, view in view }
|
||||
}))
|
||||
currentSection = []
|
||||
}
|
||||
|
@ -63,9 +62,7 @@ public struct List<SelectionValue, Content>: View
|
|||
}
|
||||
if currentSection.count > 0 {
|
||||
sections.append(AnyView(Section {
|
||||
ForEach(Array(currentSection.enumerated()), id: \.offset) { _, view in
|
||||
view
|
||||
}
|
||||
ForEach(Array(currentSection.enumerated()), id: \.offset) { _, view in view }
|
||||
}))
|
||||
}
|
||||
return AnyView(_ListRow.buildItems(sections) { view, isLast in
|
||||
|
@ -84,18 +81,14 @@ public struct List<SelectionValue, Content>: View
|
|||
public var body: some View {
|
||||
if let style = style as? ListStyleDeferredToRenderer {
|
||||
style.listBody(ScrollView {
|
||||
HStack {
|
||||
Spacer()
|
||||
}
|
||||
HStack { Spacer() }
|
||||
listStack
|
||||
.environment(\._outlineGroupStyle, _ListOutlineGroupStyle())
|
||||
})
|
||||
.frame(minHeight: 0, maxHeight: .infinity)
|
||||
} else {
|
||||
ScrollView {
|
||||
HStack {
|
||||
Spacer()
|
||||
}
|
||||
HStack { Spacer() }
|
||||
listStack
|
||||
.environment(\._outlineGroupStyle, _ListOutlineGroupStyle())
|
||||
}
|
||||
|
@ -104,14 +97,13 @@ public struct List<SelectionValue, Content>: View
|
|||
}
|
||||
|
||||
public struct _ListRow {
|
||||
static func buildItems<RowView>(_ children: [AnyView],
|
||||
@ViewBuilder rowView: @escaping (AnyView, Bool) -> RowView)
|
||||
-> some View where RowView: View {
|
||||
static func buildItems<RowView>(
|
||||
_ children: [AnyView],
|
||||
@ViewBuilder rowView: @escaping (AnyView, Bool) -> RowView
|
||||
) -> some View where RowView: View {
|
||||
ForEach(Array(children.enumerated()), id: \.offset) { offset, view in
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
Spacer()
|
||||
}
|
||||
HStack { Spacer() }
|
||||
rowView(view, offset == children.count - 1)
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +121,8 @@ public struct _ListRow {
|
|||
|
||||
/// This is a helper class that works around absence of "package private" access control in Swift
|
||||
public struct _ListProxy<SelectionValue, Content>
|
||||
where SelectionValue: Hashable, Content: View {
|
||||
where SelectionValue: Hashable, Content: View
|
||||
{
|
||||
public let subject: List<SelectionValue, Content>
|
||||
|
||||
public init(_ subject: List<SelectionValue, Content>) {
|
||||
|
@ -142,48 +135,42 @@ public struct _ListProxy<SelectionValue, Content>
|
|||
|
||||
extension List {
|
||||
// - MARK: Collection initializers
|
||||
public init<Data, RowContent>(_ data: Data,
|
||||
selection: Binding<Set<SelectionValue>>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
public init<Data, RowContent>(
|
||||
_ data: Data,
|
||||
selection: Binding<Set<SelectionValue>>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent
|
||||
)
|
||||
where Content == ForEach<Data, Data.Element.ID, HStack<RowContent>>,
|
||||
Data: RandomAccessCollection, RowContent: View,
|
||||
Data.Element: Identifiable {
|
||||
self.init(selection: selection) {
|
||||
ForEach(data) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
Data.Element: Identifiable
|
||||
{
|
||||
self.init(selection: selection) { ForEach(data) { row in HStack { rowContent(row) } } }
|
||||
}
|
||||
|
||||
public init<Data, ID, RowContent>(_ data: Data,
|
||||
|
||||
id: KeyPath<Data.Element, ID>,
|
||||
selection: Binding<Set<SelectionValue>>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
where Content == ForEach<Data, ID, HStack<RowContent>>,
|
||||
Data: RandomAccessCollection,
|
||||
ID: Hashable, RowContent: View {
|
||||
self.init(selection: selection) {
|
||||
ForEach(data, id: id) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
ID: Hashable, RowContent: View
|
||||
{
|
||||
self.init(selection: selection) { ForEach(data, id: id) { row in HStack { rowContent(row) } } }
|
||||
}
|
||||
|
||||
public init<Data, ID, RowContent>(_ data: Data,
|
||||
id: KeyPath<Data.Element, ID>,
|
||||
selection: Binding<SelectionValue?>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
public init<Data, ID, RowContent>(
|
||||
_ data: Data,
|
||||
id: KeyPath<Data.Element, ID>,
|
||||
selection: Binding<SelectionValue?>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent
|
||||
)
|
||||
where Content == ForEach<Data, ID, HStack<RowContent>>,
|
||||
Data: RandomAccessCollection, ID: Hashable, RowContent: View {
|
||||
Data: RandomAccessCollection, ID: Hashable, RowContent: View
|
||||
{
|
||||
self.init(selection: selection) {
|
||||
ForEach(data, id: id) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +179,8 @@ extension List {
|
|||
selection: Binding<SelectionValue?>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
where Content == ForEach<Data, Data.Element.ID, HStack<RowContent>>,
|
||||
Data: RandomAccessCollection, RowContent: View, Data.Element: Identifiable {
|
||||
Data: RandomAccessCollection, RowContent: View, Data.Element: Identifiable
|
||||
{
|
||||
self.init(selection: selection) {
|
||||
ForEach(data) { row in
|
||||
HStack {
|
||||
|
@ -203,112 +191,118 @@ extension List {
|
|||
}
|
||||
|
||||
// - MARK: Range initializers
|
||||
public init<RowContent>(_ data: Range<Int>,
|
||||
selection: Binding<Set<SelectionValue>>?,
|
||||
@ViewBuilder rowContent: @escaping (Int) -> RowContent)
|
||||
where Content == ForEach<Range<Int>, Int, HStack<RowContent>>, RowContent: View {
|
||||
public init<RowContent>(
|
||||
_ data: Range<Int>,
|
||||
selection: Binding<Set<SelectionValue>>?,
|
||||
@ViewBuilder rowContent: @escaping (Int) -> RowContent
|
||||
)
|
||||
where Content == ForEach<Range<Int>, Int, HStack<RowContent>>, RowContent: View
|
||||
{
|
||||
self.init(selection: selection) {
|
||||
ForEach(data) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public init<RowContent>(_ data: Range<Int>,
|
||||
selection: Binding<SelectionValue?>?,
|
||||
@ViewBuilder rowContent: @escaping (Int) -> RowContent)
|
||||
where Content == ForEach<Range<Int>, Int, HStack<RowContent>>, RowContent: View {
|
||||
public init<RowContent>(
|
||||
_ data: Range<Int>,
|
||||
selection: Binding<SelectionValue?>?,
|
||||
@ViewBuilder rowContent: @escaping (Int) -> RowContent
|
||||
)
|
||||
where Content == ForEach<Range<Int>, Int, HStack<RowContent>>, RowContent: View
|
||||
{
|
||||
self.init(selection: selection) {
|
||||
ForEach(data) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - MARK: OutlineGroup initializers
|
||||
|
||||
public init<Data, RowContent>(_ data: Data,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
selection: Binding<Set<SelectionValue>>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
where Content == OutlineGroup<Data,
|
||||
Data.Element.ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>>,
|
||||
Data: RandomAccessCollection,
|
||||
RowContent: View,
|
||||
Data.Element: Identifiable {
|
||||
public init<Data, RowContent>(
|
||||
_ data: Data,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
selection: Binding<Set<SelectionValue>>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent
|
||||
)
|
||||
where Content == OutlineGroup<
|
||||
Data,
|
||||
Data.Element.ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>
|
||||
>, Data: RandomAccessCollection, RowContent: View, Data.Element: Identifiable
|
||||
{
|
||||
self.init(selection: selection) {
|
||||
OutlineGroup(data, children: children) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public init<Data, ID, RowContent>(_ data: Data,
|
||||
id: KeyPath<Data.Element, ID>,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
selection: Binding<Set<SelectionValue>>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
where Content == OutlineGroup<Data,
|
||||
ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>>,
|
||||
Data: RandomAccessCollection,
|
||||
ID: Hashable,
|
||||
RowContent: View {
|
||||
public init<Data, ID, RowContent>(
|
||||
_ data: Data,
|
||||
id: KeyPath<Data.Element, ID>,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
selection: Binding<Set<SelectionValue>>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent
|
||||
)
|
||||
where Content == OutlineGroup<
|
||||
Data,
|
||||
ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>
|
||||
>, Data: RandomAccessCollection, ID: Hashable, RowContent: View
|
||||
{
|
||||
self.init(selection: selection) {
|
||||
OutlineGroup(data, id: id, children: children) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public init<Data, RowContent>(_ data: Data,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
selection: Binding<SelectionValue?>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
where Content == OutlineGroup<Data,
|
||||
Data.Element.ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>>,
|
||||
Data: RandomAccessCollection, RowContent: View, Data.Element: Identifiable {
|
||||
public init<Data, RowContent>(
|
||||
_ data: Data,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
selection: Binding<SelectionValue?>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent
|
||||
)
|
||||
where Content == OutlineGroup<
|
||||
Data,
|
||||
Data.Element.ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>
|
||||
>, Data: RandomAccessCollection, RowContent: View, Data.Element: Identifiable
|
||||
{
|
||||
self.init(selection: selection) {
|
||||
OutlineGroup(data, children: children) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public init<Data, ID, RowContent>(_ data: Data,
|
||||
id: KeyPath<Data.Element, ID>,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
selection: Binding<SelectionValue?>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
where Content == OutlineGroup<Data,
|
||||
ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>>,
|
||||
Data: RandomAccessCollection, ID: Hashable, RowContent: View {
|
||||
public init<Data, ID, RowContent>(
|
||||
_ data: Data,
|
||||
id: KeyPath<Data.Element, ID>,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
selection: Binding<SelectionValue?>?,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent
|
||||
)
|
||||
where Content == OutlineGroup<
|
||||
Data,
|
||||
ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>
|
||||
>, Data: RandomAccessCollection, ID: Hashable, RowContent: View
|
||||
{
|
||||
self.init(selection: selection) {
|
||||
OutlineGroup(data, id: id, children: children) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -320,76 +314,83 @@ extension List where SelectionValue == Never {
|
|||
self.content = content()
|
||||
}
|
||||
|
||||
public init<Data, RowContent>(_ data: Data,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
public init<Data, RowContent>(
|
||||
_ data: Data,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent
|
||||
)
|
||||
where Content == ForEach<Data, Data.Element.ID, HStack<RowContent>>,
|
||||
Data: RandomAccessCollection, RowContent: View, Data.Element: Identifiable {
|
||||
Data: RandomAccessCollection, RowContent: View, Data.Element: Identifiable
|
||||
{
|
||||
selection = .one(nil)
|
||||
content = ForEach(data) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
|
||||
public init<Data, RowContent>(_ data: Data,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
where Content == OutlineGroup<Data,
|
||||
Data.Element.ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>>,
|
||||
Data: RandomAccessCollection, RowContent: View, Data.Element: Identifiable {
|
||||
public init<Data, RowContent>(
|
||||
_ data: Data,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent
|
||||
)
|
||||
where Content == OutlineGroup<
|
||||
Data,
|
||||
Data.Element.ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>
|
||||
>, Data: RandomAccessCollection, RowContent: View, Data.Element: Identifiable
|
||||
{
|
||||
self.init {
|
||||
OutlineGroup(data, children: children) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public init<Data, ID, RowContent>(_ data: Data,
|
||||
id: KeyPath<Data.Element, ID>,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
where Content == OutlineGroup<Data,
|
||||
ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>>,
|
||||
Data: RandomAccessCollection, ID: Hashable, RowContent: View {
|
||||
public init<Data, ID, RowContent>(
|
||||
_ data: Data,
|
||||
id: KeyPath<Data.Element, ID>,
|
||||
children: KeyPath<Data.Element, Data?>,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent
|
||||
)
|
||||
where Content == OutlineGroup<
|
||||
Data,
|
||||
ID,
|
||||
HStack<RowContent>,
|
||||
HStack<RowContent>,
|
||||
DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>
|
||||
>, Data: RandomAccessCollection, ID: Hashable, RowContent: View
|
||||
{
|
||||
self.init {
|
||||
OutlineGroup(data, id: id, children: children) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public init<Data, ID, RowContent>(_ data: Data,
|
||||
id: KeyPath<Data.Element, ID>,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent)
|
||||
public init<Data, ID, RowContent>(
|
||||
_ data: Data,
|
||||
id: KeyPath<Data.Element, ID>,
|
||||
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent
|
||||
)
|
||||
where Content == ForEach<Data, ID, HStack<RowContent>>,
|
||||
Data: RandomAccessCollection, ID: Hashable, RowContent: View {
|
||||
Data: RandomAccessCollection, ID: Hashable, RowContent: View
|
||||
{
|
||||
selection = .one(nil)
|
||||
content = ForEach(data, id: id) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
|
||||
public init<RowContent>(_ data: Range<Int>,
|
||||
@ViewBuilder rowContent: @escaping (Int) -> RowContent)
|
||||
where Content == ForEach<Range<Int>, Int, HStack<RowContent>>, RowContent: View {
|
||||
public init<RowContent>(
|
||||
_ data: Range<Int>,
|
||||
@ViewBuilder rowContent: @escaping (Int) -> RowContent
|
||||
)
|
||||
where Content == ForEach<Range<Int>, Int, HStack<RowContent>>, RowContent: View
|
||||
{
|
||||
selection = .one(nil)
|
||||
content = ForEach(data) { row in
|
||||
HStack {
|
||||
rowContent(row)
|
||||
}
|
||||
HStack { rowContent(row) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
//
|
||||
|
||||
public struct OutlineGroup<Data, ID, Parent, Leaf, Subgroup>
|
||||
where Data: RandomAccessCollection, ID: Hashable {
|
||||
where Data: RandomAccessCollection, ID: Hashable
|
||||
{
|
||||
enum Root {
|
||||
case collection(Data)
|
||||
case single(Data.Element)
|
||||
|
@ -32,49 +33,51 @@ extension OutlineGroup where ID == Data.Element.ID,
|
|||
Parent: View,
|
||||
Parent == Leaf,
|
||||
Subgroup == DisclosureGroup<Parent, OutlineSubgroupChildren>,
|
||||
Data.Element: Identifiable {
|
||||
public init<DataElement>(_ root: DataElement,
|
||||
children: KeyPath<DataElement, Data?>,
|
||||
@ViewBuilder content: @escaping (DataElement) -> Leaf)
|
||||
where ID == DataElement.ID, DataElement: Identifiable, DataElement == Data.Element {
|
||||
self.init(root,
|
||||
id: \.id,
|
||||
children: children,
|
||||
content: content)
|
||||
Data.Element: Identifiable
|
||||
{
|
||||
public init<DataElement>(
|
||||
_ root: DataElement,
|
||||
children: KeyPath<DataElement, Data?>,
|
||||
@ViewBuilder content: @escaping (DataElement) -> Leaf
|
||||
) where ID == DataElement.ID, DataElement: Identifiable, DataElement == Data.Element {
|
||||
self.init(root, id: \.id, children: children, content: content)
|
||||
}
|
||||
|
||||
public init<DataElement>(_ data: Data,
|
||||
children: KeyPath<DataElement, Data?>,
|
||||
@ViewBuilder content: @escaping (DataElement) -> Leaf)
|
||||
where ID == DataElement.ID,
|
||||
DataElement: Identifiable,
|
||||
DataElement == Data.Element {
|
||||
self.init(data,
|
||||
id: \.id,
|
||||
children: children,
|
||||
content: content)
|
||||
public init<DataElement>(
|
||||
_ data: Data,
|
||||
children: KeyPath<DataElement, Data?>,
|
||||
@ViewBuilder content: @escaping (DataElement) -> Leaf
|
||||
) where ID == DataElement.ID, DataElement: Identifiable, DataElement == Data.Element {
|
||||
self.init(data, id: \.id, children: children, content: content)
|
||||
}
|
||||
}
|
||||
|
||||
extension OutlineGroup where Parent: View,
|
||||
Parent == Leaf,
|
||||
Subgroup == DisclosureGroup<Parent, OutlineSubgroupChildren> {
|
||||
public init<DataElement>(_ root: DataElement,
|
||||
id: KeyPath<DataElement, ID>,
|
||||
children: KeyPath<DataElement, Data?>,
|
||||
@ViewBuilder content: @escaping (DataElement) -> Leaf)
|
||||
where DataElement == Data.Element {
|
||||
Subgroup == DisclosureGroup<Parent, OutlineSubgroupChildren>
|
||||
{
|
||||
public init<DataElement>(
|
||||
_ root: DataElement,
|
||||
id: KeyPath<DataElement, ID>,
|
||||
children: KeyPath<DataElement, Data?>,
|
||||
@ViewBuilder content: @escaping (DataElement) -> Leaf
|
||||
)
|
||||
where DataElement == Data.Element
|
||||
{
|
||||
self.root = .single(root)
|
||||
self.children = children
|
||||
self.id = id
|
||||
self.content = content
|
||||
}
|
||||
|
||||
public init<DataElement>(_ data: Data,
|
||||
id: KeyPath<DataElement, ID>,
|
||||
children: KeyPath<DataElement, Data?>,
|
||||
@ViewBuilder content: @escaping (DataElement) -> Leaf)
|
||||
where DataElement == Data.Element {
|
||||
public init<DataElement>(
|
||||
_ data: Data,
|
||||
id: KeyPath<DataElement, ID>,
|
||||
children: KeyPath<DataElement, Data?>,
|
||||
@ViewBuilder content: @escaping (DataElement) -> Leaf
|
||||
)
|
||||
where DataElement == Data.Element
|
||||
{
|
||||
root = .collection(data)
|
||||
self.id = id
|
||||
self.children = children
|
||||
|
@ -90,10 +93,12 @@ extension OutlineGroup: View where Parent: View, Leaf: View, Subgroup: View {
|
|||
OutlineSubgroupChildren { () -> AnyView in
|
||||
if let subgroup = elem[keyPath: children] {
|
||||
return AnyView(DisclosureGroup(content: {
|
||||
OutlineGroup(root: .collection(subgroup),
|
||||
children: children,
|
||||
id: id,
|
||||
content: content)
|
||||
OutlineGroup(
|
||||
root: .collection(subgroup),
|
||||
children: children,
|
||||
id: id,
|
||||
content: content
|
||||
)
|
||||
}) {
|
||||
content(elem)
|
||||
})
|
||||
|
|
|
@ -77,12 +77,14 @@ extension Section: View, SectionView where Parent: View, Content: View, Footer:
|
|||
}
|
||||
|
||||
func listRow(_ style: ListStyle) -> AnyView {
|
||||
AnyView(VStack(alignment: .leading) {
|
||||
headerView(style)
|
||||
sectionContent(style)
|
||||
footerView(style)
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity))
|
||||
AnyView(
|
||||
VStack(alignment: .leading) {
|
||||
headerView(style)
|
||||
sectionContent(style)
|
||||
footerView(style)
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,40 +48,141 @@ public struct TupleView<T>: View {
|
|||
_children = [AnyView(v1), AnyView(v2), AnyView(v3)]
|
||||
}
|
||||
|
||||
// swiftlint:disable line_length
|
||||
init<T1: View, T2: View, T3: View, T4: View>(_ v1: T1, _ v2: T2, _ v3: T3, _ v4: T4) where T == (T1, T2, T3, T4) {
|
||||
init<T1: View, T2: View, T3: View, T4: View>(_ v1: T1, _ v2: T2, _ v3: T3, _ v4: T4)
|
||||
where T == (T1, T2, T3, T4)
|
||||
{
|
||||
value = (v1, v2, v3, v4)
|
||||
_children = [AnyView(v1), AnyView(v2), AnyView(v3), AnyView(v4)]
|
||||
}
|
||||
|
||||
init<T1: View, T2: View, T3: View, T4: View, T5: View>(_ v1: T1, _ v2: T2, _ v3: T3, _ v4: T4, _ v5: T5) where T == (T1, T2, T3, T4, T5) {
|
||||
init<T1: View, T2: View, T3: View, T4: View, T5: View>(
|
||||
_ v1: T1,
|
||||
_ v2: T2,
|
||||
_ v3: T3,
|
||||
_ v4: T4,
|
||||
_ v5: T5
|
||||
) where T == (T1, T2, T3, T4, T5) {
|
||||
value = (v1, v2, v3, v4, v5)
|
||||
_children = [AnyView(v1), AnyView(v2), AnyView(v3), AnyView(v4), AnyView(v5)]
|
||||
}
|
||||
|
||||
init<T1: View, T2: View, T3: View, T4: View, T5: View, T6: View>(_ v1: T1, _ v2: T2, _ v3: T3, _ v4: T4, _ v5: T5, _ v6: T6) where T == (T1, T2, T3, T4, T5, T6) {
|
||||
init<T1: View, T2: View, T3: View, T4: View, T5: View, T6: View>(
|
||||
_ v1: T1,
|
||||
_ v2: T2,
|
||||
_ v3: T3,
|
||||
_ v4: T4,
|
||||
_ v5: T5,
|
||||
_ v6: T6
|
||||
) where T == (T1, T2, T3, T4, T5, T6) {
|
||||
value = (v1, v2, v3, v4, v5, v6)
|
||||
_children = [AnyView(v1), AnyView(v2), AnyView(v3), AnyView(v4), AnyView(v5), AnyView(v6)]
|
||||
}
|
||||
|
||||
init<T1: View, T2: View, T3: View, T4: View, T5: View, T6: View, T7: View>(_ v1: T1, _ v2: T2, _ v3: T3, _ v4: T4, _ v5: T5, _ v6: T6, _ v7: T7) where T == (T1, T2, T3, T4, T5, T6, T7) {
|
||||
init<T1: View, T2: View, T3: View, T4: View, T5: View, T6: View, T7: View>(
|
||||
_ v1: T1,
|
||||
_ v2: T2,
|
||||
_ v3: T3,
|
||||
_ v4: T4,
|
||||
_ v5: T5,
|
||||
_ v6: T6,
|
||||
_ v7: T7
|
||||
) where T == (T1, T2, T3, T4, T5, T6, T7) {
|
||||
value = (v1, v2, v3, v4, v5, v6, v7)
|
||||
_children = [AnyView(v1), AnyView(v2), AnyView(v3), AnyView(v4), AnyView(v5), AnyView(v6), AnyView(v7)]
|
||||
_children = [
|
||||
AnyView(v1),
|
||||
AnyView(v2),
|
||||
AnyView(v3),
|
||||
AnyView(v4),
|
||||
AnyView(v5),
|
||||
AnyView(v6),
|
||||
AnyView(v7),
|
||||
]
|
||||
}
|
||||
|
||||
init<T1: View, T2: View, T3: View, T4: View, T5: View, T6: View, T7: View, T8: View>(_ v1: T1, _ v2: T2, _ v3: T3, _ v4: T4, _ v5: T5, _ v6: T6, _ v7: T7, _ v8: T8) where T == (T1, T2, T3, T4, T5, T6, T7, T8) {
|
||||
init<T1: View, T2: View, T3: View, T4: View, T5: View, T6: View, T7: View, T8: View>(
|
||||
_ v1: T1,
|
||||
_ v2: T2,
|
||||
_ v3: T3,
|
||||
_ v4: T4,
|
||||
_ v5: T5,
|
||||
_ v6: T6,
|
||||
_ v7: T7,
|
||||
_ v8: T8
|
||||
) where T == (T1, T2, T3, T4, T5, T6, T7, T8) {
|
||||
value = (v1, v2, v3, v4, v5, v6, v7, v8)
|
||||
_children = [AnyView(v1), AnyView(v2), AnyView(v3), AnyView(v4), AnyView(v5), AnyView(v6), AnyView(v7), AnyView(v8)]
|
||||
_children = [
|
||||
AnyView(v1),
|
||||
AnyView(v2),
|
||||
AnyView(v3),
|
||||
AnyView(v4),
|
||||
AnyView(v5),
|
||||
AnyView(v6),
|
||||
AnyView(v7),
|
||||
AnyView(v8),
|
||||
]
|
||||
}
|
||||
|
||||
init<T1: View, T2: View, T3: View, T4: View, T5: View, T6: View, T7: View, T8: View, T9: View>(_ v1: T1, _ v2: T2, _ v3: T3, _ v4: T4, _ v5: T5, _ v6: T6, _ v7: T7, _ v8: T8, _ v9: T9) where T == (T1, T2, T3, T4, T5, T6, T7, T8, T9) {
|
||||
init<T1: View, T2: View, T3: View, T4: View, T5: View, T6: View, T7: View, T8: View, T9: View>(
|
||||
_ v1: T1,
|
||||
_ v2: T2,
|
||||
_ v3: T3,
|
||||
_ v4: T4,
|
||||
_ v5: T5,
|
||||
_ v6: T6,
|
||||
_ v7: T7,
|
||||
_ v8: T8,
|
||||
_ v9: T9
|
||||
) where T == (T1, T2, T3, T4, T5, T6, T7, T8, T9) {
|
||||
value = (v1, v2, v3, v4, v5, v6, v7, v8, v9)
|
||||
_children = [AnyView(v1), AnyView(v2), AnyView(v3), AnyView(v4), AnyView(v5), AnyView(v6), AnyView(v7), AnyView(v8), AnyView(v9)]
|
||||
_children = [
|
||||
AnyView(v1),
|
||||
AnyView(v2),
|
||||
AnyView(v3),
|
||||
AnyView(v4),
|
||||
AnyView(v5),
|
||||
AnyView(v6),
|
||||
AnyView(v7),
|
||||
AnyView(v8),
|
||||
AnyView(v9),
|
||||
]
|
||||
}
|
||||
|
||||
init<T1: View, T2: View, T3: View, T4: View, T5: View, T6: View, T7: View, T8: View, T9: View, T10: View>(_ v1: T1, _ v2: T2, _ v3: T3, _ v4: T4, _ v5: T5, _ v6: T6, _ v7: T7, _ v8: T8, _ v9: T9, _ v10: T10) where T == (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) {
|
||||
init<
|
||||
T1: View,
|
||||
T2: View,
|
||||
T3: View,
|
||||
T4: View,
|
||||
T5: View,
|
||||
T6: View,
|
||||
T7: View,
|
||||
T8: View,
|
||||
T9: View,
|
||||
T10: View
|
||||
>(
|
||||
_ v1: T1,
|
||||
_ v2: T2,
|
||||
_ v3: T3,
|
||||
_ v4: T4,
|
||||
_ v5: T5,
|
||||
_ v6: T6,
|
||||
_ v7: T7,
|
||||
_ v8: T8,
|
||||
_ v9: T9,
|
||||
_ v10: T10
|
||||
) where T == (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) {
|
||||
value = (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)
|
||||
_children = [AnyView(v1), AnyView(v2), AnyView(v3), AnyView(v4), AnyView(v5), AnyView(v6), AnyView(v7), AnyView(v8), AnyView(v9), AnyView(v10)]
|
||||
_children = [
|
||||
AnyView(v1),
|
||||
AnyView(v2),
|
||||
AnyView(v3),
|
||||
AnyView(v4),
|
||||
AnyView(v5),
|
||||
AnyView(v6),
|
||||
AnyView(v7),
|
||||
AnyView(v8),
|
||||
AnyView(v9),
|
||||
AnyView(v10),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,11 +22,13 @@ public struct LazyHGrid<Content>: View where Content: View {
|
|||
let pinnedViews: PinnedScrollableViews
|
||||
let content: Content
|
||||
|
||||
public init(rows: [GridItem],
|
||||
alignment: VerticalAlignment = .center,
|
||||
spacing: CGFloat? = nil,
|
||||
pinnedViews: PinnedScrollableViews = .init(),
|
||||
@ViewBuilder content: () -> Content) {
|
||||
public init(
|
||||
rows: [GridItem],
|
||||
alignment: VerticalAlignment = .center,
|
||||
spacing: CGFloat? = nil,
|
||||
pinnedViews: PinnedScrollableViews = .init(),
|
||||
@ViewBuilder content: () -> Content
|
||||
) {
|
||||
self.rows = rows
|
||||
self.alignment = alignment
|
||||
self.spacing = spacing ?? 8
|
||||
|
|
|
@ -22,11 +22,13 @@ public struct LazyVGrid<Content>: View where Content: View {
|
|||
let pinnedViews: PinnedScrollableViews
|
||||
let content: Content
|
||||
|
||||
public init(columns: [GridItem],
|
||||
alignment: HorizontalAlignment = .center,
|
||||
spacing: CGFloat? = nil,
|
||||
pinnedViews: PinnedScrollableViews = .init(),
|
||||
@ViewBuilder content: () -> Content) {
|
||||
public init(
|
||||
columns: [GridItem],
|
||||
alignment: HorizontalAlignment = .center,
|
||||
spacing: CGFloat? = nil,
|
||||
pinnedViews: PinnedScrollableViews = .init(),
|
||||
@ViewBuilder content: () -> Content
|
||||
) {
|
||||
self.columns = columns
|
||||
self.alignment = alignment
|
||||
self.spacing = spacing ?? 8
|
||||
|
|
|
@ -40,9 +40,11 @@ public struct ScrollView<Content>: View where Content: View {
|
|||
public let axes: Axis.Set
|
||||
public let showsIndicators: Bool
|
||||
|
||||
public init(_ axes: Axis.Set = .vertical,
|
||||
showsIndicators: Bool = true,
|
||||
@ViewBuilder content: () -> Content) {
|
||||
public init(
|
||||
_ axes: Axis.Set = .vertical,
|
||||
showsIndicators: Bool = true,
|
||||
@ViewBuilder content: () -> Content
|
||||
) {
|
||||
self.axes = axes
|
||||
self.showsIndicators = showsIndicators
|
||||
self.content = content()
|
||||
|
|
|
@ -81,8 +81,10 @@ public struct _NavigationLinkProxy<Label, Destination> where Label: View, Destin
|
|||
}
|
||||
|
||||
public var label: AnyView {
|
||||
subject.style.makeBody(configuration: .init(body: AnyView(subject.label),
|
||||
isSelected: isSelected))
|
||||
subject.style.makeBody(configuration: .init(
|
||||
body: AnyView(subject.label),
|
||||
isSelected: isSelected
|
||||
))
|
||||
}
|
||||
|
||||
public var style: _AnyNavigationLinkStyle { subject.style }
|
||||
|
|
|
@ -67,7 +67,8 @@ public struct Picker<Label: View, SelectionValue: Hashable, Content: View>: View
|
|||
// update the binding.
|
||||
ForEach(0..<children.count) { index in
|
||||
if let forEach = mapAnyView(children[index], transform: { (v: ForEachProtocol) in v }),
|
||||
forEach.elementType == SelectionValue.self {
|
||||
forEach.elementType == SelectionValue.self
|
||||
{
|
||||
let nestedChildren = forEach.children
|
||||
|
||||
ForEach(0..<nestedChildren.count) { nestedIndex in
|
||||
|
@ -82,7 +83,8 @@ public struct Picker<Label: View, SelectionValue: Hashable, Content: View>: View
|
|||
}
|
||||
|
||||
extension Picker where Label == Text {
|
||||
@_disfavoredOverload public init<S: StringProtocol>(
|
||||
@_disfavoredOverload
|
||||
public init<S: StringProtocol>(
|
||||
_ title: S,
|
||||
selection: Binding<SelectionValue>,
|
||||
@ViewBuilder content: () -> Content
|
||||
|
|
|
@ -82,7 +82,7 @@ extension Text._Storage {
|
|||
switch self {
|
||||
case let .segmentedText(segments):
|
||||
return segments
|
||||
.map { $0.0.rawText }
|
||||
.map(\.0.rawText)
|
||||
.reduce("", +)
|
||||
case let .verbatim(text):
|
||||
return text
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
|
||||
/// A `View` with no effect on rendering.
|
||||
public struct EmptyView: View {
|
||||
@inlinable public init() {}
|
||||
@inlinable
|
||||
public init() {}
|
||||
|
||||
public var body: Never {
|
||||
neverBody("EmptyView")
|
||||
|
@ -26,7 +27,8 @@ public struct EmptyView: View {
|
|||
|
||||
// swiftlint:disable:next type_name
|
||||
public struct _ConditionalContent<TrueContent, FalseContent>: View
|
||||
where TrueContent: View, FalseContent: View {
|
||||
where TrueContent: View, FalseContent: View
|
||||
{
|
||||
enum Storage {
|
||||
case trueContent(TrueContent)
|
||||
case falseContent(FalseContent)
|
||||
|
@ -86,60 +88,132 @@ extension Optional: View where Wrapped: View {
|
|||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable line_length
|
||||
// swiftlint:disable large_tuple
|
||||
// swiftlint:disable function_parameter_count
|
||||
|
||||
extension ViewBuilder {
|
||||
public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0: View, C1: View {
|
||||
public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)>
|
||||
where C0: View, C1: View
|
||||
{
|
||||
TupleView(c0, c1)
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewBuilder {
|
||||
public static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2) -> TupleView<(C0, C1, C2)> where C0: View, C1: View, C2: View {
|
||||
public static func buildBlock<C0, C1, C2>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2
|
||||
) -> TupleView<(C0, C1, C2)> where C0: View, C1: View, C2: View {
|
||||
TupleView(c0, c1, c2)
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3) -> TupleView<(C0, C1, C2, C3)> where C0: View, C1: View, C2: View, C3: View {
|
||||
public static func buildBlock<C0, C1, C2, C3>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3
|
||||
) -> TupleView<(C0, C1, C2, C3)> where C0: View, C1: View, C2: View, C3: View {
|
||||
TupleView(c0, c1, c2, c3)
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4) -> TupleView<(C0, C1, C2, C3, C4)> where C0: View, C1: View, C2: View, C3: View, C4: View {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4
|
||||
) -> TupleView<(C0, C1, C2, C3, C4)> where C0: View, C1: View, C2: View, C3: View, C4: View {
|
||||
TupleView(c0, c1, c2, c3, c4)
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5) -> TupleView<(C0, C1, C2, C3, C4, C5)> where C0: View, C1: View, C2: View, C3: View, C4: View, C5: View {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4,
|
||||
_ c5: C5
|
||||
) -> TupleView<(C0, C1, C2, C3, C4, C5)>
|
||||
where C0: View, C1: View, C2: View, C3: View, C4: View, C5: View
|
||||
{
|
||||
TupleView(c0, c1, c2, c3, c4, c5)
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6) -> TupleView<(C0, C1, C2, C3, C4, C5, C6)> where C0: View, C1: View, C2: View, C3: View, C4: View, C5: View, C6: View {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4,
|
||||
_ c5: C5,
|
||||
_ c6: C6
|
||||
) -> TupleView<(C0, C1, C2, C3, C4, C5, C6)>
|
||||
where C0: View, C1: View, C2: View, C3: View, C4: View, C5: View, C6: View
|
||||
{
|
||||
TupleView(c0, c1, c2, c3, c4, c5, c6)
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7)> where C0: View, C1: View, C2: View, C3: View, C4: View, C5: View, C6: View, C7: View {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4,
|
||||
_ c5: C5,
|
||||
_ c6: C6,
|
||||
_ c7: C7
|
||||
) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7)>
|
||||
where C0: View, C1: View, C2: View, C3: View, C4: View, C5: View, C6: View, C7: View
|
||||
{
|
||||
TupleView(c0, c1, c2, c3, c4, c5, c6, c7)
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8)> where C0: View, C1: View, C2: View, C3: View, C4: View, C5: View, C6: View, C7: View, C8: View {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4,
|
||||
_ c5: C5,
|
||||
_ c6: C6,
|
||||
_ c7: C7,
|
||||
_ c8: C8
|
||||
) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8)>
|
||||
where C0: View, C1: View, C2: View, C3: View, C4: View, C5: View, C6: View, C7: View, C8: View
|
||||
{
|
||||
TupleView(c0, c1, c2, c3, c4, c5, c6, c7, c8)
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewBuilder {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8, _ c9: C9) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where C0: View, C1: View, C2: View, C3: View, C4: View, C5: View, C6: View, C7: View, C8: View, C9: View {
|
||||
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(
|
||||
_ c0: C0,
|
||||
_ c1: C1,
|
||||
_ c2: C2,
|
||||
_ c3: C3,
|
||||
_ c4: C4,
|
||||
_ c5: C5,
|
||||
_ c6: C6,
|
||||
_ c7: C7,
|
||||
_ c8: C8,
|
||||
_ c9: C9
|
||||
) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)>
|
||||
where C0: View, C1: View, C2: View, C3: View, C4: View, C5: View, C6: View, C7: View, C8: View,
|
||||
C9: View
|
||||
{
|
||||
TupleView(c0, c1, c2, c3, c4, c5, c6, c7, c8, c9)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ enum ColorSchemeObserver {
|
|||
publisher.value = .init(matchMediaDarkScheme: $0[0].object!)
|
||||
return .undefined
|
||||
}
|
||||
_ = matchMediaDarkScheme.addEventListener!("change", closure)
|
||||
_ = matchMediaDarkScheme.addListener!(closure)
|
||||
Self.closure = closure
|
||||
Self.cancellable = Self.publisher.sink { colorScheme in
|
||||
let systemBackground: String
|
||||
|
|
|
@ -30,9 +30,11 @@ extension DisclosureGroup: ViewDeferredToRenderer {
|
|||
]
|
||||
) {
|
||||
HTML("div", ["class": "_tokamak-disclosuregroup-chevron"])
|
||||
.rotationEffect(_DisclosureGroupProxy(self).isExpanded ?
|
||||
.degrees(90) :
|
||||
.degrees(0))
|
||||
.rotationEffect(
|
||||
_DisclosureGroupProxy(self).isExpanded ?
|
||||
.degrees(90) :
|
||||
.degrees(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ public struct ColorDemo: View {
|
|||
var color: Color {
|
||||
guard let v0d = Double(v0),
|
||||
let v1d = Double(v1),
|
||||
let v2d = Double(v2) else {
|
||||
let v2d = Double(v2)
|
||||
else {
|
||||
return .white
|
||||
}
|
||||
switch colorForm {
|
||||
|
|
|
@ -34,16 +34,21 @@ struct PathDemo: View {
|
|||
.fill(Color(red: 1, green: 0.75, blue: 0.1, opacity: 1))
|
||||
Path { path in
|
||||
path.addRect(.init(origin: .zero, size: .init(width: 20, height: 20)))
|
||||
path.addEllipse(in: .init(origin: .init(x: 25, y: 0),
|
||||
size: .init(width: 20, height: 20)))
|
||||
path.addRoundedRect(in: .init(origin: .init(x: 50, y: 0),
|
||||
size: .init(width: 20, height: 20)),
|
||||
cornerSize: .init(width: 4, height: 4))
|
||||
path.addArc(center: .init(x: 85, y: 10),
|
||||
radius: 10,
|
||||
startAngle: .degrees(90),
|
||||
endAngle: .degrees(180),
|
||||
clockwise: true)
|
||||
path.addEllipse(in: .init(
|
||||
origin: .init(x: 25, y: 0),
|
||||
size: .init(width: 20, height: 20)
|
||||
))
|
||||
path.addRoundedRect(
|
||||
in: .init(origin: .init(x: 50, y: 0), size: .init(width: 20, height: 20)),
|
||||
cornerSize: .init(width: 4, height: 4)
|
||||
)
|
||||
path.addArc(
|
||||
center: .init(x: 85, y: 10),
|
||||
radius: 10,
|
||||
startAngle: .degrees(90),
|
||||
endAngle: .degrees(180),
|
||||
clockwise: true
|
||||
)
|
||||
}
|
||||
.stroke(Color(red: 1, green: 0.75, blue: 0.1, opacity: 1), lineWidth: 4)
|
||||
.padding(.vertical)
|
||||
|
|
|
@ -20,8 +20,11 @@ struct PickerDemo: View {
|
|||
@State private var selection = 0
|
||||
|
||||
var body: some View {
|
||||
Picker(selection: $selection, label: Text("Text style")
|
||||
.font(.system(textStyles[selection]))) {
|
||||
Picker(
|
||||
selection: $selection,
|
||||
label: Text("Text style")
|
||||
.font(.system(textStyles[selection]))
|
||||
) {
|
||||
Text("Pick a text style...")
|
||||
ForEach(0..<textStyles.count) {
|
||||
Text(String(describing: textStyles[$0]))
|
||||
|
|
|
@ -69,12 +69,15 @@ struct TokamakDemoView: View {
|
|||
let list = title(
|
||||
List {
|
||||
Section(header: Text("Buttons")) {
|
||||
NavItem("Counter", destination:
|
||||
NavItem(
|
||||
"Counter",
|
||||
destination:
|
||||
Counter(count: Count(value: 5), limit: 15)
|
||||
.padding()
|
||||
.background(Color(red: 0.9, green: 0.9, blue: 0.9, opacity: 1.0))
|
||||
.border(Color.red, width: 3)
|
||||
.foregroundColor(.black))
|
||||
.foregroundColor(.black)
|
||||
)
|
||||
NavItem("ButtonStyle", destination: ButtonStyleDemo())
|
||||
}
|
||||
Section(header: Text("Containers")) {
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
import TokamakCore
|
||||
|
||||
private extension DOMViewModifier {
|
||||
func unwrapToStyle<T>(_ key: KeyPath<Self, T?>,
|
||||
property: String? = nil,
|
||||
defaultValue: 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;"
|
||||
|
|
|
@ -34,7 +34,8 @@ extension ModifiedContent: ViewDeferredToRenderer where Content: View {
|
|||
public var deferredBody: AnyView {
|
||||
if let domModifier = modifier as? DOMViewModifier {
|
||||
if let adjacentModifier = content as? AnyModifiedContent,
|
||||
!(adjacentModifier.anyModifier.isOrderDependent || domModifier.isOrderDependent) {
|
||||
!(adjacentModifier.anyModifier.isOrderDependent || domModifier.isOrderDependent)
|
||||
{
|
||||
// Flatten non-order-dependent modifiers
|
||||
var attr = domModifier.attributes
|
||||
for (key, val) in adjacentModifier.anyModifier.attributes {
|
||||
|
|
|
@ -25,7 +25,8 @@ extension DOMViewModifier {
|
|||
}
|
||||
|
||||
extension ModifiedContent: DOMViewModifier
|
||||
where Content: DOMViewModifier, Modifier: DOMViewModifier {
|
||||
where Content: DOMViewModifier, Modifier: DOMViewModifier
|
||||
{
|
||||
// Merge attributes
|
||||
public var attributes: [String: String] {
|
||||
var attr = content.attributes
|
||||
|
|
|
@ -16,15 +16,18 @@
|
|||
//
|
||||
import TokamakCore
|
||||
|
||||
extension StrokeStyle {
|
||||
static var zero: Self {
|
||||
.init(lineWidth: 0, lineCap: .butt, lineJoin: .miter, miterLimit: 0, dash: [], dashPhase: 0)
|
||||
}
|
||||
}
|
||||
|
||||
extension Path: ViewDeferredToRenderer {
|
||||
// TODO: Support transformations
|
||||
func svgFrom(storage: Storage,
|
||||
strokeStyle: StrokeStyle = .init(lineWidth: 0,
|
||||
lineCap: .butt,
|
||||
lineJoin: .miter,
|
||||
miterLimit: 0,
|
||||
dash: [],
|
||||
dashPhase: 0)) -> AnyView {
|
||||
func svgFrom(
|
||||
storage: Storage,
|
||||
strokeStyle: StrokeStyle = .zero
|
||||
) -> AnyView {
|
||||
let stroke = [
|
||||
"stroke-width": "\(strokeStyle.lineWidth)",
|
||||
]
|
||||
|
@ -44,11 +47,14 @@ extension Path: ViewDeferredToRenderer {
|
|||
"y": "\(rect.origin.y - (rect.size.height / 2))",
|
||||
].merging(stroke, uniquingKeysWith: uniqueKeys))))
|
||||
case let .ellipse(rect):
|
||||
return AnyView(HTML("ellipse", ["cx": flexibleCenterX ?? "\(rect.origin.x)",
|
||||
"cy": flexibleCenterY ?? "\(rect.origin.y)",
|
||||
"rx": flexibleCenterX ?? "\(rect.size.width)",
|
||||
"ry": flexibleCenterY ?? "\(rect.size.height)"]
|
||||
.merging(stroke, uniquingKeysWith: uniqueKeys)))
|
||||
return AnyView(HTML(
|
||||
"ellipse",
|
||||
["cx": flexibleCenterX ?? "\(rect.origin.x)",
|
||||
"cy": flexibleCenterY ?? "\(rect.origin.y)",
|
||||
"rx": flexibleCenterX ?? "\(rect.size.width)",
|
||||
"ry": flexibleCenterY ?? "\(rect.size.height)"]
|
||||
.merging(stroke, uniquingKeysWith: uniqueKeys)
|
||||
))
|
||||
case let .roundedRect(roundedRect):
|
||||
// When cornerRadius is nil we use 50% rx.
|
||||
let size = roundedRect.rect.size
|
||||
|
@ -56,11 +62,7 @@ extension Path: ViewDeferredToRenderer {
|
|||
if let cornerSize = roundedRect.cornerSize {
|
||||
return [
|
||||
"rx": "\(cornerSize.width)",
|
||||
"ry": """
|
||||
\(roundedRect.style == .continuous ?
|
||||
cornerSize.width :
|
||||
cornerSize.height)
|
||||
""",
|
||||
"ry": " \(roundedRect.style == .continuous ? cornerSize.width : cornerSize.height)",
|
||||
]
|
||||
} else {
|
||||
// For this to support vertical capsules, we need
|
||||
|
@ -68,29 +70,31 @@ extension Path: ViewDeferredToRenderer {
|
|||
return ["ry": "50%"]
|
||||
}
|
||||
}()
|
||||
return AnyView(HTML("rect", [
|
||||
"width": flexibleWidth ?? "\(size.width)",
|
||||
"height": flexibleHeight ?? "\(size.height)",
|
||||
"x": "\(roundedRect.rect.origin.x)",
|
||||
"y": "\(roundedRect.rect.origin.y)",
|
||||
]
|
||||
.merging(cornerRadius, uniquingKeysWith: uniqueKeys)
|
||||
.merging(stroke, uniquingKeysWith: uniqueKeys)))
|
||||
return AnyView(HTML(
|
||||
"rect",
|
||||
[
|
||||
"width": flexibleWidth ?? "\(size.width)",
|
||||
"height": flexibleHeight ?? "\(size.height)",
|
||||
"x": "\(roundedRect.rect.origin.x)",
|
||||
"y": "\(roundedRect.rect.origin.y)",
|
||||
]
|
||||
.merging(cornerRadius, uniquingKeysWith: uniqueKeys)
|
||||
.merging(stroke, uniquingKeysWith: uniqueKeys)
|
||||
))
|
||||
case let .stroked(stroked):
|
||||
return AnyView(stroked.path.svgBody(strokeStyle: stroked.style))
|
||||
case let .trimmed(trimmed):
|
||||
return trimmed.path.svgFrom(storage: trimmed.path.storage,
|
||||
strokeStyle: strokeStyle) // TODO: Trim the path
|
||||
return trimmed.path.svgFrom(
|
||||
storage: trimmed.path.storage,
|
||||
strokeStyle: strokeStyle
|
||||
) // TODO: Trim the path
|
||||
}
|
||||
}
|
||||
|
||||
func svgFrom(elements: [Element],
|
||||
strokeStyle: StrokeStyle = .init(lineWidth: 0,
|
||||
lineCap: .butt,
|
||||
lineJoin: .miter,
|
||||
miterLimit: 0,
|
||||
dash: [],
|
||||
dashPhase: 0)) -> AnyView {
|
||||
func svgFrom(
|
||||
elements: [Element],
|
||||
strokeStyle: StrokeStyle = .zero
|
||||
) -> AnyView {
|
||||
var d = [String]()
|
||||
for element in elements {
|
||||
switch element {
|
||||
|
@ -112,13 +116,10 @@ extension Path: ViewDeferredToRenderer {
|
|||
]))
|
||||
}
|
||||
|
||||
func svgFrom(subpaths: [_SubPath],
|
||||
strokeStyle: StrokeStyle = .init(lineWidth: 0,
|
||||
lineCap: .butt,
|
||||
lineJoin: .miter,
|
||||
miterLimit: 0,
|
||||
dash: [],
|
||||
dashPhase: 0)) -> AnyView {
|
||||
func svgFrom(
|
||||
subpaths: [_SubPath],
|
||||
strokeStyle: StrokeStyle = .zero
|
||||
) -> AnyView {
|
||||
AnyView(ForEach(Array(subpaths.enumerated()), id: \.offset) { _, path in
|
||||
path.path.svgBody(strokeStyle: strokeStyle)
|
||||
})
|
||||
|
@ -161,17 +162,16 @@ extension Path: ViewDeferredToRenderer {
|
|||
}
|
||||
|
||||
var size: CGSize {
|
||||
.init(width: max(storageSize.width, elementsSize.width),
|
||||
height: max(storageSize.height, elementsSize.height))
|
||||
.init(
|
||||
width: max(storageSize.width, elementsSize.width),
|
||||
height: max(storageSize.height, elementsSize.height)
|
||||
)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func svgBody(strokeStyle: StrokeStyle = .init(lineWidth: 0,
|
||||
lineCap: .butt,
|
||||
lineJoin: .miter,
|
||||
miterLimit: 0,
|
||||
dash: [],
|
||||
dashPhase: 0)) -> some View {
|
||||
func svgBody(
|
||||
strokeStyle: StrokeStyle = .zero
|
||||
) -> some View {
|
||||
svgFrom(storage: storage, strokeStyle: strokeStyle)
|
||||
svgFrom(elements: elements, strokeStyle: strokeStyle)
|
||||
svgFrom(subpaths: subpaths, strokeStyle: strokeStyle)
|
||||
|
|
|
@ -19,7 +19,8 @@ import TokamakCore
|
|||
|
||||
// Border modifier
|
||||
extension _OverlayModifier: DOMViewModifier
|
||||
where Overlay == _ShapeView<_StrokedShape<TokamakCore.Rectangle._Inset>, Color> {
|
||||
where Overlay == _ShapeView<_StrokedShape<TokamakCore.Rectangle._Inset>, Color>
|
||||
{
|
||||
public var attributes: [String: String] {
|
||||
let style = overlay.shape.style.dashPhase == 0 ? "solid" : "dashed"
|
||||
return ["style": """
|
||||
|
|
|
@ -16,22 +16,25 @@ import TokamakCore
|
|||
|
||||
extension PlainListStyle: ListStyleDeferredToRenderer {
|
||||
public func sectionHeader<Header>(_ header: Header) -> AnyView where Header: View {
|
||||
AnyView(header
|
||||
.font(.system(size: 17, weight: .medium))
|
||||
.padding(.vertical, 4)
|
||||
.padding(.leading)
|
||||
.background(Color.listSectionHeader)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
AnyView(
|
||||
header
|
||||
.font(.system(size: 17, weight: .medium))
|
||||
.padding(.vertical, 4)
|
||||
.padding(.leading)
|
||||
.background(Color.listSectionHeader)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
)
|
||||
}
|
||||
|
||||
public func sectionFooter<Footer>(_ footer: Footer) -> AnyView where Footer: View {
|
||||
AnyView(VStack(alignment: .leading) {
|
||||
Divider()
|
||||
_ListRow.listRow(footer, self, isLast: true)
|
||||
}
|
||||
.padding(.leading)
|
||||
.frame(minWidth: 0, maxWidth: .infinity))
|
||||
AnyView(
|
||||
VStack(alignment: .leading) {
|
||||
Divider()
|
||||
_ListRow.listRow(footer, self, isLast: true)
|
||||
}
|
||||
.padding(.leading)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
)
|
||||
}
|
||||
|
||||
public func sectionBody<SectionBody>(_ section: SectionBody) -> AnyView where SectionBody: View {
|
||||
|
@ -45,28 +48,32 @@ extension PlainListStyle: ListStyleDeferredToRenderer {
|
|||
|
||||
extension InsetListStyle: ListStyleDeferredToRenderer {
|
||||
public func sectionHeader<Header>(_ header: Header) -> AnyView where Header: View {
|
||||
AnyView(header
|
||||
.font(.system(size: 17, weight: .medium))
|
||||
.padding(.vertical, 4)
|
||||
.padding(.leading, 24)
|
||||
.background(Color.listSectionHeader)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
AnyView(
|
||||
header
|
||||
.font(.system(size: 17, weight: .medium))
|
||||
.padding(.vertical, 4)
|
||||
.padding(.leading, 24)
|
||||
.background(Color.listSectionHeader)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
)
|
||||
}
|
||||
|
||||
public func sectionFooter<Footer>(_ footer: Footer) -> AnyView where Footer: View {
|
||||
AnyView(VStack(alignment: .leading) {
|
||||
Divider()
|
||||
_ListRow.listRow(footer, self, isLast: true)
|
||||
}
|
||||
.padding(.leading, 24)
|
||||
.frame(minWidth: 0, maxWidth: .infinity))
|
||||
AnyView(
|
||||
VStack(alignment: .leading) {
|
||||
Divider()
|
||||
_ListRow.listRow(footer, self, isLast: true)
|
||||
}
|
||||
.padding(.leading, 24)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
)
|
||||
}
|
||||
|
||||
public func sectionBody<SectionBody>(_ section: SectionBody) -> AnyView where SectionBody: View {
|
||||
AnyView(section
|
||||
.padding(.leading, 24)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
AnyView(
|
||||
section
|
||||
.padding(.leading, 24)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -77,31 +84,36 @@ extension InsetListStyle: ListStyleDeferredToRenderer {
|
|||
|
||||
extension GroupedListStyle: ListStyleDeferredToRenderer {
|
||||
public func listBody<ListBody>(_ content: ListBody) -> AnyView where ListBody: View {
|
||||
AnyView(content
|
||||
.background(Color.groupedListBackground)
|
||||
AnyView(
|
||||
content
|
||||
.background(Color.groupedListBackground)
|
||||
)
|
||||
}
|
||||
|
||||
public func sectionHeader<Header>(_ header: Header) -> AnyView where Header: View {
|
||||
AnyView(header
|
||||
.font(.caption)
|
||||
.padding([.top, .leading])
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
AnyView(
|
||||
header
|
||||
.font(.caption)
|
||||
.padding([.top, .leading])
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
)
|
||||
}
|
||||
|
||||
public func sectionBody<SectionBody>(_ section: SectionBody) -> AnyView where SectionBody: View {
|
||||
AnyView(section
|
||||
.padding(.leading)
|
||||
.background(Color.listGroupBackground)
|
||||
.padding(.top)
|
||||
.frame(minWidth: 0, maxWidth: .infinity))
|
||||
AnyView(
|
||||
section
|
||||
.padding(.leading)
|
||||
.background(Color.listGroupBackground)
|
||||
.padding(.top)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
)
|
||||
}
|
||||
|
||||
public func sectionFooter<Footer>(_ footer: Footer) -> AnyView where Footer: View {
|
||||
AnyView(footer
|
||||
.font(.caption)
|
||||
.padding([.top, .leading])
|
||||
AnyView(
|
||||
footer
|
||||
.font(.caption)
|
||||
.padding([.top, .leading])
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -116,28 +128,32 @@ extension InsetGroupedListStyle: ListStyleDeferredToRenderer {
|
|||
}
|
||||
|
||||
public func sectionHeader<Header>(_ header: Header) -> AnyView where Header: View {
|
||||
AnyView(header
|
||||
.font(.caption)
|
||||
.padding([.top, .leading])
|
||||
.padding(.leading)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
AnyView(
|
||||
header
|
||||
.font(.caption)
|
||||
.padding([.top, .leading])
|
||||
.padding(.leading)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
)
|
||||
}
|
||||
|
||||
public func sectionBody<SectionBody>(_ section: SectionBody) -> AnyView where SectionBody: View {
|
||||
AnyView(section
|
||||
.padding(.leading)
|
||||
.background(Color.listGroupBackground)
|
||||
.cornerRadius(10)
|
||||
.padding([.horizontal, .top])
|
||||
.frame(minWidth: 0, maxWidth: .infinity))
|
||||
AnyView(
|
||||
section
|
||||
.padding(.leading)
|
||||
.background(Color.listGroupBackground)
|
||||
.cornerRadius(10)
|
||||
.padding([.horizontal, .top])
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
)
|
||||
}
|
||||
|
||||
public func sectionFooter<Footer>(_ footer: Footer) -> AnyView where Footer: View {
|
||||
AnyView(footer
|
||||
.font(.caption)
|
||||
.padding([.top, .leading])
|
||||
.padding(.leading)
|
||||
AnyView(
|
||||
footer
|
||||
.font(.caption)
|
||||
.padding([.top, .leading])
|
||||
.padding(.leading)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -149,16 +165,18 @@ extension InsetGroupedListStyle: ListStyleDeferredToRenderer {
|
|||
// TODO: Make sections collabsible (see Section.swift for more impl. details)
|
||||
extension SidebarListStyle: ListStyleDeferredToRenderer {
|
||||
public func sectionHeader<Header>(_ header: Header) -> AnyView where Header: View {
|
||||
AnyView(header
|
||||
.font(.system(size: 11, weight: .medium))
|
||||
.foregroundColor(Color._withScheme {
|
||||
switch $0 {
|
||||
case .light: return Color(.sRGB, white: 0, opacity: 0.4)
|
||||
case .dark: return Color(.sRGB, white: 1, opacity: 0.4)
|
||||
}
|
||||
})
|
||||
.padding(.vertical, 2)
|
||||
.padding(.leading, 4))
|
||||
AnyView(
|
||||
header
|
||||
.font(.system(size: 11, weight: .medium))
|
||||
.foregroundColor(Color._withScheme {
|
||||
switch $0 {
|
||||
case .light: return Color(.sRGB, white: 0, opacity: 0.4)
|
||||
case .dark: return Color(.sRGB, white: 1, opacity: 0.4)
|
||||
}
|
||||
})
|
||||
.padding(.vertical, 2)
|
||||
.padding(.leading, 4)
|
||||
)
|
||||
}
|
||||
|
||||
public func listRow<Row>(_ row: Row) -> AnyView where Row: View {
|
||||
|
@ -166,10 +184,11 @@ extension SidebarListStyle: ListStyleDeferredToRenderer {
|
|||
}
|
||||
|
||||
public func listBody<ListBody>(_ content: ListBody) -> AnyView where ListBody: View {
|
||||
AnyView(content
|
||||
._navigationLinkStyle(_SidebarNavigationLinkStyle())
|
||||
.padding([.horizontal, .top], 6)
|
||||
.background(Color.sidebarBackground)
|
||||
AnyView(
|
||||
content
|
||||
._navigationLinkStyle(_SidebarNavigationLinkStyle())
|
||||
.padding([.horizontal, .top], 6)
|
||||
.background(Color.sidebarBackground)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,10 +106,14 @@ extension Text: AnyHTML {
|
|||
case let .segmentedText(segments):
|
||||
return segments
|
||||
.map {
|
||||
TextSpan(content: $0.0.rawText,
|
||||
attributes: Self.attributes(from: $0.1,
|
||||
environment: proxy.environment))
|
||||
.outerHTML
|
||||
TextSpan(
|
||||
content: $0.0.rawText,
|
||||
attributes: Self.attributes(
|
||||
from: $0.1,
|
||||
environment: proxy.environment
|
||||
)
|
||||
)
|
||||
.outerHTML
|
||||
}
|
||||
.reduce("", +)
|
||||
}
|
||||
|
@ -118,14 +122,18 @@ extension Text: AnyHTML {
|
|||
public var tag: String { "span" }
|
||||
public var attributes: [String: String] {
|
||||
let proxy = _TextProxy(self)
|
||||
return Self.attributes(from: proxy.modifiers,
|
||||
environment: proxy.environment)
|
||||
return Self.attributes(
|
||||
from: proxy.modifiers,
|
||||
environment: proxy.environment
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension Text {
|
||||
static func attributes(from modifiers: [_Modifier],
|
||||
environment: EnvironmentValues) -> [String: String] {
|
||||
static func attributes(
|
||||
from modifiers: [_Modifier],
|
||||
environment: EnvironmentValues
|
||||
) -> [String: String] {
|
||||
let isRedacted = environment.redactionReasons.contains(.placeholder)
|
||||
|
||||
var font: Font?
|
||||
|
|
|
@ -30,8 +30,7 @@ public final class TestView: Target {
|
|||
public var view: AnyView
|
||||
|
||||
/** Initialize a new test view. */
|
||||
init<V: View>(_ view: V,
|
||||
_ subviews: [TestView] = []) {
|
||||
init<V: View>(_ view: V, _ subviews: [TestView] = []) {
|
||||
self.subviews = subviews
|
||||
self.view = AnyView(view)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue