@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
@@ -0,0 +1,400 @@
1
+ //
2
+ // StackTransition.swift
3
+ // MoMoUIKits
4
+ //
5
+ // SwiftUI mirror of Compose's `navigation/StackTransition.kt` (a 1:1 port of the RN kit's
6
+ // `forStackTransitionWithOverlay`) and of the NavHost it decorates. Every stack entry lives in
7
+ // its own UIHostingController, kept while the entry is on the stack and taken out of the window
8
+ // while covered, as UINavigationController does: a covered screen keeps its state, stops
9
+ // rendering and gets onDisappear / onAppear. The motion itself is drawn in SwiftUI, because an
10
+ // `offset` never moves the safe area the way a UIKit transform would.
11
+ //
12
+
13
+ import SwiftUI
14
+ import UIKit
15
+
16
+ let STACK_TRANSITION_DURATION: TimeInterval = 0.3
17
+
18
+ private let PARALLAX_RATIO: CGFloat = 0.3
19
+ private let SCRIM_MAX_ALPHA: CGFloat = 0.6
20
+ private let EDGE_SHADOW_MAX_ALPHA: CGFloat = 0.3
21
+ private let EDGE_SHADOW_WIDTH: CGFloat = 8
22
+
23
+ // MARK: - Host
24
+
25
+ /// The stack view behind `NavigationContainer`. `screen` builds an entry's content once;
26
+ /// `decorate` re-applies the kit environment on every update.
27
+ struct StackHost: UIViewControllerRepresentable {
28
+ let navigator: Navigator
29
+ let entries: [StackEntry]
30
+ let screen: (StackEntry) -> AnyView
31
+ let decorate: (AnyView) -> AnyView
32
+
33
+ func makeUIViewController(context: Context) -> StackController {
34
+ let controller = StackController()
35
+ navigator.stackController = controller
36
+ return controller
37
+ }
38
+
39
+ func updateUIViewController(_ controller: StackController, context: Context) {
40
+ controller.update(
41
+ entries: entries,
42
+ environment: context.environment,
43
+ screen: screen,
44
+ decorate: decorate
45
+ )
46
+ }
47
+ }
48
+
49
+ // MARK: - Controller
50
+
51
+ final class StackController: UIViewController {
52
+ private final class Card {
53
+ let entry: StackEntry
54
+ let motion = CardMotion()
55
+ var host: UIHostingController<AnyView>!
56
+
57
+ init(entry: StackEntry) {
58
+ self.entry = entry
59
+ }
60
+ }
61
+
62
+ /// One push or pop between two cards. `coverage` is how far `top` covers `under`: 1 in place,
63
+ /// 0 gone. Push plays 0 → 1, pop 1 → 0; a host gesture sets it straight from the finger.
64
+ private final class Transition {
65
+ enum Kind { case slide, rise }
66
+
67
+ let kind: Kind
68
+ let top: Card
69
+ let under: Card
70
+ let isSeek: Bool
71
+ var coverage: CGFloat
72
+ var from: CGFloat = 0
73
+ var target: CGFloat = 0
74
+ var duration: TimeInterval = 0
75
+ var startTime: CFTimeInterval?
76
+ var isAnimating = false
77
+
78
+ init(kind: Kind, top: Card, under: Card, isSeek: Bool = false, coverage: CGFloat) {
79
+ self.kind = kind
80
+ self.top = top
81
+ self.under = under
82
+ self.isSeek = isSeek
83
+ self.coverage = coverage
84
+ }
85
+ }
86
+
87
+ private var entries: [StackEntry] = []
88
+ private var cards: [Int: Card] = [:]
89
+ private var transition: Transition?
90
+ private var displayLink: CADisplayLink?
91
+ private var environment = EnvironmentValues()
92
+ private var screen: (StackEntry) -> AnyView = { _ in AnyView(EmptyView()) }
93
+ private var decorate: (AnyView) -> AnyView = { $0 }
94
+
95
+ override func viewDidLoad() {
96
+ super.viewDidLoad()
97
+ view.backgroundColor = .clear
98
+ view.clipsToBounds = true
99
+ }
100
+
101
+ override func viewDidLayoutSubviews() {
102
+ super.viewDidLayoutSubviews()
103
+ for subview in view.subviews { subview.frame = view.bounds }
104
+ }
105
+
106
+ override func viewDidDisappear(_ animated: Bool) {
107
+ super.viewDidDisappear(animated)
108
+ settle()
109
+ }
110
+
111
+ func update(
112
+ entries new: [StackEntry],
113
+ environment: EnvironmentValues,
114
+ screen: @escaping (StackEntry) -> AnyView,
115
+ decorate: @escaping (AnyView) -> AnyView
116
+ ) {
117
+ self.environment = environment
118
+ self.screen = screen
119
+ self.decorate = decorate
120
+ for card in cards.values { card.host.rootView = rootView(for: card) }
121
+ guard new != entries else { return }
122
+
123
+ settle()
124
+ let old = entries
125
+ let oldTop = old.last.flatMap { cards[$0.id] }
126
+ entries = new
127
+
128
+ let live = Set(new.map(\.id))
129
+ for (id, card) in cards where !live.contains(id) {
130
+ cards[id] = nil
131
+ // the old top may still have to animate out
132
+ if card !== oldTop { tearDown(card) }
133
+ }
134
+ for entry in new where cards[entry.id] == nil {
135
+ cards[entry.id] = makeCard(entry)
136
+ }
137
+ guard let newTop = new.last.flatMap({ cards[$0.id] }) else { return }
138
+ guard let oldTop, oldTop !== newTop else {
139
+ if oldTop == nil { attach(newTop) }
140
+ return
141
+ }
142
+
143
+ let isPush = !old.contains(newTop.entry)
144
+ guard view.window != nil, isPush || !live.contains(oldTop.entry.id) else {
145
+ attach(newTop)
146
+ leave(oldTop)
147
+ return
148
+ }
149
+ if isPush {
150
+ let kind: Transition.Kind = newTop.entry.isDialog ? .rise : .slide
151
+ play(Transition(kind: kind, top: newTop, under: oldTop, coverage: 0), to: 1)
152
+ } else {
153
+ // closing a presented flow slides it down whole, whatever was pushed inside it
154
+ let closesPresented = old.drop(while: { $0 != newTop.entry }).dropFirst().contains(where: \.isDialog)
155
+ play(Transition(kind: closesPresented ? .rise : .slide, top: oldTop, under: newTop, coverage: 1), to: 0)
156
+ }
157
+ }
158
+
159
+ // MARK: Host back gesture
160
+
161
+ func beginBackSeek() -> Bool {
162
+ settle()
163
+ guard view.window != nil, entries.count > 1,
164
+ let top = cards[entries[entries.count - 1].id], !top.entry.isDialog,
165
+ let under = cards[entries[entries.count - 2].id] else { return false }
166
+ let transition = Transition(kind: .slide, top: top, under: under, isSeek: true, coverage: 1)
167
+ self.transition = transition
168
+ view.isUserInteractionEnabled = false
169
+ attach(under, below: top)
170
+ apply(transition)
171
+ return true
172
+ }
173
+
174
+ func seekBack(to progress: CGFloat) {
175
+ guard let transition, transition.isSeek, !transition.isAnimating else { return }
176
+ transition.coverage = 1 - progress
177
+ apply(transition)
178
+ }
179
+
180
+ /// Commits the pop here; the navigator drops the same entry right after.
181
+ func finishBackSeek() -> Bool {
182
+ guard let transition, transition.isSeek, !transition.isAnimating else { return false }
183
+ entries.removeLast()
184
+ cards[transition.top.entry.id] = nil
185
+ animate(transition, to: 0)
186
+ return true
187
+ }
188
+
189
+ func cancelBackSeek() {
190
+ guard let transition, transition.isSeek, !transition.isAnimating else { return }
191
+ animate(transition, to: 1)
192
+ }
193
+
194
+ // MARK: Transitions
195
+
196
+ private func play(_ transition: Transition, to target: CGFloat) {
197
+ self.transition = transition
198
+ view.isUserInteractionEnabled = false
199
+ if transition.top.host.view.superview !== view { attach(transition.top) }
200
+ attach(transition.under, below: transition.top)
201
+ apply(transition)
202
+ animate(transition, to: target)
203
+ }
204
+
205
+ /// The rest of the way plays at full-transition pace, so a released drag keeps its speed.
206
+ private func animate(_ transition: Transition, to target: CGFloat) {
207
+ transition.from = transition.coverage
208
+ transition.target = target
209
+ transition.duration = STACK_TRANSITION_DURATION * Double(abs(target - transition.coverage))
210
+ transition.startTime = nil
211
+ transition.isAnimating = true
212
+ guard transition.duration > 0 else {
213
+ finish(transition)
214
+ return
215
+ }
216
+ startDisplayLink()
217
+ }
218
+
219
+ @objc private func tick(_ link: CADisplayLink) {
220
+ guard let transition, transition.isAnimating else {
221
+ stopDisplayLink()
222
+ return
223
+ }
224
+ // the clock starts on the first frame, so a heavy first layout doesn't eat the motion
225
+ let start = transition.startTime ?? link.targetTimestamp
226
+ transition.startTime = start
227
+ let fraction = min(max((link.targetTimestamp - start) / transition.duration, 0), 1)
228
+ // linear for the stack: the gesture maps the finger straight onto this timeline
229
+ let eased = transition.kind == .rise ? fastOutSlowIn(CGFloat(fraction)) : CGFloat(fraction)
230
+ transition.coverage = fraction >= 1
231
+ ? transition.target
232
+ : transition.from + (transition.target - transition.from) * eased
233
+ apply(transition)
234
+ if fraction >= 1 { finish(transition) }
235
+ }
236
+
237
+ /// Jumps a running transition to its end; an unreleased drag snaps back.
238
+ private func settle() {
239
+ guard let transition else { return }
240
+ if transition.isSeek, !transition.isAnimating { transition.target = 1 }
241
+ transition.coverage = transition.target
242
+ apply(transition)
243
+ finish(transition)
244
+ }
245
+
246
+ private func finish(_ transition: Transition) {
247
+ transition.isAnimating = false
248
+ if self.transition === transition { self.transition = nil }
249
+ stopDisplayLink()
250
+ view.isUserInteractionEnabled = true
251
+ transition.top.motion.state = CardMotion.State()
252
+ transition.under.motion.state = CardMotion.State()
253
+ leave(transition.target >= 1 ? transition.under : transition.top)
254
+ }
255
+
256
+ private func apply(_ transition: Transition) {
257
+ let size = view.bounds.size
258
+ let coverage = transition.coverage
259
+ switch transition.kind {
260
+ case .slide:
261
+ transition.top.motion.state = CardMotion.State(
262
+ offset: CGSize(width: (1 - coverage) * size.width, height: 0),
263
+ shadow: EDGE_SHADOW_MAX_ALPHA * coverage
264
+ )
265
+ transition.under.motion.state = CardMotion.State(
266
+ offset: CGSize(width: -PARALLAX_RATIO * size.width * coverage, height: 0),
267
+ scrim: SCRIM_MAX_ALPHA * coverage
268
+ )
269
+ case .rise:
270
+ transition.top.motion.state = CardMotion.State(offset: CGSize(width: 0, height: (1 - coverage) * size.height))
271
+ }
272
+ }
273
+
274
+ private func startDisplayLink() {
275
+ guard displayLink == nil else { return }
276
+ let link = CADisplayLink(target: self, selector: #selector(tick))
277
+ link.preferredFrameRateRange = CAFrameRateRange(minimum: 60, maximum: 120, preferred: 120)
278
+ link.add(to: .main, forMode: .common)
279
+ displayLink = link
280
+ }
281
+
282
+ private func stopDisplayLink() {
283
+ displayLink?.invalidate()
284
+ displayLink = nil
285
+ }
286
+
287
+ // MARK: Cards
288
+
289
+ private func makeCard(_ entry: StackEntry) -> Card {
290
+ let card = Card(entry: entry)
291
+ let host = UIHostingController(rootView: rootView(for: card))
292
+ host.view.backgroundColor = .clear
293
+ addChild(host)
294
+ host.didMove(toParent: self)
295
+ card.host = host
296
+ return card
297
+ }
298
+
299
+ /// The card's own environment is the container's (host environment objects included), with
300
+ /// the kit's re-applied on top; the screen itself is built once and never re-run from here.
301
+ private func rootView(for card: Card) -> AnyView {
302
+ let entry = card.entry
303
+ let screen = screen
304
+ let content = StackCard(motion: card.motion) {
305
+ StackCardContent(id: entry.id) { screen(entry) }.equatable()
306
+ }
307
+ return AnyView(decorate(AnyView(content)).environment(\.self, environment))
308
+ }
309
+
310
+ private func attach(_ card: Card, below other: Card? = nil) {
311
+ let hostView: UIView = card.host.view
312
+ hostView.frame = view.bounds
313
+ if let other, other.host.view.superview === view {
314
+ view.insertSubview(hostView, belowSubview: other.host.view)
315
+ } else {
316
+ view.addSubview(hostView)
317
+ }
318
+ }
319
+
320
+ /// Off the window while covered, released once off the stack.
321
+ private func leave(_ card: Card) {
322
+ if cards[card.entry.id] === card {
323
+ card.host.view.removeFromSuperview()
324
+ } else {
325
+ tearDown(card)
326
+ }
327
+ }
328
+
329
+ private func tearDown(_ card: Card) {
330
+ card.host.willMove(toParent: nil)
331
+ card.host.view.removeFromSuperview()
332
+ card.host.removeFromParent()
333
+ }
334
+ }
335
+
336
+ // MARK: - Card
337
+
338
+ final class CardMotion: ObservableObject {
339
+ struct State: Equatable {
340
+ var offset: CGSize = .zero
341
+ var scrim: CGFloat = 0
342
+ var shadow: CGFloat = 0
343
+ }
344
+
345
+ @Published var state = State()
346
+ }
347
+
348
+ /// Compose's `StackTransitionDecor`: the covered-screen scrim and the top card's left-edge shadow.
349
+ private struct StackCard<Content: View>: View {
350
+ @ObservedObject var motion: CardMotion
351
+ let content: Content
352
+
353
+ init(motion: CardMotion, @ViewBuilder content: () -> Content) {
354
+ self.motion = motion
355
+ self.content = content()
356
+ }
357
+
358
+ var body: some View {
359
+ let state = motion.state
360
+ content
361
+ .overlay {
362
+ Colors.pink09.opacity(state.scrim)
363
+ .ignoresSafeArea()
364
+ .allowsHitTesting(false)
365
+ }
366
+ .background(alignment: .leading) {
367
+ LinearGradient(colors: [.clear, Colors.black20], startPoint: .leading, endPoint: .trailing)
368
+ .frame(width: EDGE_SHADOW_WIDTH)
369
+ .offset(x: -EDGE_SHADOW_WIDTH)
370
+ .opacity(state.shadow)
371
+ .ignoresSafeArea()
372
+ .allowsHitTesting(false)
373
+ }
374
+ .offset(state.offset)
375
+ }
376
+ }
377
+
378
+ /// Equal by entry, so a motion frame or a root refresh never re-runs the screen body.
379
+ private struct StackCardContent: View, Equatable {
380
+ let id: Int
381
+ let build: () -> AnyView
382
+
383
+ static func == (lhs: Self, rhs: Self) -> Bool { lhs.id == rhs.id }
384
+
385
+ var body: some View { build() }
386
+ }
387
+
388
+ /// Compose's `FastOutSlowInEasing`, cubic-bezier(0.4, 0, 0.2, 1).
389
+ private func fastOutSlowIn(_ t: CGFloat) -> CGFloat {
390
+ func bezier(_ s: CGFloat, _ p1: CGFloat, _ p2: CGFloat) -> CGFloat {
391
+ 3 * (1 - s) * (1 - s) * s * p1 + 3 * (1 - s) * s * s * p2 + s * s * s
392
+ }
393
+ var low: CGFloat = 0
394
+ var high: CGFloat = 1
395
+ for _ in 0..<20 {
396
+ let mid = (low + high) / 2
397
+ if bezier(mid, 0.4, 0.2) < t { low = mid } else { high = mid }
398
+ }
399
+ return bezier((low + high) / 2, 0, 1)
400
+ }
@@ -0,0 +1,33 @@
1
+ //
2
+ // SwipeBackHaptic.swift
3
+ // MoMoUIKits
4
+ //
5
+ // SwiftUI mirror of Compose's `navigation/SwipeBackHaptic.kt`: one light tick when the host back
6
+ // gesture has dragged the screen 50pt, re-armed once it goes back under.
7
+ //
8
+
9
+ import UIKit
10
+
11
+ struct SwipeBackHaptic {
12
+ // Unscaled, so the tick lands at the same physical distance on every device.
13
+ private static let threshold: CGFloat = 50
14
+
15
+ private var fired = false
16
+
17
+ mutating func update(travelled: CGFloat, maxApi: MaxApi?) {
18
+ if travelled >= Self.threshold, !fired {
19
+ fired = true
20
+ if let maxApi {
21
+ maxApi.triggerEventVibration("light")
22
+ } else {
23
+ UIImpactFeedbackGenerator(style: .light).impactOccurred()
24
+ }
25
+ } else if travelled < Self.threshold {
26
+ fired = false
27
+ }
28
+ }
29
+
30
+ mutating func reset() {
31
+ fired = false
32
+ }
33
+ }
@@ -9,7 +9,7 @@
9
9
  import Foundation
10
10
 
11
11
  public final class ScreenTrackingState {
12
- public var time: Double = Date().timeIntervalSince1970 * 1000
12
+ public var time: Double = ScreenTracker.now()
13
13
  public var releaseNavigated: Bool = false
14
14
  public var releaseLoad: Bool = false
15
15
  public var releaseInteraction: Bool = false
@@ -22,6 +22,12 @@ public final class ScreenTrackingState {
22
22
  public enum ScreenTracker {
23
23
  private static var lastScreenName: String?
24
24
 
25
+ /// Epoch milliseconds, the clock Compose tracks with.
26
+ public static func now() -> Double { Date().timeIntervalSince1970 * 1000 }
27
+
28
+ /// Compose sends whole milliseconds (`Long`).
29
+ private static func millis(_ value: Double) -> Int64 { Int64(value.rounded()) }
30
+
25
31
  public static func trackScreenNavigated(
26
32
  maxApi: MaxApi?,
27
33
  context: MiniAppContext?,
@@ -35,7 +41,8 @@ public enum ScreenTracker {
35
41
  lastScreenName = screenName
36
42
 
37
43
  var params = buildBaseParams(context: context, screenName: screenName)
38
- params["pre_screen_name"] = previousScreen
44
+ // keeps the key with a null value; a subscript assignment of nil would drop it
45
+ params.updateValue(previousScreen, forKey: "pre_screen_name")
39
46
  params["state"] = "navigated"
40
47
  params["action"] = action
41
48
  maxApi?.track(eventName: "auto_screen_navigated", params: params)
@@ -55,7 +62,7 @@ public enum ScreenTracker {
55
62
 
56
63
  var params = buildBaseParams(context: context, screenName: screenName)
57
64
  params["state"] = "load"
58
- params["duration"] = duration
65
+ params["duration"] = millis(duration)
59
66
  maxApi?.track(eventName: "auto_screen_displayed", params: params)
60
67
 
61
68
  state.releaseLoad = true
@@ -73,8 +80,8 @@ public enum ScreenTracker {
73
80
 
74
81
  var params = buildBaseParams(context: context, screenName: screenName)
75
82
  params["state"] = "interaction"
76
- params["duration"] = duration
77
- params["total_duration"] = totalDuration
83
+ params["duration"] = millis(duration)
84
+ params["total_duration"] = millis(totalDuration)
78
85
  maxApi?.track(eventName: "auto_screen_interacted", params: params)
79
86
 
80
87
  state.releaseInteraction = true
@@ -65,21 +65,18 @@ public struct OTPKeyboard: View {
65
65
  HStack {
66
66
  KeyboardButton("", action: self.onPressKey).disabled(true).opacity(0)
67
67
  KeyboardButton("0", action: self.onPressKey)
68
+ // Frame inside the label so the whole key is tappable, not just the glyph.
68
69
  SwiftUI.Button(action: onPressBack) {
69
- HStack {
70
- Image(
71
- systemName: "delete.backward"
72
- ).foregroundColor(Colors.text)
73
- }
74
- }.frame(maxWidth: .infinity, minHeight: 48)
75
- .clipShape(RoundedRectangle(cornerRadius: 8))
70
+ Image(systemName: "delete.backward")
71
+ .foregroundColor(Colors.text)
72
+ .frame(maxWidth: .infinity, minHeight: 48)
73
+ .contentShape(Rectangle())
74
+ }
76
75
  }
77
76
  }
78
77
  .background(Colors.background)
79
78
  .valueChanged(value: value) { otp in
80
- if onChange != nil {
81
- self.onChange!(otp)
82
- }
79
+ onChange?(otp)
83
80
  }
84
81
  }
85
82
 
@@ -128,7 +125,7 @@ private struct ValueView: View {
128
125
 
129
126
  public var body: some View {
130
127
  return HStack {
131
- ForEach(0 ..< valueLength, id: \.self) { i in
128
+ ForEach(0 ..< max(valueLength, 0), id: \.self) { i in
132
129
  if i < value.count {
133
130
  Circle().foregroundColor(Colors.text).frame(width: 8, height: 8)
134
131
  } else {
@@ -14,10 +14,10 @@ import SwiftUI
14
14
  private let INDICATOR_WIDTH: CGFloat = 24
15
15
  private let PROGRESS_WIDTH: CGFloat = 72
16
16
 
17
- /// Memoized offset calculation, mirroring Compose's `calculateOffset`.
17
+ /// Mirrors Compose's `calculateOffset`; clamped because UIKit bounce overshoots the scroll range.
18
18
  private func calculateOffset(currentPosition: CGFloat, maxBound: CGFloat) -> CGFloat {
19
19
  guard maxBound > 0 else { return 0 }
20
- return (PROGRESS_WIDTH - INDICATOR_WIDTH) * (currentPosition / maxBound)
20
+ return (PROGRESS_WIDTH - INDICATOR_WIDTH) * min(max(currentPosition / maxBound, 0), 1)
21
21
  }
22
22
 
23
23
  // MARK: - PaginationScroll