@momo-kits/native-kits 0.300.3 → 0.300.4-debug

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 (272) hide show
  1. package/CLAUDE.md +51 -7
  2. package/README.md +2 -2
  3. package/build.gradle.kts +13 -0
  4. package/compose/build.gradle.kts +197 -0
  5. package/compose/build.gradle.kts.backup +197 -0
  6. package/compose/compose.podspec +47 -0
  7. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +20 -0
  8. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +6 -0
  9. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +12 -0
  10. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
  11. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +153 -0
  12. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +6 -0
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +110 -0
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/application/DesignSystemKits.kt +62 -0
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +1071 -0
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +65 -0
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +81 -0
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +338 -0
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +175 -0
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +357 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +115 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +89 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +128 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +209 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +542 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +49 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +86 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +125 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +231 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +189 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +478 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +114 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +265 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +235 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +223 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +265 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +185 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +343 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +84 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +361 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +108 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +308 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +59 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +21 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +90 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +330 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +220 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +473 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +122 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +207 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +92 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +560 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +125 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +207 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +501 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +176 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +182 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +193 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +236 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +180 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +325 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +17 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +16 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +194 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +287 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +54 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +50 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +306 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +41 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +52 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +66 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +104 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +48 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +338 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +58 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +137 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +116 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +215 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +404 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +8 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +732 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +148 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +40 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +233 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +217 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +97 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +377 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +169 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +455 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +103 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +106 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +74 -0
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +413 -0
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +39 -0
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +363 -0
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HelpCenterRequest.kt +37 -0
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +192 -0
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +133 -0
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/ToolkitRequests.kt +41 -0
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +135 -0
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +12 -0
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +91 -0
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +74 -0
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +20 -0
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +55 -0
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +15 -0
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +118 -0
  124. package/compose/src/commonTest/kotlin/vn/momo/kits/navigation/component/HelpCenterRequestTest.kt +44 -0
  125. package/compose/src/commonTest/kotlin/vn/momo/kits/navigation/component/ToolkitRequestsTest.kt +62 -0
  126. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +42 -0
  127. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +45 -0
  128. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +36 -0
  129. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +38 -0
  130. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
  131. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +217 -0
  132. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +138 -0
  133. package/gradle/libs.versions.toml +68 -0
  134. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  135. package/gradle/wrapper/gradle-wrapper.properties +8 -0
  136. package/gradle.properties +26 -0
  137. package/gradlew +252 -0
  138. package/gradlew.bat +94 -0
  139. package/ios/Application/ApplicationEnvironment.swift +24 -6
  140. package/ios/Application/DesignSystemKits.swift +100 -0
  141. package/ios/Application/DesignSystemKitsPayload.swift +68 -0
  142. package/ios/Application/MaxApi.swift +30 -3
  143. package/ios/Avatar/Avatar.swift +4 -3
  144. package/ios/Badge/Badge.swift +6 -4
  145. package/ios/Badge/BadgeDot.swift +1 -1
  146. package/ios/Badge/BadgeRibbon.swift +8 -2
  147. package/ios/Button/Button.swift +15 -12
  148. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +64 -18
  149. package/ios/Carousel/Carousel.swift +29 -12
  150. package/ios/Checkbox/Checkbox.swift +7 -3
  151. package/ios/Chip/Chip.swift +5 -4
  152. package/ios/Collapse/Collapse.swift +70 -19
  153. package/ios/Colors+Radius+Spacing/Colors.swift +10 -1
  154. package/ios/Colors+Radius+Spacing/Radius.swift +6 -0
  155. package/ios/DateTimePicker/DateTimePicker.swift +54 -20
  156. package/ios/DateTimePicker/WheelPicker.swift +103 -105
  157. package/ios/Divider/Divider.swift +37 -4
  158. package/ios/Extensions/Color++.swift +38 -9
  159. package/ios/Extensions/OptionalEnvironmentObject.swift +12 -0
  160. package/ios/Extensions/SkeletonUICompat.swift +11 -0
  161. package/ios/Icon/Icon.swift +21 -23
  162. package/ios/Icon/Icons.swift +1329 -0
  163. package/ios/IconButton/IconButton.swift +15 -7
  164. package/ios/Image/Image.swift +7 -23
  165. package/ios/Information/Information.swift +27 -9
  166. package/ios/Input/ErrorView.swift +2 -2
  167. package/ios/Input/Input.swift +171 -148
  168. package/ios/Input/InputPhoneNumber.swift +10 -9
  169. package/ios/Input/InputSearch.swift +107 -78
  170. package/ios/Input/InputTextArea.swift +133 -148
  171. package/ios/InputDropDown/InputDropDown.swift +10 -7
  172. package/ios/InputMoney/InputMoney.swift +32 -11
  173. package/ios/InputOTP/InputOTP.swift +22 -12
  174. package/ios/Layout/Card.swift +50 -0
  175. package/ios/Layout/GridContext.swift +187 -3
  176. package/ios/Layout/Item.swift +5 -4
  177. package/ios/Layout/ScreenLayout.swift +415 -0
  178. package/ios/Layout/Section.swift +4 -100
  179. package/ios/Loader/Loader.swift +5 -9
  180. package/ios/Lottie/LottieView.swift +14 -2
  181. package/ios/{Application/Navigation/Overplay → Navigation}/BottomSheet.swift +169 -29
  182. package/ios/Navigation/BottomTab/BottomTab.swift +332 -0
  183. package/ios/{Application/Navigation → Navigation}/BottomTab/BottomTabBar.swift +18 -7
  184. package/ios/Navigation/BottomTab/DuoBarCompression.swift +104 -0
  185. package/ios/Navigation/BottomTab/DuoTabBar.swift +329 -0
  186. package/ios/{Application → Navigation/Component}/FloatingButton.swift +43 -54
  187. package/ios/Navigation/Component/Header.swift +545 -0
  188. package/ios/Navigation/Component/HeaderBackground.swift +154 -0
  189. package/ios/Navigation/Component/HeaderJourney.swift +73 -0
  190. package/ios/Navigation/Component/HeaderLocation.swift +48 -0
  191. package/ios/Navigation/Component/HeaderRight.swift +425 -0
  192. package/ios/Navigation/Component/HeaderTitle.swift +36 -0
  193. package/ios/{Application/Navigation → Navigation/Component}/HeaderUser.swift +21 -24
  194. package/ios/Navigation/Component/SideBar.swift +183 -0
  195. package/ios/{Application/Navigation/Overplay → Navigation/Component}/SnackBar.swift +8 -8
  196. package/ios/Navigation/HostBackGestureBridge.swift +78 -0
  197. package/ios/{Application/Navigation/Overplay → Navigation}/ModalScreen.swift +9 -2
  198. package/ios/Navigation/Navigation.swift +204 -0
  199. package/ios/Navigation/NavigationContainer.swift +195 -0
  200. package/ios/{Application/Navigation → Navigation}/Navigator.swift +207 -107
  201. package/ios/Navigation/StackScreen.swift +930 -0
  202. package/ios/Navigation/StackTransition.swift +400 -0
  203. package/ios/Navigation/SwipeBackHaptic.swift +33 -0
  204. package/ios/{Application/Navigation → Navigation}/Tracking/ScreenTracker.swift +12 -5
  205. package/ios/OTPKeyboard/OTPKeyboard.swift +8 -11
  206. package/ios/Pagination/PaginationScroll.swift +2 -2
  207. package/ios/Popup/PopupDisplay.swift +72 -135
  208. package/ios/Popup/PopupInput.swift +10 -13
  209. package/ios/Popup/PopupLayout.swift +138 -0
  210. package/ios/Popup/PopupNotify.swift +59 -69
  211. package/ios/Popup/PopupPromotion.swift +31 -47
  212. package/ios/PopupView/FullscreenPopup.swift +13 -19
  213. package/ios/PopupView/PopupView.swift +1 -1
  214. package/ios/PopupView/Utils++.swift +0 -8
  215. package/ios/ProgressInfo/ProgressInfo.swift +4 -2
  216. package/ios/Radio/Radio.swift +2 -1
  217. package/ios/Rating/Rating.swift +9 -1
  218. package/ios/Resources/dot_loading.json +558 -0
  219. package/ios/Resources/lottie_circle_loader.json +1 -0
  220. package/ios/ScrollIndicator/ScrollIndicator.swift +11 -10
  221. package/ios/Skeleton/Skeleton.swift +22 -27
  222. package/ios/Slider/Slider.swift +16 -18
  223. package/ios/Stepper/Stepper.swift +7 -3
  224. package/ios/Steps/Steps.swift +8 -6
  225. package/ios/SuggestAction/SuggestAction.swift +5 -0
  226. package/ios/Swipeable/SwipeCell.swift +10 -6
  227. package/ios/Switch/Switch.swift +22 -20
  228. package/ios/TabView/TabView.swift +102 -21
  229. package/ios/Tag/Tag.swift +15 -4
  230. package/ios/Template/Logo/Logo.swift +2 -1
  231. package/ios/Template/TrustBanner/TrustBanner.swift +109 -55
  232. package/ios/Title/Title.swift +6 -17
  233. package/ios/Tooltip/Tooltip.swift +29 -14
  234. package/ios/Typography/FontScale.swift +17 -14
  235. package/ios/Typography/Text.swift +156 -20
  236. package/ios/Typography/Typography.swift +2 -2
  237. package/ios/Uploader/Uploader.swift +3 -1
  238. package/ios/native-kits.podspec +2 -3
  239. package/ios-demo/MoMoUIKitsDemo.podspec +1 -3
  240. package/ios-demo/README.md +120 -0
  241. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +1 -1
  242. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DuoTabDemo.swift +80 -0
  243. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +2 -0
  244. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IPhoneDuoDemo.swift +173 -0
  245. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +77 -1
  246. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +1 -0
  247. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +2 -2
  248. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +2 -0
  249. package/package.json +1 -1
  250. package/publish.sh +19 -2
  251. package/scripts/gen-ios-icons.mjs +36 -0
  252. package/settings.gradle.kts +64 -0
  253. package/ios/Application/Components.swift +0 -270
  254. package/ios/Application/ComposeApi.swift +0 -22
  255. package/ios/Application/HeaderRight.swift +0 -306
  256. package/ios/Application/Navigation/BottomTab/BottomTab.swift +0 -104
  257. package/ios/Application/Navigation/HeaderBackProps.swift +0 -66
  258. package/ios/Application/Navigation/HeaderTitle.swift +0 -57
  259. package/ios/Application/Navigation/NavigationContainer.swift +0 -213
  260. package/ios/Application/Navigation/NavigationOptions.swift +0 -109
  261. package/ios/Application/Navigation/NavigatorManager.swift +0 -22
  262. package/ios/Application/Navigation/component/Header.swift +0 -178
  263. package/ios/Application/Navigation/component/HeaderBackground.swift +0 -83
  264. package/ios/Application/Navigation/component/HeaderColor.swift +0 -65
  265. package/ios/Application/Navigation/component/HeaderRightWidthKey.swift +0 -11
  266. package/ios/Application/Navigation/component/NavigationFooter.swift +0 -90
  267. package/ios/Application/Navigation/component/NavigationHeaderRight.swift +0 -196
  268. package/ios/Application/Screen.swift +0 -250
  269. package/ios/Application/StackScreen.swift +0 -492
  270. package/ios/Typography/FontScaleStore.swift +0 -58
  271. package/ios/Typography/KitDesignSystem.swift +0 -17
  272. /package/ios/{Application/Navigation → Navigation}/BottomTab/CurvedContainer.swift +0 -0
