@momo-kits/native-kits 0.162.2-beta.1 → 0.162.2-sp.1-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 (295) hide show
  1. package/.claude/settings.local.json +55 -0
  2. package/build.gradle.kts +11 -0
  3. package/compose/build.gradle.kts +186 -0
  4. package/compose/build.gradle.kts.backup +186 -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/Platform.android.kt +123 -0
  8. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  9. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  10. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  11. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  12. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  13. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  14. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  19. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  20. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  21. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +57 -0
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +109 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +201 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +222 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +48 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +305 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +921 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +121 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +403 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +85 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +340 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +198 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +357 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +123 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +94 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +136 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +224 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +76 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +148 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +188 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +116 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +452 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +172 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +255 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +235 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +233 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +259 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +241 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +364 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +92 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +352 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +103 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +338 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +70 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +17 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +96 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +348 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +256 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +494 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +131 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +215 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +96 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +531 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +92 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +135 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +214 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +590 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +177 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +192 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +205 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +239 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +191 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +16 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +188 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +285 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +57 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +68 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +14 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +50 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +253 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +133 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +104 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +145 -0
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +345 -0
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +8 -0
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +556 -0
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +161 -0
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +243 -0
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +187 -0
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +315 -0
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +80 -0
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +306 -0
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +34 -0
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +370 -0
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +131 -0
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +167 -0
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +72 -0
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +66 -0
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +70 -0
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +15 -0
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +105 -0
  127. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +33 -0
  128. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +186 -0
  129. package/gradle/libs.versions.toml +67 -0
  130. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  131. package/gradle/wrapper/gradle-wrapper.properties +8 -0
  132. package/gradle.properties +26 -0
  133. package/gradlew +252 -0
  134. package/gradlew.bat +94 -0
  135. package/ios/Application/Components.swift +34 -43
  136. package/ios/Application/FloatingButton.swift +10 -8
  137. package/ios/Application/Navigation/BottomTab/BottomTab.swift +102 -0
  138. package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +215 -0
  139. package/ios/Application/Navigation/BottomTab/CurvedContainer.swift +65 -0
  140. package/ios/Application/Navigation/HeaderBackProps.swift +66 -0
  141. package/ios/Application/Navigation/HeaderTitle.swift +57 -0
  142. package/ios/Application/Navigation/HeaderUser.swift +209 -0
  143. package/ios/Application/Navigation/NavigationContainer.swift +151 -0
  144. package/ios/Application/Navigation/NavigationOptions.swift +109 -0
  145. package/ios/Application/Navigation/Navigator.swift +360 -0
  146. package/ios/Application/Navigation/Overplay/BottomSheet.swift +176 -0
  147. package/ios/Application/Navigation/Overplay/ModalScreen.swift +68 -0
  148. package/ios/Application/Navigation/Overplay/SnackBar.swift +144 -0
  149. package/ios/Application/Navigation/component/Header.swift +178 -0
  150. package/ios/Application/Navigation/component/HeaderBackground.swift +83 -0
  151. package/ios/Application/Navigation/component/HeaderColor.swift +65 -0
  152. package/ios/Application/StackScreen.swift +449 -0
  153. package/ios/Avatar/Avatar.swift +193 -0
  154. package/ios/Badge/Badge.swift +11 -13
  155. package/ios/Badge/BadgeRibbon.swift +12 -19
  156. package/ios/BaselineView/BaselineView.swift +163 -0
  157. package/ios/Button/Button.swift +62 -23
  158. package/ios/Carousel/Carousel.swift +181 -0
  159. package/ios/Checkbox/Checkbox.swift +14 -12
  160. package/ios/Chip/Chip.swift +23 -9
  161. package/ios/Collapse/Collapse.swift +182 -0
  162. package/ios/Colors+Radius+Spacing/Colors.swift +1 -1
  163. package/ios/Colors+Radius+Spacing/Theme.swift +295 -0
  164. package/ios/DateTimePicker/DateTimePicker.swift +210 -0
  165. package/ios/DateTimePicker/DateTimePickerTypes.swift +55 -0
  166. package/ios/DateTimePicker/DateTimePickerUtils.swift +167 -0
  167. package/ios/DateTimePicker/WheelPicker.swift +161 -0
  168. package/ios/Divider/Divider.swift +16 -0
  169. package/ios/Icon/Icon.swift +6 -1
  170. package/ios/IconButton/IconButton.swift +112 -0
  171. package/ios/Information/Information.swift +151 -0
  172. package/ios/Input/Input.swift +42 -25
  173. package/ios/Input/InputPhoneNumber.swift +21 -19
  174. package/ios/Input/InputSearch.swift +101 -45
  175. package/ios/Input/InputTextArea.swift +67 -40
  176. package/ios/InputDropDown/InputDropDown.swift +198 -0
  177. package/ios/InputMoney/InputMoney.swift +335 -0
  178. package/ios/InputOTP/InputOTP.swift +210 -0
  179. package/ios/Loader/Loader.swift +113 -0
  180. package/ios/MoMoUIKits.podspec +5 -0
  181. package/ios/OTPKeyboard/KeyboardButton.swift +1 -1
  182. package/ios/Pagination/PaginationDot.swift +61 -0
  183. package/ios/Pagination/PaginationNumber.swift +35 -0
  184. package/ios/Pagination/PaginationScroll.swift +101 -0
  185. package/ios/Pagination/PaginationWhiteDot.swift +37 -0
  186. package/ios/Popup/PopupDisplay.swift +10 -12
  187. package/ios/Popup/PopupInput.swift +2 -6
  188. package/ios/Popup/PopupNotify.swift +219 -0
  189. package/ios/ProgressInfo/ProgressInfo.swift +294 -0
  190. package/ios/Radio/Radio.swift +70 -0
  191. package/ios/Rating/Rating.swift +82 -0
  192. package/ios/Skeleton/Skeleton.swift +99 -0
  193. package/ios/Slider/Slider.swift +237 -0
  194. package/ios/Stepper/Stepper.swift +220 -0
  195. package/ios/Steps/Steps.swift +451 -0
  196. package/ios/SuggestAction/SuggestAction.swift +97 -0
  197. package/ios/Swipeable/SwipeCell.swift +185 -0
  198. package/ios/Swipeable/SwipeCellModel.swift +21 -0
  199. package/ios/TabView/TabView.swift +530 -0
  200. package/ios/Tag/Tag.swift +98 -0
  201. package/ios/Template/TrustBanner/TrustBanner.swift +2 -0
  202. package/ios/Title/Title.swift +269 -0
  203. package/ios/Tooltip/Tooltip.swift +482 -0
  204. package/ios/Typography/Text.swift +86 -24
  205. package/ios/Typography/Typography.swift +31 -6
  206. package/ios/Uploader/Uploader.swift +183 -0
  207. package/ios/native-kits.podspec +58 -8
  208. package/ios-demo/MoMoUIKitsDemo.podspec +18 -0
  209. package/ios-demo/README.md +120 -0
  210. package/ios-demo/Resources/dot_loading.json +558 -0
  211. package/ios-demo/Resources/icon.json +4052 -0
  212. package/ios-demo/Resources/lottie_circle_loader.json +1 -0
  213. package/ios-demo/Sources/MoMoUIKitsDemo/DemoScaffold.swift +48 -0
  214. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsBadgeDemoView.swift +25 -0
  215. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsButtonDemoView.swift +26 -0
  216. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsCheckboxDemoView.swift +19 -0
  217. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsChipDemoView.swift +33 -0
  218. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsInputDemoView.swift +48 -0
  219. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsPopupDemoView.swift +21 -0
  220. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsRadioDemoView.swift +17 -0
  221. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsTypographyDemoView.swift +28 -0
  222. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoContext.swift +31 -0
  223. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoFactory.swift +72 -0
  224. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AnimatedHeaderDemo.swift +110 -0
  225. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +93 -0
  226. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +269 -0
  227. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BaselineView.swift +117 -0
  228. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BottomTabDemo.swift +89 -0
  229. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +100 -0
  230. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +126 -0
  231. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +63 -0
  232. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +20 -0
  233. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +93 -0
  234. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +107 -0
  235. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +124 -0
  236. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +14 -0
  237. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/HeaderUserDemo.swift +49 -0
  238. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +261 -0
  239. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +58 -0
  240. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +78 -0
  241. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +138 -0
  242. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +111 -0
  243. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +136 -0
  244. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +107 -0
  245. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +73 -0
  246. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +100 -0
  247. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +32 -0
  248. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +57 -0
  249. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +70 -0
  250. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +227 -0
  251. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +72 -0
  252. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +175 -0
  253. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +121 -0
  254. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +76 -0
  255. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +89 -0
  256. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +32 -0
  257. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +56 -0
  258. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +32 -0
  259. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +150 -0
  260. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +138 -0
  261. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +103 -0
  262. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +94 -0
  263. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +79 -0
  264. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +152 -0
  265. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +33 -0
  266. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +190 -0
  267. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +34 -0
  268. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +182 -0
  269. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +109 -0
  270. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +187 -0
  271. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +87 -0
  272. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +131 -0
  273. package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +50 -0
  274. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
  275. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
  276. package/local.properties +8 -0
  277. package/package.json +1 -1
  278. package/publish.sh +50 -0
  279. package/scripts/gen-ios-color.mjs +136 -0
  280. package/settings.gradle.kts +64 -0
  281. package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Example.xcscheme +0 -32
  282. package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  283. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  284. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/WorkspaceSettings.xcsettings +0 -16
  285. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
  286. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +0 -5
  287. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
  288. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
  289. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImage.xcscheme +0 -58
  290. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +0 -58
  291. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SkeletonUI.xcscheme +0 -58
  292. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios-LottiePrivacyInfo.xcscheme +0 -58
  293. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios.xcscheme +0 -58
  294. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +0 -60
  295. package/ios/Typography/MomoFontScale.swift +0 -36
