@use-voltra/ios-client 2.1.1 → 2.2.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/README.md +61 -8
- package/build/commonjs/dynamic-widget/api.js +15 -0
- package/build/commonjs/dynamic-widget/api.js.map +1 -0
- package/build/commonjs/index.js +15 -7
- package/build/commonjs/index.js.map +1 -1
- package/build/commonjs/native/NativeVoltra.js.map +1 -1
- package/build/module/dynamic-widget/api.js +10 -0
- package/build/module/dynamic-widget/api.js.map +1 -0
- package/build/module/index.js +1 -0
- package/build/module/index.js.map +1 -1
- package/build/module/native/NativeVoltra.js.map +1 -1
- package/build/typescript/commonjs/dynamic-widget/api.d.ts +8 -0
- package/build/typescript/commonjs/dynamic-widget/api.d.ts.map +1 -0
- package/build/typescript/commonjs/index.d.ts +1 -0
- package/build/typescript/commonjs/index.d.ts.map +1 -1
- package/build/typescript/commonjs/native/NativeVoltra.d.ts +1 -0
- package/build/typescript/commonjs/native/NativeVoltra.d.ts.map +1 -1
- package/build/typescript/module/dynamic-widget/api.d.ts +8 -0
- package/build/typescript/module/dynamic-widget/api.d.ts.map +1 -0
- package/build/typescript/module/index.d.ts +1 -0
- package/build/typescript/module/index.d.ts.map +1 -1
- package/build/typescript/module/native/NativeVoltra.d.ts +1 -0
- package/build/typescript/module/native/NativeVoltra.d.ts.map +1 -1
- package/expo-plugin/build/cjs/index.js +3 -1
- package/expo-plugin/build/cjs/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/index.js +1 -1
- package/expo-plugin/build/cjs/ios-widget/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/podfile.js +38 -12
- package/expo-plugin/build/cjs/ios-widget/podfile.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/buildPhases.js +143 -107
- package/expo-plugin/build/cjs/ios-widget/xcode/buildPhases.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/configurationList.js +30 -22
- package/expo-plugin/build/cjs/ios-widget/xcode/configurationList.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/fileReferences.js +50 -0
- package/expo-plugin/build/cjs/ios-widget/xcode/fileReferences.js.map +1 -0
- package/expo-plugin/build/cjs/ios-widget/xcode/groups.js +45 -43
- package/expo-plugin/build/cjs/ios-widget/xcode/groups.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/index.js +77 -91
- package/expo-plugin/build/cjs/ios-widget/xcode/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/mainAppSettings.js +41 -39
- package/expo-plugin/build/cjs/ios-widget/xcode/mainAppSettings.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/productFile.js +2 -2
- package/expo-plugin/build/cjs/ios-widget/xcode/productFile.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/target.js +29 -63
- package/expo-plugin/build/cjs/ios-widget/xcode/target.js.map +1 -1
- package/expo-plugin/build/esm/index.js +3 -1
- package/expo-plugin/build/esm/index.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/index.js +1 -1
- package/expo-plugin/build/esm/ios-widget/index.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/podfile.js +36 -11
- package/expo-plugin/build/esm/ios-widget/podfile.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/buildPhases.js +143 -106
- package/expo-plugin/build/esm/ios-widget/xcode/buildPhases.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/configurationList.js +31 -22
- package/expo-plugin/build/esm/ios-widget/xcode/configurationList.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/fileReferences.js +45 -0
- package/expo-plugin/build/esm/ios-widget/xcode/fileReferences.js.map +1 -0
- package/expo-plugin/build/esm/ios-widget/xcode/groups.js +45 -42
- package/expo-plugin/build/esm/ios-widget/xcode/groups.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/index.js +81 -96
- package/expo-plugin/build/esm/ios-widget/xcode/index.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/mainAppSettings.js +41 -39
- package/expo-plugin/build/esm/ios-widget/xcode/mainAppSettings.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/productFile.js +3 -2
- package/expo-plugin/build/esm/ios-widget/xcode/productFile.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/target.js +28 -62
- package/expo-plugin/build/esm/ios-widget/xcode/target.js.map +1 -1
- package/expo-plugin/build/types/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/podfile.d.ts +19 -1
- package/expo-plugin/build/types/ios-widget/podfile.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/buildPhases.d.ts +3 -7
- package/expo-plugin/build/types/ios-widget/xcode/buildPhases.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/configurationList.d.ts +15 -10
- package/expo-plugin/build/types/ios-widget/xcode/configurationList.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/fileReferences.d.ts +16 -0
- package/expo-plugin/build/types/ios-widget/xcode/fileReferences.d.ts.map +1 -0
- package/expo-plugin/build/types/ios-widget/xcode/groups.d.ts +0 -4
- package/expo-plugin/build/types/ios-widget/xcode/groups.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/index.d.ts +22 -3
- package/expo-plugin/build/types/ios-widget/xcode/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/mainAppSettings.d.ts +16 -4
- package/expo-plugin/build/types/ios-widget/xcode/mainAppSettings.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/productFile.d.ts +0 -4
- package/expo-plugin/build/types/ios-widget/xcode/productFile.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/target.d.ts +11 -26
- package/expo-plugin/build/types/ios-widget/xcode/target.d.ts.map +1 -1
- package/expo-plugin/src/index.ts +5 -1
- package/expo-plugin/src/ios-widget/index.ts +1 -1
- package/expo-plugin/src/ios-widget/podfile.ts +46 -13
- package/expo-plugin/src/ios-widget/xcode/__fixtures__/fresh.pbxproj +197 -0
- package/expo-plugin/src/ios-widget/xcode/__fixtures__/with-existing-extension.pbxproj +321 -0
- package/expo-plugin/src/ios-widget/xcode/__fixtures__/with-per-config-signing.pbxproj +203 -0
- package/expo-plugin/src/ios-widget/xcode/__snapshots__/applyXcodeChanges.node.test.ts.snap +357 -0
- package/expo-plugin/src/ios-widget/xcode/__tests__/pbxConsistency.ts +130 -0
- package/expo-plugin/src/ios-widget/xcode/buildPhases.ts +151 -152
- package/expo-plugin/src/ios-widget/xcode/configurationList.ts +52 -35
- package/expo-plugin/src/ios-widget/xcode/fileReferences.ts +51 -0
- package/expo-plugin/src/ios-widget/xcode/groups.ts +52 -54
- package/expo-plugin/src/ios-widget/xcode/index.ts +107 -119
- package/expo-plugin/src/ios-widget/xcode/mainAppSettings.ts +59 -54
- package/expo-plugin/src/ios-widget/xcode/productFile.ts +3 -2
- package/expo-plugin/src/ios-widget/xcode/target.ts +31 -83
- package/ios/Package.swift +7 -1
- package/ios/app/NativeVoltra.mm +19 -0
- package/ios/app/VoltraModule.swift +18 -0
- package/ios/app/VoltraModuleImpl.swift +16 -0
- package/ios/shared/DynamicWidgetPropsCodec.swift +51 -0
- package/ios/shared/DynamicWidgetPropsStorage.swift +53 -0
- package/ios/shared/DynamicWidgetPropsStore.swift +50 -0
- package/ios/shared/DynamicWidgetRenderCoordinator.swift +31 -0
- package/ios/shared/DynamicWidgetUpdater.swift +30 -0
- package/ios/shared/VoltraConstants.swift +4 -0
- package/ios/shared/VoltraJSRenderer.swift +3 -1
- package/ios/shared/VoltraNode.swift +6 -2
- package/ios/shared/VoltraWidgetDefaults.swift +9 -1
- package/ios/target/VoltraClientWidgetRuntime.swift +17 -5
- package/ios/target/VoltraHomeWidget.swift +6 -2
- package/ios/target/VoltraWidget.swift +3 -1
- package/ios/ui/Helpers/VoltraDeepLinkResolver.swift +3 -1
- package/ios/ui/Helpers/VoltraProgressDriver.swift +6 -2
- package/ios/ui/Layout/VoltraFlexStackLayout.swift +9 -3
- package/ios/ui/Style/JSColorParser.swift +24 -8
- package/ios/ui/Style/JSGradientParser.swift +36 -12
- package/ios/ui/Style/JSStyleParser.swift +36 -12
- package/ios/ui/Style/LayoutStyle.swift +12 -4
- package/ios/ui/Views/VoltraChart.swift +52 -16
- package/ios/ui/Views/VoltraLinearGradient.swift +6 -2
- package/package.json +5 -5
- package/src/dynamic-widget/api.ts +25 -0
- package/src/index.ts +1 -0
- package/src/native/NativeVoltra.ts +1 -0
|
@@ -8,7 +8,9 @@ enum JSColorParser {
|
|
|
8
8
|
// Optimize: standard trim and lowercase
|
|
9
9
|
let trimmed = string.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
|
10
10
|
|
|
11
|
-
if trimmed.isEmpty {
|
|
11
|
+
if trimmed.isEmpty {
|
|
12
|
+
return nil
|
|
13
|
+
}
|
|
12
14
|
|
|
13
15
|
// 1. Hex (with or without #)
|
|
14
16
|
if trimmed.hasPrefix("#") {
|
|
@@ -57,7 +59,9 @@ enum JSColorParser {
|
|
|
57
59
|
guard let string = value as? String else { return nil }
|
|
58
60
|
|
|
59
61
|
let trimmed = string.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
|
60
|
-
if trimmed.isEmpty {
|
|
62
|
+
if trimmed.isEmpty {
|
|
63
|
+
return nil
|
|
64
|
+
}
|
|
61
65
|
|
|
62
66
|
if trimmed.hasPrefix("#") {
|
|
63
67
|
return parseHexComponents(trimmed)
|
|
@@ -477,7 +481,9 @@ enum JSColorParser {
|
|
|
477
481
|
|
|
478
482
|
private static func normalizeUnit(_ value: Double) -> Double {
|
|
479
483
|
var result = value.truncatingRemainder(dividingBy: 1)
|
|
480
|
-
if result < 0 {
|
|
484
|
+
if result < 0 {
|
|
485
|
+
result += 1
|
|
486
|
+
}
|
|
481
487
|
return result
|
|
482
488
|
}
|
|
483
489
|
|
|
@@ -506,12 +512,22 @@ enum JSColorParser {
|
|
|
506
512
|
/// Helper function for HSL to RGB conversion
|
|
507
513
|
private static func hueToRgb(p: Double, q: Double, t: Double) -> Double {
|
|
508
514
|
var t = t
|
|
509
|
-
if t < 0 {
|
|
510
|
-
|
|
515
|
+
if t < 0 {
|
|
516
|
+
t += 1
|
|
517
|
+
}
|
|
518
|
+
if t > 1 {
|
|
519
|
+
t -= 1
|
|
520
|
+
}
|
|
511
521
|
|
|
512
|
-
if t < 1.0 / 6.0 {
|
|
513
|
-
|
|
514
|
-
|
|
522
|
+
if t < 1.0 / 6.0 {
|
|
523
|
+
return p + (q - p) * 6 * t
|
|
524
|
+
}
|
|
525
|
+
if t < 1.0 / 2.0 {
|
|
526
|
+
return q
|
|
527
|
+
}
|
|
528
|
+
if t < 2.0 / 3.0 {
|
|
529
|
+
return p + (q - p) * (2.0 / 3.0 - t) * 6
|
|
530
|
+
}
|
|
515
531
|
return p
|
|
516
532
|
}
|
|
517
533
|
}
|
|
@@ -200,12 +200,16 @@ enum JSGradientParser {
|
|
|
200
200
|
depth += 1
|
|
201
201
|
} else if char == ")" {
|
|
202
202
|
depth -= 1
|
|
203
|
-
if depth < 0 {
|
|
203
|
+
if depth < 0 {
|
|
204
|
+
return []
|
|
205
|
+
}
|
|
204
206
|
}
|
|
205
207
|
|
|
206
208
|
if char == ",", depth == 0 {
|
|
207
209
|
let token = current.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
208
|
-
if token.isEmpty {
|
|
210
|
+
if token.isEmpty {
|
|
211
|
+
return []
|
|
212
|
+
}
|
|
209
213
|
args.append(token)
|
|
210
214
|
current = ""
|
|
211
215
|
} else {
|
|
@@ -216,7 +220,9 @@ enum JSGradientParser {
|
|
|
216
220
|
guard depth == 0 else { return [] }
|
|
217
221
|
|
|
218
222
|
let token = current.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
219
|
-
if token.isEmpty {
|
|
223
|
+
if token.isEmpty {
|
|
224
|
+
return []
|
|
225
|
+
}
|
|
220
226
|
args.append(token)
|
|
221
227
|
return args
|
|
222
228
|
}
|
|
@@ -231,7 +237,9 @@ enum JSGradientParser {
|
|
|
231
237
|
depth += 1
|
|
232
238
|
} else if char == ")" {
|
|
233
239
|
depth -= 1
|
|
234
|
-
if depth < 0 {
|
|
240
|
+
if depth < 0 {
|
|
241
|
+
return []
|
|
242
|
+
}
|
|
235
243
|
}
|
|
236
244
|
|
|
237
245
|
if char.isWhitespace, depth == 0 {
|
|
@@ -269,10 +277,14 @@ enum JSGradientParser {
|
|
|
269
277
|
for word in words {
|
|
270
278
|
switch word {
|
|
271
279
|
case "left", "right":
|
|
272
|
-
if horizontal != nil {
|
|
280
|
+
if horizontal != nil {
|
|
281
|
+
return nil
|
|
282
|
+
}
|
|
273
283
|
horizontal = word
|
|
274
284
|
case "top", "bottom":
|
|
275
|
-
if vertical != nil {
|
|
285
|
+
if vertical != nil {
|
|
286
|
+
return nil
|
|
287
|
+
}
|
|
276
288
|
vertical = word
|
|
277
289
|
default:
|
|
278
290
|
return nil
|
|
@@ -418,10 +430,14 @@ enum JSGradientParser {
|
|
|
418
430
|
for token in tokens {
|
|
419
431
|
switch token {
|
|
420
432
|
case "left":
|
|
421
|
-
if x != nil {
|
|
433
|
+
if x != nil {
|
|
434
|
+
return nil
|
|
435
|
+
}
|
|
422
436
|
x = 0
|
|
423
437
|
case "right":
|
|
424
|
-
if x != nil {
|
|
438
|
+
if x != nil {
|
|
439
|
+
return nil
|
|
440
|
+
}
|
|
425
441
|
x = 1
|
|
426
442
|
case "center":
|
|
427
443
|
if x == nil {
|
|
@@ -432,10 +448,14 @@ enum JSGradientParser {
|
|
|
432
448
|
return nil
|
|
433
449
|
}
|
|
434
450
|
case "top":
|
|
435
|
-
if y != nil {
|
|
451
|
+
if y != nil {
|
|
452
|
+
return nil
|
|
453
|
+
}
|
|
436
454
|
y = 0
|
|
437
455
|
case "bottom":
|
|
438
|
-
if y != nil {
|
|
456
|
+
if y != nil {
|
|
457
|
+
return nil
|
|
458
|
+
}
|
|
439
459
|
y = 1
|
|
440
460
|
default:
|
|
441
461
|
return nil
|
|
@@ -613,8 +633,12 @@ enum JSGradientParser {
|
|
|
613
633
|
guard !stops.isEmpty else { return [] }
|
|
614
634
|
|
|
615
635
|
var positions = stops.map(\.position)
|
|
616
|
-
if positions.first == nil {
|
|
617
|
-
|
|
636
|
+
if positions.first == nil {
|
|
637
|
+
positions[0] = 0
|
|
638
|
+
}
|
|
639
|
+
if positions.last == nil {
|
|
640
|
+
positions[positions.count - 1] = 1
|
|
641
|
+
}
|
|
618
642
|
|
|
619
643
|
var lastDefined: Double?
|
|
620
644
|
for idx in positions.indices {
|
|
@@ -2,16 +2,24 @@ import SwiftUI
|
|
|
2
2
|
|
|
3
3
|
enum JSStyleParser {
|
|
4
4
|
static func number(_ value: Any?) -> CGFloat? {
|
|
5
|
-
if let v = value as? CGFloat {
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
if let v = value as? CGFloat {
|
|
6
|
+
return v
|
|
7
|
+
}
|
|
8
|
+
if let v = value as? Double {
|
|
9
|
+
return CGFloat(v)
|
|
10
|
+
}
|
|
11
|
+
if let v = value as? Int {
|
|
12
|
+
return CGFloat(v)
|
|
13
|
+
}
|
|
8
14
|
// Handle "20.5" strings if necessary, though rarer in raw JSON objects
|
|
9
15
|
return nil
|
|
10
16
|
}
|
|
11
17
|
|
|
12
18
|
static func sizeValue(_ value: Any?) -> SizeValue? {
|
|
13
19
|
// Numeric → Fixed
|
|
14
|
-
if let n = number(value) {
|
|
20
|
+
if let n = number(value) {
|
|
21
|
+
return .fixed(n)
|
|
22
|
+
}
|
|
15
23
|
// String → Fill / Wrap / try numeric
|
|
16
24
|
guard let str = value as? String else { return nil }
|
|
17
25
|
switch str {
|
|
@@ -19,7 +27,9 @@ enum JSStyleParser {
|
|
|
19
27
|
case "auto": return .wrap
|
|
20
28
|
default:
|
|
21
29
|
// Try parsing as numeric string
|
|
22
|
-
if let n = Double(str) {
|
|
30
|
+
if let n = Double(str) {
|
|
31
|
+
return .fixed(CGFloat(n))
|
|
32
|
+
}
|
|
23
33
|
return nil
|
|
24
34
|
}
|
|
25
35
|
}
|
|
@@ -50,8 +60,12 @@ enum JSStyleParser {
|
|
|
50
60
|
static func boolean(_ value: Any?) -> Bool {
|
|
51
61
|
guard let value = value else { return false }
|
|
52
62
|
|
|
53
|
-
if let bool = value as? Bool {
|
|
54
|
-
|
|
63
|
+
if let bool = value as? Bool {
|
|
64
|
+
return bool
|
|
65
|
+
}
|
|
66
|
+
if let int = value as? Int {
|
|
67
|
+
return int == 1
|
|
68
|
+
}
|
|
55
69
|
if let string = value as? String {
|
|
56
70
|
return string.lowercased() == "true"
|
|
57
71
|
}
|
|
@@ -107,9 +121,15 @@ enum JSStyleParser {
|
|
|
107
121
|
let hasUnderline = string.contains("underline")
|
|
108
122
|
let hasLineThrough = string.contains("line-through") || string.contains("strikethrough")
|
|
109
123
|
|
|
110
|
-
if hasUnderline, hasLineThrough {
|
|
111
|
-
|
|
112
|
-
|
|
124
|
+
if hasUnderline, hasLineThrough {
|
|
125
|
+
return .underlineLineThrough
|
|
126
|
+
}
|
|
127
|
+
if hasUnderline {
|
|
128
|
+
return .underline
|
|
129
|
+
}
|
|
130
|
+
if hasLineThrough {
|
|
131
|
+
return .lineThrough
|
|
132
|
+
}
|
|
113
133
|
return .none
|
|
114
134
|
}
|
|
115
135
|
|
|
@@ -128,8 +148,12 @@ enum JSStyleParser {
|
|
|
128
148
|
static func overflow(_ value: Any?) -> Overflow? {
|
|
129
149
|
guard let string = (value as? String)?.lowercased() else { return nil }
|
|
130
150
|
|
|
131
|
-
if string == "hidden" {
|
|
132
|
-
|
|
151
|
+
if string == "hidden" {
|
|
152
|
+
return .hidden
|
|
153
|
+
}
|
|
154
|
+
if string == "visible" {
|
|
155
|
+
return .visible
|
|
156
|
+
}
|
|
133
157
|
return nil
|
|
134
158
|
}
|
|
135
159
|
|
|
@@ -112,15 +112,23 @@ struct LayoutModifier: ViewModifier {
|
|
|
112
112
|
|
|
113
113
|
/// Derive effective ideal width: explicit width, then flexBasis, then nil
|
|
114
114
|
private var effectiveIdealWidth: CGFloat? {
|
|
115
|
-
if let w = widthValue {
|
|
116
|
-
|
|
115
|
+
if let w = widthValue {
|
|
116
|
+
return w
|
|
117
|
+
}
|
|
118
|
+
if case let .fixed(v) = style.flexBasis {
|
|
119
|
+
return v
|
|
120
|
+
}
|
|
117
121
|
return nil
|
|
118
122
|
}
|
|
119
123
|
|
|
120
124
|
/// Derive effective ideal height: explicit height, then flexBasis, then nil
|
|
121
125
|
private var effectiveIdealHeight: CGFloat? {
|
|
122
|
-
if let h = heightValue {
|
|
123
|
-
|
|
126
|
+
if let h = heightValue {
|
|
127
|
+
return h
|
|
128
|
+
}
|
|
129
|
+
if case let .fixed(v) = style.flexBasis {
|
|
130
|
+
return v
|
|
131
|
+
}
|
|
124
132
|
return nil
|
|
125
133
|
}
|
|
126
134
|
|
|
@@ -49,7 +49,9 @@ public struct VoltraChart: VoltraView {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
private func bool(_ v: JSONValue) -> Bool? {
|
|
52
|
-
if case let .bool(value) = v {
|
|
52
|
+
if case let .bool(value) = v {
|
|
53
|
+
return value
|
|
54
|
+
}
|
|
53
55
|
return nil
|
|
54
56
|
}
|
|
55
57
|
|
|
@@ -60,16 +62,22 @@ public struct VoltraChart: VoltraView {
|
|
|
60
62
|
else { return nil }
|
|
61
63
|
|
|
62
64
|
let props = dict.compactMapValues { jsonValue(from: $0) }
|
|
63
|
-
if props.isEmpty {
|
|
65
|
+
if props.isEmpty {
|
|
66
|
+
return nil
|
|
67
|
+
}
|
|
64
68
|
|
|
65
69
|
let visible = props["v"].flatMap(bool) ?? props["visible"].flatMap(bool)
|
|
66
70
|
let color = (props["c"] ?? props["color"]).flatMap {
|
|
67
|
-
if case let .string(value) = $0 {
|
|
71
|
+
if case let .string(value) = $0 {
|
|
72
|
+
return JSColorParser.parse(value)
|
|
73
|
+
}
|
|
68
74
|
return nil
|
|
69
75
|
}
|
|
70
76
|
let lineWidth = (props["lw"] ?? props["lineWidth"]).flatMap(num).map { CGFloat($0) }
|
|
71
77
|
let dash = ((props["d"] ?? props["dash"]).flatMap {
|
|
72
|
-
if case let .array(values) = $0 {
|
|
78
|
+
if case let .array(values) = $0 {
|
|
79
|
+
return values.compactMap(num).map { CGFloat($0) }
|
|
80
|
+
}
|
|
73
81
|
return nil
|
|
74
82
|
})
|
|
75
83
|
|
|
@@ -140,7 +148,11 @@ public struct VoltraChart: VoltraView {
|
|
|
140
148
|
default: return 0
|
|
141
149
|
}
|
|
142
150
|
}()
|
|
143
|
-
let series: String? = pt.count >= 3 ? {
|
|
151
|
+
let series: String? = pt.count >= 3 ? {
|
|
152
|
+
if case let .string(s) = pt[2] {
|
|
153
|
+
return s
|
|
154
|
+
}; return nil
|
|
155
|
+
}() : nil
|
|
144
156
|
switch pt[0] {
|
|
145
157
|
case let .string(x): return (x, nil, y, series)
|
|
146
158
|
case let .double(x): return (nil, x, y, series)
|
|
@@ -186,12 +198,24 @@ public struct VoltraChart: VoltraView {
|
|
|
186
198
|
|
|
187
199
|
@ChartContentBuilder
|
|
188
200
|
private func buildMark(_ m: WireMark) -> some ChartContent {
|
|
189
|
-
if m.type == "bar" {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if m.type == "
|
|
193
|
-
|
|
194
|
-
|
|
201
|
+
if m.type == "bar" {
|
|
202
|
+
barContent(m)
|
|
203
|
+
}
|
|
204
|
+
if m.type == "line" {
|
|
205
|
+
lineContent(m)
|
|
206
|
+
}
|
|
207
|
+
if m.type == "area" {
|
|
208
|
+
areaContent(m)
|
|
209
|
+
}
|
|
210
|
+
if m.type == "point" {
|
|
211
|
+
pointContent(m)
|
|
212
|
+
}
|
|
213
|
+
if m.type == "rule" {
|
|
214
|
+
ruleContent(m)
|
|
215
|
+
}
|
|
216
|
+
if #available(iOS 17.0, macOS 14.0, *), m.type == "sector" {
|
|
217
|
+
sectorContent(m)
|
|
218
|
+
}
|
|
195
219
|
}
|
|
196
220
|
|
|
197
221
|
// MARK: Bar
|
|
@@ -208,10 +232,16 @@ public struct VoltraChart: VoltraView {
|
|
|
208
232
|
let (xStr, xNum, y, series) = xy(pt)
|
|
209
233
|
let cr: CGFloat? = props["cr"].flatMap(num).map { CGFloat($0) }
|
|
210
234
|
let barWidth: MarkDimension = {
|
|
211
|
-
if let v = props["w"].flatMap(num) {
|
|
235
|
+
if let v = props["w"].flatMap(num) {
|
|
236
|
+
return .fixed(CGFloat(v))
|
|
237
|
+
}
|
|
212
238
|
return .automatic
|
|
213
239
|
}()
|
|
214
|
-
let grouped: Bool = {
|
|
240
|
+
let grouped: Bool = {
|
|
241
|
+
if case let .string(s)? = props["stk"] {
|
|
242
|
+
return s == "grouped"
|
|
243
|
+
}; return false
|
|
244
|
+
}()
|
|
215
245
|
|
|
216
246
|
if let x = xStr {
|
|
217
247
|
if let series {
|
|
@@ -555,15 +585,21 @@ public struct VoltraChart: VoltraView {
|
|
|
555
585
|
case let .string(category) = pt[1]
|
|
556
586
|
{
|
|
557
587
|
let inner: MarkDimension = {
|
|
558
|
-
if let v = props["ir"].flatMap(num) {
|
|
588
|
+
if let v = props["ir"].flatMap(num) {
|
|
589
|
+
return .ratio(CGFloat(v))
|
|
590
|
+
}
|
|
559
591
|
return .automatic
|
|
560
592
|
}()
|
|
561
593
|
let outer: MarkDimension = {
|
|
562
|
-
if let v = props["or"].flatMap(num) {
|
|
594
|
+
if let v = props["or"].flatMap(num) {
|
|
595
|
+
return .ratio(CGFloat(v))
|
|
596
|
+
}
|
|
563
597
|
return .automatic
|
|
564
598
|
}()
|
|
565
599
|
let inset: CGFloat = {
|
|
566
|
-
if let v = props["agin"].flatMap(num) {
|
|
600
|
+
if let v = props["agin"].flatMap(num) {
|
|
601
|
+
return CGFloat(v)
|
|
602
|
+
}
|
|
567
603
|
return 0
|
|
568
604
|
}()
|
|
569
605
|
|
|
@@ -57,12 +57,16 @@ public struct VoltraLinearGradient: VoltraView {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
if !stops.isEmpty {
|
|
60
|
+
if !stops.isEmpty {
|
|
61
|
+
return Gradient(stops: stops)
|
|
62
|
+
}
|
|
61
63
|
}
|
|
62
64
|
if let colorsStr = params.colors {
|
|
63
65
|
let parts = colorsStr.split(separator: "|").map(String.init)
|
|
64
66
|
let colors: [Color] = parts.compactMap { JSColorParser.parse($0) }
|
|
65
|
-
if !colors.isEmpty {
|
|
67
|
+
if !colors.isEmpty {
|
|
68
|
+
return Gradient(colors: colors)
|
|
69
|
+
}
|
|
66
70
|
}
|
|
67
71
|
// Fallback neutral gradient
|
|
68
72
|
return Gradient(colors: [Color.black.opacity(0.25), Color.black.opacity(0.05)])
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@use-voltra/ios-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Client-only Voltra APIs for iOS",
|
|
5
5
|
"main": "./build/commonjs/index.js",
|
|
6
6
|
"module": "./build/module/index.js",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"@expo/plist": "^0.3.5",
|
|
40
40
|
"dedent": "^1.7.1",
|
|
41
41
|
"xcode": "^3.0.1",
|
|
42
|
-
"@use-voltra/
|
|
43
|
-
"@use-voltra/
|
|
44
|
-
"@use-voltra/
|
|
42
|
+
"@use-voltra/compiler": "^2.2.0",
|
|
43
|
+
"@use-voltra/expo-plugin": "^2.2.0",
|
|
44
|
+
"@use-voltra/ios": "^2.2.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"expo": "*",
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
"format:swift:fix": "swiftformat ios",
|
|
126
126
|
"lint": "oxlint src expo-plugin/src",
|
|
127
127
|
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit && tsc -p expo-plugin/tsconfig.typecheck.json --noEmit",
|
|
128
|
-
"test": "jest --config expo-plugin/jest.config.js",
|
|
128
|
+
"test": "jest --config jest.dynamic-widget.config.js && jest --config expo-plugin/jest.config.js",
|
|
129
129
|
"test:swift": "cd ios && swift test"
|
|
130
130
|
}
|
|
131
131
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getNativeVoltra } from '../native/NativeVoltra.js'
|
|
2
|
+
import { assertRunningOnApple } from '../utils/assertRunningOnApple.js'
|
|
3
|
+
|
|
4
|
+
export type DynamicWidgetPropsValue =
|
|
5
|
+
| string
|
|
6
|
+
| number
|
|
7
|
+
| boolean
|
|
8
|
+
| null
|
|
9
|
+
| ReadonlyArray<DynamicWidgetPropsValue>
|
|
10
|
+
| Readonly<{ [dynamicWidgetPropName: string]: DynamicWidgetPropsValue }>
|
|
11
|
+
|
|
12
|
+
export type DynamicWidgetProps = Readonly<{
|
|
13
|
+
[dynamicWidgetPropName: string]: DynamicWidgetPropsValue
|
|
14
|
+
}>
|
|
15
|
+
|
|
16
|
+
export const updateDynamicWidget = async (
|
|
17
|
+
dynamicWidgetId: string,
|
|
18
|
+
dynamicWidgetProps: DynamicWidgetProps
|
|
19
|
+
): Promise<void> => {
|
|
20
|
+
if (!assertRunningOnApple()) return Promise.resolve()
|
|
21
|
+
|
|
22
|
+
const dynamicWidgetPropsJson = JSON.stringify(dynamicWidgetProps)
|
|
23
|
+
|
|
24
|
+
return getNativeVoltra().updateDynamicWidget(dynamicWidgetId, dynamicWidgetPropsJson)
|
|
25
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ export {
|
|
|
5
5
|
} from './components/VoltraLiveActivityPreview.js'
|
|
6
6
|
export { VoltraView, type VoltraViewProps } from './components/VoltraView.js'
|
|
7
7
|
export { VoltraWidgetPreview, type VoltraWidgetPreviewProps } from './components/VoltraWidgetPreview.js'
|
|
8
|
+
export { type DynamicWidgetProps, type DynamicWidgetPropsValue, updateDynamicWidget } from './dynamic-widget/api.js'
|
|
8
9
|
export * from './events.js'
|
|
9
10
|
export { isGlassSupported, isHeadless, useIsHeadless } from './helpers.js'
|
|
10
11
|
export { logger, type VoltraLogLevel } from './logger.js'
|
|
@@ -100,6 +100,7 @@ export interface Spec extends TurboModule {
|
|
|
100
100
|
preloadImages(images: PreloadImageOptions[]): Promise<PreloadImagesResult>
|
|
101
101
|
reloadLiveActivities(activityNames?: string[] | null): Promise<void>
|
|
102
102
|
clearPreloadedImages(keys?: string[] | null): Promise<void>
|
|
103
|
+
updateDynamicWidget(dynamicWidgetId: string, dynamicWidgetPropsJson: string): Promise<void>
|
|
103
104
|
updateWidget(widgetId: string, jsonString: string, options: UpdateWidgetOptions): Promise<void>
|
|
104
105
|
scheduleWidget(widgetId: string, timelineJson: string): Promise<void>
|
|
105
106
|
reloadWidgets(widgetIds?: string[] | null): Promise<void>
|