@craft-native/ios 0.0.207 → 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/package.json
CHANGED
package/templates/CraftApp.swift
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
|
|
@@ -3959,11 +3959,16 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
3959
3959
|
// Each screen says whether it wants the tab bar, so one that hid it
|
|
3960
3960
|
// never leaves it hidden for the next.
|
|
3961
3961
|
CraftChrome.shared.setHiddenByScreen(tabBarHidden)
|
|
3962
|
+
CraftChrome.shared.updateTabAccessory(tabAccessory)
|
|
3962
3963
|
refreshTraitDefaults()
|
|
3963
3964
|
}
|
|
3964
3965
|
|
|
3965
3966
|
override func viewWillDisappear(_ animated: Bool) {
|
|
3966
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)
|
|
3967
3972
|
// Popped (or its stack dismissed) while the bar was away: it comes
|
|
3968
3973
|
// back for whatever shows next, a web page included.
|
|
3969
3974
|
if tabBarHidden, isMovingFromParent || isBeingDismissed || navigationController?.isBeingDismissed == true {
|
|
@@ -4529,6 +4534,7 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
4529
4534
|
private var statusBarHiddenOverride: Bool?
|
|
4530
4535
|
/// The app's tab bar away while this screen shows (`tabBarHidden`).
|
|
4531
4536
|
private var tabBarHidden = false
|
|
4537
|
+
private var tabAccessory: [String: Any]?
|
|
4532
4538
|
/// Whether a back-swipe may leave this screen at all, the edge's
|
|
4533
4539
|
/// included (`swipeBack: false`): a screen that steps through its own
|
|
4534
4540
|
/// pages with a Back of its own (a first-run tour's questions) would
|
|
@@ -4575,6 +4581,12 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
4575
4581
|
}
|
|
4576
4582
|
// The app script has no screen, so no bar and no tab bar to change.
|
|
4577
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
|
+
}
|
|
4578
4590
|
if options.keys.contains("title") {
|
|
4579
4591
|
navigationItem.title = options["title"] as? String
|
|
4580
4592
|
titleFromOptions = true
|
|
@@ -6939,8 +6951,15 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
|
|
|
6939
6951
|
case "900": weight = .black
|
|
6940
6952
|
default: weight = .regular
|
|
6941
6953
|
}
|
|
6942
|
-
|
|
6943
|
-
|
|
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)
|
|
6944
6963
|
if style["fontStyle"] as? String == "italic",
|
|
6945
6964
|
let descriptor = font.fontDescriptor.withSymbolicTraits(.traitItalic) {
|
|
6946
6965
|
font = UIFont(descriptor: descriptor, size: size)
|