@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
@@ -10,9 +10,8 @@ private let wheelPickerBorderWidth: CGFloat = 1
10
10
 
11
11
  /// A reusable single-column wheel picker, mirroring Compose `WheelPicker.kt`.
12
12
  ///
13
- /// The data is padded with two empty rows at the top and bottom so the first/last
14
- /// real value can be centered. The currently centered row is reported back via
15
- /// `onChange(name, value)`.
13
+ /// Five rows tall with the selection in the middle row. A drag always settles on a row
14
+ /// (Compose snaps once the scroll stops) and then reports it via `onChange(name, value)`.
16
15
  public struct WheelPicker: View {
17
16
  @Environment(\.appTheme) private var theme
18
17
 
@@ -28,68 +27,50 @@ public struct WheelPicker: View {
28
27
  self.data = data
29
28
  self.selectedData = selectedData
30
29
  self.onChange = onChange
30
+ _restIndex = State(initialValue: Self.index(of: selectedData, in: data))
31
31
  }
32
32
 
33
33
  // MARK: Public
34
34
 
35
35
  public var body: some View {
36
- let paddedData = ["", ""] + data + ["", ""]
37
-
38
- return GeometryReader { geo in
39
- let height = geo.size.height
40
- ScrollViewReader { proxy in
41
- ScrollView(.vertical, showsIndicators: false) {
42
- LazyVStack(spacing: 0) {
43
- ForEach(Array(paddedData.enumerated()), id: \.offset) { index, text in
44
- WheelPickerItem(
45
- text: text,
46
- isSelected: index == selectedIndex,
47
- index: index,
48
- scrollOffset: scrollOffset,
49
- viewportHeight: height
50
- )
51
- .frame(height: wheelItemHeight)
52
- .id(index)
53
- }
54
- }
55
- .background(
56
- GeometryReader { inner in
57
- Color.clear.preference(
58
- key: WheelOffsetKey.self,
59
- value: inner.frame(in: .named(scrollSpace)).minY
60
- )
61
- }
62
- )
63
- }
64
- .coordinateSpace(name: scrollSpace)
65
- .onPreferenceChange(WheelOffsetKey.self) { value in
66
- scrollOffset = value
67
- updateSelection(paddedData: paddedData, viewportHeight: height)
68
- }
69
- .onAppear {
70
- let initial = max(paddedData.firstIndex(of: selectedData) ?? 2, 2)
71
- selectedIndex = initial
72
- DispatchQueue.main.async {
73
- proxy.scrollTo(initial, anchor: .center)
36
+ let position = self.position
37
+ let centerSlot = CGFloat(wheelVisibleCount / 2)
38
+
39
+ return Rectangle()
40
+ .fill(theme.colors.background.surface)
41
+ .overlay(
42
+ // Compose draws the selection band behind the rows.
43
+ Rectangle()
44
+ .fill(Colors.blue10)
45
+ .opacity(0.2)
46
+ .frame(height: wheelItemHeight)
47
+ )
48
+ .overlay(
49
+ VStack(spacing: 0) {
50
+ ForEach(Array(data.enumerated()), id: \.offset) { index, text in
51
+ WheelPickerItem(text: text, distance: abs(CGFloat(index) - position))
74
52
  }
75
53
  }
54
+ .offset(y: (centerSlot - position) * wheelItemHeight),
55
+ alignment: .top
56
+ )
57
+ .frame(maxWidth: .infinity)
58
+ .frame(height: wheelItemHeight * CGFloat(wheelVisibleCount))
59
+ .clipShape(RoundedRectangle(cornerRadius: Radius.S))
60
+ .overlay(
61
+ RoundedRectangle(cornerRadius: Radius.S)
62
+ .strokeBorder(theme.colors.border.default, lineWidth: wheelPickerBorderWidth)
63
+ )
64
+ .contentShape(Rectangle())
65
+ .gesture(dragGesture)
66
+ .onAppear { reportIfUnlisted() }
67
+ .onChange(of: selectedData) { _ in syncToSelection() }
68
+ .onChange(of: data) { _ in syncToSelection() }
69
+ .accessibilityElement()
70
+ .accessibilityValue(data.indices.contains(restIndex) ? data[restIndex] : "")
71
+ .accessibilityAdjustableAction { direction in
72
+ settle(at: restIndex + (direction == .increment ? 1 : -1))
76
73
  }
77
- }
78
- .frame(height: wheelItemHeight * CGFloat(wheelVisibleCount))
79
- .overlay(
80
- RoundedRectangle(cornerRadius: Radius.S)
81
- .stroke(theme.colors.border.default, lineWidth: wheelPickerBorderWidth)
82
- )
83
- .background(theme.colors.background.surface.clipShape(RoundedRectangle(cornerRadius: Radius.S)))
84
- .overlay(
85
- // Centered translucent selection band.
86
- Rectangle()
87
- .fill(Colors.blue10)
88
- .opacity(0.2)
89
- .frame(height: wheelItemHeight)
90
- .allowsHitTesting(false)
91
- )
92
- .clipShape(RoundedRectangle(cornerRadius: Radius.S))
93
74
  }
94
75
 
95
76
  // MARK: Internal
@@ -99,24 +80,60 @@ public struct WheelPicker: View {
99
80
  let selectedData: String
100
81
  let onChange: (String, String) -> Void
101
82
 
102
- @State private var selectedIndex: Int = 0
103
- @State private var scrollOffset: CGFloat = 0
104
-
105
- private let scrollSpace = "wheelScroll"
106
-
107
- /// Map the current scroll offset to the centered index and report changes.
108
- private func updateSelection(paddedData: [String], viewportHeight: CGFloat) {
109
- // `scrollOffset` is the top of the content relative to the viewport (<= 0 when scrolled).
110
- let centerY = viewportHeight / 2
111
- let contentCenter = -scrollOffset + centerY
112
- let rawIndex = Int((contentCenter / wheelItemHeight).rounded()) - 1
113
- let clamped = max(2, min(rawIndex, paddedData.count - 3))
114
- guard clamped != selectedIndex else { return }
115
- selectedIndex = clamped
116
- let value = paddedData[clamped]
117
- if !value.isEmpty {
118
- onChange(name, value)
83
+ // MARK: Private
84
+
85
+ @State private var restIndex: Int
86
+ @State private var dragTranslation: CGFloat = 0
87
+
88
+ /// Fractional row index under the band; past either end the drag meets resistance.
89
+ private var position: CGFloat {
90
+ let raw = CGFloat(restIndex) - dragTranslation / wheelItemHeight
91
+ let last = CGFloat(max(0, data.count - 1))
92
+ if raw < 0 { return raw * 0.3 }
93
+ if raw > last { return last + (raw - last) * 0.3 }
94
+ return raw
95
+ }
96
+
97
+ private var dragGesture: some Gesture {
98
+ DragGesture(minimumDistance: 4)
99
+ .onChanged { value in
100
+ dragTranslation = value.translation.height
101
+ }
102
+ .onEnded { value in
103
+ let predicted = CGFloat(restIndex) - value.predictedEndTranslation.height / wheelItemHeight
104
+ settle(at: Int(predicted.rounded()))
105
+ }
106
+ }
107
+
108
+ /// Like Compose `paddedData.indexOf(selectedData).coerceAtLeast(2)`: an unknown value shows the first row.
109
+ private static func index(of value: String, in data: [String]) -> Int {
110
+ data.firstIndex(of: value) ?? 0
111
+ }
112
+
113
+ private func settle(at index: Int) {
114
+ let target = min(max(index, 0), max(0, data.count - 1))
115
+ let rows = Double(abs(CGFloat(target) - position))
116
+ withAnimation(.easeOut(duration: min(0.5, 0.2 + 0.03 * rows))) {
117
+ restIndex = target
118
+ dragTranslation = 0
119
119
  }
120
+ guard data.indices.contains(target), data[target] != selectedData else { return }
121
+ onChange(name, data[target])
122
+ }
123
+
124
+ /// The parent may coerce the value (e.g. day 31 → 28) or swap the list; jump without animation
125
+ /// like Compose `scrollToItem`.
126
+ private func syncToSelection() {
127
+ restIndex = Self.index(of: selectedData, in: data)
128
+ dragTranslation = 0
129
+ reportIfUnlisted()
130
+ }
131
+
132
+ /// Compose reports the row the wheel lands on, so a value missing from `data` (minute 07 with a
133
+ /// 5-minute interval, an unset AM/PM) takes the shown row's value instead of drifting from it.
134
+ private func reportIfUnlisted() {
135
+ guard data.indices.contains(restIndex), !data.contains(selectedData) else { return }
136
+ onChange(name, data[restIndex])
120
137
  }
121
138
  }
122
139
 
@@ -126,40 +143,21 @@ private struct WheelPickerItem: View {
126
143
  @Environment(\.appTheme) private var theme
127
144
 
128
145
  let text: String
129
- let isSelected: Bool
130
- let index: Int
131
- let scrollOffset: CGFloat
132
- let viewportHeight: CGFloat
146
+ /// Rows between this one and the band.
147
+ let distance: CGFloat
133
148
 
134
149
  var body: some View {
135
- let itemCenterInContent = CGFloat(index) * wheelItemHeight + wheelItemHeight / 2
136
- let itemCenterInViewport = itemCenterInContent + scrollOffset
137
- let distanceFromCenter = abs(itemCenterInViewport - viewportHeight / 2) / wheelItemHeight
138
-
139
- let alpha: Double
140
- switch distanceFromCenter {
141
- case ..<1: alpha = 1.0
142
- case ..<2: alpha = 0.8
143
- default: alpha = 0.4
144
- }
145
-
146
- let scale: CGFloat = isSelected ? 1.0 : 0.87
147
-
148
- return ZStack {
149
- MomoText(text, typography: .actionSBold, color: theme.colors.text.default)
150
- .scaleEffect(scale)
151
- }
152
- .frame(maxWidth: .infinity)
153
- .frame(height: wheelItemHeight)
154
- .opacity(alpha)
150
+ MomoText(text, typography: .actionSBold, color: theme.colors.text.default)
151
+ .scaleEffect(1 - 0.13 * min(distance, 1))
152
+ .frame(maxWidth: .infinity)
153
+ .frame(height: wheelItemHeight)
154
+ .opacity(Self.opacity(distance))
155
155
  }
156
- }
157
-
158
- // MARK: - WheelOffsetKey
159
156
 
160
- private struct WheelOffsetKey: PreferenceKey {
161
- static var defaultValue: CGFloat = 0
162
- static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
163
- value = nextValue()
157
+ // RN parity: 1 on the band, 0.8 one row away, 0.4 from two rows on.
158
+ private static func opacity(_ distance: CGFloat) -> Double {
159
+ if distance <= 1 { return Double(1 - 0.2 * distance) }
160
+ if distance <= 2 { return Double(0.8 - 0.4 * (distance - 1)) }
161
+ return 0.4
164
162
  }
165
163
  }
@@ -1,16 +1,49 @@
1
1
  import Foundation
2
2
  import SwiftUI
3
3
 
4
+ public enum DividerType {
5
+ case `default`
6
+ case dash
7
+ }
8
+
4
9
  public struct MomoDivider: View {
5
10
  @Environment(\.appTheme) private var theme
6
11
 
7
- public init() {}
12
+ private let useMargin: Bool
13
+ private let type: DividerType
14
+
15
+ public init(useMargin: Bool = false, type: DividerType = .default) {
16
+ self.useMargin = useMargin
17
+ self.type = type
18
+ }
8
19
 
9
20
  public var body: some View {
10
- Rectangle()
11
- .fill(theme.colors.border.default)
21
+ line
12
22
  .frame(maxWidth: .infinity)
13
23
  .frame(height: 1)
14
- .padding(.vertical, Spacing.XS)
24
+ .padding(.vertical, useMargin ? Spacing.XS : 0)
25
+ }
26
+
27
+ @ViewBuilder
28
+ private var line: some View {
29
+ switch type {
30
+ case .default:
31
+ Rectangle().fill(theme.colors.border.default)
32
+ case .dash:
33
+ DividerDashLine()
34
+ .stroke(
35
+ theme.colors.border.default,
36
+ style: StrokeStyle(lineWidth: 1, lineCap: .round, dash: [4, 4])
37
+ )
38
+ }
39
+ }
40
+ }
41
+
42
+ private struct DividerDashLine: Shape {
43
+ func path(in rect: CGRect) -> Path {
44
+ var path = Path()
45
+ path.move(to: CGPoint(x: rect.minX, y: rect.midY))
46
+ path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
47
+ return path
15
48
  }
16
49
  }
@@ -43,15 +43,44 @@ 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
+ )
67
+ }
68
+ }
69
+
70
+ extension Color {
71
+ /// Compose's `lerp(start, stop, fraction)`, in sRGB; `Color.mix` needs iOS 18.
72
+ func lerp(to other: Color, _ fraction: CGFloat) -> Color {
73
+ let t = min(max(fraction, 0), 1)
74
+ var (r1, g1, b1, a1): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
75
+ var (r2, g2, b2, a2): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
76
+ UIColor(self).getRed(&r1, green: &g1, blue: &b1, alpha: &a1)
77
+ UIColor(other).getRed(&r2, green: &g2, blue: &b2, alpha: &a2)
78
+ return Color(
79
+ .sRGB,
80
+ red: r1 + (r2 - r1) * t,
81
+ green: g1 + (g2 - g1) * t,
82
+ blue: b1 + (b2 - b1) * t,
83
+ opacity: a1 + (a2 - a1) * t
84
+ )
56
85
  }
57
86
  }
@@ -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
+ }
@@ -0,0 +1,11 @@
1
+ // File: ios/Extensions/SkeletonUICompat.swift
2
+ // Created At: 2026-10-07 12:03:28 +07:00
3
+ // Created By: AI
4
+ // AI Agent: Claude Code
5
+ // Model: claude-opus-5-5
6
+
7
+ // AI-GENERATED START: keep SkeletonUI extensions visible to MoMoUIKits clients
8
+ // Unused here on purpose: Swift 5 exposes extension members of every module a dependency imports, so clients
9
+ // that only `import MoMoUIKits` rely on SkeletonUI's (e.g. `Text(String?)` in NativeWidget). Removing it breaks them.
10
+ import SkeletonUI
11
+ // AI-GENERATED END: keep SkeletonUI extensions visible to MoMoUIKits clients
@@ -1,30 +1,20 @@
1
+ import SDWebImageSwiftUI
1
2
  import SwiftUI
2
3
 
3
4
  struct IconSource: Codable {
4
5
  let uri: String
5
6
  }
6
7
 
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 [:]
8
+ // The compiled-in map (Icons.swift) wins; a host `icon.json` in the main bundle only adds keys
9
+ // the kit doesn't know, so hosts that shipped one keep their extra icons.
10
+ let iconSources: [String: String] = {
11
+ guard let url = Bundle.main.url(forResource: "icon", withExtension: "json"),
12
+ let data = try? Data(contentsOf: url),
13
+ let hostIcons = try? JSONDecoder().decode([String: IconSource].self, from: data) else {
14
+ return kitIcons
11
15
  }
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"]
16
+ return kitIcons.merging(hostIcons.mapValues(\.uri)) { kit, _ in kit }
17
+ }()
28
18
 
29
19
  // Compose defaults `color` to the theme text color while `color = null` means "no tint".
30
20
  // Swift can't tell an omitted argument from an explicit `nil`, so the default is this
@@ -53,16 +43,24 @@ public struct Icon: View {
53
43
  }
54
44
 
55
45
  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 {
46
+ // Mirror Compose: an https source is used as-is, anything else is a key into the icon map
47
+ if let uri = source.contains("https") ? source : iconSources[source] {
58
48
  let requestedColor = color == iconThemeColor ? theme.colors.text.default : color
59
49
  // Mirror Compose: certain icons (e.g. branded glyphs) are never tinted
60
50
  let resolvedColor = noThemeIcons.contains(source) ? nil : requestedColor
61
- ImageView(uri, color: resolvedColor)
51
+ // Bare WebImage like Compose's AsyncImage: no skeleton while loading, nothing on failure.
52
+ WebImage(url: URL(string: uri), isAnimating: .constant(true))
53
+ .resizable()
54
+ .renderingMode(resolvedColor != nil ? .template : .original)
55
+ .scaledToFit()
56
+ .foregroundColor(resolvedColor)
62
57
  .frame(width: size, height: size)
63
58
  // Mirrors Compose's auto-generated `contentDescription = "img|$iconUrl"`
64
59
  // when no explicit label is provided.
65
60
  .accessibilityLabel(accessibilityLabel ?? "img|\(uri)")
61
+ } else {
62
+ // Compose keeps the sized box for an unknown key, so layouts don't collapse.
63
+ Color.clear.frame(width: size, height: size)
66
64
  }
67
65
  }
68
66
  }