@momo-kits/native-kits 0.162.2-debug → 0.162.2-sp.1

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 (278) hide show
  1. package/.claude/settings.local.json +55 -0
  2. package/ios/Application/Components.swift +34 -43
  3. package/ios/Application/FloatingButton.swift +10 -8
  4. package/ios/Application/Navigation/BottomTab/BottomTab.swift +102 -0
  5. package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +215 -0
  6. package/ios/Application/Navigation/BottomTab/CurvedContainer.swift +65 -0
  7. package/ios/Application/Navigation/HeaderBackProps.swift +66 -0
  8. package/ios/Application/Navigation/HeaderTitle.swift +57 -0
  9. package/ios/Application/Navigation/HeaderUser.swift +209 -0
  10. package/ios/Application/Navigation/NavigationContainer.swift +151 -0
  11. package/ios/Application/Navigation/NavigationOptions.swift +109 -0
  12. package/ios/Application/Navigation/Navigator.swift +360 -0
  13. package/ios/Application/Navigation/Overplay/BottomSheet.swift +176 -0
  14. package/ios/Application/Navigation/Overplay/ModalScreen.swift +68 -0
  15. package/ios/Application/Navigation/Overplay/SnackBar.swift +144 -0
  16. package/ios/Application/Navigation/component/Header.swift +178 -0
  17. package/ios/Application/Navigation/component/HeaderBackground.swift +83 -0
  18. package/ios/Application/Navigation/component/HeaderColor.swift +65 -0
  19. package/ios/Application/StackScreen.swift +449 -0
  20. package/ios/Avatar/Avatar.swift +193 -0
  21. package/ios/Badge/Badge.swift +11 -13
  22. package/ios/Badge/BadgeRibbon.swift +12 -19
  23. package/ios/BaselineView/BaselineView.swift +163 -0
  24. package/ios/Button/Button.swift +62 -23
  25. package/ios/Carousel/Carousel.swift +181 -0
  26. package/ios/Checkbox/Checkbox.swift +14 -12
  27. package/ios/Chip/Chip.swift +23 -9
  28. package/ios/Collapse/Collapse.swift +182 -0
  29. package/ios/Colors+Radius+Spacing/Colors.swift +1 -1
  30. package/ios/Colors+Radius+Spacing/Theme.swift +295 -0
  31. package/ios/DateTimePicker/DateTimePicker.swift +210 -0
  32. package/ios/DateTimePicker/DateTimePickerTypes.swift +55 -0
  33. package/ios/DateTimePicker/DateTimePickerUtils.swift +167 -0
  34. package/ios/DateTimePicker/WheelPicker.swift +161 -0
  35. package/ios/Divider/Divider.swift +16 -0
  36. package/ios/Icon/Icon.swift +6 -1
  37. package/ios/IconButton/IconButton.swift +112 -0
  38. package/ios/Information/Information.swift +151 -0
  39. package/ios/Input/Input.swift +42 -25
  40. package/ios/Input/InputPhoneNumber.swift +21 -19
  41. package/ios/Input/InputSearch.swift +101 -45
  42. package/ios/Input/InputTextArea.swift +67 -40
  43. package/ios/InputDropDown/InputDropDown.swift +198 -0
  44. package/ios/InputMoney/InputMoney.swift +335 -0
  45. package/ios/InputOTP/InputOTP.swift +210 -0
  46. package/ios/Loader/Loader.swift +113 -0
  47. package/ios/MoMoUIKits.podspec +5 -0
  48. package/ios/OTPKeyboard/KeyboardButton.swift +1 -1
  49. package/ios/Pagination/PaginationDot.swift +61 -0
  50. package/ios/Pagination/PaginationNumber.swift +35 -0
  51. package/ios/Pagination/PaginationScroll.swift +101 -0
  52. package/ios/Pagination/PaginationWhiteDot.swift +37 -0
  53. package/ios/Popup/PopupDisplay.swift +10 -12
  54. package/ios/Popup/PopupInput.swift +2 -6
  55. package/ios/Popup/PopupNotify.swift +219 -0
  56. package/ios/ProgressInfo/ProgressInfo.swift +294 -0
  57. package/ios/Radio/Radio.swift +70 -0
  58. package/ios/Rating/Rating.swift +82 -0
  59. package/ios/Skeleton/Skeleton.swift +99 -0
  60. package/ios/Slider/Slider.swift +237 -0
  61. package/ios/Stepper/Stepper.swift +220 -0
  62. package/ios/Steps/Steps.swift +451 -0
  63. package/ios/SuggestAction/SuggestAction.swift +97 -0
  64. package/ios/Swipeable/SwipeCell.swift +185 -0
  65. package/ios/Swipeable/SwipeCellModel.swift +21 -0
  66. package/ios/TabView/TabView.swift +530 -0
  67. package/ios/Tag/Tag.swift +98 -0
  68. package/ios/Template/TrustBanner/TrustBanner.swift +2 -0
  69. package/ios/Title/Title.swift +269 -0
  70. package/ios/Tooltip/Tooltip.swift +482 -0
  71. package/ios/Typography/Text.swift +77 -5
  72. package/ios/Typography/Typography.swift +9 -0
  73. package/ios/Uploader/Uploader.swift +183 -0
  74. package/ios/native-kits.podspec +58 -8
  75. package/ios-demo/MoMoUIKitsDemo.podspec +18 -0
  76. package/ios-demo/Resources/dot_loading.json +558 -0
  77. package/ios-demo/Resources/icon.json +4052 -0
  78. package/ios-demo/Resources/lottie_circle_loader.json +1 -0
  79. package/ios-demo/Sources/MoMoUIKitsDemo/DemoScaffold.swift +48 -0
  80. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsBadgeDemoView.swift +25 -0
  81. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsButtonDemoView.swift +26 -0
  82. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsCheckboxDemoView.swift +19 -0
  83. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsChipDemoView.swift +33 -0
  84. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsInputDemoView.swift +48 -0
  85. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsPopupDemoView.swift +21 -0
  86. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsRadioDemoView.swift +17 -0
  87. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsTypographyDemoView.swift +28 -0
  88. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoContext.swift +31 -0
  89. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoFactory.swift +72 -0
  90. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AnimatedHeaderDemo.swift +110 -0
  91. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +93 -0
  92. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +269 -0
  93. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BaselineView.swift +117 -0
  94. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BottomTabDemo.swift +89 -0
  95. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +100 -0
  96. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +126 -0
  97. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +63 -0
  98. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +20 -0
  99. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +93 -0
  100. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +107 -0
  101. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +124 -0
  102. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +14 -0
  103. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/HeaderUserDemo.swift +49 -0
  104. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +261 -0
  105. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +58 -0
  106. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +78 -0
  107. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +138 -0
  108. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +111 -0
  109. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +136 -0
  110. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +107 -0
  111. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +73 -0
  112. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +100 -0
  113. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +32 -0
  114. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +57 -0
  115. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +70 -0
  116. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +227 -0
  117. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +72 -0
  118. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +175 -0
  119. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +121 -0
  120. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +76 -0
  121. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +89 -0
  122. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +32 -0
  123. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +56 -0
  124. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +32 -0
  125. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +150 -0
  126. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +138 -0
  127. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +103 -0
  128. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +94 -0
  129. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +79 -0
  130. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +152 -0
  131. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +33 -0
  132. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +190 -0
  133. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +34 -0
  134. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +182 -0
  135. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +109 -0
  136. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +187 -0
  137. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +87 -0
  138. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +131 -0
  139. package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +50 -0
  140. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
  141. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
  142. package/package.json +1 -1
  143. package/publish.sh +50 -0
  144. package/scripts/gen-ios-color.mjs +136 -0
  145. package/build.gradle.kts +0 -11
  146. package/compose/build.gradle.kts +0 -186
  147. package/compose/build.gradle.kts.backup +0 -186
  148. package/compose/compose.podspec +0 -47
  149. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
  150. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -123
  151. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  152. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  153. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  154. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  155. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  156. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  157. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  158. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  159. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  160. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  161. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  162. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  163. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  164. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  165. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -57
  166. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -109
  167. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -201
  168. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -222
  169. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -48
  170. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  171. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  172. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  173. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -305
  174. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  175. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -921
  176. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -121
  177. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -403
  178. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  179. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
  180. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -85
  181. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  182. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -340
  183. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -198
  184. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -357
  185. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -123
  186. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -94
  187. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -136
  188. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -224
  189. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -543
  190. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -23
  191. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
  192. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -148
  193. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -188
  194. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -116
  195. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -452
  196. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -172
  197. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -255
  198. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -235
  199. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -233
  200. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -259
  201. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -241
  202. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -364
  203. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
  204. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  205. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  206. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -92
  207. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  208. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -352
  209. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -103
  210. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -338
  211. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -70
  212. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  213. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -17
  214. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -96
  215. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -348
  216. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -256
  217. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -494
  218. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -131
  219. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -215
  220. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -96
  221. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -531
  222. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -92
  223. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -135
  224. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -214
  225. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -590
  226. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -177
  227. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -192
  228. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -205
  229. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  230. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -239
  231. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -191
  232. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -306
  233. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  234. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  235. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
  236. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -285
  237. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -2
  238. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -35
  239. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -2
  240. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -57
  241. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -68
  242. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  243. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -14
  244. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -50
  245. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  246. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -253
  247. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -133
  248. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -104
  249. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -145
  250. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -345
  251. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  252. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -556
  253. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -161
  254. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -243
  255. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  256. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -187
  257. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -315
  258. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -80
  259. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -306
  260. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -34
  261. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -370
  262. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -131
  263. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -167
  264. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -72
  265. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -66
  266. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  267. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -70
  268. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  269. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -105
  270. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -33
  271. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -186
  272. package/gradle/libs.versions.toml +0 -67
  273. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  274. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  275. package/gradle.properties +0 -26
  276. package/gradlew +0 -252
  277. package/gradlew.bat +0 -94
  278. package/settings.gradle.kts +0 -64
