@momo-kits/native-kits 0.163.1-beta.8 → 0.163.1-beta.9-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 (334) hide show
  1. package/CLAUDE.md +1 -1
  2. package/build.gradle.kts +11 -0
  3. package/compose/build.gradle.kts +190 -0
  4. package/compose/build.gradle.kts.backup +190 -0
  5. package/compose/compose.podspec +47 -0
  6. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +6 -0
  7. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
  8. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +150 -0
  9. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  10. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  11. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  12. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  13. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  14. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  19. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  20. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  21. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  22. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +52 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +106 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +183 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +207 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +39 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +294 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +826 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +110 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +378 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +56 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +82 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +338 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +175 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +356 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +113 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +89 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +128 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +209 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +76 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +125 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +231 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +112 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +477 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +114 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +214 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +240 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +216 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +259 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +182 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +343 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +84 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +328 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +97 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +310 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +59 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +21 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +90 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +323 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +217 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +473 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +122 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +199 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +91 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +470 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +88 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +131 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +203 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +498 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +175 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +182 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +193 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +234 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +188 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +22 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +16 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +188 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +276 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +65 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +48 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +51 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +52 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +66 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +104 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +48 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +253 -0
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +129 -0
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +100 -0
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +172 -0
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +360 -0
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +8 -0
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +581 -0
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +156 -0
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +225 -0
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +169 -0
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +320 -0
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +81 -0
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +309 -0
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +34 -0
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +360 -0
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +132 -0
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +128 -0
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +91 -0
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +69 -0
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +55 -0
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +15 -0
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +105 -0
  132. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +32 -0
  133. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
  134. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +207 -0
  135. package/gradle/libs.versions.toml +69 -0
  136. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  137. package/gradle/wrapper/gradle-wrapper.properties +8 -0
  138. package/gradle.properties +26 -0
  139. package/gradlew +252 -0
  140. package/gradlew.bat +94 -0
  141. package/ios/Application/ApplicationEnvironment.swift +15 -2
  142. package/ios/Application/Components.swift +50 -44
  143. package/ios/Application/FloatingButton.swift +10 -9
  144. package/ios/Application/HeaderRight.swift +79 -45
  145. package/ios/Application/Localize.swift +277 -0
  146. package/ios/Application/MaxApi.swift +18 -0
  147. package/ios/Application/Navigation/BottomTab/BottomTab.swift +104 -0
  148. package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +215 -0
  149. package/ios/Application/Navigation/BottomTab/CurvedContainer.swift +65 -0
  150. package/ios/Application/Navigation/HeaderBackProps.swift +66 -0
  151. package/ios/Application/Navigation/HeaderTitle.swift +57 -0
  152. package/ios/Application/Navigation/HeaderUser.swift +209 -0
  153. package/ios/Application/Navigation/NavigationContainer.swift +200 -0
  154. package/ios/Application/Navigation/NavigationOptions.swift +109 -0
  155. package/ios/Application/Navigation/Navigator.swift +385 -0
  156. package/ios/Application/Navigation/Overplay/BottomSheet.swift +256 -0
  157. package/ios/Application/Navigation/Overplay/ModalScreen.swift +74 -0
  158. package/ios/Application/Navigation/Overplay/SnackBar.swift +144 -0
  159. package/ios/Application/Navigation/Tracking/ScreenTracker.swift +117 -0
  160. package/ios/Application/Navigation/component/Header.swift +178 -0
  161. package/ios/Application/Navigation/component/HeaderBackground.swift +83 -0
  162. package/ios/Application/Navigation/component/HeaderColor.swift +65 -0
  163. package/ios/Application/Screen.swift +2 -1
  164. package/ios/Application/StackScreen.swift +501 -0
  165. package/ios/Avatar/Avatar.swift +193 -0
  166. package/ios/Badge/Badge.swift +11 -14
  167. package/ios/Badge/BadgeRibbon.swift +92 -21
  168. package/ios/BaselineView/BaselineView.swift +163 -0
  169. package/ios/Button/Button.swift +124 -29
  170. package/ios/Carousel/Carousel.swift +196 -0
  171. package/ios/Checkbox/Checkbox.swift +23 -28
  172. package/ios/Chip/Chip.swift +56 -33
  173. package/ios/Collapse/Collapse.swift +192 -0
  174. package/ios/Colors+Radius+Spacing/Colors.swift +20 -17
  175. package/ios/Colors+Radius+Spacing/Spacing.swift +3 -1
  176. package/ios/Colors+Radius+Spacing/Theme.swift +295 -0
  177. package/ios/DateTimePicker/DateTimePicker.swift +212 -0
  178. package/ios/DateTimePicker/DateTimePickerTypes.swift +55 -0
  179. package/ios/DateTimePicker/DateTimePickerUtils.swift +167 -0
  180. package/ios/DateTimePicker/WheelPicker.swift +165 -0
  181. package/ios/Divider/Divider.swift +16 -0
  182. package/ios/Extensions/ActiveOpacityButtonStyle.swift +14 -0
  183. package/ios/Extensions/Color++.swift +32 -0
  184. package/ios/Icon/Icon.swift +10 -1
  185. package/ios/IconButton/IconButton.swift +140 -0
  186. package/ios/Image/Image.swift +16 -3
  187. package/ios/Information/Information.swift +3 -1
  188. package/ios/Input/ErrorView.swift +3 -1
  189. package/ios/Input/Input.swift +72 -33
  190. package/ios/Input/InputPhoneNumber.swift +33 -21
  191. package/ios/Input/InputSearch.swift +107 -48
  192. package/ios/Input/InputTextArea.swift +134 -64
  193. package/ios/InputDropDown/InputDropDown.swift +201 -0
  194. package/ios/InputMoney/InputMoney.swift +347 -0
  195. package/ios/InputOTP/InputOTP.swift +210 -0
  196. package/ios/Loader/Loader.swift +113 -0
  197. package/ios/MoMoUIKits.podspec +5 -0
  198. package/ios/Pagination/PaginationDot.swift +61 -0
  199. package/ios/Pagination/PaginationNumber.swift +35 -0
  200. package/ios/Pagination/PaginationScroll.swift +101 -0
  201. package/ios/Pagination/PaginationWhiteDot.swift +37 -0
  202. package/ios/Popup/PopupDisplay.swift +11 -20
  203. package/ios/Popup/PopupInput.swift +2 -8
  204. package/ios/Popup/PopupNotify.swift +218 -0
  205. package/ios/Popup/PopupPromotion.swift +16 -8
  206. package/ios/ProgressInfo/ProgressInfo.swift +296 -0
  207. package/ios/Radio/Radio.swift +69 -0
  208. package/ios/Rating/Rating.swift +82 -0
  209. package/ios/Resources/MoMoUIKitsColors.xcassets/AccentColor.colorset/Contents.json +11 -0
  210. package/ios/Resources/MoMoUIKitsColors.xcassets/Background.colorset/Contents.json +38 -0
  211. package/ios/Resources/MoMoUIKitsColors.xcassets/Border.colorset/Contents.json +38 -0
  212. package/ios/Resources/MoMoUIKitsColors.xcassets/Card.colorset/Contents.json +38 -0
  213. package/ios/Resources/MoMoUIKitsColors.xcassets/Contents.json +6 -0
  214. package/ios/Resources/MoMoUIKitsColors.xcassets/Error.colorset/Contents.json +38 -0
  215. package/ios/Resources/MoMoUIKitsColors.xcassets/Primary.colorset/Contents.json +38 -0
  216. package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryDark.colorset/Contents.json +38 -0
  217. package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryLight.colorset/Contents.json +38 -0
  218. package/ios/Resources/MoMoUIKitsColors.xcassets/Secondary.colorset/Contents.json +38 -0
  219. package/ios/Resources/MoMoUIKitsColors.xcassets/Success.colorset/Contents.json +38 -0
  220. package/ios/Resources/MoMoUIKitsColors.xcassets/Text.colorset/Contents.json +38 -0
  221. package/ios/Resources/MoMoUIKitsColors.xcassets/TextSecondary.colorset/Contents.json +38 -0
  222. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/Contents.json +9 -0
  223. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-default.colorset/Contents.json +38 -0
  224. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-disable.colorset/Contents.json +38 -0
  225. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-pressed.colorset/Contents.json +38 -0
  226. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-selected.colorset/Contents.json +38 -0
  227. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-surface.colorset/Contents.json +38 -0
  228. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-tonal.colorset/Contents.json +38 -0
  229. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-default.colorset/Contents.json +38 -0
  230. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-disable.colorset/Contents.json +38 -0
  231. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/gradient.colorset/Contents.json +38 -0
  232. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/primary.colorset/Contents.json +38 -0
  233. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/secondary.colorset/Contents.json +38 -0
  234. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-container.colorset/Contents.json +38 -0
  235. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-primary.colorset/Contents.json +38 -0
  236. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-secondary.colorset/Contents.json +38 -0
  237. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-default.colorset/Contents.json +38 -0
  238. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-disable.colorset/Contents.json +38 -0
  239. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-hint.colorset/Contents.json +38 -0
  240. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-secondary.colorset/Contents.json +38 -0
  241. package/ios/Resources/MoMoUIKitsColors.xcassets/Warning.colorset/Contents.json +38 -0
  242. package/ios/Skeleton/Skeleton.swift +99 -0
  243. package/ios/Slider/Slider.swift +237 -0
  244. package/ios/Stepper/Stepper.swift +220 -0
  245. package/ios/Steps/Steps.swift +467 -0
  246. package/ios/SuggestAction/SuggestAction.swift +99 -0
  247. package/ios/Swipeable/SwipeCell.swift +187 -0
  248. package/ios/Swipeable/SwipeCellModel.swift +21 -0
  249. package/ios/Switch/Switch.swift +53 -28
  250. package/ios/TabView/TabView.swift +534 -0
  251. package/ios/Tag/Tag.swift +98 -0
  252. package/ios/Template/TrustBanner/TrustBanner.swift +6 -7
  253. package/ios/Title/Title.swift +269 -0
  254. package/ios/Tooltip/Tooltip.swift +485 -0
  255. package/ios/Typography/FontScaleStore.swift +19 -0
  256. package/ios/Typography/Text.swift +79 -5
  257. package/ios/Typography/Typography.swift +3 -0
  258. package/ios/Uploader/Uploader.swift +174 -0
  259. package/ios/native-kits.podspec +61 -8
  260. package/ios-demo/MoMoUIKitsDemo.podspec +20 -0
  261. package/ios-demo/README.md +120 -0
  262. package/ios-demo/Resources/dot_loading.json +558 -0
  263. package/ios-demo/Resources/icon.json +4052 -0
  264. package/ios-demo/Resources/lottie_circle_loader.json +1 -0
  265. package/ios-demo/Sources/MoMoUIKitsDemo/DemoScaffold.swift +48 -0
  266. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsBadgeDemoView.swift +25 -0
  267. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsButtonDemoView.swift +26 -0
  268. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsCheckboxDemoView.swift +19 -0
  269. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsChipDemoView.swift +33 -0
  270. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsInputDemoView.swift +48 -0
  271. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsPopupDemoView.swift +21 -0
  272. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsRadioDemoView.swift +17 -0
  273. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsTypographyDemoView.swift +28 -0
  274. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoContext.swift +31 -0
  275. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoFactory.swift +24 -0
  276. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AnimatedHeaderDemo.swift +110 -0
  277. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +93 -0
  278. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +269 -0
  279. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BaselineView.swift +117 -0
  280. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BottomTabDemo.swift +89 -0
  281. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +100 -0
  282. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +126 -0
  283. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +63 -0
  284. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +20 -0
  285. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +93 -0
  286. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +107 -0
  287. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +124 -0
  288. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +14 -0
  289. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/HeaderUserDemo.swift +49 -0
  290. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +279 -0
  291. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +58 -0
  292. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +78 -0
  293. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +138 -0
  294. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +111 -0
  295. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +136 -0
  296. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +107 -0
  297. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +73 -0
  298. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +100 -0
  299. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +32 -0
  300. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +57 -0
  301. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +70 -0
  302. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LocalizeDemo.swift +188 -0
  303. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +229 -0
  304. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +72 -0
  305. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +175 -0
  306. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +121 -0
  307. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +76 -0
  308. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +89 -0
  309. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +32 -0
  310. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +56 -0
  311. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +32 -0
  312. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +150 -0
  313. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +138 -0
  314. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +103 -0
  315. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +94 -0
  316. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +79 -0
  317. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +152 -0
  318. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +33 -0
  319. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +190 -0
  320. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +34 -0
  321. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +182 -0
  322. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +109 -0
  323. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +187 -0
  324. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +87 -0
  325. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +131 -0
  326. package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +51 -0
  327. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
  328. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
  329. package/local.properties +8 -0
  330. package/package.json +1 -1
  331. package/publish.sh +53 -0
  332. package/scripts/gen-ios-color.mjs +136 -0
  333. package/settings.gradle.kts +64 -0
  334. package/.claude/settings.local.json +0 -62
