@momo-kits/native-kits 0.167.1-beta.9-debug → 0.167.1-duo-search.1

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.
Files changed (189) hide show
  1. package/CLAUDE.md +36 -0
  2. package/ios/Application/ApplicationEnvironment.swift +6 -0
  3. package/ios/Application/Components.swift +1 -3
  4. package/ios/Application/HeaderRight.swift +32 -14
  5. package/ios/Application/Layout/ScreenLayout.swift +312 -0
  6. package/ios/Application/Navigation/BottomTab/BottomTab.swift +67 -10
  7. package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +5 -2
  8. package/ios/Application/Navigation/BottomTab/DuoBarCompression.swift +105 -0
  9. package/ios/Application/Navigation/BottomTab/DuoTabBar.swift +304 -0
  10. package/ios/Application/Navigation/HeaderUser.swift +4 -4
  11. package/ios/Application/Navigation/NavigationContainer.swift +48 -42
  12. package/ios/Application/Navigation/Navigator.swift +122 -29
  13. package/ios/Application/Navigation/NavigatorManager.swift +13 -6
  14. package/ios/Application/Navigation/Overplay/BottomSheet.swift +41 -4
  15. package/ios/Application/Navigation/Overplay/ModalScreen.swift +7 -0
  16. package/ios/Application/Navigation/component/DuoScrollGradient.swift +54 -0
  17. package/ios/Application/Navigation/component/Header.swift +11 -6
  18. package/ios/Application/Navigation/component/HeaderBackground.swift +3 -2
  19. package/ios/Application/Navigation/component/NavigationFooter.swift +1 -1
  20. package/ios/Application/Navigation/component/NavigationHeaderRight.swift +93 -9
  21. package/ios/Application/Navigation/component/SideBar.swift +155 -0
  22. package/ios/Application/StackScreen.swift +175 -18
  23. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +59 -5
  24. package/ios/Colors+Radius+Spacing/Colors.swift +1 -1
  25. package/ios/Extensions/Color++.swift +20 -9
  26. package/ios/Extensions/OptionalEnvironmentObject.swift +12 -0
  27. package/ios/Icon/Icon.swift +14 -22
  28. package/ios/Icon/Icons.swift +1329 -0
  29. package/ios/Image/Image.swift +16 -5
  30. package/ios/Lottie/LottieView.swift +4 -2
  31. package/ios/Popup/PopupDisplay.swift +84 -67
  32. package/ios/Popup/PopupLayout.swift +45 -0
  33. package/ios/Popup/PopupNotify.swift +44 -26
  34. package/ios/Popup/PopupPromotion.swift +18 -6
  35. package/ios/Resources/dot_loading.json +558 -0
  36. package/ios/Resources/lottie_circle_loader.json +1 -0
  37. package/ios/Template/TrustBanner/TrustBanner.swift +69 -31
  38. package/ios/Typography/FontScale.swift +3 -3
  39. package/ios/native-kits.podspec +1 -1
  40. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  41. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DuoTabDemo.swift +80 -0
  42. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +2 -0
  43. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IPhoneDuoDemo.swift +173 -0
  44. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +1 -0
  45. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +2 -2
  46. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +2 -0
  47. package/package.json +1 -1
  48. package/scripts/gen-ios-icons.mjs +36 -0
  49. package/build.gradle.kts +0 -11
  50. package/compose/build.gradle.kts +0 -190
  51. package/compose/build.gradle.kts.backup +0 -190
  52. package/compose/compose.podspec +0 -47
  53. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
  54. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
  55. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
  56. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
  57. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -151
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -124
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -831
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -82
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -356
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -113
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -49
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -189
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -475
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -266
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -240
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -223
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -264
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -185
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -328
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -97
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -310
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -323
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -220
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -199
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -552
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -88
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -125
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -207
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -498
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -176
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -234
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -188
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -16
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +0 -14
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  132. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  133. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -221
  134. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -270
  135. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -52
  136. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -38
  137. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -39
  138. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
  139. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
  140. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  141. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
  142. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
  143. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  144. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -299
  145. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +0 -58
  146. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -129
  147. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -106
  148. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -201
  149. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -393
  150. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  151. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -595
  152. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -148
  153. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -35
  154. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -175
  155. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -225
  156. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  157. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
  158. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -358
  159. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -83
  160. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +0 -106
  161. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +0 -75
  162. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -309
  163. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -40
  164. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -364
  165. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
  166. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
  167. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -12
  168. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
  169. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
  170. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -71
  171. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  172. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
  173. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  174. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -105
  175. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -40
  176. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -45
  177. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
  178. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -38
  179. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
  180. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -213
  181. package/gradle/libs.versions.toml +0 -69
  182. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  183. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  184. package/gradle.properties +0 -26
  185. package/gradlew +0 -252
  186. package/gradlew.bat +0 -94
  187. package/ios-demo/README.md +0 -120
  188. package/local.properties +0 -8
  189. package/settings.gradle.kts +0 -64