@@ -0,0 +1,360 @@
1
+ //
2
+ // Navigator.swift
3
+ // MoMoUIKits
4
+ //
5
+ // SwiftUI mirror of Compose's Navigator + DynamicScreenRegistry.
6
+ // Screens are registered by Int id; the NavigationStack path stores routes
7
+ // by id and looks up content from the registry on render.
8
+ //
9
+
10
+ import SwiftUI
11
+ import Combine
12
+
13
+ // MARK: - Routes
14
+
15
+ public struct DynamicScreenRoute: Hashable, Identifiable {
16
+ public let id: Int
17
+ }
18
+
19
+ public struct DynamicDialogRoute: Hashable, Identifiable {
20
+ public let id: Int
21
+ }
22
+
23
+ // MARK: - Registry
24
+
25
+ public struct DynamicScreen {
26
+ public let id: Int
27
+ public let name: String
28
+ public let content: () -> AnyView
29
+ public var options: NavigationOptions?
30
+ }
31
+
32
+ public final class DynamicScreenRegistry {
33
+ public static let shared = DynamicScreenRegistry()
34
+
35
+ private var screens: [Int: DynamicScreen] = [:]
36
+ private var idCounter: Int = 1
37
+
38
+ private init() {}
39
+
40
+ @discardableResult
41
+ public func register(
42
+ screenName: String = "",
43
+ content: @escaping () -> AnyView,
44
+ options: NavigationOptions? = nil
45
+ ) -> DynamicScreenRoute {
46
+ let id = idCounter
47
+ idCounter += 1
48
+ screens[id] = DynamicScreen(id: id, name: screenName, content: content, options: options)
49
+ return DynamicScreenRoute(id: id)
50
+ }
51
+
52
+ public func unregister(id: Int) {
53
+ screens.removeValue(forKey: id)
54
+ }
55
+
56
+ public func unregisterAll() {
57
+ screens.removeAll()
58
+ }
59
+
60
+ public func getScreen(id: Int) -> DynamicScreen? { screens[id] }
61
+
62
+ public func latest() -> DynamicScreen? {
63
+ screens.max(by: { $0.key < $1.key })?.value
64
+ }
65
+
66
+ public func setOptions(id: Int, options: NavigationOptions) {
67
+ screens[id]?.options = options
68
+ }
69
+ }
70
+
71
+ // MARK: - Overplay
72
+
73
+ public enum OverplayType {
74
+ case modal, bottomSheet, snackBar
75
+ }
76
+
77
+ public struct OverplayItem: Identifiable {
78
+ public let id = UUID()
79
+ public let type: OverplayType
80
+ public let content: () -> AnyView
81
+ public let barrierDismissible: Bool
82
+ public let onDismiss: (() -> Void)?
83
+ // Bottom-sheet params (mirrors Compose's OverplayComponentParams.BottomSheet).
84
+ public var isSurface: Bool = false
85
+ public var header: BottomSheetHeader? = nil
86
+ // Snack-bar payload (mirrors Compose's SnackBar value).
87
+ public var snackBar: SnackBar? = nil
88
+ }
89
+
90
+ // MARK: - Navigator
91
+
92
+ @available(iOS 16.0, *)
93
+ public final class Navigator: ObservableObject {
94
+ @Published public var path: [DynamicScreenRoute] = []
95
+ @Published public var presented: DynamicDialogRoute?
96
+ @Published public var overplay: OverplayItem?
97
+
98
+ /// Animated-close handler registered by the active overplay component
99
+ /// (mirrors Compose's `OverplayComponentRegistry.bindClose`). When set, a
100
+ /// dismiss request runs the component's exit animation before the item is
101
+ /// actually removed via `finishOverplayDismiss`.
102
+ private var overplayDismissHandler: (() -> Void)?
103
+
104
+ public private(set) var rootRoute: DynamicScreenRoute
105
+
106
+ public init(
107
+ initialScreenName: String = "",
108
+ initialContent: @escaping () -> AnyView,
109
+ options: NavigationOptions? = nil
110
+ ) {
111
+ self.rootRoute = DynamicScreenRegistry.shared.register(
112
+ screenName: initialScreenName,
113
+ content: initialContent,
114
+ options: options
115
+ )
116
+ }
117
+
118
+ // MARK: Stack
119
+
120
+ public func push<V: View>(@ViewBuilder _ content: @escaping () -> V, options: NavigationOptions? = nil) {
121
+ let route = DynamicScreenRegistry.shared.register(
122
+ screenName: options?.screenName ?? "",
123
+ content: { AnyView(content()) },
124
+ options: options
125
+ )
126
+ path.append(route)
127
+ }
128
+
129
+ public func push<V: View>(
130
+ screenName: String,
131
+ @ViewBuilder _ content: @escaping () -> V,
132
+ options: NavigationOptions? = nil
133
+ ) {
134
+ let route = DynamicScreenRegistry.shared.register(
135
+ screenName: screenName,
136
+ content: { AnyView(content()) },
137
+ options: options
138
+ )
139
+ path.append(route)
140
+ }
141
+
142
+ public func replace<V: View>(@ViewBuilder _ content: @escaping () -> V, options: NavigationOptions? = nil) {
143
+ guard !path.isEmpty else { return }
144
+ let removed = path.removeLast()
145
+ DynamicScreenRegistry.shared.unregister(id: removed.id)
146
+ push(content, options: options)
147
+ }
148
+
149
+ public func replace<V: View>(
150
+ screenName: String,
151
+ @ViewBuilder _ content: @escaping () -> V,
152
+ options: NavigationOptions? = nil
153
+ ) {
154
+ guard !path.isEmpty else { return }
155
+ let removed = path.removeLast()
156
+ DynamicScreenRegistry.shared.unregister(id: removed.id)
157
+ push(screenName: screenName, content, options: options)
158
+ }
159
+
160
+ public func reset<V: View>(@ViewBuilder _ content: @escaping () -> V, options: NavigationOptions? = nil) {
161
+ for route in path { DynamicScreenRegistry.shared.unregister(id: route.id) }
162
+ DynamicScreenRegistry.shared.unregister(id: rootRoute.id)
163
+ path.removeAll()
164
+ let route = DynamicScreenRegistry.shared.register(
165
+ screenName: options?.screenName ?? "",
166
+ content: { AnyView(content()) },
167
+ options: options
168
+ )
169
+ rootRoute = route
170
+ }
171
+
172
+ public func reset<V: View>(
173
+ screenName: String,
174
+ @ViewBuilder _ content: @escaping () -> V,
175
+ options: NavigationOptions? = nil
176
+ ) {
177
+ for route in path { DynamicScreenRegistry.shared.unregister(id: route.id) }
178
+ DynamicScreenRegistry.shared.unregister(id: rootRoute.id)
179
+ path.removeAll()
180
+ let route = DynamicScreenRegistry.shared.register(
181
+ screenName: screenName,
182
+ content: { AnyView(content()) },
183
+ options: options
184
+ )
185
+ rootRoute = route
186
+ }
187
+
188
+ public func pop(_ count: Int = 1, callback: (() -> Void)? = nil) {
189
+ var remaining = count
190
+ while remaining > 0 {
191
+ if overplay != nil {
192
+ hideOverplay()
193
+ } else if presented != nil {
194
+ let dismissedId = presented?.id
195
+ presented = nil
196
+ if let id = dismissedId { DynamicScreenRegistry.shared.unregister(id: id) }
197
+ } else if !path.isEmpty {
198
+ let removed = path.removeLast()
199
+ DynamicScreenRegistry.shared.unregister(id: removed.id)
200
+ } else {
201
+ break
202
+ }
203
+ remaining -= 1
204
+ }
205
+ callback?()
206
+ }
207
+
208
+ public func popToRoot() {
209
+ for route in path { DynamicScreenRegistry.shared.unregister(id: route.id) }
210
+ path.removeAll()
211
+ }
212
+
213
+ public func onBackSafe(callback: (() -> Void)? = nil) {
214
+ let latest = DynamicScreenRegistry.shared.latest()
215
+ if let onBack = latest?.options?.onBackHandler {
216
+ onBack()
217
+ return
218
+ }
219
+ if let preventBack = latest?.options?.headerBackProps?.preventBack {
220
+ showModal {
221
+ PopupDisplay(
222
+ isPresented: .constant(true),
223
+ title: preventBack.title,
224
+ description: preventBack.description,
225
+ url: preventBack.image,
226
+ buttonDirection: preventBack.buttonDirection,
227
+ buttonType: .button,
228
+ actionButtonTitle: preventBack.primary?.title ?? "",
229
+ closeButtonTitle: preventBack.secondary?.title ?? "",
230
+ onPressAction: { [weak self] in
231
+ preventBack.primary?.onPress?()
232
+ // Close the popup, then leave the screen (matches Compose's pop(2)).
233
+ self?.pop(2, callback: callback)
234
+ },
235
+ onPressCloseButton: { [weak self] in
236
+ preventBack.secondary?.onPress?()
237
+ self?.hideOverplay()
238
+ },
239
+ onClose: { [weak self] in
240
+ preventBack.onIconClose?()
241
+ self?.hideOverplay()
242
+ },
243
+ errorCode: preventBack.error,
244
+ isShowCloseIcon: preventBack.isShowCloseIcon
245
+ )
246
+ }
247
+ return
248
+ }
249
+ pop(1, callback: callback)
250
+ }
251
+
252
+ // MARK: Modal-style screen (vertical slide)
253
+
254
+ public func present<V: View>(@ViewBuilder _ content: @escaping () -> V, options: NavigationOptions? = nil) {
255
+ let route = DynamicScreenRegistry.shared.register(
256
+ screenName: options?.screenName ?? "",
257
+ content: { AnyView(content()) },
258
+ options: options
259
+ )
260
+ presented = DynamicDialogRoute(id: route.id)
261
+ }
262
+
263
+ public func present<V: View>(
264
+ screenName: String,
265
+ @ViewBuilder _ content: @escaping () -> V,
266
+ options: NavigationOptions? = nil
267
+ ) {
268
+ let route = DynamicScreenRegistry.shared.register(
269
+ screenName: screenName,
270
+ content: { AnyView(content()) },
271
+ options: options
272
+ )
273
+ presented = DynamicDialogRoute(id: route.id)
274
+ }
275
+
276
+ public func dismiss() {
277
+ if let id = presented?.id {
278
+ DynamicScreenRegistry.shared.unregister(id: id)
279
+ }
280
+ presented = nil
281
+ }
282
+
283
+ // MARK: Overplay
284
+
285
+ public func showModal<V: View>(
286
+ @ViewBuilder _ content: @escaping () -> V,
287
+ barrierDismissible: Bool = true,
288
+ onDismiss: (() -> Void)? = nil
289
+ ) {
290
+ overplayDismissHandler = nil
291
+ overplay = OverplayItem(
292
+ type: .modal,
293
+ content: { AnyView(content()) },
294
+ barrierDismissible: barrierDismissible,
295
+ onDismiss: onDismiss
296
+ )
297
+ }
298
+
299
+ public func showBottomSheet<V: View>(
300
+ @ViewBuilder _ content: @escaping () -> V,
301
+ isSurface: Bool = false,
302
+ barrierDismissible: Bool = true,
303
+ header: BottomSheetHeader? = nil,
304
+ onDismiss: (() -> Void)? = nil
305
+ ) {
306
+ overplayDismissHandler = nil
307
+ overplay = OverplayItem(
308
+ type: .bottomSheet,
309
+ content: { AnyView(content()) },
310
+ barrierDismissible: barrierDismissible,
311
+ onDismiss: onDismiss,
312
+ isSurface: isSurface,
313
+ header: header
314
+ )
315
+ }
316
+
317
+ /// Mirrors Compose's `showSnackBar(snackBar:)`.
318
+ public func showSnackBar(_ snackBar: SnackBar, onDismiss: (() -> Void)? = nil) {
319
+ overplayDismissHandler = nil
320
+ overplay = OverplayItem(
321
+ type: .snackBar,
322
+ content: { AnyView(EmptyView()) },
323
+ barrierDismissible: false,
324
+ onDismiss: onDismiss,
325
+ snackBar: snackBar
326
+ )
327
+ }
328
+
329
+ // MARK: Overplay dismissal
330
+
331
+ /// Registered by the active overplay component so external dismiss requests
332
+ /// run its exit animation (mirrors Compose's `bindClose`).
333
+ public func registerOverplayDismiss(_ handler: @escaping () -> Void) {
334
+ overplayDismissHandler = handler
335
+ }
336
+
337
+ /// Removes the overplay and fires its `onDismiss` (mirrors Compose's
338
+ /// `hardClearAfterDismiss`). Called by a component once its exit animation
339
+ /// has completed.
340
+ public func finishOverplayDismiss() {
341
+ let dismissCallback = overplay?.onDismiss
342
+ overplayDismissHandler = nil
343
+ overplay = nil
344
+ dismissCallback?()
345
+ }
346
+
347
+ public func hideOverplay() {
348
+ if let close = overplayDismissHandler {
349
+ // Component runs its exit animation, then calls finishOverplayDismiss.
350
+ overplayDismissHandler = nil
351
+ close()
352
+ } else {
353
+ finishOverplayDismiss()
354
+ }
355
+ }
356
+
357
+ public func hideSnackBar() {
358
+ if overplay?.type == .snackBar { hideOverplay() }
359
+ }
360
+ }
@@ -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
+ }