@@ -0,0 +1,167 @@
1
+ import Foundation
2
+
3
+ // MARK: - DateTimePickerUtils
4
+
5
+ /// Pure helper functions mirroring Compose `DateTimePickerUtils.kt`.
6
+ public enum DateTimePickerUtils {
7
+
8
+ /// Time mode list for 12-hour clock (only-hour format).
9
+ public static let timeMode: [String] = ["AM", "PM"]
10
+
11
+ /// Pad a number with a leading zero if it's less than 10.
12
+ public static func paddingNum(_ num: Int) -> String {
13
+ return num > 9 ? String(num) : "0\(num)"
14
+ }
15
+
16
+ /// Format a `Date` into a string, matching Compose `formatLocalDateTime`.
17
+ public static func formatDate(
18
+ _ date: Date,
19
+ format: String = "yyyy-MM-dd HH:mm",
20
+ calendar: Calendar = Calendar.current
21
+ ) -> String {
22
+ let c = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date)
23
+ let year = c.year ?? 0
24
+ let month = c.month ?? 1
25
+ let day = c.day ?? 1
26
+ let hour = c.hour ?? 0
27
+ let minute = c.minute ?? 0
28
+
29
+ switch format {
30
+ case "yyyy-MM-dd HH:mm":
31
+ return "\(year)-\(paddingNum(month))-\(paddingNum(day)) \(paddingNum(hour)):\(paddingNum(minute))"
32
+ case "dd-MM-yyyy":
33
+ return "\(paddingNum(day))-\(paddingNum(month))-\(year)"
34
+ case "HH:mm":
35
+ return "\(paddingNum(hour)):\(paddingNum(minute))"
36
+ default:
37
+ return "\(year)-\(paddingNum(month))-\(paddingNum(day)) \(paddingNum(hour)):\(paddingNum(minute))"
38
+ }
39
+ }
40
+
41
+ /// Number of days in a given month/year.
42
+ private static func daysInMonth(year: Int, month: Int) -> Int {
43
+ switch month {
44
+ case 1, 3, 5, 7, 8, 10, 12: return 31
45
+ case 4, 6, 9, 11: return 30
46
+ case 2: return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 29 : 28
47
+ default: return 31
48
+ }
49
+ }
50
+
51
+ /// Get a list of day strings constrained by min/max date.
52
+ public static func getDaysInMonth(
53
+ year: Int,
54
+ month: Int,
55
+ minDate: DateComponents,
56
+ maxDate: DateComponents
57
+ ) -> [String] {
58
+ let maxDay = daysInMonth(year: year, month: month)
59
+ var startDay = 1
60
+ var endDay = maxDay
61
+
62
+ if year == minDate.year && month == minDate.month {
63
+ startDay = minDate.day ?? 1
64
+ }
65
+ if year == maxDate.year && month == maxDate.month {
66
+ endDay = maxDate.day ?? maxDay
67
+ }
68
+
69
+ guard startDay <= endDay else { return [paddingNum(startDay)] }
70
+ return (startDay...endDay).map { paddingNum($0) }
71
+ }
72
+
73
+ /// Get a list of month strings constrained by min/max date for a year.
74
+ public static func getMonths(
75
+ minDate: DateComponents,
76
+ maxDate: DateComponents,
77
+ currentYear: Int
78
+ ) -> [String] {
79
+ var startMonth = 1
80
+ var endMonth = 12
81
+
82
+ if currentYear == minDate.year {
83
+ startMonth = minDate.month ?? 1
84
+ }
85
+ if currentYear == maxDate.year {
86
+ endMonth = maxDate.month ?? 12
87
+ }
88
+
89
+ guard startMonth <= endMonth else { return [paddingNum(startMonth)] }
90
+ return (startMonth...endMonth).map { paddingNum($0) }
91
+ }
92
+
93
+ /// Get a list of year strings between min and max date.
94
+ public static func getYears(minDate: DateComponents, maxDate: DateComponents) -> [String] {
95
+ let startYear = minDate.year ?? 0
96
+ let endYear = maxDate.year ?? 0
97
+ guard startYear <= endYear else { return [String(startYear)] }
98
+ return (startYear...endYear).map { String($0) }
99
+ }
100
+
101
+ /// Get a list of hours for either a 12-hour or 24-hour clock.
102
+ public static func getHours(hourMode: Int) -> [String] {
103
+ var hours: [String] = []
104
+ for i in 0..<hourMode {
105
+ let hour = hourMode == 12 ? i + 1 : i
106
+ hours.append(paddingNum(hour))
107
+ }
108
+ return hours
109
+ }
110
+
111
+ /// Get a list of minutes stepped by `interval`.
112
+ public static func getMinutes(interval: Int) -> [String] {
113
+ let step = max(1, interval)
114
+ var minutes: [String] = []
115
+ var min = 0
116
+ while min < 60 {
117
+ minutes.append(paddingNum(min))
118
+ min += step
119
+ }
120
+ return minutes
121
+ }
122
+
123
+ /// Today's date.
124
+ public static func getCurrentDateTime() -> Date {
125
+ return Date()
126
+ }
127
+
128
+ /// Create a date a certain number of years before/after now.
129
+ public static func createRelativeDate(years: Int, calendar: Calendar = Calendar.current) -> Date {
130
+ let now = Date()
131
+ return calendar.date(byAdding: .year, value: years, to: now) ?? now
132
+ }
133
+
134
+ /// Resolve the wheel columns from a format string. Mirrors Compose `getDateComponents`.
135
+ public static func getDateComponents(
136
+ format: String,
137
+ currentData: DateTimePickerData,
138
+ minDate: DateComponents,
139
+ maxDate: DateComponents,
140
+ minuteInterval: Int
141
+ ) -> [DateTimePickerComponent] {
142
+ let formatParts = format.split(whereSeparator: { !$0.isLetter }).map { String($0) }
143
+ let isOnlyHour = formatParts.count == 1 && formatParts[0] == "HH"
144
+
145
+ let dayData = getDaysInMonth(year: currentData.year, month: currentData.month, minDate: minDate, maxDate: maxDate)
146
+ let monthData = getMonths(minDate: minDate, maxDate: maxDate, currentYear: currentData.year)
147
+ let yearData = getYears(minDate: minDate, maxDate: maxDate)
148
+ let hourData = getHours(hourMode: isOnlyHour ? 12 : 24)
149
+ let minData = getMinutes(interval: minuteInterval)
150
+
151
+ var components: [DateTimePickerComponent] = []
152
+ for part in formatParts {
153
+ switch part {
154
+ case "DD": components.append(DateTimePickerComponent(name: "day", data: dayData))
155
+ case "MM": components.append(DateTimePickerComponent(name: "month", data: monthData))
156
+ case "YYYY": components.append(DateTimePickerComponent(name: "year", data: yearData))
157
+ case "HH": components.append(DateTimePickerComponent(name: "hour", data: hourData))
158
+ case "mm": components.append(DateTimePickerComponent(name: "minute", data: minData))
159
+ default: break
160
+ }
161
+ }
162
+ if isOnlyHour {
163
+ components.append(DateTimePickerComponent(name: "timeMode", data: timeMode))
164
+ }
165
+ return components
166
+ }
167
+ }
@@ -0,0 +1,165 @@
1
+ import SwiftUI
2
+
3
+ // MARK: - Constants
4
+
5
+ private let wheelItemHeight: CGFloat = 42
6
+ private let wheelVisibleCount: Int = 5
7
+ private let wheelPickerBorderWidth: CGFloat = 1
8
+
9
+ // MARK: - WheelPicker
10
+
11
+ /// A reusable single-column wheel picker, mirroring Compose `WheelPicker.kt`.
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)`.
16
+ public struct WheelPicker: View {
17
+ @Environment(\.appTheme) private var theme
18
+
19
+ // MARK: Lifecycle
20
+
21
+ public init(
22
+ name: String,
23
+ data: [String],
24
+ selectedData: String,
25
+ onChange: @escaping (String, String) -> Void
26
+ ) {
27
+ self.name = name
28
+ self.data = data
29
+ self.selectedData = selectedData
30
+ self.onChange = onChange
31
+ }
32
+
33
+ // MARK: Public
34
+
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)
74
+ }
75
+ }
76
+ }
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
+ }
94
+
95
+ // MARK: Internal
96
+
97
+ let name: String
98
+ let data: [String]
99
+ let selectedData: String
100
+ let onChange: (String, String) -> Void
101
+
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)
119
+ }
120
+ }
121
+ }
122
+
123
+ // MARK: - WheelPickerItem
124
+
125
+ private struct WheelPickerItem: View {
126
+ @Environment(\.appTheme) private var theme
127
+
128
+ let text: String
129
+ let isSelected: Bool
130
+ let index: Int
131
+ let scrollOffset: CGFloat
132
+ let viewportHeight: CGFloat
133
+
134
+ 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)
155
+ }
156
+ }
157
+
158
+ // MARK: - WheelOffsetKey
159
+
160
+ private struct WheelOffsetKey: PreferenceKey {
161
+ static var defaultValue: CGFloat = 0
162
+ static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
163
+ value = nextValue()
164
+ }
165
+ }
@@ -0,0 +1,16 @@
1
+ import Foundation
2
+ import SwiftUI
3
+
4
+ public struct MomoDivider: View {
5
+ @Environment(\.appTheme) private var theme
6
+
7
+ public init() {}
8
+
9
+ public var body: some View {
10
+ Rectangle()
11
+ .fill(theme.colors.border.default)
12
+ .frame(maxWidth: .infinity)
13
+ .frame(height: 1)
14
+ .padding(.vertical, Spacing.XS)
15
+ }
16
+ }
@@ -0,0 +1,14 @@
1
+ import SwiftUI
2
+
3
+ /// Mirrors Compose's `Modifier.activeOpacityClickable(activeOpacity:)` (modifier/Clickable.kt):
4
+ /// fades the whole tappable subtree to `activeOpacity` while pressed, animated, instead of
5
+ /// relying on a platform-default press indication.
6
+ struct ActiveOpacityButtonStyle: ButtonStyle {
7
+ var activeOpacity: Double = 0.2
8
+
9
+ func makeBody(configuration: Configuration) -> some View {
10
+ configuration.label
11
+ .opacity(configuration.isPressed ? activeOpacity : 1)
12
+ .animation(.default, value: configuration.isPressed)
13
+ }
14
+ }
@@ -1,6 +1,38 @@
1
1
  import SwiftUI
2
+ import Foundation
3
+
4
+ private final class MoMoUIKitsBundleToken {}
5
+
6
+ enum MoMoUIKitsResources {
7
+ static let bundle: Bundle = {
8
+ let bundleName = "MoMoUIKitsResources"
9
+ let tokenBundle = Bundle(for: MoMoUIKitsBundleToken.self)
10
+ let frameworkBundle = Bundle(identifier: "org.cocoapods.MoMoUIKits")
11
+ let candidates = [
12
+ Bundle.main.resourceURL,
13
+ tokenBundle.resourceURL,
14
+ tokenBundle.bundleURL,
15
+ frameworkBundle?.resourceURL,
16
+ frameworkBundle?.bundleURL
17
+ ]
18
+
19
+ for candidate in candidates {
20
+ guard let bundleURL = candidate?.appendingPathComponent("\(bundleName).bundle"),
21
+ let bundle = Bundle(url: bundleURL) else {
22
+ continue
23
+ }
24
+ return bundle
25
+ }
26
+
27
+ return Bundle.main
28
+ }()
29
+ }
2
30
 
3
31
  public extension Color {
32
+ static func momoAsset(_ name: String) -> Color {
33
+ Color(name, bundle: MoMoUIKitsResources.bundle)
34
+ }
35
+
4
36
  init(hex: UInt, alpha: Double = 1) {
5
37
  self.init(
6
38
  .sRGB,
@@ -23,6 +23,9 @@ func loadIconSources() -> [String: IconSource] {
23
23
  // Load the JSON data into a global variable
24
24
  let iconSources: [String: IconSource] = loadIconSources()
25
25
 
26
+ // Icons that must never be tinted (mirror Compose `noThemeIcons`)
27
+ let noThemeIcons: [String] = ["ic_round_momo_tiny"]
28
+
26
29
  // Icon ViewModel
27
30
  public struct Icon: View {
28
31
  var source: String
@@ -44,7 +47,13 @@ public struct Icon: View {
44
47
 
45
48
  public var body: some View {
46
49
  if let uri = iconSources[source]?.uri {
47
- ImageView(uri, color: color).frame(width: size, height: size)
50
+ // Mirror Compose: certain icons (e.g. branded glyphs) are never tinted
51
+ let resolvedColor = noThemeIcons.contains(source) ? nil : color
52
+ ImageView(uri, color: resolvedColor)
53
+ .frame(width: size, height: size)
54
+ // Mirrors Compose's auto-generated `contentDescription = "img|$iconUrl"`
55
+ // when no explicit label is provided.
56
+ .accessibilityLabel(accessibilityLabel ?? "img|\(uri)")
48
57
  }
49
58
  }
50
59
  }
@@ -0,0 +1,140 @@
1
+ import Foundation
2
+ import SwiftUI
3
+
4
+ // MARK: - IconSize
5
+
6
+ public enum IconSize {
7
+ case large
8
+ case medium
9
+ case small
10
+
11
+ /// Container width/height of the button.
12
+ var containerSize: CGFloat {
13
+ switch self {
14
+ case .large: return 48
15
+ case .medium: return 36
16
+ case .small: return 28
17
+ }
18
+ }
19
+
20
+ /// Glyph size of the icon inside the button.
21
+ var iconSize: CGFloat {
22
+ switch self {
23
+ case .large: return 24
24
+ case .medium, .small: return 16
25
+ }
26
+ }
27
+ }
28
+
29
+ // MARK: - IconShape
30
+
31
+ public enum IconShape {
32
+ case circle
33
+ case square
34
+ }
35
+
36
+ // MARK: - IconButton
37
+
38
+ public struct IconButton: View {
39
+ @Environment(\.appTheme) private var theme
40
+
41
+ var icon: String
42
+ var onClick: () -> Void
43
+ var type: ButtonType
44
+ var size: IconSize
45
+ var shape: IconShape
46
+ var color: Color?
47
+
48
+ public init(
49
+ icon: String = "",
50
+ onClick: @escaping () -> Void,
51
+ type: ButtonType = .primary,
52
+ size: IconSize = .small,
53
+ shape: IconShape = .circle,
54
+ color: Color? = nil
55
+ ) {
56
+ self.icon = icon
57
+ self.onClick = onClick
58
+ self.type = type
59
+ self.size = size
60
+ self.shape = shape
61
+ self.color = color
62
+ }
63
+
64
+ private var isEnabled: Bool {
65
+ type != .disabled
66
+ }
67
+
68
+ public var body: some View {
69
+ let bg = backgroundColor
70
+ let fg = contentColor
71
+ // OUTLINE allows an override color for its border, mirroring Compose `color ?? theme.colors.primary`.
72
+ let border: Color? = type == .outline ? (color ?? theme.colors.primary) : borderColor
73
+ let borderWidth = type.borderWidth
74
+
75
+ SwiftUI.Button(action: {
76
+ if isEnabled {
77
+ onClick()
78
+ }
79
+ }) {
80
+ Icon(source: icon, size: size.iconSize, color: fg)
81
+ .frame(width: size.containerSize, height: size.containerSize)
82
+ .background(bg)
83
+ .clipShape(IconButtonShape(shape))
84
+ .overlay(
85
+ IconButtonShape(shape)
86
+ .stroke(border ?? .clear, lineWidth: border != nil ? borderWidth : 0)
87
+ )
88
+ }
89
+ .buttonStyle(.plain)
90
+ .disabled(!isEnabled)
91
+ }
92
+
93
+ private var backgroundColor: Color {
94
+ switch type {
95
+ case .disabled: return theme.colors.background.disable
96
+ case .primary: return theme.colors.primary
97
+ case .secondary, .outline: return theme.colors.background.surface
98
+ case .tonal: return theme.colors.background.tonal
99
+ case .danger: return theme.colors.error.primary
100
+ case .text: return .clear
101
+ }
102
+ }
103
+
104
+ private var contentColor: Color {
105
+ switch type {
106
+ case .disabled: return theme.colors.text.disable
107
+ case .primary, .danger: return Colors.black01
108
+ case .secondary: return theme.colors.text.default
109
+ case .outline, .tonal, .text: return theme.colors.primary
110
+ }
111
+ }
112
+
113
+ private var borderColor: Color? {
114
+ switch type {
115
+ case .secondary: return theme.colors.border.default
116
+ case .outline: return color ?? theme.colors.primary
117
+ default: return nil
118
+ }
119
+ }
120
+ }
121
+
122
+ /// Type-erased shape switch (`Circle` vs a fixed `Radius.S` rounded rect) — mirrors
123
+ /// Compose's `IconShape.toShape()`. `AnyShape` needs iOS 17+, so this hand-rolls the same
124
+ /// erasure at the deployment target's iOS 15 floor.
125
+ private struct IconButtonShape: Shape {
126
+ let shape: IconShape
127
+
128
+ init(_ shape: IconShape) {
129
+ self.shape = shape
130
+ }
131
+
132
+ func path(in rect: CGRect) -> Path {
133
+ switch shape {
134
+ case .circle:
135
+ return Circle().path(in: rect)
136
+ case .square:
137
+ return RoundedRectangle(cornerRadius: Radius.S).path(in: rect)
138
+ }
139
+ }
140
+ }
@@ -5,15 +5,23 @@ import SDWebImageSwiftUI
5
5
  import SkeletonUI
6
6
  import SwiftUI
7
7
 
8
+ public enum ImageState {
9
+ case loading, success, error
10
+ }
11
+
8
12
  public struct ImageView: View {
13
+ @Environment(\.appTheme) private var theme
14
+
9
15
  // MARK: Lifecycle
10
16
 
11
- public init(_ url: String, aspectRatio: CGFloat? = nil, contentMode: ContentMode = ContentMode.fit, placeholder: AnyView? = nil, color: Color? = nil) {
17
+ public init(_ url: String, aspectRatio: CGFloat? = nil, contentMode: ContentMode = ContentMode.fit, placeholder: AnyView? = nil, color: Color? = nil, loading: Bool = true, onStateChanged: ((ImageState) -> Void)? = nil) {
12
18
  self.url = url
13
19
  self.aspectRatio = aspectRatio
14
20
  self.contentMode = contentMode
15
21
  self.placeholder = placeholder
16
22
  self.color = color
23
+ self.loading = loading
24
+ self.onStateChanged = onStateChanged
17
25
  }
18
26
 
19
27
  // MARK: Public
@@ -22,9 +30,11 @@ public struct ImageView: View {
22
30
  return WebImage(url: URL(string: url), isAnimating: .constant(true))
23
31
  .onFailure { _ in
24
32
  error = true
33
+ onStateChanged?(.error)
25
34
  }
26
35
  .onSuccess { _, _, _ in
27
36
  error = false
37
+ onStateChanged?(.success)
28
38
  }
29
39
  .resizable()
30
40
  .renderingMode(color != nil ? .template : .original)
@@ -34,20 +44,21 @@ public struct ImageView: View {
34
44
  Image("media_fail")
35
45
  .resizable()
36
46
  .renderingMode(.template)
37
- .foregroundColor(Colors.black08)
47
+ .foregroundColor(theme.colors.text.disable)
38
48
  .frame(width: 24, height: 24)
39
49
  } else if placeholder != nil {
40
50
  placeholder
41
51
  }
42
52
  })
43
53
  .frame(maxWidth: .infinity, maxHeight: .infinity)
44
- .skeleton(with: !error && placeholder == nil)
54
+ .skeleton(with: loading && !error && placeholder == nil)
45
55
  .shape(type: .rectangle)
46
56
  }
47
57
  .scaledToFit()
48
58
  .transition(.fade)
49
59
  .aspectRatio(aspectRatio, contentMode: contentMode)
50
60
  .foregroundColor(color)
61
+ .onAppear { onStateChanged?(.loading) }
51
62
  }
52
63
 
53
64
  // MARK: Internal
@@ -56,6 +67,8 @@ public struct ImageView: View {
56
67
  var contentMode: ContentMode
57
68
  var placeholder: AnyView?
58
69
  var color: Color?
70
+ var loading: Bool
71
+ var onStateChanged: ((ImageState) -> Void)?
59
72
 
60
73
  @State var error: Bool = false
61
74
  var url: String
@@ -7,6 +7,8 @@ public enum InformationState {
7
7
  }
8
8
 
9
9
  public struct Information: View {
10
+ @Environment(\.appTheme) private var theme
11
+
10
12
  private let title: String?
11
13
  private let description: String
12
14
  private let state: InformationState
@@ -93,7 +95,7 @@ public struct Information: View {
93
95
  .frame(maxWidth: .infinity, alignment: .leading)
94
96
 
95
97
  if let onPressClose, showIconClose {
96
- Icon(source: "navigation_close", size: 16, color: Colors.black17)
98
+ Icon(source: "navigation_close", size: 16, color: theme.colors.text.default)
97
99
  .contentShape(Rectangle())
98
100
  .onTapGesture(perform: onPressClose)
99
101
  }
@@ -8,6 +8,8 @@
8
8
  import SwiftUI
9
9
 
10
10
  public struct ErrorView: View {
11
+ @Environment(\.appTheme) private var theme
12
+
11
13
  public var errorMessage: String
12
14
  public var errorSpacing: Bool
13
15
  public var hintText: String
@@ -43,7 +45,7 @@ public struct ErrorView: View {
43
45
  // MARK: - Helpers
44
46
 
45
47
  private func displayColor() -> Color {
46
- !errorMessage.isEmpty ? Colors.red03 : Colors.black12
48
+ !errorMessage.isEmpty ? theme.colors.error.primary : theme.colors.text.hint
47
49
  }
48
50
 
49
51
  private func displayText() -> String {