@@ -0,0 +1,176 @@
1
+ //
2
+ // BottomSheet.swift
3
+ // MoMoUIKits
4
+ //
5
+ // SwiftUI mirror of Compose's `BottomSheet` (navigation/BottomSheet.kt).
6
+ // A sheet that slides up from the bottom over a dimmed scrim, with a drag
7
+ // handle, a header (title or custom), a divider and the content body.
8
+ // Dragging down past a threshold (or tapping the scrim) dismisses it.
9
+ // Driven by `Navigator.showBottomSheet`.
10
+ //
11
+
12
+ import SwiftUI
13
+
14
+ // MARK: - Header model
15
+
16
+ /// Mirrors Compose's `sealed class BottomHeader` (Title / Custom).
17
+ public struct BottomSheetHeader {
18
+ enum Style {
19
+ case title(String)
20
+ case custom(() -> AnyView)
21
+ }
22
+
23
+ let style: Style
24
+
25
+ /// Mirrors `BottomHeader.Title`.
26
+ public static func title(_ text: String = "Bottom Sheet Title") -> BottomSheetHeader {
27
+ BottomSheetHeader(style: .title(text))
28
+ }
29
+
30
+ /// Mirrors `BottomHeader.Custom`.
31
+ public static func custom<V: View>(@ViewBuilder _ content: @escaping () -> V) -> BottomSheetHeader {
32
+ BottomSheetHeader(style: .custom({ AnyView(content()) }))
33
+ }
34
+ }
35
+
36
+ // MARK: - Bottom sheet view
37
+
38
+ @available(iOS 16.0, *)
39
+ struct BottomSheetView<Content: View>: View {
40
+ let header: BottomSheetHeader
41
+ let isSurface: Bool
42
+ let barrierDismissible: Bool
43
+ let content: () -> Content
44
+
45
+ @EnvironmentObject private var navigator: Navigator
46
+
47
+ /// Vertical translation of the sheet; starts off-screen and animates to 0.
48
+ @State private var sheetOffset: CGFloat = UIScreen.main.bounds.height
49
+ @State private var scrimAlpha: CGFloat = 0
50
+ @State private var sheetHeight: CGFloat = 0
51
+ @State private var didAppear = false
52
+
53
+ /// Mirrors Compose's `sheetCloseOffset` (100dp drag threshold to dismiss).
54
+ private let closeThreshold: CGFloat = 100
55
+
56
+ private var screenHeight: CGFloat { UIScreen.main.bounds.height }
57
+
58
+ private var backgroundColor: Color {
59
+ // Compose uses background.surface (white) for `isSurface`, otherwise
60
+ // background.default. Both resolve to white in the current iOS palette.
61
+ isSurface ? Colors.black01 : Colors.black01
62
+ }
63
+
64
+ var body: some View {
65
+ ZStack(alignment: .bottom) {
66
+ // Dimmed scrim (max 0.3 alpha, mirrors Compose).
67
+ Color.black.opacity(scrimAlpha)
68
+ .ignoresSafeArea()
69
+ .contentShape(Rectangle())
70
+ .onTapGesture {
71
+ if barrierDismissible { close() }
72
+ }
73
+
74
+ sheet
75
+ .offset(y: sheetOffset)
76
+ }
77
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
78
+ .onAppear {
79
+ guard !didAppear else { return }
80
+ didAppear = true
81
+ navigator.registerOverplayDismiss { close() }
82
+ open()
83
+ }
84
+ }
85
+
86
+ private var sheet: some View {
87
+ VStack(spacing: 0) {
88
+ // Drag handle + header (the draggable region).
89
+ VStack(spacing: 0) {
90
+ Spacer().frame(height: 8)
91
+ Capsule()
92
+ .fill(Colors.black06)
93
+ .frame(width: 40, height: 4)
94
+ Spacer().frame(height: 4)
95
+ headerView
96
+ .frame(height: 56)
97
+ .padding(.horizontal, Spacing.M)
98
+ }
99
+ .frame(maxWidth: .infinity)
100
+ .frame(height: 72)
101
+ .contentShape(Rectangle())
102
+ .gesture(dragGesture)
103
+
104
+ Rectangle()
105
+ .fill(Colors.black04)
106
+ .frame(height: 1)
107
+
108
+ content()
109
+ }
110
+ .frame(maxWidth: .infinity)
111
+ .frame(maxHeight: screenHeight - safeAreaTopInset() - 90, alignment: .bottom)
112
+ .background(
113
+ GeometryReader { geo in
114
+ Color.clear.onAppear { sheetHeight = geo.size.height }
115
+ }
116
+ )
117
+ .background(backgroundColor)
118
+ .clipShape(RoundedCorner(radius: Radius.M, corners: [.topLeft, .topRight]))
119
+ }
120
+
121
+ @ViewBuilder
122
+ private var headerView: some View {
123
+ switch header.style {
124
+ case .title(let text):
125
+ HStack(spacing: 0) {
126
+ Color.clear.frame(width: 24, height: 24)
127
+ MomoText(text, typography: .headerDefaultBold, color: Colors.black17)
128
+ .frame(maxWidth: .infinity, alignment: .center)
129
+ Icon(source: "navigation_close", size: 24, color: Colors.black17)
130
+ .frame(width: 24, height: 24)
131
+ .contentShape(Rectangle())
132
+ .onTapGesture { close() }
133
+ }
134
+ case .custom(let builder):
135
+ builder()
136
+ }
137
+ }
138
+
139
+ // MARK: - Drag handling (mirrors Compose's detectDragGestures)
140
+
141
+ private var dragGesture: some Gesture {
142
+ DragGesture()
143
+ .onChanged { value in
144
+ let newOffset = max(value.translation.height, 0)
145
+ sheetOffset = newOffset
146
+ }
147
+ .onEnded { _ in
148
+ if sheetOffset > closeThreshold {
149
+ close()
150
+ } else {
151
+ withAnimation(.spring(response: 0.3, dampingFraction: 0.9)) {
152
+ sheetOffset = 0
153
+ }
154
+ }
155
+ }
156
+ }
157
+
158
+ // MARK: - Open / close animations
159
+
160
+ private func open() {
161
+ DispatchQueue.main.async {
162
+ withAnimation(.easeOut(duration: 0.1)) { scrimAlpha = 0.3 }
163
+ withAnimation(.timingCurve(0.05, 0.7, 0.1, 1, duration: 0.35)) { sheetOffset = 0 }
164
+ }
165
+ }
166
+
167
+ private func close() {
168
+ withAnimation(.timingCurve(0.3, 0, 0.8, 0.15, duration: 0.2)) {
169
+ sheetOffset = max(sheetHeight, screenHeight)
170
+ scrimAlpha = 0
171
+ }
172
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
173
+ navigator.finishOverplayDismiss()
174
+ }
175
+ }
176
+ }
@@ -0,0 +1,68 @@
1
+ //
2
+ // ModalScreen.swift
3
+ // MoMoUIKits
4
+ //
5
+ // SwiftUI mirror of Compose's `ModalScreen` (navigation/ModalScreen.kt).
6
+ // A centered overlay that fades + scales in over a dimmed scrim, and animates
7
+ // back out before the overplay is removed. Driven by `Navigator.showModal`.
8
+ //
9
+
10
+ import SwiftUI
11
+
12
+ @available(iOS 16.0, *)
13
+ struct ModalScreen<Content: View>: View {
14
+ let barrierDismissible: Bool
15
+ let content: () -> Content
16
+
17
+ @EnvironmentObject private var navigator: Navigator
18
+
19
+ @State private var scrimOpacity: CGFloat = 0
20
+ @State private var contentScale: CGFloat = 0.8
21
+ @State private var contentOpacity: CGFloat = 0
22
+ @State private var didAppear = false
23
+
24
+ var body: some View {
25
+ ZStack {
26
+ // Dimmed scrim (mirrors `Color.Black.copy(alpha = 0.6f * alpha)`).
27
+ Color.black.opacity(0.6 * scrimOpacity)
28
+ .ignoresSafeArea()
29
+ .contentShape(Rectangle())
30
+ .onTapGesture {
31
+ if barrierDismissible { navigator.hideOverplay() }
32
+ }
33
+
34
+ content()
35
+ .scaleEffect(contentScale)
36
+ .opacity(contentOpacity)
37
+ }
38
+ .onAppear {
39
+ guard !didAppear else { return }
40
+ didAppear = true
41
+ navigator.registerOverplayDismiss { close() }
42
+ open()
43
+ }
44
+ }
45
+
46
+ // Mirrors Compose's `openEvent`: 250ms fade + scale to 1.
47
+ private func open() {
48
+ DispatchQueue.main.async {
49
+ withAnimation(.easeOut(duration: 0.25)) {
50
+ scrimOpacity = 1
51
+ contentScale = 1
52
+ contentOpacity = 1
53
+ }
54
+ }
55
+ }
56
+
57
+ // Mirrors Compose's `closeEvent`: 200ms fade + scale back to 0.8, then remove.
58
+ private func close() {
59
+ withAnimation(.easeIn(duration: 0.2)) {
60
+ scrimOpacity = 0
61
+ contentScale = 0.8
62
+ contentOpacity = 0
63
+ }
64
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
65
+ navigator.finishOverplayDismiss()
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,144 @@
1
+ //
2
+ // SnackBar.swift
3
+ // MoMoUIKits
4
+ //
5
+ // SwiftUI mirror of Compose's `SnackBar` (navigation/component/SnackBar.kt).
6
+ // A snack bar slides up from the bottom (just above the footer / home
7
+ // indicator), stays for `duration`, then slides back down and is removed.
8
+ // `Navigator.showSnackBar(_:)` drives it through the overplay host.
9
+ //
10
+
11
+ import Foundation
12
+ import SwiftUI
13
+
14
+ // MARK: - SnackBar model
15
+
16
+ /// Mirrors Compose's `sealed class SnackBar` (Custom / Toast). A `nil` duration
17
+ /// keeps the snack bar on screen until dismissed manually.
18
+ public struct SnackBar {
19
+ public enum Style {
20
+ case custom
21
+ case toast
22
+ }
23
+
24
+ public let style: Style
25
+ public let duration: TimeInterval?
26
+ public let content: (() -> AnyView)?
27
+
28
+ private init(style: Style, duration: TimeInterval?, content: (() -> AnyView)?) {
29
+ self.style = style
30
+ self.duration = duration
31
+ self.content = content
32
+ }
33
+
34
+ /// Mirrors `SnackBar.Custom`: renders arbitrary content.
35
+ public static func custom<V: View>(
36
+ duration: TimeInterval? = 3.0,
37
+ @ViewBuilder content: @escaping () -> V
38
+ ) -> SnackBar {
39
+ SnackBar(style: .custom, duration: duration, content: { AnyView(content()) })
40
+ }
41
+
42
+ /// Mirrors `SnackBar.Toast`: a placeholder with no custom content (parity with
43
+ /// Compose where `Toast` currently renders nothing).
44
+ public static func toast(duration: TimeInterval? = 3.0) -> SnackBar {
45
+ SnackBar(style: .toast, duration: duration, content: nil)
46
+ }
47
+ }
48
+
49
+ // MARK: - SnackBar host view
50
+
51
+ /// Self-animating container. Slides the content up on appear, schedules an
52
+ /// auto-dismiss after `duration`, and animates out before removing the overplay.
53
+ @available(iOS 16.0, *)
54
+ struct SnackBarView: View {
55
+ let snackBar: SnackBar
56
+ /// Bottom inset so the bar sits above the footer / home indicator
57
+ /// (mirrors Compose's `footerHeight` offset).
58
+ let bottomInset: CGFloat
59
+
60
+ @EnvironmentObject private var navigator: Navigator
61
+
62
+ @State private var contentHeight: CGFloat = 0
63
+ @State private var offsetY: CGFloat = 0
64
+ @State private var didAppear = false
65
+ @State private var isClosing = false
66
+ @State private var autoDismissWorkItem: DispatchWorkItem?
67
+
68
+ var body: some View {
69
+ VStack(spacing: 0) {
70
+ Spacer(minLength: 0)
71
+ content
72
+ .background(
73
+ GeometryReader { geo in
74
+ Color.clear.onAppear { contentHeight = geo.size.height }
75
+ }
76
+ )
77
+ .offset(y: offsetY)
78
+ .padding(.bottom, bottomInset)
79
+ }
80
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
81
+ .onAppear {
82
+ guard !didAppear else { return }
83
+ didAppear = true
84
+ offsetY = max(contentHeight, 200) + bottomInset
85
+ open()
86
+ registerClose()
87
+ scheduleAutoDismiss()
88
+ }
89
+ .onDisappear {
90
+ autoDismissWorkItem?.cancel()
91
+ autoDismissWorkItem = nil
92
+ }
93
+ }
94
+
95
+ @ViewBuilder
96
+ private var content: some View {
97
+ switch snackBar.style {
98
+ case .custom:
99
+ snackBar.content?()
100
+ case .toast:
101
+ EmptyView()
102
+ }
103
+ }
104
+
105
+ // Mirrors Compose's `openEvent`: 350ms slide up.
106
+ private func open() {
107
+ DispatchQueue.main.async {
108
+ withAnimation(.easeOut(duration: 0.35)) {
109
+ offsetY = 0
110
+ }
111
+ }
112
+ }
113
+
114
+ // Animated slide down, then remove (mirrors Compose's `closeEvent`/`hideSnackBar`).
115
+ private func close() {
116
+ guard !isClosing else { return }
117
+ isClosing = true
118
+ autoDismissWorkItem?.cancel()
119
+ autoDismissWorkItem = nil
120
+
121
+ withAnimation(.easeIn(duration: 0.2)) {
122
+ offsetY = max(contentHeight, 200) + bottomInset
123
+ }
124
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
125
+ navigator.finishOverplayDismiss()
126
+ }
127
+ }
128
+
129
+ private func registerClose() {
130
+ navigator.registerOverplayDismiss { close() }
131
+ }
132
+
133
+ private func scheduleAutoDismiss() {
134
+ guard let duration = snackBar.duration else { return }
135
+ let workItem = DispatchWorkItem {
136
+ // Only auto-dismiss if this snack bar is still the active overplay.
137
+ if navigator.overplay?.type == .snackBar {
138
+ navigator.hideSnackBar()
139
+ }
140
+ }
141
+ autoDismissWorkItem = workItem
142
+ DispatchQueue.main.asyncAfter(deadline: .now() + duration, execute: workItem)
143
+ }
144
+ }
@@ -0,0 +1,178 @@
1
+ //
2
+ // Header.swift
3
+ // MoMoUIKits
4
+ //
5
+ // SwiftUI mirror of Compose's `Header` (navigation/component/Header.kt).
6
+ // Renders the 52pt header bar: a circular back button (colors resolved via
7
+ // `getHeaderColor`), the title area (`HeaderContent` → plain title, user title
8
+ // or inline search), the header-right toolkit, and a scroll-triggered bottom
9
+ // shadow. The header band background itself is painted by `HeaderBackground`.
10
+ //
11
+ // Named `NavigationHeader` to coexist with the legacy `Header` in
12
+ // `Components.swift` (kept as-is, used as a package elsewhere; to be marked
13
+ // deprecated later). Used by the new `StackScreen` navigation path.
14
+ //
15
+
16
+ import SwiftUI
17
+
18
+ public struct NavigationHeader: View {
19
+ var headerType: HeaderType = .default
20
+ var titlePosition: TitlePosition
21
+ var title: String
22
+ /// Optional rich title (mirrors Compose's `HeaderTitle`); `.user` renders an
23
+ /// avatar group, `.default`/nil renders plain `title`.
24
+ var headerTitle: HeaderTitle?
25
+ var headerRight: (() -> any View)? = { HeaderRight() }
26
+ var goBack: (() -> Void)?
27
+ var opacity: CGFloat = 1
28
+ var animatedHeader: AnimatedHeader?
29
+ var scrollState: CGFloat = 0
30
+ var inputSearchProps: InputSearchProps?
31
+ var tintColor: Color?
32
+ /// Title opacity; used by the animated search header to fade the title out on scroll.
33
+ var titleOpacity: CGFloat = 1
34
+
35
+ public init(
36
+ headerType: HeaderType = .default,
37
+ titlePosition: TitlePosition,
38
+ title: String,
39
+ headerTitle: HeaderTitle? = nil,
40
+ headerRight: (() -> any View)? = { HeaderRight() },
41
+ goBack: (() -> Void)? = nil,
42
+ opacity: CGFloat = 1,
43
+ animatedHeader: AnimatedHeader? = nil,
44
+ scrollState: CGFloat = 0,
45
+ inputSearchProps: InputSearchProps? = nil,
46
+ tintColor: Color? = nil,
47
+ titleOpacity: CGFloat = 1
48
+ ) {
49
+ self.headerType = headerType
50
+ self.titlePosition = titlePosition
51
+ self.title = title
52
+ self.headerTitle = headerTitle
53
+ self.headerRight = headerRight
54
+ self.goBack = goBack
55
+ self.opacity = opacity
56
+ self.animatedHeader = animatedHeader
57
+ self.scrollState = scrollState
58
+ self.inputSearchProps = inputSearchProps
59
+ self.tintColor = tintColor
60
+ self.titleOpacity = titleOpacity
61
+ }
62
+
63
+ private var isAnimated: Bool { animatedHeader != nil }
64
+ private var isSurface: Bool { animatedHeader?.isSurface ?? true }
65
+
66
+ private var headerColor: HeaderColor {
67
+ getHeaderColor(isAnimated: isAnimated, isSurface: isSurface, opacity: opacity, tintColor: tintColor)
68
+ }
69
+
70
+ /// Centered title needs a full-width overlay to stay screen-centered, not
71
+ /// boxed between the back button and the header-right (mirrors Compose).
72
+ private var centerTitle: Bool {
73
+ guard inputSearchProps == nil else { return false }
74
+ let isDefault = headerTitle == nil || headerTitle?.defaultTitle != nil
75
+ return titlePosition == .center && isDefault
76
+ }
77
+
78
+ public var body: some View {
79
+ if headerType != .none {
80
+ ZStack {
81
+ HStack(spacing: 0) {
82
+ if let goBack {
83
+ BackButton(color: headerColor, onBack: goBack)
84
+ Spacer().frame(width: Spacing.S)
85
+ }
86
+
87
+ if centerTitle {
88
+ Spacer()
89
+ } else {
90
+ titleArea(centered: false)
91
+ .frame(maxWidth: .infinity, alignment: .leading)
92
+ }
93
+
94
+ if let headerRight {
95
+ AnyView(headerRight())
96
+ .background(
97
+ GeometryReader { geo in
98
+ Color.clear.preference(key: HeaderRightWidthKey.self, value: geo.size.width)
99
+ }
100
+ )
101
+ }
102
+ }
103
+ .padding(.horizontal, Spacing.M)
104
+
105
+ if centerTitle {
106
+ titleArea(centered: true)
107
+ .padding(.horizontal, Spacing.M)
108
+ }
109
+ }
110
+ .frame(height: HEADER_HEIGHT)
111
+ .overlay(alignment: .bottom) { VerticalShadow(opacity: opacity) }
112
+ }
113
+ }
114
+
115
+ /// Mirrors Compose's `HeaderContent`: plain title, user title, or — when a
116
+ /// header search is active — the inline search field.
117
+ @ViewBuilder
118
+ private func titleArea(centered: Bool) -> some View {
119
+ if let inputSearchProps {
120
+ InputSearch(props: inputSearchProps)
121
+ } else if case let .user(userData)? = headerTitle {
122
+ if #available(iOS 16.0, *) {
123
+ HeaderUserView(userData)
124
+ }
125
+ } else {
126
+ MomoText(
127
+ headerTitle?.defaultTitle ?? title,
128
+ typography: .actionSBold,
129
+ color: headerColor.tintIconColor,
130
+ textAlign: centered ? .center : .leading,
131
+ maxLines: 1
132
+ )
133
+ .opacity(titleOpacity)
134
+ .truncationMode(.tail)
135
+ .frame(maxWidth: centered ? .infinity : nil, alignment: centered ? .center : .leading)
136
+ }
137
+ }
138
+ }
139
+
140
+ // MARK: - Back button
141
+
142
+ /// Mirrors Compose's `BackButton`: a 28pt circular control with the back arrow.
143
+ private struct BackButton: View {
144
+ let color: HeaderColor
145
+ let onBack: () -> Void
146
+
147
+ var body: some View {
148
+ SwiftUI.Button(action: onBack) {
149
+ Circle()
150
+ .fill(color.backgroundButton)
151
+ .overlay(Circle().stroke(color.borderColor, lineWidth: 0.2))
152
+ .frame(width: 28, height: 28)
153
+ .overlay(Icon(source: "arrow-back", size: 20, color: color.tintIconColor))
154
+ }
155
+ .buttonStyle(.plain)
156
+ }
157
+ }
158
+
159
+ // MARK: - Vertical shadow
160
+
161
+ /// Mirrors Compose's `VerticalShadow`: a 6pt drop shadow under the header that
162
+ /// only appears once the header is fully opaque (scrolled).
163
+ private struct VerticalShadow: View {
164
+ let opacity: CGFloat
165
+
166
+ var body: some View {
167
+ if opacity >= 1 {
168
+ LinearGradient(
169
+ gradient: Gradient(colors: [Color.black.opacity(0.05), .clear]),
170
+ startPoint: .top,
171
+ endPoint: .bottom
172
+ )
173
+ .frame(height: 6)
174
+ .frame(maxWidth: .infinity)
175
+ .offset(y: 6)
176
+ }
177
+ }
178
+ }
@@ -0,0 +1,83 @@
1
+ //
2
+ // HeaderBackground.swift
3
+ // MoMoUIKits
4
+ //
5
+ // SwiftUI mirror of Compose's `HeaderBackground` (navigation/component/HeaderBackground.kt).
6
+ // Paints the header band behind the `Header`: a flat surface for `.default`,
7
+ // the taller pink gradient for `.extended`, fading out as the screen scrolls.
8
+ // Stays transparent when the header is transparent or the content is full-screen.
9
+ //
10
+ // Named `NavigationHeaderBackground` to coexist with the legacy
11
+ // `HeaderBackground` in `Components.swift` (kept as-is, used as a package
12
+ // elsewhere; to be marked deprecated later). Used by the new `StackScreen`.
13
+ //
14
+
15
+ import SwiftUI
16
+
17
+ public struct NavigationHeaderBackground: View {
18
+ var headerType: HeaderType = .default
19
+ var scrollState: CGFloat
20
+ var headerTransparent: Bool = false
21
+ var fullScreenContent: Bool = false
22
+
23
+ public init(
24
+ headerType: HeaderType = .default,
25
+ scrollState: CGFloat = 0,
26
+ headerTransparent: Bool = false,
27
+ fullScreenContent: Bool = false
28
+ ) {
29
+ self.headerType = headerType
30
+ self.scrollState = scrollState
31
+ self.headerTransparent = headerTransparent
32
+ self.fullScreenContent = fullScreenContent
33
+ }
34
+
35
+ private func pinkGradient(topColor: Color, bottomColor: Color) -> LinearGradient {
36
+ LinearGradient(
37
+ gradient: Gradient(colors: [
38
+ topColor,
39
+ bottomColor
40
+ ]),
41
+ startPoint: .top,
42
+ endPoint: .bottom
43
+ )
44
+ }
45
+
46
+ public var body: some View {
47
+ let statusBarHeight = safeAreaTopInset()
48
+ let opacity = max(0, 1 - scrollState / CGFloat(HEADER_HEIGHT))
49
+ let minHeight = fullScreenContent ? 0 : statusBarHeight + HEADER_HEIGHT
50
+ let maxHeight: CGFloat = 154
51
+ let backgroundColor = headerTransparent ? Color.clear : Colors.black01
52
+ let topColor = opacity == 0 ? backgroundColor : Color(hex: 0xFDCADE)
53
+
54
+ Group {
55
+ switch headerType {
56
+ case .default:
57
+ ZStack(alignment: .bottom) {
58
+ backgroundColor
59
+ .frame(height: minHeight)
60
+ if !headerTransparent {
61
+ pinkGradient(topColor: topColor, bottomColor: backgroundColor)
62
+ .frame(height: maxHeight)
63
+ .frame(height: minHeight, alignment: .top)
64
+ .clipped()
65
+ }
66
+ }
67
+
68
+ case .extended:
69
+ ZStack {
70
+ if !headerTransparent {
71
+ backgroundColor
72
+ .frame(height: maxHeight)
73
+ pinkGradient(topColor: topColor, bottomColor: backgroundColor)
74
+ .frame(height: maxHeight)
75
+ }
76
+ }
77
+
78
+ case .none:
79
+ EmptyView()
80
+ }
81
+ }
82
+ }
83
+ }