@@ -26,7 +26,10 @@ public struct CalculatorKeyboard: View {
26
26
  if (value.count > 0 ){
27
27
  value.removeLast()
28
28
  }
29
-
29
+ // Keys map 1:1 onto `tempValue` characters, so both trims stay aligned.
30
+ if (tempValue.count > 0 ){
31
+ tempValue.removeLast()
32
+ }
30
33
  }
31
34
 
32
35
  func onPressClear(key: String){
@@ -41,12 +44,63 @@ public struct CalculatorKeyboard: View {
41
44
  if (tempValue.last?.isNumber == false){
42
45
  tempValue.removeLast()
43
46
  }
44
- let expression = NSExpression(format: tempValue)
45
-
46
- value = String(expression.expressionValue(with: nil, context: nil) as! Int)
47
- if (Int(value) ?? 0 < 0){
47
+ // Overflow and division by zero are treated like a negative result: cleared.
48
+ if let result = Self.evaluate(tempValue), result >= 0 {
49
+ value = String(result)
50
+ } else {
48
51
  value = ""
49
52
  }
53
+ // The next keys continue from the shown result, not the old expression.
54
+ tempValue = value
55
+ }
56
+
57
+ /// Integer `+ - * /` with the usual precedence, as NSExpression did, but nil instead of a
58
+ /// crash when a number or result leaves `Int` range.
59
+ static func evaluate(_ expression: String) -> Int? {
60
+ var numbers: [Int] = []
61
+ var operators: [Character] = []
62
+ var digits = ""
63
+ for char in expression {
64
+ if ("0"..."9").contains(char) {
65
+ digits.append(char)
66
+ continue
67
+ }
68
+ guard let number = Int(digits) else { return nil }
69
+ numbers.append(number)
70
+ operators.append(char)
71
+ digits = ""
72
+ }
73
+ guard let last = Int(digits) else { return nil }
74
+ numbers.append(last)
75
+
76
+ var terms = [numbers[0]]
77
+ var signs: [Character] = []
78
+ for (op, number) in zip(operators, numbers.dropFirst()) {
79
+ switch op {
80
+ case "*":
81
+ let (product, overflow) = terms[terms.count - 1].multipliedReportingOverflow(by: number)
82
+ if overflow { return nil }
83
+ terms[terms.count - 1] = product
84
+ case "/":
85
+ guard number != 0 else { return nil }
86
+ terms[terms.count - 1] /= number
87
+ case "+", "-":
88
+ terms.append(number)
89
+ signs.append(op)
90
+ default:
91
+ return nil
92
+ }
93
+ }
94
+
95
+ var result = terms[0]
96
+ for (sign, term) in zip(signs, terms.dropFirst()) {
97
+ let (next, overflow) = sign == "+"
98
+ ? result.addingReportingOverflow(term)
99
+ : result.subtractingReportingOverflow(term)
100
+ if overflow { return nil }
101
+ result = next
102
+ }
103
+ return result
50
104
  }
51
105
 
52
106
  func onPressKey(key:String){
@@ -133,7 +133,7 @@ public enum Colors {
133
133
  public static let yellow06 = Color(hex: "ffe066")
134
134
  public static let yellow05 = Color(hex: "ffd633")
135
135
  public static let yellow04 = Color(hex: "ffd119")
136
- public static let yellow03 = Color(hex: "fc0")
136
+ public static let yellow03 = Color(hex: "ffcc00")
137
137
  public static let yellow02 = Color(hex: "e6b800")
138
138
  public static let yellow01 = Color(hex: "cca300")
139
139
 
@@ -43,15 +43,26 @@ public extension Color {
43
43
  )
44
44
  }
45
45
 
46
+ /// CSS-style `RGB`, `RGBA`, `RRGGBB` or `RRGGBBAA`, `#` optional; anything else is black.
46
47
  init(hex: String) {
47
- let scanner = Scanner(string: hex)
48
- var rgbValue: UInt64 = 0
49
- scanner.scanHexInt64(&rgbValue)
50
-
51
- let r = (rgbValue & 0xff0000) >> 16
52
- let g = (rgbValue & 0xff00) >> 8
53
- let b = rgbValue & 0xff
54
-
55
- self.init(red: Double(r) / 0xff, green: Double(g) / 0xff, blue: Double(b) / 0xff)
48
+ var digits = hex.trimmingCharacters(in: .whitespacesAndNewlines)
49
+ if digits.hasPrefix("#") { digits.removeFirst() }
50
+ if digits.count == 3 || digits.count == 4 {
51
+ digits = String(digits.flatMap { [$0, $0] })
52
+ }
53
+ guard digits.count == 6 || digits.count == 8,
54
+ digits.allSatisfy(\.isHexDigit),
55
+ let value = UInt64(digits, radix: 16) else {
56
+ self.init(red: 0, green: 0, blue: 0)
57
+ return
58
+ }
59
+ let rgba = digits.count == 8 ? value : value << 8 | 0xFF
60
+ self.init(
61
+ .sRGB,
62
+ red: Double((rgba >> 24) & 0xFF) / 255,
63
+ green: Double((rgba >> 16) & 0xFF) / 255,
64
+ blue: Double((rgba >> 8) & 0xFF) / 255,
65
+ opacity: Double(rgba & 0xFF) / 255
66
+ )
56
67
  }
57
68
  }
@@ -0,0 +1,12 @@
1
+ import SwiftUI
2
+
3
+ /// `@EnvironmentObject` that reads nil instead of trapping when nothing was injected.
4
+ /// `_store` is the backing field of the `@frozen` `EnvironmentObject`, so its layout is ABI-stable.
5
+ @propertyWrapper
6
+ struct OptionalEnvironmentObject<Object: ObservableObject>: DynamicProperty {
7
+ @EnvironmentObject private var object: Object
8
+
9
+ var wrappedValue: Object? {
10
+ Mirror(reflecting: _object).descendant("_store") as? Object
11
+ }
12
+ }
@@ -4,27 +4,16 @@ struct IconSource: Codable {
4
4
  let uri: String
5
5
  }
6
6
 
7
- func loadIconSources() -> [String: IconSource] {
8
- guard let url = Bundle.main.url(forResource: "icon", withExtension: "json") else {
9
- print("Error: icon.json not found")
10
- return [:]
7
+ // The compiled-in map (Icons.swift) wins; a host `icon.json` in the main bundle only adds keys
8
+ // the kit doesn't know, so hosts that shipped one keep their extra icons.
9
+ let iconSources: [String: String] = {
10
+ guard let url = Bundle.main.url(forResource: "icon", withExtension: "json"),
11
+ let data = try? Data(contentsOf: url),
12
+ let hostIcons = try? JSONDecoder().decode([String: IconSource].self, from: data) else {
13
+ return kitIcons
11
14
  }
12
-
13
- do {
14
- let data = try Data(contentsOf: url)
15
- let decoded = try JSONDecoder().decode([String: IconSource].self, from: data)
16
- return decoded
17
- } catch {
18
- print("Error decoding icon.json: \(error)")
19
- return [:]
20
- }
21
- }
22
-
23
- // Load the JSON data into a global variable
24
- let iconSources: [String: IconSource] = loadIconSources()
25
-
26
- // Icons that must never be tinted (mirror Compose `noThemeIcons`)
27
- let noThemeIcons: [String] = ["ic_round_momo_tiny"]
15
+ return kitIcons.merging(hostIcons.mapValues(\.uri)) { kit, _ in kit }
16
+ }()
28
17
 
29
18
  // Compose defaults `color` to the theme text color while `color = null` means "no tint".
30
19
  // Swift can't tell an omitted argument from an explicit `nil`, so the default is this
@@ -53,8 +42,8 @@ public struct Icon: View {
53
42
  }
54
43
 
55
44
  public var body: some View {
56
- // Mirror Compose: an https source is used as-is, anything else is a key into icon.json
57
- if let uri = source.contains("https") ? source : iconSources[source]?.uri {
45
+ // Mirror Compose: an https source is used as-is, anything else is a key into the icon map
46
+ if let uri = source.contains("https") ? source : iconSources[source] {
58
47
  let requestedColor = color == iconThemeColor ? theme.colors.text.default : color
59
48
  // Mirror Compose: certain icons (e.g. branded glyphs) are never tinted
60
49
  let resolvedColor = noThemeIcons.contains(source) ? nil : requestedColor
@@ -63,6 +52,9 @@ public struct Icon: View {
63
52
  // Mirrors Compose's auto-generated `contentDescription = "img|$iconUrl"`
64
53
  // when no explicit label is provided.
65
54
  .accessibilityLabel(accessibilityLabel ?? "img|\(uri)")
55
+ } else {
56
+ // Compose keeps the sized box for an unknown key, so layouts don't collapse.
57
+ Color.clear.frame(width: size, height: size)
66
58
  }
67
59
  }
68
60
  }