@momo-kits/native-kits 0.167.1-duo.2-debug → 0.167.1-duo.20

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 (266) hide show
  1. package/CLAUDE.md +36 -8
  2. package/README.md +2 -2
  3. package/ios/Application/ApplicationEnvironment.swift +17 -0
  4. package/ios/Application/MaxApi.swift +12 -3
  5. package/ios/Avatar/Avatar.swift +4 -3
  6. package/ios/Badge/Badge.swift +6 -4
  7. package/ios/Badge/BadgeDot.swift +1 -1
  8. package/ios/Badge/BadgeRibbon.swift +0 -1
  9. package/ios/Button/Button.swift +15 -12
  10. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +64 -18
  11. package/ios/Carousel/Carousel.swift +29 -12
  12. package/ios/Checkbox/Checkbox.swift +7 -3
  13. package/ios/Chip/Chip.swift +5 -4
  14. package/ios/Collapse/Collapse.swift +70 -19
  15. package/ios/Colors+Radius+Spacing/Colors.swift +10 -1
  16. package/ios/Colors+Radius+Spacing/Radius.swift +6 -0
  17. package/ios/DateTimePicker/DateTimePicker.swift +54 -20
  18. package/ios/DateTimePicker/WheelPicker.swift +103 -105
  19. package/ios/Divider/Divider.swift +37 -4
  20. package/ios/Extensions/Color++.swift +38 -9
  21. package/ios/Extensions/OptionalEnvironmentObject.swift +12 -0
  22. package/ios/Extensions/SkeletonUICompat.swift +11 -0
  23. package/ios/Icon/Icon.swift +21 -23
  24. package/ios/Icon/Icons.swift +1329 -0
  25. package/ios/IconButton/IconButton.swift +15 -7
  26. package/ios/Image/Image.swift +7 -23
  27. package/ios/Information/Information.swift +27 -9
  28. package/ios/Input/ErrorView.swift +2 -2
  29. package/ios/Input/Input.swift +160 -147
  30. package/ios/Input/InputPhoneNumber.swift +12 -9
  31. package/ios/Input/InputSearch.swift +102 -75
  32. package/ios/Input/InputTextArea.swift +128 -145
  33. package/ios/InputDropDown/InputDropDown.swift +10 -7
  34. package/ios/InputMoney/InputMoney.swift +33 -11
  35. package/ios/InputOTP/InputOTP.swift +22 -12
  36. package/ios/Layout/Card.swift +50 -0
  37. package/ios/Layout/GridContext.swift +187 -3
  38. package/ios/Layout/Item.swift +5 -4
  39. package/ios/Layout/ScreenLayout.swift +380 -0
  40. package/ios/Layout/Section.swift +4 -100
  41. package/ios/Loader/Loader.swift +5 -9
  42. package/ios/Lottie/LottieView.swift +14 -2
  43. package/ios/{Application/Navigation/Overplay → Navigation}/BottomSheet.swift +128 -9
  44. package/ios/Navigation/BottomTab/BottomTab.swift +185 -0
  45. package/ios/{Application/Navigation → Navigation}/BottomTab/BottomTabBar.swift +15 -7
  46. package/ios/Navigation/BottomTab/DuoBarCompression.swift +105 -0
  47. package/ios/Navigation/BottomTab/DuoTabBar.swift +304 -0
  48. package/ios/{Application → Navigation/Component}/FloatingButton.swift +14 -3
  49. package/ios/Navigation/Component/Header.swift +531 -0
  50. package/ios/Navigation/Component/HeaderBackground.swift +133 -0
  51. package/ios/Navigation/Component/HeaderJourney.swift +73 -0
  52. package/ios/Navigation/Component/HeaderLocation.swift +48 -0
  53. package/ios/Navigation/Component/HeaderRight.swift +377 -0
  54. package/ios/Navigation/Component/HeaderTitle.swift +36 -0
  55. package/ios/{Application/Navigation → Navigation/Component}/HeaderUser.swift +21 -24
  56. package/ios/Navigation/Component/SideBar.swift +183 -0
  57. package/ios/{Application/Navigation/Overplay → Navigation/Component}/SnackBar.swift +5 -6
  58. package/ios/Navigation/HostBackGestureBridge.swift +78 -0
  59. package/ios/{Application/Navigation/Overplay → Navigation}/ModalScreen.swift +5 -2
  60. package/ios/Navigation/Navigation.swift +204 -0
  61. package/ios/Navigation/NavigationContainer.swift +194 -0
  62. package/ios/{Application/Navigation → Navigation}/Navigator.swift +177 -91
  63. package/ios/Navigation/StackScreen.swift +820 -0
  64. package/ios/Navigation/StackTransition.swift +400 -0
  65. package/ios/Navigation/SwipeBackHaptic.swift +33 -0
  66. package/ios/{Application/Navigation → Navigation}/Tracking/ScreenTracker.swift +12 -5
  67. package/ios/OTPKeyboard/OTPKeyboard.swift +8 -11
  68. package/ios/Pagination/PaginationScroll.swift +2 -2
  69. package/ios/Popup/PopupDisplay.swift +72 -136
  70. package/ios/Popup/PopupInput.swift +10 -13
  71. package/ios/Popup/PopupLayout.swift +140 -0
  72. package/ios/Popup/PopupNotify.swift +56 -73
  73. package/ios/Popup/PopupPromotion.swift +31 -47
  74. package/ios/PopupView/FullscreenPopup.swift +13 -19
  75. package/ios/PopupView/PopupView.swift +1 -1
  76. package/ios/PopupView/Utils++.swift +0 -8
  77. package/ios/ProgressInfo/ProgressInfo.swift +4 -2
  78. package/ios/Radio/Radio.swift +2 -1
  79. package/ios/Rating/Rating.swift +9 -1
  80. package/ios/Resources/dot_loading.json +558 -0
  81. package/ios/Resources/lottie_circle_loader.json +1 -0
  82. package/ios/ScrollIndicator/ScrollIndicator.swift +11 -10
  83. package/ios/Skeleton/Skeleton.swift +22 -27
  84. package/ios/Slider/Slider.swift +16 -18
  85. package/ios/Stepper/Stepper.swift +6 -1
  86. package/ios/Steps/Steps.swift +8 -6
  87. package/ios/SuggestAction/SuggestAction.swift +5 -0
  88. package/ios/Swipeable/SwipeCell.swift +10 -6
  89. package/ios/Switch/Switch.swift +22 -20
  90. package/ios/TabView/TabView.swift +102 -21
  91. package/ios/Tag/Tag.swift +15 -4
  92. package/ios/Template/Logo/Logo.swift +2 -1
  93. package/ios/Template/TrustBanner/TrustBanner.swift +106 -54
  94. package/ios/Title/Title.swift +6 -17
  95. package/ios/Tooltip/Tooltip.swift +29 -14
  96. package/ios/Typography/Text.swift +61 -19
  97. package/ios/Uploader/Uploader.swift +3 -1
  98. package/ios/native-kits.podspec +2 -1
  99. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  100. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +1 -1
  101. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DuoTabDemo.swift +80 -0
  102. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +1 -0
  103. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IPhoneDuoDemo.swift +173 -0
  104. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +77 -1
  105. package/package.json +1 -1
  106. package/scripts/gen-ios-icons.mjs +36 -0
  107. package/build.gradle.kts +0 -11
  108. package/compose/build.gradle.kts +0 -190
  109. package/compose/build.gradle.kts.backup +0 -190
  110. package/compose/compose.podspec +0 -47
  111. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
  112. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
  113. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
  114. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
  115. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -151
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -124
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -831
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  132. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
  133. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -82
  134. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  135. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
  136. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
  137. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -356
  138. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -113
  139. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
  140. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
  141. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
  142. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
  143. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -49
  144. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
  145. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
  146. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
  147. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -189
  148. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -475
  149. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
  150. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -266
  151. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -240
  152. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -223
  153. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -264
  154. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -185
  155. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
  156. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
  157. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  158. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  159. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
  160. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  161. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -334
  162. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -98
  163. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -310
  164. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
  165. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  166. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
  167. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
  168. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -323
  169. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -220
  170. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
  171. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
  172. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -199
  173. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
  174. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -552
  175. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -88
  176. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -125
  177. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -207
  178. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -498
  179. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -176
  180. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
  181. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
  182. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  183. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -234
  184. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -188
  185. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
  186. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -16
  187. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +0 -18
  188. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
  189. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  190. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  191. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
  192. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -297
  193. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -54
  194. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -50
  195. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +0 -157
  196. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -41
  197. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
  198. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
  199. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  200. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
  201. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
  202. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  203. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -299
  204. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +0 -58
  205. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -129
  206. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -106
  207. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -205
  208. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -393
  209. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  210. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -622
  211. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -148
  212. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -35
  213. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -175
  214. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -232
  215. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  216. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
  217. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -381
  218. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -83
  219. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +0 -105
  220. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +0 -74
  221. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -347
  222. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -37
  223. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -363
  224. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +0 -169
  225. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
  226. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
  227. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -12
  228. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
  229. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
  230. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -71
  231. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  232. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
  233. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  234. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -118
  235. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -40
  236. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -45
  237. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
  238. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -38
  239. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
  240. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -213
  241. package/gradle/libs.versions.toml +0 -69
  242. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  243. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  244. package/gradle.properties +0 -26
  245. package/gradlew +0 -252
  246. package/gradlew.bat +0 -94
  247. package/ios/Application/Components.swift +0 -270
  248. package/ios/Application/ComposeApi.swift +0 -22
  249. package/ios/Application/HeaderRight.swift +0 -306
  250. package/ios/Application/Navigation/BottomTab/BottomTab.swift +0 -104
  251. package/ios/Application/Navigation/HeaderBackProps.swift +0 -66
  252. package/ios/Application/Navigation/HeaderTitle.swift +0 -57
  253. package/ios/Application/Navigation/NavigationContainer.swift +0 -213
  254. package/ios/Application/Navigation/NavigationOptions.swift +0 -109
  255. package/ios/Application/Navigation/NavigatorManager.swift +0 -22
  256. package/ios/Application/Navigation/component/Header.swift +0 -178
  257. package/ios/Application/Navigation/component/HeaderBackground.swift +0 -83
  258. package/ios/Application/Navigation/component/HeaderColor.swift +0 -65
  259. package/ios/Application/Navigation/component/HeaderRightWidthKey.swift +0 -11
  260. package/ios/Application/Navigation/component/NavigationFooter.swift +0 -90
  261. package/ios/Application/Navigation/component/NavigationHeaderRight.swift +0 -196
  262. package/ios/Application/Screen.swift +0 -250
  263. package/ios/Application/StackScreen.swift +0 -492
  264. package/ios-demo/README.md +0 -120
  265. package/settings.gradle.kts +0 -64
  266. /package/ios/{Application/Navigation → Navigation}/BottomTab/CurvedContainer.swift +0 -0
