@swiftbrowser/swift 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Package.swift +23 -0
- package/README.md +12 -2
- package/Sources/Charts/Charts.swift +65 -0
- package/Sources/FoundationBridge/FoundationBridge.swift +77 -0
- package/Sources/FoundationBridge/Locale.swift +86 -0
- package/Sources/FoundationBridge/Timer.swift +48 -0
- package/Sources/FoundationBridge/UITextChecker.swift +30 -0
- package/Sources/FoundationLite/Common.swift +3 -0
- package/Sources/FoundationLite/FoundationLite.swift +171 -0
- package/Sources/FoundationLite/Interaction.swift +146 -0
- package/Sources/FoundationLite/Timer.swift +48 -0
- package/Sources/SwiftUI/API/Accessibility.swift +132 -0
- package/Sources/SwiftUI/API/Alert.swift +221 -0
- package/Sources/SwiftUI/API/Animation.swift +253 -0
- package/Sources/SwiftUI/API/App.swift +57 -0
- package/Sources/SwiftUI/API/Color.swift +161 -0
- package/Sources/SwiftUI/API/Controls.swift +268 -0
- package/Sources/SwiftUI/API/CustomLayout.swift +403 -0
- package/Sources/SwiftUI/API/Decorations.swift +92 -0
- package/Sources/SwiftUI/API/EditMode.swift +269 -0
- package/Sources/SwiftUI/API/Effects.swift +290 -0
- package/Sources/SwiftUI/API/Environment.swift +355 -0
- package/Sources/SwiftUI/API/Focus.swift +129 -0
- package/Sources/SwiftUI/API/Font.swift +131 -0
- package/Sources/SwiftUI/API/Gauge.swift +289 -0
- package/Sources/SwiftUI/API/Geometry.swift +89 -0
- package/Sources/SwiftUI/API/GeometryReader.swift +124 -0
- package/Sources/SwiftUI/API/Gestures.swift +342 -0
- package/Sources/SwiftUI/API/Grid.swift +188 -0
- package/Sources/SwiftUI/API/LabelStyle.swift +117 -0
- package/Sources/SwiftUI/API/Layout.swift +165 -0
- package/Sources/SwiftUI/API/Lists.swift +276 -0
- package/Sources/SwiftUI/API/Menu.swift +51 -0
- package/Sources/SwiftUI/API/Modifiers.swift +243 -0
- package/Sources/SwiftUI/API/Navigation.swift +371 -0
- package/Sources/SwiftUI/API/ObservableObject.swift +279 -0
- package/Sources/SwiftUI/API/OnChange.swift +48 -0
- package/Sources/SwiftUI/API/Phase8Controls.swift +394 -0
- package/Sources/SwiftUI/API/Picker.swift +176 -0
- package/Sources/SwiftUI/API/Presentation.swift +109 -0
- package/Sources/SwiftUI/API/Primitives.swift +390 -0
- package/Sources/SwiftUI/API/Publishers.swift +107 -0
- package/Sources/SwiftUI/API/RowActions.swift +83 -0
- package/Sources/SwiftUI/API/ScrollTargets.swift +104 -0
- package/Sources/SwiftUI/API/ShapeStyle.swift +311 -0
- package/Sources/SwiftUI/API/State.swift +127 -0
- package/Sources/SwiftUI/API/StrokeStyle.swift +30 -0
- package/Sources/SwiftUI/API/Tabs.swift +119 -0
- package/Sources/SwiftUI/API/Tasks.swift +35 -0
- package/Sources/SwiftUI/API/Timeline.swift +212 -0
- package/Sources/SwiftUI/API/Toolbar.swift +215 -0
- package/Sources/SwiftUI/API/View.swift +207 -0
- package/Sources/SwiftUI/API/ViewModifier.swift +40 -0
- package/Sources/SwiftUI/API/VisualEffect.swift +82 -0
- package/Sources/SwiftUI/Charts/Axis.swift +319 -0
- package/Sources/SwiftUI/Charts/Chart.swift +646 -0
- package/Sources/SwiftUI/Charts/ChartContent.swift +376 -0
- package/Sources/SwiftUI/Charts/Marks.swift +204 -0
- package/Sources/SwiftUI/Charts/Plottable.swift +99 -0
- package/Sources/SwiftUI/Charts/Scales.swift +326 -0
- package/Sources/SwiftUI/Runtime/Executor.swift +83 -0
- package/Sources/SwiftUI/Runtime/Exports.swift +65 -0
- package/Sources/SwiftUI/Runtime/JSON.swift +71 -0
- package/Sources/SwiftUI/Runtime/JSONParser.swift +443 -0
- package/Sources/SwiftUI/Runtime/Ops.swift +106 -0
- package/Sources/SwiftUI/Runtime/Reconciler.swift +210 -0
- package/Sources/SwiftUI/Runtime/Runtime.swift +1367 -0
- package/Sources/_FoundationCommon/Bundle.swift +82 -0
- package/Sources/_FoundationCommon/UserDefaults.swift +170 -0
- package/Sources/_FoundationCommon/_FoundationCommon.swift +10 -0
- package/index.d.ts +2 -0
- package/index.mjs +16 -0
- package/package.json +28 -4
- package/sync-sources.mjs +19 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/// How a change is animated. Encoded for the renderer as documented in
|
|
2
|
+
/// docs/ops-protocol.md (Phase 3).
|
|
3
|
+
public struct Animation: Equatable, Sendable {
|
|
4
|
+
enum Kind: String, Sendable {
|
|
5
|
+
case `default`, linear, easeIn, easeOut, easeInOut, spring
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
var kind: Kind
|
|
9
|
+
var duration: Double
|
|
10
|
+
var bounce: Double
|
|
11
|
+
var delayBy: Double
|
|
12
|
+
/// `.repeatCount` / `.repeatForever`: `count` nil with `forever` false means once.
|
|
13
|
+
var repeatCount: Int?
|
|
14
|
+
var repeatForever = false
|
|
15
|
+
var autoreverses = true
|
|
16
|
+
|
|
17
|
+
init(kind: Kind, duration: Double = 0.35, bounce: Double = 0, delay: Double = 0) {
|
|
18
|
+
self.kind = kind
|
|
19
|
+
self.duration = duration
|
|
20
|
+
self.bounce = bounce
|
|
21
|
+
self.delayBy = delay
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public static let `default` = Animation(kind: .default)
|
|
25
|
+
public static let linear = Animation(kind: .linear)
|
|
26
|
+
public static let easeIn = Animation(kind: .easeIn)
|
|
27
|
+
public static let easeOut = Animation(kind: .easeOut)
|
|
28
|
+
public static let easeInOut = Animation(kind: .easeInOut)
|
|
29
|
+
public static let spring = Animation(kind: .spring, duration: 0.5, bounce: 0)
|
|
30
|
+
public static let bouncy = Animation(kind: .spring, duration: 0.5, bounce: 0.3)
|
|
31
|
+
public static let smooth = Animation(kind: .spring, duration: 0.5, bounce: 0)
|
|
32
|
+
public static let snappy = Animation(kind: .spring, duration: 0.5, bounce: 0.15)
|
|
33
|
+
|
|
34
|
+
public static func linear(duration: Double) -> Animation { Animation(kind: .linear, duration: duration) }
|
|
35
|
+
public static func easeIn(duration: Double) -> Animation { Animation(kind: .easeIn, duration: duration) }
|
|
36
|
+
public static func easeOut(duration: Double) -> Animation { Animation(kind: .easeOut, duration: duration) }
|
|
37
|
+
public static func easeInOut(duration: Double) -> Animation { Animation(kind: .easeInOut, duration: duration) }
|
|
38
|
+
public static func spring(duration: Double = 0.5, bounce: Double = 0) -> Animation {
|
|
39
|
+
Animation(kind: .spring, duration: duration, bounce: bounce)
|
|
40
|
+
}
|
|
41
|
+
/// The pre-iOS 17 spring: `response` is the duration, the damping fraction
|
|
42
|
+
/// maps onto bounce (`1` is a smooth spring, lower values overshoot).
|
|
43
|
+
public static func spring(response: Double = 0.5, dampingFraction: Double = 0.825,
|
|
44
|
+
blendDuration: Double = 0) -> Animation {
|
|
45
|
+
Animation(kind: .spring, duration: response, bounce: max(0, min(1, 1 - dampingFraction)))
|
|
46
|
+
}
|
|
47
|
+
public static func interactiveSpring(response: Double = 0.15, dampingFraction: Double = 0.86,
|
|
48
|
+
blendDuration: Double = 0.25) -> Animation {
|
|
49
|
+
spring(response: response, dampingFraction: dampingFraction, blendDuration: blendDuration)
|
|
50
|
+
}
|
|
51
|
+
public static func bouncy(duration: Double = 0.5, extraBounce: Double = 0) -> Animation {
|
|
52
|
+
Animation(kind: .spring, duration: duration, bounce: 0.3 + extraBounce)
|
|
53
|
+
}
|
|
54
|
+
public static func smooth(duration: Double = 0.5, extraBounce: Double = 0) -> Animation {
|
|
55
|
+
Animation(kind: .spring, duration: duration, bounce: extraBounce)
|
|
56
|
+
}
|
|
57
|
+
public static func snappy(duration: Double = 0.5, extraBounce: Double = 0) -> Animation {
|
|
58
|
+
Animation(kind: .spring, duration: duration, bounce: 0.15 + extraBounce)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public func delay(_ delay: Double) -> Animation {
|
|
62
|
+
var copy = self
|
|
63
|
+
copy.delayBy = delay
|
|
64
|
+
return copy
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public func speed(_ speed: Double) -> Animation {
|
|
68
|
+
var copy = self
|
|
69
|
+
copy.duration = speed > 0 ? duration / speed : duration
|
|
70
|
+
return copy
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/// Repeats the animation `repeatCount` times, reversing on alternate runs
|
|
74
|
+
/// when `autoreverses`.
|
|
75
|
+
public func repeatCount(_ repeatCount: Int, autoreverses: Bool = true) -> Animation {
|
|
76
|
+
var copy = self
|
|
77
|
+
copy.repeatCount = repeatCount
|
|
78
|
+
copy.repeatForever = false
|
|
79
|
+
copy.autoreverses = autoreverses
|
|
80
|
+
return copy
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public func repeatForever(autoreverses: Bool = true) -> Animation {
|
|
84
|
+
var copy = self
|
|
85
|
+
copy.repeatCount = nil
|
|
86
|
+
copy.repeatForever = true
|
|
87
|
+
copy.autoreverses = autoreverses
|
|
88
|
+
return copy
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
var _json: _JSON {
|
|
92
|
+
var object: [String: _JSON] = ["type": .string(kind.rawValue), "duration": .number(duration)]
|
|
93
|
+
if bounce != 0 { object["bounce"] = .number(bounce) }
|
|
94
|
+
if delayBy != 0 { object["delay"] = .number(delayBy) }
|
|
95
|
+
if repeatForever || repeatCount != nil {
|
|
96
|
+
object["repeat"] = .object([
|
|
97
|
+
"count": repeatForever ? .string("forever") : .number(Double(repeatCount ?? 1)),
|
|
98
|
+
"autoreverses": .bool(autoreverses),
|
|
99
|
+
])
|
|
100
|
+
}
|
|
101
|
+
return .object(object)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
extension Binding {
|
|
106
|
+
/// A binding whose writes animate the view changes they cause.
|
|
107
|
+
public func animation(_ animation: Animation? = .default) -> Binding<Value> {
|
|
108
|
+
let setter = self.setter
|
|
109
|
+
return Binding(get: getter) { value in
|
|
110
|
+
// Bindings are written from the main actor (event handlers, bodies).
|
|
111
|
+
MainActor.assumeIsolated { _Runtime.shared.beginTransaction(animation) }
|
|
112
|
+
setter(value)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// Runs `body` and animates the view changes it causes.
|
|
118
|
+
@MainActor
|
|
119
|
+
public func withAnimation<Result>(_ animation: Animation? = .default,
|
|
120
|
+
_ body: () throws -> Result) rethrows -> Result {
|
|
121
|
+
_Runtime.shared.beginTransaction(animation)
|
|
122
|
+
return try body()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// MARK: - Transitions
|
|
126
|
+
|
|
127
|
+
/// How a view appears and disappears when inserted or removed with animation.
|
|
128
|
+
public struct AnyTransition: Sendable {
|
|
129
|
+
struct Part: Sendable {
|
|
130
|
+
var kind: String
|
|
131
|
+
var edge: Edge?
|
|
132
|
+
var scale: Double?
|
|
133
|
+
var offset: CGSize?
|
|
134
|
+
/// `asymmetric`: the transitions for insertion and removal.
|
|
135
|
+
var insertion: [Part]?
|
|
136
|
+
var removal: [Part]?
|
|
137
|
+
|
|
138
|
+
var _json: _JSON {
|
|
139
|
+
var object: [String: _JSON] = ["kind": .string(kind)]
|
|
140
|
+
if let edge { object["edge"] = .string(edge.name) }
|
|
141
|
+
if let scale { object["scale"] = .number(scale) }
|
|
142
|
+
if let offset {
|
|
143
|
+
object["x"] = .number(offset.width)
|
|
144
|
+
object["y"] = .number(offset.height)
|
|
145
|
+
}
|
|
146
|
+
if let insertion { object["insertion"] = AnyTransition(parts: insertion)._json }
|
|
147
|
+
if let removal { object["removal"] = AnyTransition(parts: removal)._json }
|
|
148
|
+
return .object(object)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public static func asymmetric(insertion: AnyTransition, removal: AnyTransition) -> AnyTransition {
|
|
153
|
+
AnyTransition(parts: [Part(kind: "asymmetric", insertion: insertion.parts, removal: removal.parts)])
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
var parts: [Part]
|
|
157
|
+
|
|
158
|
+
public static let identity = AnyTransition(parts: [Part(kind: "identity")])
|
|
159
|
+
public static let opacity = AnyTransition(parts: [Part(kind: "opacity")])
|
|
160
|
+
public static let slide = AnyTransition(parts: [Part(kind: "slide")])
|
|
161
|
+
public static let scale = AnyTransition(parts: [Part(kind: "scale", scale: 0.5)])
|
|
162
|
+
|
|
163
|
+
public static func scale(scale: Double) -> AnyTransition {
|
|
164
|
+
AnyTransition(parts: [Part(kind: "scale", scale: scale)])
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/// The anchor is accepted for source compatibility; scaling is about the center.
|
|
168
|
+
public static func scale(scale: Double, anchor: UnitPoint) -> AnyTransition {
|
|
169
|
+
AnyTransition(parts: [Part(kind: "scale", scale: scale)])
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/// Slides in from / out to the given offset (points).
|
|
173
|
+
public static func offset(x: CGFloat = 0, y: CGFloat = 0) -> AnyTransition {
|
|
174
|
+
AnyTransition(parts: [Part(kind: "offset", offset: CGSize(width: x, height: y))])
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public static func offset(_ offset: CGSize) -> AnyTransition {
|
|
178
|
+
AnyTransition(parts: [Part(kind: "offset", offset: offset)])
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public static func move(edge: Edge) -> AnyTransition {
|
|
182
|
+
AnyTransition(parts: [Part(kind: "move", edge: edge)])
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public func combined(with other: AnyTransition) -> AnyTransition {
|
|
186
|
+
AnyTransition(parts: parts + other.parts)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/// A transition between two states of a `ViewModifier`. The shim cannot
|
|
190
|
+
/// diff arbitrary modifiers, so it is accepted and rendered as `opacity`
|
|
191
|
+
/// (docs/ops-protocol.md, Phase 8).
|
|
192
|
+
public static func modifier<E: ViewModifier>(active: E, identity: E) -> AnyTransition {
|
|
193
|
+
.opacity
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
var _json: _JSON {
|
|
197
|
+
parts.count == 1 ? parts[0]._json : .array(parts.map(\._json))
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
extension Edge {
|
|
202
|
+
var name: String {
|
|
203
|
+
switch self {
|
|
204
|
+
case .top: "top"
|
|
205
|
+
case .leading: "leading"
|
|
206
|
+
case .bottom: "bottom"
|
|
207
|
+
case .trailing: "trailing"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// MARK: - Modifiers
|
|
213
|
+
|
|
214
|
+
/// Views whose subtree animates when `value` changes.
|
|
215
|
+
protocol _AnimatedView {
|
|
216
|
+
var _animation: Animation? { get }
|
|
217
|
+
/// Whether the tracked value differs from a previously stored one.
|
|
218
|
+
func _changed(since previous: Any?) -> Bool
|
|
219
|
+
var _value: Any { get }
|
|
220
|
+
var _content: [any View] { get }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
struct _AnimationView<Content: View, Value: Equatable> {
|
|
224
|
+
let content: Content
|
|
225
|
+
let animation: Animation?
|
|
226
|
+
let value: Value
|
|
227
|
+
}
|
|
228
|
+
extension _AnimationView: _PrimitiveView {}
|
|
229
|
+
extension _AnimationView: _HostView {
|
|
230
|
+
var _kind: String { "styled" }
|
|
231
|
+
func _props(in environment: EnvironmentValues) -> _JSON { .object(["style": .object([:])]) }
|
|
232
|
+
var _content: [any View] { [content] }
|
|
233
|
+
}
|
|
234
|
+
extension _AnimationView: _AnimatedView {
|
|
235
|
+
var _animation: Animation? { animation }
|
|
236
|
+
var _value: Any { value }
|
|
237
|
+
func _changed(since previous: Any?) -> Bool {
|
|
238
|
+
guard let previous = previous as? Value else { return true }
|
|
239
|
+
return previous != value
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
extension View {
|
|
244
|
+
/// Animates changes to this view whenever `value` changes.
|
|
245
|
+
public func animation<V: Equatable>(_ animation: Animation?, value: V) -> some View {
|
|
246
|
+
_AnimationView(content: self, animation: animation, value: value)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/// The transition to use when this view is inserted or removed with animation.
|
|
250
|
+
public func transition(_ transition: AnyTransition) -> some View {
|
|
251
|
+
_styled { $0.transition = transition }
|
|
252
|
+
}
|
|
253
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/// A part of an app's user interface with a life cycle managed by the system.
|
|
2
|
+
@MainActor @preconcurrency
|
|
3
|
+
public protocol Scene {
|
|
4
|
+
associatedtype Body: Scene
|
|
5
|
+
@SceneBuilder var body: Self.Body { get }
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
extension Never: Scene {}
|
|
9
|
+
|
|
10
|
+
/// Scenes the runtime can mount directly.
|
|
11
|
+
protocol _RootScene {
|
|
12
|
+
var _rootView: any View { get }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@resultBuilder
|
|
16
|
+
public enum SceneBuilder {
|
|
17
|
+
public static func buildBlock<Content: Scene>(_ content: Content) -> Content { content }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/// A scene that presents a view hierarchy in a window (on the web, the screen).
|
|
21
|
+
public struct WindowGroup<Content: View> {
|
|
22
|
+
let content: Content
|
|
23
|
+
|
|
24
|
+
public init(@ViewBuilder content: () -> Content) {
|
|
25
|
+
self.content = content()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public init(_ title: String, @ViewBuilder content: () -> Content) {
|
|
29
|
+
self.content = content()
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
extension WindowGroup: Scene {
|
|
34
|
+
public typealias Body = Never
|
|
35
|
+
public var body: Never { fatalError("WindowGroup is a primitive scene") }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
extension WindowGroup: _RootScene {
|
|
39
|
+
var _rootView: any View { content }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// The structure and behavior of an app. Mark the conforming type `@main`.
|
|
43
|
+
@MainActor @preconcurrency
|
|
44
|
+
public protocol App {
|
|
45
|
+
associatedtype Body: Scene
|
|
46
|
+
@SceneBuilder var body: Self.Body { get }
|
|
47
|
+
init()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
extension App {
|
|
51
|
+
/// Entry point used by `@main`. Mounts the app's root view and, in the
|
|
52
|
+
/// browser, returns while the module stays alive to receive events.
|
|
53
|
+
public static func main() {
|
|
54
|
+
_installHostExecutor()
|
|
55
|
+
_Runtime.shared.launch(Self())
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
public struct Color: Hashable, Sendable {
|
|
2
|
+
enum Storage: Hashable, Sendable {
|
|
3
|
+
case rgba(red: Double, green: Double, blue: Double, opacity: Double)
|
|
4
|
+
case semantic(name: String, opacity: Double)
|
|
5
|
+
/// A `.colorset` from the asset catalog (light/dark resolved by the renderer).
|
|
6
|
+
case named(name: String, opacity: Double)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let storage: Storage
|
|
10
|
+
|
|
11
|
+
public init(red: Double, green: Double, blue: Double, opacity: Double = 1) {
|
|
12
|
+
storage = .rgba(red: red, green: green, blue: blue, opacity: opacity)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/// A color from the asset catalog, possibly namespaced (`"dough/plain-bg"`).
|
|
16
|
+
/// SwiftUI's `bundle:` parameter is not offered (see `Image.init(_:)`).
|
|
17
|
+
public init(_ name: String) {
|
|
18
|
+
storage = .named(name: name, opacity: 1)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public init(white: Double, opacity: Double = 1) {
|
|
22
|
+
storage = .rgba(red: white, green: white, blue: white, opacity: opacity)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
init(semantic name: String) {
|
|
26
|
+
storage = .semantic(name: name, opacity: 1)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// iOS system palette, light appearance.
|
|
30
|
+
public static let red = Color(red: 1.0, green: 0.231, blue: 0.188)
|
|
31
|
+
public static let orange = Color(red: 1.0, green: 0.584, blue: 0.0)
|
|
32
|
+
public static let yellow = Color(red: 1.0, green: 0.8, blue: 0.0)
|
|
33
|
+
public static let green = Color(red: 0.204, green: 0.78, blue: 0.349)
|
|
34
|
+
public static let mint = Color(red: 0.0, green: 0.78, blue: 0.745)
|
|
35
|
+
public static let teal = Color(red: 0.188, green: 0.69, blue: 0.78)
|
|
36
|
+
public static let cyan = Color(red: 0.196, green: 0.678, blue: 0.902)
|
|
37
|
+
public static let blue = Color(red: 0.0, green: 0.478, blue: 1.0)
|
|
38
|
+
public static let indigo = Color(red: 0.345, green: 0.337, blue: 0.839)
|
|
39
|
+
public static let purple = Color(red: 0.686, green: 0.322, blue: 0.871)
|
|
40
|
+
public static let pink = Color(red: 1.0, green: 0.176, blue: 0.333)
|
|
41
|
+
public static let brown = Color(red: 0.635, green: 0.518, blue: 0.368)
|
|
42
|
+
public static let gray = Color(red: 0.557, green: 0.557, blue: 0.576)
|
|
43
|
+
public static let black = Color(red: 0, green: 0, blue: 0)
|
|
44
|
+
public static let white = Color(red: 1, green: 1, blue: 1)
|
|
45
|
+
|
|
46
|
+
// Semantic colors the renderer resolves per color scheme.
|
|
47
|
+
public static let clear = Color(semantic: "clear")
|
|
48
|
+
public static let primary = Color(semantic: "primary")
|
|
49
|
+
public static let secondary = Color(semantic: "secondary")
|
|
50
|
+
public static let accentColor = Color(semantic: "accent")
|
|
51
|
+
|
|
52
|
+
public func opacity(_ opacity: Double) -> Color {
|
|
53
|
+
switch storage {
|
|
54
|
+
case .rgba(let r, let g, let b, let a):
|
|
55
|
+
Color(red: r, green: g, blue: b, opacity: a * opacity)
|
|
56
|
+
case .semantic(let name, let a):
|
|
57
|
+
Color(storage: .semantic(name: name, opacity: a * opacity))
|
|
58
|
+
case .named(let name, let a):
|
|
59
|
+
Color(storage: .named(name: name, opacity: a * opacity))
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
init(storage: Storage) { self.storage = storage }
|
|
64
|
+
|
|
65
|
+
public var _json: _JSON {
|
|
66
|
+
switch storage {
|
|
67
|
+
case .rgba(let r, let g, let b, let a):
|
|
68
|
+
.object(["r": .number(r), "g": .number(g), "b": .number(b), "a": .number(a)])
|
|
69
|
+
case .semantic(let name, let a):
|
|
70
|
+
a == 1 ? .object(["name": .string(name)]) : .object(["name": .string(name), "a": .number(a)])
|
|
71
|
+
case .named(let name, let a):
|
|
72
|
+
.object(["named": .string(name), "opacity": .number(a)])
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// MARK: - Shapes (clipping only, for now)
|
|
78
|
+
|
|
79
|
+
public protocol Shape: Sendable {
|
|
80
|
+
var _name: String { get }
|
|
81
|
+
var _cornerRadius: CGFloat { get }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public struct Rectangle: Shape {
|
|
85
|
+
public init() {}
|
|
86
|
+
public var _name: String { "rectangle" }
|
|
87
|
+
public var _cornerRadius: CGFloat { 0 }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/// Accepted for source compatibility; corners render continuous either way.
|
|
91
|
+
public enum RoundedCornerStyle: Hashable, Sendable {
|
|
92
|
+
case circular, continuous
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public struct RoundedRectangle: Shape {
|
|
96
|
+
public var cornerRadius: CGFloat
|
|
97
|
+
public var style: RoundedCornerStyle
|
|
98
|
+
public init(cornerRadius: CGFloat, style: RoundedCornerStyle = .continuous) {
|
|
99
|
+
self.cornerRadius = cornerRadius
|
|
100
|
+
self.style = style
|
|
101
|
+
}
|
|
102
|
+
public init(cornerSize: CGSize, style: RoundedCornerStyle = .continuous) {
|
|
103
|
+
cornerRadius = min(cornerSize.width, cornerSize.height)
|
|
104
|
+
self.style = style
|
|
105
|
+
}
|
|
106
|
+
public var _name: String { "roundedRectangle" }
|
|
107
|
+
public var _cornerRadius: CGFloat { cornerRadius }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public struct Circle: Shape {
|
|
111
|
+
public init() {}
|
|
112
|
+
public var _name: String { "circle" }
|
|
113
|
+
public var _cornerRadius: CGFloat { 9999 }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public struct Capsule: Shape {
|
|
117
|
+
public init() {}
|
|
118
|
+
public var _name: String { "capsule" }
|
|
119
|
+
public var _cornerRadius: CGFloat { 9999 }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public struct Ellipse: Shape {
|
|
123
|
+
public init() {}
|
|
124
|
+
public var _name: String { "ellipse" }
|
|
125
|
+
public var _cornerRadius: CGFloat { 9999 }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/// The container's shape (`.containerShape`), rendered as a 12pt rounded
|
|
129
|
+
/// rectangle, the corner radius the Food Truck cards use.
|
|
130
|
+
public struct ContainerRelativeShape: Shape {
|
|
131
|
+
public init() {}
|
|
132
|
+
public var _name: String { "containerRelative" }
|
|
133
|
+
public var _cornerRadius: CGFloat { 12 }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Shapes as static members (`.clipShape(.capsule)`, `.background(.red, in: .rect(cornerRadius: 8))`).
|
|
137
|
+
extension Shape where Self == Capsule {
|
|
138
|
+
public static var capsule: Capsule { Capsule() }
|
|
139
|
+
/// The shape of a button's border; drawn as a capsule.
|
|
140
|
+
public static var buttonBorder: Capsule { Capsule() }
|
|
141
|
+
}
|
|
142
|
+
extension Shape where Self == Circle {
|
|
143
|
+
public static var circle: Circle { Circle() }
|
|
144
|
+
}
|
|
145
|
+
extension Shape where Self == Ellipse {
|
|
146
|
+
public static var ellipse: Ellipse { Ellipse() }
|
|
147
|
+
}
|
|
148
|
+
extension Shape where Self == Rectangle {
|
|
149
|
+
public static var rect: Rectangle { Rectangle() }
|
|
150
|
+
}
|
|
151
|
+
extension Shape where Self == RoundedRectangle {
|
|
152
|
+
public static func rect(cornerRadius: CGFloat, style: RoundedCornerStyle = .continuous) -> RoundedRectangle {
|
|
153
|
+
RoundedRectangle(cornerRadius: cornerRadius, style: style)
|
|
154
|
+
}
|
|
155
|
+
public static func rect(cornerSize: CGSize, style: RoundedCornerStyle = .continuous) -> RoundedRectangle {
|
|
156
|
+
RoundedRectangle(cornerSize: cornerSize, style: style)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
extension Shape where Self == ContainerRelativeShape {
|
|
160
|
+
public static var containerRelative: ContainerRelativeShape { ContainerRelativeShape() }
|
|
161
|
+
}
|