craft-native 0.0.215 → 0.0.217
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/dist/cli.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/ios/templates/CraftApp.swift +5 -3
- package/dist/ios/templates/CraftHybrid.swift +10 -6
- package/dist/ios/templates/CraftNativeFlatList.swift +1 -1
- package/dist/ios/templates/CraftNativeScreen.swift +21 -11
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3424,7 +3424,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
|
|
|
3424
3424
|
`);
|
|
3425
3425
|
}
|
|
3426
3426
|
// package.json
|
|
3427
|
-
var version = "0.0.
|
|
3427
|
+
var version = "0.0.217";
|
|
3428
3428
|
|
|
3429
3429
|
// bin/cli.ts
|
|
3430
3430
|
var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -797,9 +797,11 @@ final class CraftChrome: ObservableObject {
|
|
|
797
797
|
|
|
798
798
|
/// Move the tab indicator with an in-flight native-stack swipe. The
|
|
799
799
|
/// controller commits or restores this preview when the finger lifts.
|
|
800
|
-
func beginTabSwipe(to id: String) {
|
|
801
|
-
guard id !=
|
|
802
|
-
|
|
800
|
+
func beginTabSwipe(to id: String, from previous: String) {
|
|
801
|
+
guard id != previous, tabs.contains(where: { $0.id == id }) else { return }
|
|
802
|
+
// A page's pending selection report may disagree with the native
|
|
803
|
+
// stack. Cancellation belongs to the stack the finger left.
|
|
804
|
+
tabSwipePrevious = previous
|
|
803
805
|
withAnimation(nil) { selected = id }
|
|
804
806
|
}
|
|
805
807
|
|
|
@@ -1203,7 +1203,7 @@ final class CraftHybridController: UIViewController, UINavigationControllerDeleg
|
|
|
1203
1203
|
tabSwipeFrom = -direction * width
|
|
1204
1204
|
target.view.frame = view.bounds.offsetBy(dx: tabSwipeFrom, dy: 0)
|
|
1205
1205
|
view.bringSubviewToFront(target.view)
|
|
1206
|
-
CraftChrome.shared.beginTabSwipe(to: id)
|
|
1206
|
+
CraftChrome.shared.beginTabSwipe(to: id, from: currentTab)
|
|
1207
1207
|
return true
|
|
1208
1208
|
}
|
|
1209
1209
|
|
|
@@ -1668,12 +1668,16 @@ final class CraftHybridController: UIViewController, UINavigationControllerDeleg
|
|
|
1668
1668
|
/// tab's root: over a native screen, or on an entry the shell pushed
|
|
1669
1669
|
/// there, the page cannot know which tab it is in (a workout page
|
|
1670
1670
|
/// loaded on its own lights Calendar, though Today opened it). The bar
|
|
1671
|
-
/// then keeps the tab that is on screen.
|
|
1671
|
+
/// then keeps the tab that is on screen, or the finger's active preview.
|
|
1672
1672
|
func pageSelectedTab(_ id: String) {
|
|
1673
|
-
guard id != currentTab, pendingTab?.id != id else { return }
|
|
1674
|
-
guard
|
|
1675
|
-
|
|
1676
|
-
DispatchQueue.main.async {
|
|
1673
|
+
guard id != (activeTabSwipeTarget ?? currentTab), pendingTab?.id != id else { return }
|
|
1674
|
+
guard activeTabSwipeTarget == nil,
|
|
1675
|
+
let top = visibleStack?.topViewController as? CraftHybridWebSlot, top.isTabRoot else {
|
|
1676
|
+
DispatchQueue.main.async { [weak self] in
|
|
1677
|
+
guard let self, self.hybrid.controller === self else { return }
|
|
1678
|
+
// Resolve ownership when the correction runs: a newer tap
|
|
1679
|
+
// or swipe may have arrived while a native root was mounting.
|
|
1680
|
+
let shown = self.activeTabSwipeTarget ?? self.currentTab
|
|
1677
1681
|
guard CraftChrome.shared.selected != shown else { return }
|
|
1678
1682
|
CraftChrome.shared.selected = shown
|
|
1679
1683
|
}
|
|
@@ -308,7 +308,7 @@ final class CraftNativeFlatList: UICollectionView, UICollectionViewDelegateFlowL
|
|
|
308
308
|
|
|
309
309
|
func setContentContainerStyle(_ raw: [String: Any]?) {
|
|
310
310
|
func nonNegative(_ value: Any?) -> CGFloat? {
|
|
311
|
-
guard
|
|
311
|
+
guard let number = craftNativeNumber(value) else { return nil }
|
|
312
312
|
let points = CGFloat(truncating: number)
|
|
313
313
|
guard points.isFinite, points >= 0 else { return nil }
|
|
314
314
|
return points
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Foundation
|
|
2
|
+
import CoreFoundation
|
|
2
3
|
import AVFoundation
|
|
3
4
|
import AVKit
|
|
4
5
|
import CryptoKit
|
|
@@ -12,32 +13,41 @@ import UIKit
|
|
|
12
13
|
|
|
13
14
|
private let craftNativeCapabilityTimeoutMilliseconds = 30_000
|
|
14
15
|
|
|
16
|
+
/// Foundation's `NSNumber(0/1) is Bool` is true even for JSON numbers.
|
|
17
|
+
/// Check the Core Foundation identity so real booleans stay invalid numeric
|
|
18
|
+
/// props while zero lengths, flex factors and opacity 1 remain numbers.
|
|
19
|
+
func craftNativeNumber(_ value: Any?) -> NSNumber? {
|
|
20
|
+
guard let number = value as? NSNumber,
|
|
21
|
+
CFGetTypeID(number) != CFBooleanGetTypeID() else { return nil }
|
|
22
|
+
return number
|
|
23
|
+
}
|
|
24
|
+
|
|
15
25
|
/// A finite number from a prop, for the views outside the screen controller,
|
|
16
26
|
/// which has its own: the keyboard-avoiding view and SVG text read theirs
|
|
17
27
|
/// with it, and without it the template did not compile.
|
|
18
28
|
private func number(_ value: Any?) -> CGFloat? {
|
|
19
29
|
// JavaScript booleans bridge to NSNumber on Apple platforms; they are
|
|
20
30
|
// invalid numeric styles and must stay unset like Android's Number cast.
|
|
21
|
-
guard
|
|
31
|
+
guard let number = craftNativeNumber(value) else { return nil }
|
|
22
32
|
let value = CGFloat(truncating: number)
|
|
23
33
|
return value.isFinite ? value : nil
|
|
24
34
|
}
|
|
25
35
|
|
|
26
36
|
private func craftNativeFontWeight(_ value: Any?) -> String? {
|
|
27
37
|
if let value = value as? String { return value }
|
|
28
|
-
guard
|
|
38
|
+
guard let number = craftNativeNumber(value), number.doubleValue.isFinite else { return nil }
|
|
29
39
|
let integer = number.doubleValue.rounded()
|
|
30
40
|
return integer == number.doubleValue ? String(Int(integer)) : nil
|
|
31
41
|
}
|
|
32
42
|
|
|
33
43
|
private func craftNativePickerValue(_ value: Any?) -> String? {
|
|
34
44
|
if let value = value as? String, !value.isEmpty { return value }
|
|
35
|
-
if
|
|
45
|
+
if let value = craftNativeNumber(value), value.doubleValue.isFinite { return String(value.doubleValue) }
|
|
36
46
|
return nil
|
|
37
47
|
}
|
|
38
48
|
|
|
39
49
|
private func craftNativeGridColumnCount(_ value: Any?) -> Int {
|
|
40
|
-
if
|
|
50
|
+
if let number = craftNativeNumber(value) { return max(1, number.intValue) }
|
|
41
51
|
guard let text = value as? String else { return 1 }
|
|
42
52
|
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
43
53
|
if trimmed.hasPrefix("repeat(") {
|
|
@@ -1387,7 +1397,7 @@ private final class CraftNativeMapView: MKMapView, MKMapViewDelegate {
|
|
|
1387
1397
|
}
|
|
1388
1398
|
|
|
1389
1399
|
private static func numeric(_ value: Any?) -> Double? {
|
|
1390
|
-
guard
|
|
1400
|
+
guard let number = craftNativeNumber(value) else { return nil }
|
|
1391
1401
|
let value = number.doubleValue
|
|
1392
1402
|
return value.isFinite ? value : nil
|
|
1393
1403
|
}
|
|
@@ -1458,7 +1468,7 @@ private enum CraftNativeLength: Equatable {
|
|
|
1458
1468
|
init?(_ value: Any?) {
|
|
1459
1469
|
// JavaScript booleans can bridge to NSNumber on Apple platforms;
|
|
1460
1470
|
// they are invalid CSS lengths and must stay unset like Android.
|
|
1461
|
-
if
|
|
1471
|
+
if let number = craftNativeNumber(value) {
|
|
1462
1472
|
let points = CGFloat(truncating: number)
|
|
1463
1473
|
guard points.isFinite else { return nil }
|
|
1464
1474
|
self = .points(points)
|
|
@@ -1516,7 +1526,7 @@ private struct CraftNativeLayoutStyle {
|
|
|
1516
1526
|
|
|
1517
1527
|
init(_ raw: [String: Any]) {
|
|
1518
1528
|
func number(_ value: Any?) -> CGFloat? {
|
|
1519
|
-
guard
|
|
1529
|
+
guard let number = craftNativeNumber(value) else { return nil }
|
|
1520
1530
|
let value = CGFloat(truncating: number)
|
|
1521
1531
|
return value.isFinite ? value : nil
|
|
1522
1532
|
}
|
|
@@ -5000,7 +5010,7 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
5000
5010
|
else if let symbol = spec["symbol"] as? String { button.setImage(UIImage(systemName: symbol, withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular)), for: .normal) }
|
|
5001
5011
|
button.accessibilityIdentifier = spec["id"] as? String
|
|
5002
5012
|
button.accessibilityLabel = spec["accessibilityLabel"] as? String
|
|
5003
|
-
if
|
|
5013
|
+
if let value = craftNativeNumber(spec["badge"]), value.intValue > 0 {
|
|
5004
5014
|
let dot = spec["badgeStyle"] as? String == "dot"
|
|
5005
5015
|
let size: CGFloat = dot ? 9 : 18
|
|
5006
5016
|
// The fill is a tinted symbol, not a background colour: on iOS 26
|
|
@@ -7658,7 +7668,7 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
7658
7668
|
/// Countdown values use seconds when numeric, or `HH:mm[:ss]` text.
|
|
7659
7669
|
static func countdownDuration(_ value: Any?) -> TimeInterval? {
|
|
7660
7670
|
let maximum: TimeInterval = 23 * 3600 + 59 * 60 + 59
|
|
7661
|
-
if let number =
|
|
7671
|
+
if let number = craftNativeNumber(value) {
|
|
7662
7672
|
let seconds = number.doubleValue
|
|
7663
7673
|
guard seconds.isFinite else { return nil }
|
|
7664
7674
|
return min(maximum, max(0, seconds))
|
|
@@ -7679,7 +7689,7 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
7679
7689
|
/// time), `2026-10-12T07:30` (local), a full ISO 8601 string, or
|
|
7680
7690
|
/// milliseconds since 1970. Nil for anything else.
|
|
7681
7691
|
static func pickerDate(_ value: Any?) -> Date? {
|
|
7682
|
-
if let number =
|
|
7692
|
+
if let number = craftNativeNumber(value) {
|
|
7683
7693
|
let milliseconds = number.doubleValue
|
|
7684
7694
|
guard milliseconds.isFinite else { return nil }
|
|
7685
7695
|
return Date(timeIntervalSince1970: milliseconds / 1000)
|
|
@@ -7851,7 +7861,7 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
7851
7861
|
}
|
|
7852
7862
|
|
|
7853
7863
|
private func number(_ value: Any?) -> CGFloat? {
|
|
7854
|
-
guard
|
|
7864
|
+
guard let number = craftNativeNumber(value) else { return nil }
|
|
7855
7865
|
let value = CGFloat(truncating: number)
|
|
7856
7866
|
return value.isFinite ? value : nil
|
|
7857
7867
|
}
|