@@ -0,0 +1,183 @@
1
+ //
2
+ // SideBar.swift
3
+ // MoMoUIKits
4
+ //
5
+ // SwiftUI mirror of Compose's `navigation/component/SideBar.kt`. iPhone Duo: back and toolkit
6
+ // leave the header bar for a column in the side safe area, as the system bars do.
7
+ // Port of RN `SideBarButton.tsx` + `useSideBarItemStyle`.
8
+ //
9
+
10
+ import SwiftUI
11
+
12
+ private let sideBarIconSize: CGFloat = 24
13
+
14
+ /// The back button and toolkit column, placed in window coordinates over the side strip.
15
+ struct HeaderSideBar: View {
16
+ let sideBar: SideBarLayout
17
+ let goBack: (() -> Void)?
18
+ let toolkit: (data: HeaderRightData?, tintColor: Color?)?
19
+ let headerColor: HeaderColor
20
+ /// What footer / tab bar / home indicator take from the bottom, gap included; the column stays above it.
21
+ let bottomInset: CGFloat
22
+
23
+ @Environment(\.screenLayout) private var layout
24
+ @Environment(\.applicationEnvironment) private var environment
25
+ @Environment(\.duoBarCompression) private var compression
26
+ @State private var columnHeight: CGFloat = 0
27
+
28
+ private var isRight: Bool { sideBar.edge == .right }
29
+
30
+ private var top: CGFloat {
31
+ let maxY = layout.height - bottomInset - columnHeight
32
+ return max(min(sideBar.top, maxY), 0)
33
+ }
34
+
35
+ /// Full height, so the tab bar compression decision follows this screen's toolkit.
36
+ private var fullHeight: CGFloat {
37
+ let toolkitHeight = toolkit.map {
38
+ Spacing.M + toolkitColumnHeight($0.data ?? HeaderRightData(), context: environment.applicationContext)
39
+ }
40
+ return DuoMetrics.controlSize + (toolkitHeight ?? 0)
41
+ }
42
+
43
+ var body: some View {
44
+ VStack(alignment: isRight ? .leading : .trailing, spacing: Spacing.M) {
45
+ if let goBack {
46
+ SideBarButton(
47
+ icon: "arrow-back",
48
+ headerColor: headerColor,
49
+ accessibilityId: "btn_navigation_back",
50
+ action: goBack
51
+ )
52
+ } else {
53
+ // keep the slot so the toolkit does not jump between root and pushed screens
54
+ Color.clear.frame(width: DuoMetrics.controlSize, height: DuoMetrics.controlSize)
55
+ }
56
+ if let toolkit {
57
+ if compression.toolbarHidden {
58
+ // an open tab rail takes this slot for a moment
59
+ EmptyView()
60
+ } else if compression.toolbarCompressed {
61
+ // HIG "Toolbar compressed": tools fold into one button, distinct from the useMore icon
62
+ SideBarButton(
63
+ icon: "navigation_menu",
64
+ headerColor: headerColor,
65
+ showBadge: toolkit.data?.showBadge ?? false,
66
+ accessibilityId: "btn_navigation_toolbar",
67
+ action: compression.expandToolbar
68
+ )
69
+ } else {
70
+ Toolkit(
71
+ headerRight: toolkit.data ?? HeaderRightData(),
72
+ tintColor: toolkit.tintColor,
73
+ layout: .sideBarColumn
74
+ )
75
+ .environment(\.headerColor, headerColor)
76
+ }
77
+ }
78
+ }
79
+ .padding(isRight ? .leading : .trailing, Spacing.M)
80
+ .frame(width: sideBar.width, alignment: isRight ? .leading : .trailing)
81
+ .background(
82
+ GeometryReader { proxy in
83
+ Color.clear
84
+ .onAppear { columnHeight = proxy.size.height }
85
+ .onChange(of: proxy.size.height) { columnHeight = $0 }
86
+ }
87
+ )
88
+ .padding(.top, top)
89
+ .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: isRight ? .topTrailing : .topLeading)
90
+ .ignoresSafeArea()
91
+ .onAppear { compression.setToolbarHeight(fullHeight) }
92
+ .onChange(of: fullHeight) { compression.setToolbarHeight($0) }
93
+ }
94
+ }
95
+
96
+ /// Dark glass under light icons (banner headers), light glass otherwise.
97
+ private struct SideBarGlass<S: Shape>: ViewModifier {
98
+ let headerColor: HeaderColor
99
+ let shape: S
100
+
101
+ private var isDark: Bool { headerColor.tintIconColor == Colors.black01 || headerColor.tintIconColor == .white }
102
+
103
+ func body(content: Content) -> some View {
104
+ if isDark {
105
+ content
106
+ .background(shape.fill(Colors.black20.opacity(0.5)))
107
+ .overlay(shape.stroke(Colors.black01.opacity(0.2), lineWidth: 0.5))
108
+ } else {
109
+ content
110
+ .background(
111
+ shape.fill(Colors.black01.opacity(0.85))
112
+ .shadow(color: Color.black.opacity(0.12), radius: 4, x: 0, y: 2)
113
+ )
114
+ .overlay(shape.stroke(Colors.black20.opacity(0.08), lineWidth: 0.5))
115
+ }
116
+ }
117
+ }
118
+
119
+ /// 48pt glass circle for a single side bar control.
120
+ struct SideBarButton: View {
121
+ let icon: String
122
+ let headerColor: HeaderColor
123
+ var showBadge: Bool = false
124
+ var disabled: Bool = false
125
+ var accessibilityId: String?
126
+ let action: () -> Void
127
+
128
+ var body: some View {
129
+ SwiftUI.Button(action: action) {
130
+ Icon(source: icon, size: sideBarIconSize, color: headerColor.tintIconColor)
131
+ .frame(width: DuoMetrics.controlSize, height: DuoMetrics.controlSize)
132
+ .modifier(SideBarGlass(headerColor: headerColor, shape: Circle()))
133
+ .overlay(alignment: .topTrailing) {
134
+ if showBadge {
135
+ BadgeDot(size: .small).offset(x: -Spacing.XXS, y: Spacing.XXS)
136
+ }
137
+ }
138
+ }
139
+ .buttonStyle(ActiveOpacityButtonStyle())
140
+ .disabled(disabled)
141
+ .accessibilityIdentifier(accessibilityId ?? "")
142
+ }
143
+ }
144
+
145
+ /// 48pt glass capsule grouping related controls, one item per 50pt: vertical in the side bar,
146
+ /// horizontal on a header row.
147
+ struct SideBarGroup<Content: View>: View {
148
+ let headerColor: HeaderColor
149
+ let itemCount: Int
150
+ var horizontal: Bool = false
151
+ @ViewBuilder let content: () -> Content
152
+
153
+ var body: some View {
154
+ let length = itemCount > 1 ? DuoMetrics.itemPitch * CGFloat(itemCount) : DuoMetrics.controlSize
155
+ Group {
156
+ if horizontal {
157
+ HStack(spacing: 0) { content() }
158
+ .frame(width: length, height: DuoMetrics.controlSize)
159
+ } else {
160
+ VStack(spacing: 0) { content() }
161
+ .frame(width: DuoMetrics.controlSize, height: length)
162
+ }
163
+ }
164
+ .modifier(SideBarGlass(headerColor: headerColor, shape: RoundedRectangle(cornerRadius: Radius.XL)))
165
+ }
166
+ }
167
+
168
+ struct SideBarGroupItem: View {
169
+ let icon: String
170
+ let headerColor: HeaderColor
171
+ let accessibilityId: String
172
+ let action: () -> Void
173
+
174
+ var body: some View {
175
+ SwiftUI.Button(action: action) {
176
+ Icon(source: icon, size: sideBarIconSize, color: headerColor.tintIconColor)
177
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
178
+ .contentShape(Rectangle())
179
+ }
180
+ .buttonStyle(ActiveOpacityButtonStyle())
181
+ .accessibilityIdentifier(accessibilityId)
182
+ }
183
+ }
@@ -2,9 +2,8 @@
2
2
  // SnackBar.swift
