craft-native 0.0.206 → 0.0.209
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/android/templates/CraftNativeShell.kt.template +38 -11
- package/dist/android/templates/MainActivityNative.kt.template +210 -172
- package/dist/cli.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/ios/templates/CraftApp.swift +36 -1
- package/dist/ios/templates/CraftHybrid.swift +3 -1
- package/dist/ios/templates/CraftNativeScreen.swift +34 -3
- 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.209";
|
|
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
|
@@ -621,6 +621,7 @@ final class CraftChrome: ObservableObject {
|
|
|
621
621
|
}
|
|
622
622
|
|
|
623
623
|
@Published var tabs: [Tab] = []
|
|
624
|
+
@Published var tabAccessory: Tab?
|
|
624
625
|
@Published var selected: String?
|
|
625
626
|
@Published var tabBarVisible = false
|
|
626
627
|
@Published var splashVisible = true
|
|
@@ -688,6 +689,16 @@ final class CraftChrome: ObservableObject {
|
|
|
688
689
|
tabs[index].badge = (item["badge"] as? String).flatMap { $0.isEmpty ? nil : String($0.prefix(8)) }
|
|
689
690
|
}
|
|
690
691
|
}
|
|
692
|
+
/// A destination beside the tab pill, outside the tab stacks and swipe order.
|
|
693
|
+
func updateTabAccessory(_ item: [String: Any]?) {
|
|
694
|
+
guard let item, let path = item["path"] as? String,
|
|
695
|
+
path.hasPrefix("/"), !path.hasPrefix("//"),
|
|
696
|
+
let title = item["title"] as? String else { tabAccessory = nil; return }
|
|
697
|
+
tabAccessory = Tab(id: path, title: title, symbol: item["symbol"] as? String ?? "message",
|
|
698
|
+
badge: (item["badge"] as? String).flatMap { $0.isEmpty ? nil : String($0.prefix(8)) },
|
|
699
|
+
accessibilityLabel: item["accessibilityLabel"] as? String)
|
|
700
|
+
}
|
|
701
|
+
|
|
691
702
|
func setHiddenByScreen(_ hidden: Bool) {
|
|
692
703
|
guard hiddenByScreen != hidden else { return }
|
|
693
704
|
hiddenByScreen = hidden
|
|
@@ -913,7 +924,31 @@ struct CraftTabBarView: View {
|
|
|
913
924
|
|
|
914
925
|
var body: some View {
|
|
915
926
|
if chrome.tabBarVisible && !chrome.tabs.isEmpty {
|
|
916
|
-
|
|
927
|
+
HStack(spacing: 8) {
|
|
928
|
+
bar
|
|
929
|
+
if let accessory = chrome.tabAccessory {
|
|
930
|
+
Button { CraftHybrid.shared.open(accessory.id) } label: {
|
|
931
|
+
Image(systemName: accessory.symbol)
|
|
932
|
+
.font(.system(size: iconSize))
|
|
933
|
+
.frame(width: 62, height: 62)
|
|
934
|
+
.background(.ultraThinMaterial, in: Circle())
|
|
935
|
+
.overlay(alignment: .topTrailing) {
|
|
936
|
+
if let badge = accessory.badge {
|
|
937
|
+
Text(badge)
|
|
938
|
+
.font(.system(size: badgeSize, weight: .bold))
|
|
939
|
+
.foregroundStyle(.white)
|
|
940
|
+
.padding(.horizontal, 4)
|
|
941
|
+
.frame(minWidth: 18, minHeight: 18)
|
|
942
|
+
.background(Capsule().fill(Color.red))
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
.buttonStyle(.plain)
|
|
947
|
+
.accessibilityLabel(accessory.accessibilityLabel ?? accessory.title)
|
|
948
|
+
.accessibilityValue(accessory.badge ?? "")
|
|
949
|
+
.accessibilityIdentifier("craft-tab-accessory")
|
|
950
|
+
}
|
|
951
|
+
}
|
|
917
952
|
.padding(.horizontal, 16)
|
|
918
953
|
.padding(.bottom, 4)
|
|
919
954
|
.background(GeometryReader { proxy in
|
|
@@ -854,9 +854,11 @@ final class CraftHybrid: NSObject {
|
|
|
854
854
|
let show: (CraftHybridController) -> Void = { [weak self] controller in
|
|
855
855
|
if native { controller.showNative(path: path, replace: false, fromLink: true) } else { self?.openOutside(url.absoluteString) }
|
|
856
856
|
}
|
|
857
|
-
guard let controller else {
|
|
857
|
+
guard let controller, controller.isViewLoaded else {
|
|
858
858
|
// Before the shell: a hybrid app's page has it; an all-native app
|
|
859
859
|
// opens it once the shell is up (a link that launched the app).
|
|
860
|
+
// Construction assigns controller before viewDidLoad makes the
|
|
861
|
+
// navigation stacks; a link in that interval must wait too.
|
|
860
862
|
guard !hasWeb else { return false }
|
|
861
863
|
untilShell.append(show)
|
|
862
864
|
return true
|
|
@@ -21,6 +21,13 @@ private func number(_ value: Any?) -> CGFloat? {
|
|
|
21
21
|
return value.isFinite ? value : nil
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
private func craftNativeFontWeight(_ value: Any?) -> String? {
|
|
25
|
+
if let value = value as? String { return value }
|
|
26
|
+
guard !(value is Bool), let number = value as? NSNumber, number.doubleValue.isFinite else { return nil }
|
|
27
|
+
let integer = number.doubleValue.rounded()
|
|
28
|
+
return integer == number.doubleValue ? String(Int(integer)) : nil
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
private func craftNativePickerValue(_ value: Any?) -> String? {
|
|
25
32
|
if let value = value as? String, !value.isEmpty { return value }
|
|
26
33
|
if let value = value as? NSNumber, value.doubleValue.isFinite { return String(value.doubleValue) }
|
|
@@ -1228,6 +1235,11 @@ private final class CraftNativeMapView: MKMapView, MKMapViewDelegate {
|
|
|
1228
1235
|
return MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: latitude, longitude: longitude), span: MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta))
|
|
1229
1236
|
}
|
|
1230
1237
|
|
|
1238
|
+
private func nonEmptyHandler(_ handler: String?) -> String? {
|
|
1239
|
+
guard let handler, !handler.isEmpty else { return nil }
|
|
1240
|
+
return handler
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1231
1243
|
private static func color(_ value: String?) -> UIColor {
|
|
1232
1244
|
switch value?.lowercased() {
|
|
1233
1245
|
case "red": return .systemRed
|
|
@@ -3947,11 +3959,16 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
3947
3959
|
// Each screen says whether it wants the tab bar, so one that hid it
|
|
3948
3960
|
// never leaves it hidden for the next.
|
|
3949
3961
|
CraftChrome.shared.setHiddenByScreen(tabBarHidden)
|
|
3962
|
+
CraftChrome.shared.updateTabAccessory(tabAccessory)
|
|
3950
3963
|
refreshTraitDefaults()
|
|
3951
3964
|
}
|
|
3952
3965
|
|
|
3953
3966
|
override func viewWillDisappear(_ animated: Bool) {
|
|
3954
3967
|
super.viewWillDisappear(animated)
|
|
3968
|
+
// The accessory belongs to the visible native screen. Clear the
|
|
3969
|
+
// shared shell state before a hybrid/web route appears, otherwise a
|
|
3970
|
+
// destination from the outgoing screen remains tappable on top of it.
|
|
3971
|
+
CraftChrome.shared.updateTabAccessory(nil)
|
|
3955
3972
|
// Popped (or its stack dismissed) while the bar was away: it comes
|
|
3956
3973
|
// back for whatever shows next, a web page included.
|
|
3957
3974
|
if tabBarHidden, isMovingFromParent || isBeingDismissed || navigationController?.isBeingDismissed == true {
|
|
@@ -4517,6 +4534,7 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
4517
4534
|
private var statusBarHiddenOverride: Bool?
|
|
4518
4535
|
/// The app's tab bar away while this screen shows (`tabBarHidden`).
|
|
4519
4536
|
private var tabBarHidden = false
|
|
4537
|
+
private var tabAccessory: [String: Any]?
|
|
4520
4538
|
/// Whether a back-swipe may leave this screen at all, the edge's
|
|
4521
4539
|
/// included (`swipeBack: false`): a screen that steps through its own
|
|
4522
4540
|
/// pages with a Back of its own (a first-run tour's questions) would
|
|
@@ -4563,6 +4581,12 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
4563
4581
|
}
|
|
4564
4582
|
// The app script has no screen, so no bar and no tab bar to change.
|
|
4565
4583
|
guard !isAppScript else { return }
|
|
4584
|
+
if options.keys.contains("tabAccessory") {
|
|
4585
|
+
tabAccessory = options["tabAccessory"] as? [String: Any]
|
|
4586
|
+
if navigationController?.topViewController === self, view.window != nil {
|
|
4587
|
+
CraftChrome.shared.updateTabAccessory(tabAccessory)
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4566
4590
|
if options.keys.contains("title") {
|
|
4567
4591
|
navigationItem.title = options["title"] as? String
|
|
4568
4592
|
titleFromOptions = true
|
|
@@ -6610,7 +6634,7 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
6610
6634
|
(icon as? CraftNativeIconView)?.defaultBox = box == nil && fontSize == nil ? 20 : nil
|
|
6611
6635
|
let pointSize = fontSize ?? (box ?? 20) * 0.84
|
|
6612
6636
|
let weight: UIImage.SymbolWeight
|
|
6613
|
-
switch style["fontWeight"]
|
|
6637
|
+
switch craftNativeFontWeight(style["fontWeight"]) {
|
|
6614
6638
|
case "100": weight = .ultraLight
|
|
6615
6639
|
case "200": weight = .thin
|
|
6616
6640
|
case "300": weight = .light
|
|
@@ -6927,8 +6951,15 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
6927
6951
|
case "900": weight = .black
|
|
6928
6952
|
default: weight = .regular
|
|
6929
6953
|
}
|
|
6930
|
-
|
|
6931
|
-
|
|
6954
|
+
// Android's TextView uses SP, so its native text scales with the
|
|
6955
|
+
// user's content-size setting. Apply the same Dynamic Type multiplier
|
|
6956
|
+
// here before assigning the font to labels, buttons, and inputs.
|
|
6957
|
+
let scaledSize = UIFontMetrics(forTextStyle: .body).scaledValue(
|
|
6958
|
+
for: size,
|
|
6959
|
+
compatibleWith: traitCollection
|
|
6960
|
+
)
|
|
6961
|
+
var font = (style["fontFamily"] as? String).flatMap { UIFont(name: $0, size: scaledSize) }
|
|
6962
|
+
?? .systemFont(ofSize: scaledSize, weight: weight)
|
|
6932
6963
|
if style["fontStyle"] as? String == "italic",
|
|
6933
6964
|
let descriptor = font.fontDescriptor.withSymbolicTraits(.traitItalic) {
|
|
6934
6965
|
font = UIFont(descriptor: descriptor, size: size)
|