@@ -44,8 +44,6 @@ private struct ShimmerLoading: View {
44
44
  let durationMillis: Int
45
45
  let angleOfAxisY: CGFloat
46
46
 
47
- @State private var phase: CGFloat = 0
48
-
49
47
  // Matches Compose `SHADOW_BRUSH_PERCENTAGE = 0.6f`.
50
48
  private static let shadowBrushPercentage: CGFloat = 0.6
51
49
 
@@ -67,33 +65,30 @@ private struct ShimmerLoading: View {
67
65
  size.width + widthOfShadowBrush
68
66
  }
69
67
 
68
+ // Clock-driven rather than an onAppear animation: gradient points aren't reliably animatable,
69
+ // and a view first laid out at zero width (or resized later) would never (re)start.
70
70
  var body: some View {
71
- let startX = phase - widthOfShadowBrush
72
- let endX = phase
71
+ TimelineView(.animation) { timeline in
72
+ Rectangle().fill(gradient(at: timeline.date))
73
+ }
74
+ }
75
+
76
+ private func gradient(at date: Date) -> LinearGradient {
77
+ let duration = Double(max(durationMillis, 1)) / 1000
78
+ let progress = date.timeIntervalSinceReferenceDate.truncatingRemainder(dividingBy: duration) / duration
79
+ let endX = CGFloat(progress) * animationTarget
80
+ let startX = endX - widthOfShadowBrush
73
81
 
74
- Rectangle()
75
- .fill(
76
- LinearGradient(
77
- gradient: Gradient(colors: Self.shimmerColors),
78
- startPoint: .init(
79
- x: size.width > 0 ? startX / size.width : 0,
80
- y: 0
81
- ),
82
- endPoint: .init(
83
- x: size.width > 0 ? endX / size.width : 0,
84
- y: size.height > 0 ? angleOfAxisY / size.height : 0
85
- )
86
- )
82
+ return LinearGradient(
83
+ gradient: Gradient(colors: Self.shimmerColors),
84
+ startPoint: .init(
85
+ x: size.width > 0 ? startX / size.width : 0,
86
+ y: 0
87
+ ),
88
+ endPoint: .init(
89
+ x: size.width > 0 ? endX / size.width : 0,
90
+ y: size.height > 0 ? angleOfAxisY / size.height : 0
87
91
  )
88
- .onAppear {
89
- guard size.width > 0 else { return }
90
- phase = 0
91
- withAnimation(
92
- .linear(duration: Double(durationMillis) / 1000.0)
93
- .repeatForever(autoreverses: false)
94
- ) {
95
- phase = animationTarget
96
- }
97
- }
92
+ )
98
93
  }
99
94
  }
@@ -24,12 +24,14 @@ private func getValueForPosition(
24
24
  step: CGFloat
25
25
  ) -> CGFloat {
26
26
  let availableSpace = containerWidth - thumbWidth
27
- if availableSpace <= 0 { return minV }
28
- let relStepUnit = step / (maxV - minV)
27
+ if availableSpace <= 0 || maxV <= minV { return minV }
29
28
  var relPosition = (positionInView - thumbWidth / 2) / availableSpace
29
+ // A zero step would make the snap math NaN, which later traps in `Int(_:)`.
30
+ if step <= 0 { return clampF(minV + relPosition * (maxV - minV), minV, maxV) }
31
+ let relStepUnit = step / (maxV - minV)
30
32
  let relOffset = relPosition.truncatingRemainder(dividingBy: relStepUnit)
31
33
  relPosition -= relOffset
32
- if relStepUnit != 0, relOffset / relStepUnit >= 0.5 { relPosition += relStepUnit }
34
+ if relOffset / relStepUnit >= 0.5 { relPosition += relStepUnit }
33
35
  let steps = (relPosition / relStepUnit).rounded()
34
36
  return clampF(minV + steps * step, minV, maxV)
35
37
  }
@@ -49,7 +51,8 @@ private func formatLabel(_ value: CGFloat) -> String {
49
51
  if value == value.rounded() {
50
52
  return String(Int(value))
51
53
  }
52
- return String(format: "%.1f", value)
54
+ // Truncates to one decimal like Compose's `(value * 10).toLong() / 10.0`.
55
+ return String(Double((value * 10).rounded(.towardZero)) / 10)
53
56
  }
54
57
 
55
58
  // ── Component ─────────────────────────────────────────────────────────────────
@@ -64,8 +67,6 @@ public struct MomoSlider: View {
64
67
  private let minV: CGFloat
65
68
  private let maxV: CGFloat
66
69
  private let step: CGFloat
67
- private let initLow: CGFloat
68
- private let initHigh: CGFloat
69
70
  private let minRange: CGFloat
70
71
  private let disableRange: Bool
71
72
  private let floatingLabel: Bool
@@ -74,11 +75,10 @@ public struct MomoSlider: View {
74
75
  private let onSliderTouchStart: (CGFloat, CGFloat) -> Void
75
76
  private let onSliderTouchEnd: (CGFloat, CGFloat) -> Void
76
77
 
77
- @State private var lowValue: CGFloat = 0
78
- @State private var highValue: CGFloat = 0
78
+ @State private var lowValue: CGFloat
79
+ @State private var highValue: CGFloat
79
80
  @State private var draggingLow: Bool = true
80
81
  @State private var isDragging: Bool = false
81
- @State private var didInit: Bool = false
82
82
 
83
83
  public init(
84
84
  min: CGFloat,
@@ -105,8 +105,10 @@ public struct MomoSlider: View {
105
105
  self.onSliderTouchStart = onSliderTouchStart
106
106
  self.onSliderTouchEnd = onSliderTouchEnd
107
107
 
108
- self.initLow = clampF(low ?? min, min, max)
109
- self.initHigh = disableRange ? max : clampF(high ?? max, min, max)
108
+ let startLow = clampF(low ?? min, min, max)
109
+ let startHigh = disableRange ? max : clampF(high ?? max, min, max)
110
+ _lowValue = State(initialValue: startLow)
111
+ _highValue = State(initialValue: startHigh)
110
112
  }
111
113
 
112
114
  private var thumbColor: Color { disabled ? theme.colors.text.disable : theme.colors.primary }
@@ -165,17 +167,13 @@ public struct MomoSlider: View {
165
167
  }
166
168
  }
167
169
  .frame(width: trackWidth, height: topPad + THUMB_SIZE, alignment: .topLeading)
170
+ // Compose's spring(stiffness = 1200) is critically damped.
171
+ .animation(.interpolatingSpring(stiffness: 1200, damping: 2 * sqrt(1200)), value: lowValue)
172
+ .animation(.interpolatingSpring(stiffness: 1200, damping: 2 * sqrt(1200)), value: highValue)
168
173
  .contentShape(Rectangle())
169
174
  .gesture(dragGesture(trackWidth: trackWidth))
170
175
  }
171
176
  .frame(height: (floatingLabel ? (THUMB_SIZE + LABEL_GAP) : 0) + THUMB_SIZE)
172
- .onAppear {
173
- if !didInit {
174
- lowValue = initLow
175
- highValue = initHigh
176
- didInit = true
177
- }
178
- }
179
177
  }
180
178
 
181
179
  private var thumb: some View {
@@ -84,7 +84,6 @@ private struct StepperButton: View {
84
84
 
85
85
  private struct StepperNumberView: View {
86
86
  @Environment(\.appTheme) private var theme
87
- @Environment(\.momoFontScale) private var fontScale
88
87
 
89
88
  @Binding var text: String
90
89
  var size: StepperSize
@@ -106,12 +105,13 @@ private struct StepperNumberView: View {
106
105
  MomoText(text, typography: .descriptionDefaultRegular, color: textColor)
107
106
  }
108
107
  }
109
- .font(.system(size: fontScale(12)))
108
+ .kitFont(size: 12)
110
109
  .ignoreBoldTextSetting()
111
110
  .foregroundColor(textColor)
111
+ // Compose's min width includes the horizontal padding.
112
+ .padding(.horizontal, Spacing.XS)
112
113
  .frame(minWidth: specs.numberMinWidth)
113
114
  .frame(height: specs.numberHeight)
114
- .padding(.horizontal, Spacing.XS)
115
115
  .overlay(
116
116
  RoundedRectangle(cornerRadius: Radius.S)
117
117
  .stroke(borderColor, lineWidth: 1)
@@ -217,5 +217,9 @@ public struct MomoStepper: View {
217
217
  if clamped != value { value = clamped }
218
218
  editingText = String(clamped)
219
219
  }
220
+ // Keeps the editable field in step with values set by the owner of the binding.
221
+ .onChange(of: value) { newValue in
222
+ editingText = String(newValue)
223
+ }
220
224
  }
221
225
  }
@@ -162,8 +162,9 @@ private struct StepsHorizontal: View {
162
162
 
163
163
  var body: some View {
164
164
  HStack(alignment: .top, spacing: 0) {
165
- ForEach(Array(steps.enumerated()), id: \.element.id) { index, item in
166
- column(index: index, item: item)
165
+ // Keyed by position like Compose: `StepItem.id` is a fresh UUID per instance.
166
+ ForEach(steps.indices, id: \.self) { index in
167
+ column(index: index, item: steps[index])
167
168
  .frame(maxWidth: .infinity)
168
169
  }
169
170
  }
@@ -234,7 +235,7 @@ private struct StepsHorizontal: View {
234
235
  .clipShape(RoundedCorner(radius: Radius.XS, corners: [.topLeft, .bottomLeft]))
235
236
  }
236
237
  }
237
- .frame(maxWidth: .infinity)
238
+ .frame(maxWidth: .infinity, alignment: .leading)
238
239
 
239
240
  if !item.title.isEmpty {
240
241
  MomoText(item.title, typography: titleStyle, color: titleColor)
@@ -316,8 +317,8 @@ private struct StepsVertical: View {
316
317
 
317
318
  var body: some View {
318
319
  VStack(spacing: 0) {
319
- ForEach(Array(steps.enumerated()), id: \.element.id) { index, item in
320
- row(index: index, item: item)
320
+ ForEach(steps.indices, id: \.self) { index in
321
+ row(index: index, item: steps[index])
321
322
  }
322
323
  }
323
324
  .frame(maxWidth: .infinity)
@@ -358,8 +359,9 @@ private struct StepsVertical: View {
358
359
  customIcon: customIcon
359
360
  )
360
361
  if !isLast {
362
+ // Compose pads inside the fixed height, so the drawn line is 8pt shorter.
361
363
  lineColor
362
- .frame(width: 2, height: connectorHeight)
364
+ .frame(width: 2, height: connectorHeight - Spacing.XS * 2)
363
365
  .padding(.vertical, Spacing.XS)
364
366
  }
365
367
  }
@@ -65,6 +65,11 @@ public struct SuggestAction: View {
65
65
 
66
66
  Text(annotatedMessage)
67
67
  .foregroundColor(theme.colors.text.default)
68
+ .lineSpacing(
69
+ fontScale(TypographyStyle.bodyDefaultRegular.lineHeight)
70
+ - fontScale(TypographyStyle.bodyDefaultRegular.fontSize)
71
+ )
72
+ .ignoreBoldTextSetting()
68
73
  .frame(maxWidth: .infinity, alignment: .leading)
69
74
  .padding(.trailing, Spacing.M)
70
75
 
@@ -20,6 +20,7 @@ public struct Swipe<Content: View>: View {
20
20
 
21
21
  @State private var offsetX: CGFloat = 0
22
22
  @State private var dragStartOffsetX: CGFloat?
23
+ @GestureState private var isDragging = false
23
24
 
24
25
  public init(
25
26
  leftActions: [SwipeAction] = [],
@@ -87,14 +88,17 @@ public struct Swipe<Content: View>: View {
87
88
  .offset(x: offsetX)
88
89
  .gesture(
89
90
  DragGesture(minimumDistance: 8, coordinateSpace: .local)
91
+ .updating($isDragging) { _, dragging, _ in dragging = true }
90
92
  .onChanged { value in
91
93
  dragOnChanged(value: value, leftWidth: leftWidth, rightWidth: rightWidth)
92
94
  }
93
- .onEnded { _ in
94
- dragStartOffsetX = nil
95
- snapToClosest(leftWidth: leftWidth, rightWidth: rightWidth)
96
- }
97
95
  )
96
+ // Gesture state also resets on cancel, so a stolen drag still snaps (Compose `onDragCancel`).
97
+ .onChange(of: isDragging) { dragging in
98
+ guard !dragging else { return }
99
+ dragStartOffsetX = nil
100
+ snapToClosest(leftWidth: leftWidth, rightWidth: rightWidth)
101
+ }
98
102
  }
99
103
  .frame(maxWidth: .infinity)
100
104
  .frame(height: height)
@@ -166,7 +170,7 @@ private struct SwipeActionButton: View {
166
170
 
167
171
  var body: some View {
168
172
  SwiftUI.Button(action: action.onPress) {
169
- VStack(spacing: Spacing.XXS) {
173
+ VStack(spacing: 0) {
170
174
  if !action.icon.isEmpty {
171
175
  Icon(source: action.icon, size: 20, color: Colors.black01)
172
176
  }
@@ -184,7 +188,7 @@ private struct SwipeActionButton: View {
184
188
  .background(action.backgroundColor ?? defaultBackgroundColor)
185
189
  .clipShape(RoundedRectangle(cornerRadius: itemRadius))
186
190
  }
187
- .buttonStyle(.plain)
191
+ .buttonStyle(ActiveOpacityButtonStyle())
188
192
  }
189
193
  }
190
194
 
@@ -41,29 +41,31 @@ public struct Switch: View {
41
41
  accessibilityId?.isEmpty == false ? accessibilityId! : "toggle_\(title?.isEmpty == false ? title! : "unknown")_\(value)"
42
42
  }
43
43
 
44
+ private func toggle() {
45
+ // Not re-read from the binding: a `.constant` / one-way binding would report the stale value.
46
+ let newValue = !value
47
+ value = newValue
48
+ onChange?(newValue)
49
+ }
50
+
44
51
  public var body: some View {
45
- SwiftUI.Button(action: {
46
- withAnimation {
47
- value.toggle()
48
- onChange?(value)
49
- }
50
- }) {
51
- HStack {
52
- HStack {}
53
- .frame(width: 6, height: 6)
54
- .background(backgroundColor)
55
- .clipShape(Circle())
56
- }
57
- .frame(width: 14, height: 14)
58
- .background(circleColor)
59
- .clipShape(Circle())
60
- .padding(.leading, Spacing.XS)
61
- .padding(.trailing, Spacing.XS)
52
+ // The whole track is the label so all of it is tappable, as in Compose.
53
+ SwiftUI.Button(action: toggle) {
54
+ Circle()
55
+ .fill(backgroundColor)
56
+ .frame(width: 6, height: 6)
57
+ .frame(width: 14, height: 14)
58
+ .background(Circle().fill(circleColor))
59
+ .padding(.horizontal, Spacing.XS)
60
+ .frame(width: 38, height: 20, alignment: value ? .trailing : .leading)
61
+ .background(backgroundColor)
62
+ .clipShape(Capsule())
63
+ .contentShape(Capsule())
64
+ .animation(.default, value: value)
62
65
  }
66
+ // Custom style so `.disabled` doesn't add a system dim on top of the disabled colors.
67
+ .buttonStyle(ActiveOpacityButtonStyle())
63
68
  .disabled(disabled)
64
- .frame(width: 38, height: 20, alignment: value ? .trailing : .leading)
65
- .background(backgroundColor)
66
- .clipShape(Capsule())
67
69
  .accessibilityIdentifier(automationId)
68
70
  }
69
71
  }
@@ -328,8 +328,13 @@ private struct ScrollableTabBar: View {
328
328
  Rectangle()
329
329
  .stroke(theme.colors.border.default, lineWidth: 0.5)
330
330
  )
331
+ // Compose scrolls the selected tab to the leading edge, initial page included.
331
332
  .onChange(of: selectedIndex) { index in
332
- withAnimation { proxy.scrollTo(index, anchor: .center) }
333
+ withAnimation { proxy.scrollTo(index, anchor: .leading) }
334
+ }
335
+ .onAppear {
336
+ guard selectedIndex > 0 else { return }
337
+ DispatchQueue.main.async { proxy.scrollTo(selectedIndex, anchor: .leading) }
333
338
  }
334
339
  }
335
340
  }
@@ -346,6 +351,11 @@ private struct TabFramePreferenceKey: PreferenceKey {
346
351
  // Card tab bar
347
352
  // ---------------------------------------------------------------------------
348
353
 
354
+ private let cardTabHeight: CGFloat = 40
355
+ private let cardTabActiveHeight: CGFloat = 44
356
+
357
+ /// Two layers, as in Compose / react-kits: a flat strip where every tab looks unselected,
358
+ /// and one raised card for the active tab, 4pt taller and joined to the strip by curved ears.
349
359
  private struct CardTabBar: View {
350
360
  @Environment(\.appTheme) private var theme
351
361
 
@@ -357,47 +367,116 @@ private struct CardTabBar: View {
357
367
  let onPress: (Int) -> Void
358
368
 
359
369
  var body: some View {
360
- HStack(alignment: .bottom, spacing: 0) {
361
- ForEach(tabs.indices, id: \.self) { index in
362
- let tab = tabs[index]
363
- let isActive = selectedIndex == index
364
- let iconColor = isActive ? selectedColor : unselectedColor
365
-
366
- SwiftUI.Button(action: { onPress(index) }) {
367
- cardItem(tab: tab, isActive: isActive, iconColor: iconColor)
368
- .frame(maxWidth: .infinity)
369
- .frame(height: isActive ? 44 : 40)
370
- .background(isActive ? theme.colors.background.surface : theme.colors.background.tonal)
371
- .clipShape(UnstyledRoundedRectangle(topLeft: Radius.M, topRight: Radius.M))
372
- .contentShape(Rectangle())
370
+ GeometryReader { geo in
371
+ let itemWidth = geo.size.width / CGFloat(Swift.max(tabs.count, 1))
372
+
373
+ ZStack(alignment: .bottomLeading) {
374
+ HStack(spacing: 0) {
375
+ ForEach(tabs.indices, id: \.self) { index in
376
+ SwiftUI.Button(action: { onPress(index) }) {
377
+ cardItem(tab: tabs[index], isActive: false)
378
+ .padding(.horizontal, Spacing.S)
379
+ .frame(width: itemWidth, height: cardTabHeight)
380
+ .background(Colors.black02)
381
+ .clipShape(UnstyledRoundedRectangle(topLeft: Radius.M, topRight: Radius.M))
382
+ .contentShape(Rectangle())
383
+ }
384
+ .buttonStyle(ActiveOpacityButtonStyle())
385
+ }
386
+ }
387
+
388
+ if let active = tabs[safe: selectedIndex] {
389
+ activeCard(active, itemWidth: itemWidth)
373
390
  }
374
- .buttonStyle(ActiveOpacityButtonStyle())
375
391
  }
392
+ .frame(width: geo.size.width, height: cardTabActiveHeight, alignment: .bottomLeading)
376
393
  }
377
- .frame(maxWidth: .infinity)
378
- .padding(.top, Spacing.XS)
394
+ // The raised card overflows the strip into the top `Spacing.XS` margin.
395
+ .frame(height: cardTabActiveHeight)
396
+ }
397
+
398
+ private func activeCard(_ tab: TabViewItem, itemWidth: CGFloat) -> some View {
399
+ let surface = theme.colors.background.surface
400
+ let pathWidth: CGFloat = tabs.count > 2 ? 22 : 28
401
+ let isFirst = selectedIndex == 0
402
+ let isLast = selectedIndex == tabs.count - 1
403
+
404
+ return HStack(alignment: .bottom, spacing: 0) {
405
+ // Each ear is nudged 8pt under the card so the join has no seam.
406
+ if !isFirst { cardEar(mirrored: true, width: pathWidth, color: surface).offset(x: 8) }
407
+ SwiftUI.Button(action: { onPress(selectedIndex) }) {
408
+ cardItem(tab: tab, isActive: true)
409
+ .padding(.horizontal, tabs.count == 3 ? Spacing.S : Spacing.M)
410
+ .frame(width: itemWidth, height: cardTabActiveHeight)
411
+ .background(surface)
412
+ .clipShape(UnstyledRoundedRectangle(topLeft: Radius.M, topRight: Radius.M))
413
+ .contentShape(Rectangle())
414
+ }
415
+ .buttonStyle(ActiveOpacityButtonStyle())
416
+ if !isLast { cardEar(mirrored: false, width: pathWidth, color: surface).offset(x: -8) }
417
+ }
418
+ .offset(x: itemWidth * CGFloat(selectedIndex) - (isFirst ? 0 : pathWidth))
419
+ }
420
+
421
+ private func cardEar(mirrored: Bool, width: CGFloat, color: Color) -> some View {
422
+ CardTabEarShape(mirrored: mirrored)
423
+ .fill(color)
424
+ .frame(width: width, height: cardTabActiveHeight)
425
+ .clipped()
426
+ .allowsHitTesting(false)
379
427
  }
380
428
 
381
429
  @ViewBuilder
382
- private func cardItem(tab: TabViewItem, isActive: Bool, iconColor: Color) -> some View {
430
+ private func cardItem(tab: TabViewItem, isActive: Bool) -> some View {
431
+ let color = isActive ? selectedColor : unselectedColor
383
432
  HStack(spacing: 0) {
384
433
  if let renderIcon = tab.renderIcon {
385
434
  renderIcon(isActive)
386
435
  Spacer().frame(width: Spacing.XS)
387
436
  } else if let icon = tab.icon {
388
- Icon(source: icon, size: 18, color: iconColor)
437
+ Icon(source: icon, size: 18, color: color)
389
438
  Spacer().frame(width: Spacing.XS)
390
439
  }
391
440
  MomoText(
392
441
  tab.title,
393
442
  typography: isActive ? .headerSSemibold : .bodyDefaultRegular,
394
- color: isActive ? selectedColor : unselectedColor
443
+ color: color
395
444
  )
396
445
  .lineLimit(1)
397
446
 
398
447
  tabBadge(tab)
399
448
  }
400
- .padding(.horizontal, Spacing.S)
449
+ }
450
+ }
451
+
452
+ /// react-kits' 28x44 ear path, in points; not scaled to the frame, which clips it at a 22pt width.
453
+ private struct CardTabEarShape: Shape {
454
+ let mirrored: Bool
455
+
456
+ func path(in rect: CGRect) -> Path {
457
+ var path = Path()
458
+ path.move(to: CGPoint(x: 0, y: 0))
459
+ path.addLine(to: CGPoint(x: 0.60765, y: 0))
460
+ path.addCurve(
461
+ to: CGPoint(x: 12.4602, y: 10.0244),
462
+ control1: CGPoint(x: 6.47582, y: 0),
463
+ control2: CGPoint(x: 11.4819, y: 4.23831)
464
+ )
465
+ path.addCurve(
466
+ to: CGPoint(x: 16.6925, y: 34),
467
+ control1: CGPoint(x: 13.9248, y: 18.6872),
468
+ control2: CGPoint(x: 15.9294, y: 30.37)
469
+ )
470
+ path.addCurve(
471
+ to: CGPoint(x: 27.9996, y: 44),
472
+ control1: CGPoint(x: 17.9536, y: 40),
473
+ control2: CGPoint(x: 22.259, y: 44)
474
+ )
475
+ path.addLine(to: CGPoint(x: 0, y: 44))
476
+ path.closeSubpath()
477
+ return mirrored
478
+ ? path.applying(CGAffineTransform(a: -1, b: 0, c: 0, d: 1, tx: rect.width, ty: 0))
479
+ : path
401
480
  }
402
481
  }
403
482
 
@@ -426,6 +505,8 @@ private struct TabItemView: View {
426
505
  rowBody
427
506
  }
428
507
  }
508
+ // Equal-width bars hit-test the whole cell, like Compose's weighted clickable.
509
+ .frame(maxWidth: scrollable ? nil : .infinity)
429
510
  .contentShape(Rectangle())
430
511
  }
431
512
  .buttonStyle(ActiveOpacityButtonStyle())
package/ios/Tag/Tag.swift CHANGED
@@ -45,26 +45,37 @@ public struct Tag: View {
45
45
  }
46
46
  }
47
47
 
48
+ // RN only accepts the `_03` palette as a custom tag color.
49
+ private static let customColors: [Color] = [
50
+ Colors.black03, Colors.pink03, Colors.violet03, Colors.indigo03,
51
+ Colors.blue03, Colors.mint03, Colors.green03, Colors.lime03,
52
+ Colors.yellow03, Colors.gold03, Colors.orange03, Colors.red03
53
+ ]
54
+
48
55
  private let label: String
49
56
  private let icon: String?
50
57
  private let color: TagColor
51
58
  private let size: TagSize
59
+ private let customColor: Color?
52
60
 
53
61
  public init(
54
62
  label: String = "Label",
55
63
  icon: String? = nil,
56
64
  color: TagColor = .default,
57
- size: TagSize = .large
65
+ size: TagSize = .large,
66
+ customColor: Color? = nil
58
67
  ) {
59
68
  self.label = label
60
69
  self.icon = icon
61
70
  self.color = color
62
71
  self.size = size
72
+ self.customColor = customColor
63
73
  }
64
74
 
65
75
  public var body: some View {
66
- let tagColor = color.backgroundColor
67
- let labelColor = color.textColor
76
+ let custom = customColor.flatMap { Self.customColors.contains($0) ? $0 : nil }
77
+ let tagColor = custom ?? color.backgroundColor
78
+ let labelColor = custom != nil ? Colors.black01 : color.textColor
68
79
 
69
80
  HStack(spacing: 0) {
70
81
  if let icon {
@@ -75,7 +86,7 @@ public struct Tag: View {
75
86
  .frame(height: fontScale(size.height))
76
87
  .padding(.horizontal, Spacing.S)
77
88
  .background(
78
- RoundedRectangle(cornerRadius: Radius.S, style: .continuous)
89
+ RoundedRectangle(cornerRadius: Radius.S)
79
90
  .fill(tagColor)
80
91
  )
81
92
  }
@@ -57,7 +57,8 @@ private extension View {
57
57
  func containerBackground (_ type: String, _ useBackground: Bool, _ backgroundColor: Color) -> some View {
58
58
  Group {
59
59
  if (useBackground && type != "icon") {
60
- self.background(backgroundColor)
60
+ // Same shape as the border, or the square corners (and the shadow) show around it.
61
+ self.background(RoundedRectangle(cornerRadius: 8).fill(backgroundColor))
61
62
  } else {
62
63
  self
63
64
  }