3
3
  // MoMoUIKits
4
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.
5
+ // SwiftUI mirror of Compose's `navigation/component/SnackBar.kt`: slides up above the screen's
6
+ // footer (or the home indicator), stays for `duration`, then slides back down.
8
7
  // `Navigator.showSnackBar(_:)` drives it through the overplay host.
9
8
  //
10
9
 
@@ -50,11 +49,10 @@ public struct SnackBar {
50
49
 
51
50
  /// Self-animating container. Slides the content up on appear, schedules an
52
51
  /// auto-dismiss after `duration`, and animates out before removing the overplay.
53
- @available(iOS 16.0, *)
54
52
  struct SnackBarView: View {
55
53
  let snackBar: SnackBar
56
- /// Bottom inset so the bar sits above the footer / home indicator
57
- /// (mirrors Compose's `footerHeight` offset).
54
+ /// Distance from the window bottom to the top of the screen's footer, or the navigation bar
55
+ /// inset without one (Compose's `footerHeight` offset).
58
56
  let bottomInset: CGFloat
59
57
 
60
58
  @EnvironmentObject private var navigator: Navigator
@@ -78,6 +76,7 @@ struct SnackBarView: View {
78
76
  .padding(.bottom, bottomInset)
79
77
  }
80
78
  .frame(maxWidth: .infinity, maxHeight: .infinity)
79
+ .ignoresSafeArea()
81
80
  .onAppear {
82
81
  guard !didAppear else { return }
83
82
  didAppear = true
@@ -0,0 +1,78 @@
1
+ //
2
+ // HostBackGestureBridge.swift
3
+ // MoMoUIKits
4
+ //
5
+ // SwiftUI mirror of Compose's `navigation/HostBackGestureBridge.kt`: the host owns the edge-pan
6
+ // recogniser and routes a back into the topmost kit stack. NavigationContainer attaches itself.
7
+ // `started` / `progressed` / `completed` / `cancelled` scrub the pop transition with the finger;
8
+ // a host that only calls `pop` gets the regular animated back.
9
+ //
10
+
11
+ import UIKit
12
+
13
+ public final class HostBackGestureBridge {
14
+ public static let shared = HostBackGestureBridge()
15
+ private init() {}
16
+
17
+ // Weak: a container torn down without disappearing must not keep receiving backs.
18
+ private var navigators: [WeakNavigator] = []
19
+ private weak var gestureTarget: Navigator?
20
+
21
+ /// Set while a bottom tab other than the first is selected; the host shows its floating arrow.
22
+ public var shouldUseFloatingArrowBack = false
23
+
24
+ public func attach(_ navigator: Navigator) {
25
+ navigators.removeAll { $0.value == nil }
26
+ guard !navigators.contains(where: { $0.value === navigator }) else { return }
27
+ navigators.append(WeakNavigator(value: navigator))
28
+ }
29
+
30
+ public func detach(_ navigator: Navigator) {
31
+ navigators.removeAll { $0.value == nil || $0.value === navigator }
32
+ if gestureTarget === navigator { gestureTarget = nil }
33
+ }
34
+
35
+ /// Whether a kit stack is on screen at all.
36
+ public func checkCanPop() -> Bool { top() != nil }
37
+
38
+ /// Whether the top stack pops a screen itself; false means a back dismisses the mini app.
39
+ public func canPopInner() -> Bool { top()?.canPop() == true }
40
+
41
+ public func pop() { top()?.onBackSafe() }
42
+
43
+ public func started() {
44
+ guard let target = top() else { return }
45
+ gestureTarget = target
46
+ target.backStarted()
47
+ }
48
+
49
+ /// `progress` is the touch travel over the window width, 0...1.
50
+ public func progressed(_ progress: CGFloat) {
51
+ gestureTarget?.backProgressed(min(max(progress, 0), 1))
52
+ }
53
+
54
+ public func completed() {
55
+ (gestureTarget ?? top())?.backCompleted()
56
+ gestureTarget = nil
57
+ }
58
+
59
+ public func cancelled() {
60
+ gestureTarget?.backCancelled()
61
+ gestureTarget = nil
62
+ }
63
+
64
+ @available(*, deprecated, renamed: "attach")
65
+ public func push(_ navigator: Navigator) { attach(navigator) }
66
+
67
+ @available(*, deprecated, renamed: "detach")
68
+ public func remove(_ navigator: Navigator) { detach(navigator) }
69
+
70
+ private func top() -> Navigator? { navigators.last { $0.value != nil }?.value }
71
+ }
72
+
73
+ @available(*, deprecated, renamed: "HostBackGestureBridge")
74
+ public typealias NavigatorManager = HostBackGestureBridge
75
+
76
+ private struct WeakNavigator {
77
+ weak var value: Navigator?
78
+ }
@@ -9,13 +9,13 @@
9
9
 
10
10
  import SwiftUI
11
11
 
12
- @available(iOS 16.0, *)
13
12
  struct ModalScreen<Content: View>: View {
14
13
  let barrierDismissible: Bool
15
14
  let content: () -> Content
16
15
 
17
16
  @EnvironmentObject private var navigator: Navigator
18
17
  @Environment(\.applicationEnvironment) private var appEnv
18
+ @Environment(\.screenLayout) private var layout
19
19
 
20
20
  @State private var scrimOpacity: CGFloat = 0
21
21
  @State private var contentScale: CGFloat = 0.8
@@ -35,8 +35,11 @@ struct ModalScreen<Content: View>: View {
35
35
  content()
36
36
  .scaleEffect(contentScale)
37
37
  .opacity(contentOpacity)
38
+ // iPhone Duo: center below the side status bar and above the home indicator
39
+ .padding(.top, layout.isDuoDevice ? layout.duoTopInset : 0)
40
+ .padding(.bottom, layout.isDuoDevice ? layout.insets.bottom : 0)
38
41
  }
39
- // Center on the full screen like Compose; landscape safe areas are asymmetric (camera on one side).
42
+ // Full screen like RN's Modal, so asymmetric landscape insets don't shift the content sideways.
40
43
  .frame(maxWidth: .infinity, maxHeight: .infinity)
41
44
  .ignoresSafeArea(.container)
42
45
  .onAppear {
@@ -0,0 +1,204 @@
1
+ //
2
+ // Navigation.swift
3
+ // MoMoUIKits
4
+ //
5
+ // SwiftUI mirror of Compose's `navigation/Navigation.kt`: a screen's `NavigationOptions` and the
6
+ // per-screen `Navigation` that updates them at runtime.
7
+ //
8
+
9
+ import SwiftUI
10
+
11
+ /// Per-screen handle (Compose `LocalNavigation`). Read it inside a screen with
12
+ /// `@EnvironmentObject var navigation: Navigation` and call `setOptions` to change the header,
13
+ /// footer or back handling after the screen is shown.
14
+ public final class Navigation: ObservableObject {
15
+ public let id: Int
16
+ public let bottomTabIndex: Int
17
+ @Published public private(set) var options: NavigationOptions
18
+
19
+ private weak var registry: DynamicScreenRegistry?
20
+ /// What the footer (or navigation bar) takes from the window bottom; lifts snack bars.
21
+ var bottomObstruction: CGFloat = 0
22
+
23
+ init(
24
+ id: Int = -1,
25
+ bottomTabIndex: Int = -1,
26
+ options: NavigationOptions?,
27
+ registry: DynamicScreenRegistry? = nil
28
+ ) {
29
+ self.id = id
30
+ self.bottomTabIndex = bottomTabIndex
31
+ self.options = options ?? NavigationOptions()
32
+ self.registry = registry
33
+ if id != -1 { registry?.bind(self) }
34
+ }
35
+
36
+ public func setOptions(_ options: NavigationOptions) {
37
+ update(options)
38
+ }
39
+
40
+ /// Changes only what the closure touches, like Compose's named-argument `setOptions`.
41
+ public func setOptions(_ transform: (inout NavigationOptions) -> Void) {
42
+ var updated = options
43
+ transform(&updated)
44
+ update(updated)
45
+ }
46
+
47
+ private func update(_ updated: NavigationOptions) {
48
+ options = updated
49
+ // back handling reads the registry copy
50
+ if id != -1 { registry?.setOptions(id: id, options: updated) }
51
+ }
52
+ }
53
+
54
+ public struct NavigationOptions {
55
+ public var screenName: String?
56
+ public var title: String
57
+ /// Rich header title (Compose `headerTitle`); `title` is used when nil.
58
+ public var headerTitle: HeaderTitle?
59
+ public var titlePosition: TitlePosition
60
+ public var headerType: HeaderType
61
+ /// Compose's `HeaderType.Default/Extended(useAnimated:)`: with `inputSearchProps`, the search
62
+ /// rises into the header on scroll.
63
+ public var useAnimated: Bool
64
+ /// Compose's `HeaderType.Transparent`; with `fullScreenContent` the content starts under it.
65
+ public var headerTransparent: Bool
66
+ public var fullScreenContent: Bool
67
+ public var hiddenBack: Bool
68
+ public var backgroundColor: Color?
69
+ // AI-GENERATED START: custom screen background view (Compose backgroundComponent)
70
+ /// Drawn instead of `backgroundColor` over the whole window: under the header and the status bar,
71
+ /// across the iPhone Duo side strips, and not shrunk by the keyboard. Pair with `headerTransparent`.
72
+ public var background: (() -> AnyView)?
73
+ // AI-GENERATED END: custom screen background view (Compose backgroundComponent)
74
+ public var tintColor: Color?
75
+ public var scrollable: Bool
76
+ /// Compose's `ScrollData.scrollToTopCallback`, fired on a status-bar tap.
77
+ public var scrollToTopCallback: (() -> Void)?
78
+ public var useAvoidKeyboard: Bool
79
+ /// Compose's `KeyboardOptions.keyboardShouldPersistTaps`: a tap anywhere hides the keyboard.
80
+ public var keyboardShouldPersistTaps: Bool
81
+ public var headerBackProps: HeaderBackProps?
82
+ /// Toolkit data for the default header right (Compose `HeaderRight.Toolkit`). Use `headerRight`
83
+ /// for a custom view and nil for none.
84
+ public var headerRightData: HeaderRightData?
85
+ public var headerRight: (() -> any View)?
86
+ public var footer: (() -> AnyView)?
87
+ public var footerTransparent: Bool
88
+ public var footerUseMargin: Bool
89
+ public var animatedHeader: AnimatedHeader?
90
+ public var layoutOffset: CGFloat
91
+ public var inputSearchProps: InputSearchProps?
92
+ public var fabProps: FabProps?
93
+ public var onBackHandler: (() -> Void)?
94
+
95
+ public init(
96
+ screenName: String? = nil,
97
+ title: String = "Stack",
98
+ headerTitle: HeaderTitle? = nil,
99
+ titlePosition: TitlePosition = .left,
100
+ headerType: HeaderType = .default,
101
+ useAnimated: Bool = false,
102
+ headerTransparent: Bool = false,
103
+ fullScreenContent: Bool = false,
104
+ hiddenBack: Bool = false,
105
+ backgroundColor: Color? = nil,
106
+ // AI-GENERATED START: custom screen background view (Compose backgroundComponent)
107
+ background: (() -> AnyView)? = nil,
108
+ // AI-GENERATED END: custom screen background view (Compose backgroundComponent)
109
+ tintColor: Color? = Colors.black17,
110
+ scrollable: Bool = true,
111
+ scrollToTopCallback: (() -> Void)? = nil,
112
+ useAvoidKeyboard: Bool = true,
113
+ keyboardShouldPersistTaps: Bool = false,
114
+ headerBackProps: HeaderBackProps? = nil,
115
+ headerRightData: HeaderRightData? = nil,
116
+ headerRight: (() -> any View)? = { HeaderRight() },
117
+ footer: (() -> AnyView)? = nil,
118
+ footerTransparent: Bool = false,
119
+ footerUseMargin: Bool = true,
120
+ animatedHeader: AnimatedHeader? = nil,
121
+ layoutOffset: CGFloat = 56,
122
+ inputSearchProps: InputSearchProps? = nil,
123
+ fabProps: FabProps? = nil,
124
+ onBackHandler: (() -> Void)? = nil
125
+ ) {
126
+ self.screenName = screenName
127
+ self.title = title
128
+ self.headerTitle = headerTitle
129
+ self.titlePosition = titlePosition
130
+ self.headerType = headerType
131
+ self.useAnimated = useAnimated
132
+ self.headerTransparent = headerTransparent
133
+ self.fullScreenContent = fullScreenContent
134
+ self.hiddenBack = hiddenBack
135
+ self.backgroundColor = backgroundColor
136
+ // AI-GENERATED START: custom screen background view (Compose backgroundComponent)
137
+ self.background = background
138
+ // AI-GENERATED END: custom screen background view (Compose backgroundComponent)
139
+ self.tintColor = tintColor
140
+ self.scrollable = scrollable
141
+ self.scrollToTopCallback = scrollToTopCallback
142
+ self.useAvoidKeyboard = useAvoidKeyboard
143
+ self.keyboardShouldPersistTaps = keyboardShouldPersistTaps
144
+ self.headerBackProps = headerBackProps
145
+ self.headerRightData = headerRightData
146
+ self.headerRight = headerRight
147
+ self.footer = footer
148
+ self.footerTransparent = footerTransparent
149
+ self.footerUseMargin = footerUseMargin
150
+ self.animatedHeader = animatedHeader
151
+ self.layoutOffset = layoutOffset
152
+ self.inputSearchProps = inputSearchProps
153
+ self.fabProps = fabProps
154
+ self.onBackHandler = onBackHandler
155
+ }
156
+ }
157
+
158
+ extension NavigationOptions {
159
+ var resolvedHeaderRight: (() -> any View)? {
160
+ guard let headerRightData else { return headerRight }
161
+ return { HeaderRight(headerRight: headerRightData, tintColor: tintColor) }
162
+ }
163
+ }
164
+
165
+ /// `StackScreen` built from options, shared by stack screens and bottom-tab screens.
166
+ struct OptionsStackScreen: View {
167
+ let options: NavigationOptions
168
+ let screenName: String
169
+ let goBack: (() -> Void)?
170
+ let content: () -> AnyView
171
+
172
+ var body: some View {
173
+ StackScreen(
174
+ backgroundColor: options.backgroundColor,
175
+ // AI-GENERATED START: custom screen background view (Compose backgroundComponent)
176
+ background: options.background,
177
+ // AI-GENERATED END: custom screen background view (Compose backgroundComponent)
178
+ headerTransparent: options.headerTransparent,
179
+ fullScreenContent: options.fullScreenContent,
180
+ tintColor: options.tintColor ?? Colors.black17,
181
+ isBack: !options.hiddenBack,
182
+ headerType: options.headerType,
183
+ useAnimated: options.useAnimated,
184
+ title: options.title,
185
+ headerTitle: options.headerTitle,
186
+ titlePosition: options.titlePosition,
187
+ goBack: options.hiddenBack ? nil : goBack,
188
+ scrollable: options.scrollable,
189
+ scrollToTopCallback: options.scrollToTopCallback,
190
+ useAvoidKeyboard: options.useAvoidKeyboard,
191
+ keyboardShouldPersistTaps: options.keyboardShouldPersistTaps,
192
+ footer: options.footer,
193
+ footerTransparent: options.footerTransparent,
194
+ footerUseMargin: options.footerUseMargin,
195
+ headerRight: options.resolvedHeaderRight,
196
+ animatedHeader: options.animatedHeader,
197
+ layoutOffset: options.layoutOffset,
198
+ inputSearchProps: options.inputSearchProps,
199
+ fabProps: options.fabProps,
200
+ screenName: screenName,
201
+ content: content
202
+ )
203
+ }
204
+ }