@momo-kits/native-kits 0.167.1-duo.14 → 0.167.1-duo.15-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 (153) hide show
  1. package/CLAUDE.md +1 -1
  2. package/build.gradle.kts +11 -0
  3. package/compose/build.gradle.kts +204 -0
  4. package/compose/build.gradle.kts.backup +204 -0
  5. package/compose/compose.podspec +47 -0
  6. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +19 -0
  7. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +6 -0
  8. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +12 -0
  9. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
  10. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +153 -0
  11. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +6 -0
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +52 -0
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +124 -0
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +183 -0
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +207 -0
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +39 -0
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +293 -0
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +831 -0
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +110 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +378 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +56 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +81 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +338 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +175 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +357 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +115 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +89 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +128 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +209 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +542 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +49 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +76 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +125 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +231 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +189 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +478 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +114 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +265 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +235 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +223 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +265 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +185 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +343 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +84 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +361 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +108 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +308 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +59 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +21 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +90 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +330 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +220 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +473 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +122 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +207 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +92 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +560 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +125 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +207 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +501 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +176 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +182 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +193 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +236 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +180 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +325 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +16 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +18 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +22 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +16 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +188 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +297 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +54 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +50 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +260 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +41 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +52 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +66 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +104 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +48 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +338 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +58 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +137 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +106 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +205 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +393 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +8 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +708 -0
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +148 -0
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +35 -0
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +218 -0
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +231 -0
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +98 -0
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +312 -0
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +169 -0
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +408 -0
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +103 -0
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +106 -0
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +74 -0
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +366 -0
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +37 -0
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +363 -0
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +185 -0
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +133 -0
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +127 -0
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +12 -0
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +91 -0
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +74 -0
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +13 -0
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +55 -0
  132. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +15 -0
  133. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +118 -0
  134. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +40 -0
  135. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +45 -0
  136. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +32 -0
  137. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +38 -0
  138. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
  139. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +217 -0
  140. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +94 -0
  141. package/gradle/libs.versions.toml +69 -0
  142. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  143. package/gradle/wrapper/gradle-wrapper.properties +8 -0
  144. package/gradle.properties +26 -0
  145. package/gradlew +252 -0
  146. package/gradlew.bat +94 -0
  147. package/ios/Layout/ScreenLayout.swift +52 -30
  148. package/ios/Navigation/StackScreen.swift +22 -8
  149. package/ios/native-kits.podspec +1 -1
  150. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  151. package/ios-demo/README.md +120 -0
  152. package/package.json +1 -1
  153. package/settings.gradle.kts +64 -0
@@ -110,6 +110,12 @@ extension ScreenLayout {
110
110
  let sideInset = max(insets.leading, insets.trailing)
111
111
  // narrower strips cannot host a control 12pt from the inner edge
112
112
  if sideInset >= DuoMetrics.controlSize + Spacing.M {
113
+ let edge: SideBarEdge = insets.trailing >= insets.leading ? .right : .left
114
+ let stripLeft = edge == .right ? width - sideInset : 0
115
+ // clear of the camera and of the status bar cluster, which grows for calls and Live
116
+ // Activities; region frames already include the system's margin
117
+ let occlusion = stripOcclusion(reservedRegions, stripLeft: stripLeft, stripRight: stripLeft + sideInset, windowHeight: height)
118
+
113
119
  var top = insets.top + HeaderMetrics.barHeight + Spacing.M
114
120
  if insets.top < HeaderMetrics.statusBarMinInset {
115
121
  // status bar lives in the strip: start under its cluster, as the native bar does
@@ -118,8 +124,11 @@ extension ScreenLayout {
118
124
  } else if height >= DuoMetrics.innerMinHeight {
119
125
  top = DuoMetrics.firstItemTopLandscape
120
126
  } else {
121
- // outer display in landscape: no status bar in the strip
127
+ // outer display in landscape: no status bar in the strip, the title row centers
128
+ // on the camera when it sits at the top end, otherwise on the back button
122
129
  top = DuoMetrics.edgeInset
130
+ let titleCenterY = occlusion.top > top ? occlusion.topCenter : top + DuoMetrics.controlSize / 2
131
+ (headerHeight, headerStatusBarHeight) = centeredHeaderGeometry(centerY: titleCenterY)
123
132
  }
124
133
 
125
134
  if height > width && width < DuoMetrics.innerMinHeight {
@@ -129,11 +138,6 @@ extension ScreenLayout {
129
138
  }
130
139
  }
131
140
 
132
- let edge: SideBarEdge = insets.trailing >= insets.leading ? .right : .left
133
- let stripLeft = edge == .right ? width - sideInset : 0
134
- // clear of the camera and of the status bar cluster, which grows for calls and Live
135
- // Activities; region frames already include the system's margin
136
- let occlusion = stripOcclusion(reservedRegions, stripLeft: stripLeft, stripRight: stripLeft + sideInset, windowHeight: height)
137
141
  sideBar = SideBarLayout(
138
142
  edge: edge,
139
143
  width: sideInset,
@@ -159,18 +163,29 @@ extension ScreenLayout {
159
163
  )
160
164
  }
161
165
 
166
+ /// Bar row centered on a window y, at least iPhoneMinHeight tall and reaching 8pt below
167
+ /// a side bar control centered there.
168
+ private static func centeredHeaderGeometry(centerY: CGFloat) -> (CGFloat, CGFloat) {
169
+ let height = max(HeaderMetrics.iPhoneMinHeight, centerY + DuoMetrics.controlSize / 2 + Spacing.S)
170
+ return (height, max(0, centerY * 2 - height))
171
+ }
172
+
162
173
  /// How far system regions reach into a side strip from its top and from its bottom end
163
- /// (e.g. the camera, which sits at either end depending on the rotation).
174
+ /// (e.g. the camera, which sits at either end depending on the rotation), and the center y
175
+ /// of the region reaching furthest from the top.
164
176
  private static func stripOcclusion(
165
177
  _ regions: [CGRect],
166
178
  stripLeft: CGFloat,
167
179
  stripRight: CGFloat,
168
180
  windowHeight: CGFloat
169
- ) -> (top: CGFloat, bottom: CGFloat) {
170
- regions.reduce(into: (top: CGFloat(0), bottom: CGFloat(0))) { occlusion, region in
181
+ ) -> (top: CGFloat, topCenter: CGFloat, bottom: CGFloat) {
182
+ regions.reduce(into: (top: CGFloat(0), topCenter: CGFloat(0), bottom: CGFloat(0))) { occlusion, region in
171
183
  guard region.minX < stripRight && region.maxX > stripLeft else { return }
172
184
  if region.midY < windowHeight / 2 {
173
- occlusion.top = max(occlusion.top, region.maxY)
185
+ if region.maxY > occlusion.top {
186
+ occlusion.top = region.maxY
187
+ occlusion.topCenter = region.midY
188
+ }
174
189
  } else {
175
190
  occlusion.bottom = max(occlusion.bottom, windowHeight - region.minY)
176
191
  }
@@ -204,16 +219,20 @@ public func isIPhoneDuoDevice(windowSize: CGSize? = nil) -> Bool {
204
219
  /// System occlusion regions (iOS 27.1+) in window coordinates: the iPhone Duo camera, and the
205
220
  /// status bar cluster as it grows for a call or a Live Activity. Empty before iOS 27.1.
206
221
  enum ReservedRegions {
207
- // last report of the probe, so `ScreenLayout.current` includes it
208
- static var current: [CGRect] = []
222
+ // last report of a probe, so `ScreenLayout.current` includes it
223
+ private(set) static var current: [CGRect] = []
224
+ static let didChange = Notification.Name("MoMoUIKitsReservedRegionsDidChange")
225
+
226
+ fileprivate static func publish(_ regions: [CGRect]) {
227
+ guard regions != current else { return }
228
+ current = regions
229
+ NotificationCenter.default.post(name: didChange, object: nil)
230
+ }
209
231
  }
210
232
 
211
233
  /// Invisible probe: reading the regions in layoutSubviews makes UIKit run it again when they
212
234
  /// change, so nothing polls. Port of RN `@momo-kits/reserved-regions`.
213
235
  private final class ReservedRegionsProbe: UIView {
214
- var onChange: (() -> Void)?
215
- private var last: [CGRect]?
216
-
217
236
  override init(frame: CGRect) {
218
237
  super.init(frame: frame)
219
238
  isUserInteractionEnabled = false
@@ -223,12 +242,19 @@ private final class ReservedRegionsProbe: UIView {
223
242
 
224
243
  override func layoutSubviews() {
225
244
  super.layoutSubviews()
245
+ // read even when not publishing, so UIKit keeps re-running this when they change
226
246
  let regions = occlusionRegions()
227
- guard regions != last else { return }
228
- last = regions
229
- ReservedRegions.current = regions
247
+ // every screen has a probe but the regions are window-wide: one sliding in on a push or
248
+ // a present, or off the window, would overwrite them with a partial read
249
+ guard spansWindow else { return }
230
250
  // layout pass: publish on the next turn instead of mutating SwiftUI state mid-update
231
- DispatchQueue.main.async { [weak self] in self?.onChange?() }
251
+ DispatchQueue.main.async { ReservedRegions.publish(regions) }
252
+ }
253
+
254
+ private var spansWindow: Bool {
255
+ guard let window else { return false }
256
+ let frame = convert(bounds, to: nil)
257
+ return abs(frame.minX) < 1 && abs(frame.maxX - window.bounds.width) < 1 && abs(frame.minY) < 1
232
258
  }
233
259
 
234
260
  override func didMoveToWindow() {
@@ -250,17 +276,9 @@ private final class ReservedRegionsProbe: UIView {
250
276
  }
251
277
 
252
278
  private struct ReservedRegionsProbeView: UIViewRepresentable {
253
- let onChange: () -> Void
279
+ func makeUIView(context: Context) -> ReservedRegionsProbe { ReservedRegionsProbe() }
254
280
 
255
- func makeUIView(context: Context) -> ReservedRegionsProbe {
256
- let probe = ReservedRegionsProbe()
257
- probe.onChange = onChange
258
- return probe
259
- }
260
-
261
- func updateUIView(_ probe: ReservedRegionsProbe, context: Context) {
262
- probe.onChange = onChange
263
- }
281
+ func updateUIView(_ probe: ReservedRegionsProbe, context: Context) {}
264
282
  }
265
283
 
266
284
  // MARK: - Environment
@@ -292,7 +310,11 @@ private struct ScreenLayoutReader: ViewModifier {
292
310
  .onChange(of: proxy.safeAreaInsets) { _ in refresh() }
293
311
  }
294
312
  )
295
- .background(ReservedRegionsProbeView { refresh() }.ignoresSafeArea())
313
+ .background(ReservedRegionsProbeView().ignoresSafeArea())
314
+ // any screen's probe may report, so every reader follows the shared value
315
+ .onReceive(NotificationCenter.default.publisher(for: ReservedRegions.didChange)) { _ in
316
+ refresh()
317
+ }
296
318
  .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
297
319
  refresh()
298
320
  }
@@ -431,13 +431,23 @@ public struct StackScreen<Content: View>: View {
431
431
  // top-aligned: an extended band runs past the bar, under the content
432
432
  .background(alignment: .top) {
433
433
  ZStack(alignment: .top) {
434
- NavigationHeaderBackground(
435
- headerType: headerType,
436
- scrollState: scrollOffset,
437
- headerTransparent: headerTransparent,
438
- fullScreenContent: fullScreenContent,
439
- backgroundColor: backgroundColor
440
- )
434
+ if layout.sideBar != nil && inputSearchType != .none && !headerTransparent {
435
+ // RN HeaderExtendHeader with search on the side bar layout: the
436
+ // gradient fades out within the header box, as without the search
437
+ DuoScrollGradient(
438
+ scrollOffset: scrollOffset,
439
+ headerHeight: layout.headerHeight,
440
+ extended: headerType == .extended
441
+ )
442
+ } else {
443
+ NavigationHeaderBackground(
444
+ headerType: headerType,
445
+ scrollState: scrollOffset,
446
+ headerTransparent: headerTransparent,
447
+ fullScreenContent: fullScreenContent,
448
+ backgroundColor: backgroundColor
449
+ )
450
+ }
441
451
  HeaderBarBackground(opacity: opacity, transparent: headerTransparent || headerType == .none)
442
452
  }
443
453
  .edgesIgnoringSafeArea([.top, .horizontal])
@@ -688,6 +698,7 @@ public struct NavigationFooter: View {
688
698
  }
689
699
 
690
700
  @Environment(\.appTheme) private var theme
701
+ @Environment(\.screenLayout) private var layout
691
702
 
692
703
  /// Read from the window, not from an enclosing `GeometryProxy`: the proxy's bottom
693
704
  /// inset grows to the keyboard height while the keyboard is up.
@@ -733,9 +744,10 @@ public struct NavigationFooter: View {
733
744
  .padding(.bottom, Self.bottomPadding - (Spacing.S - margin))
734
745
  // Compose paints the surface all the way to the bottom of the screen; the
735
746
  // footer's own frame stops at the safe area, so only the fill bleeds down.
747
+ // With side insets (iPhone Duo) it stays inside them, off the side bar.
736
748
  .background(
737
749
  (transparent ? Color.clear : theme.colors.background.surface)
738
- .ignoresSafeArea(.container, edges: [.bottom, .horizontal])
750
+ .ignoresSafeArea(.container, edges: hasSideInsets ? .bottom : [.bottom, .horizontal])
739
751
  )
740
752
  .overlay(alignment: .top) {
741
753
  if !transparent { shadow }
@@ -744,6 +756,8 @@ public struct NavigationFooter: View {
744
756
  }
745
757
  }
746
758
 
759
+ private var hasSideInsets: Bool { layout.insetLeft > 0 || layout.insetRight > 0 }
760
+
747
761
  /// Compose offsets the shadow box by -6dp, so it lands on the content above the
748
762
  /// footer rather than on the footer surface itself.
749
763
  private var shadow: some View {
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'MoMoUIKits'
3
- s.version = '0.167.1-beta.4'
3
+ s.version = '0.167.1-duo.15'
4
4
  s.summary = 'MoMoUIKits for iOS'
5
5
  s.homepage = 'https://momo.vn'
6
6
  s.license = { :type => 'MIT' }
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'MoMoUIKitsDemo'
3
- s.version = '0.167.1-beta.4'
3
+ s.version = '0.167.1-duo.15'
4
4
  s.summary = 'Demo browser for MoMoUIKits SwiftUI components'
5
5
  s.homepage = 'https://momo.vn'
6
6
  s.license = { :type => 'MIT' }
@@ -0,0 +1,120 @@
1
+ # MoMoUIKitsDemo
2
+
3
+ SwiftUI demo browser for `MoMoUIKits`.
4
+
5
+ The package can optionally host a Compose UIKits screen by receiving a
6
+ `UIViewController` factory from the host app. It does not import the KMP
7
+ `shared` module directly.
8
+
9
+ SwiftUI mode reuses the full demo screen set from
10
+ `sample/iosApp/iosApp/Demo`, including the sample `HomeView` registry and demo
11
+ screens for all currently available components.
12
+
13
+ ## CocoaPods
14
+
15
+ In the host app `Podfile`, include both local pods:
16
+
17
+ ```ruby
18
+ pod 'MoMoUIKits', :path => '../momo-native-kits/ios/native-kits.podspec'
19
+ pod 'MoMoUIKitsDemo', :path => '../momo-native-kits/ios-demo'
20
+ ```
21
+
22
+ Adjust the relative paths to match the host app checkout.
23
+
24
+ ## Host App Usage
25
+
26
+ ```swift
27
+ import MoMoUIKitsDemo
28
+ import shared
29
+
30
+ class UIKitsViewController: BaseComposeAppViewController {
31
+ override func getViewController() -> UIViewController? {
32
+ let params = self.application.data as? [String: Any]
33
+
34
+ return MoMoUIKitsDemoViewControllerFactory.make(
35
+ context: MoMoUIKitsDemoContext(
36
+ appId: params?["appId"] as? String ?? "",
37
+ appCode: params?["code"] as? String ?? "",
38
+ appName: params?["name"] as? String,
39
+ appIcon: params?["icon"] as? String ?? ""
40
+ ),
41
+ composeViewController: {
42
+ UIKitsScreenComposeViewControllerKt.UIKitsScreenComposeViewController(
43
+ params: params
44
+ )
45
+ }
46
+ )
47
+ }
48
+
49
+ override func viewDidDisappear(_ animated: Bool) {
50
+ super.viewDidDisappear(animated)
51
+ composeViewController = nil
52
+ }
53
+ }
54
+ ```
55
+
56
+ If the host does not pass `composeViewController`, the demo opens directly in
57
+ SwiftUI mode.
58
+
59
+ ## Included SwiftUI Demos
60
+
61
+ The pod includes the sample demo screens for:
62
+
63
+ - Animated Header
64
+ - Avatar
65
+ - Badge
66
+ - Baseline View
67
+ - Bottom Tab
68
+ - Button
69
+ - Carousel
70
+ - Checkbox
71
+ - Chip
72
+ - Collapse
73
+ - DateTimePicker
74
+ - Divider
75
+ - Header User
76
+ - Icon Button
77
+ - Image
78
+ - Information
79
+ - Input
80
+ - Input DropDown
81
+ - Input Money
82
+ - Input OTP
83
+ - Input Phone Number
84
+ - Input Search
85
+ - Input TextArea
86
+ - Loader
87
+ - Navigation
88
+ - Pagination
89
+ - Popup Display
90
+ - Popup Notify
91
+ - Popup Promotion
92
+ - Progress Info
93
+ - Radio
94
+ - Rating
95
+ - Skeleton
96
+ - Slider
97
+ - SnackBar
98
+ - Stepper
99
+ - Steps
100
+ - Suggest Action
101
+ - Swipe
102
+ - Switch
103
+ - TabView
104
+ - Tag
105
+ - Theme
106
+ - Title
107
+ - Tooltip
108
+ - Typography
109
+ - Uploader
110
+
111
+ ## Validation Notes
112
+
113
+ Validated locally with:
114
+
115
+ ```sh
116
+ pod ipc spec ios/MoMoUIKits.podspec
117
+ pod ipc spec ios-demo/MoMoUIKitsDemo.podspec
118
+ pod lib lint ios/MoMoUIKits.podspec --allow-warnings --skip-import-validation
119
+ pod lib lint ios-demo/MoMoUIKitsDemo.podspec --allow-warnings --skip-import-validation --include-podspecs=ios/MoMoUIKits.podspec
120
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.167.1-duo.14",
3
+ "version": "0.167.1-duo.15-debug",
4
4
  "private": false,
5
5
  "dependeNavigationncies": {},
6
6
  "devDependencies": {},
@@ -0,0 +1,64 @@
1
+ import org.gradle.kotlin.dsl.maven
2
+
3
+ rootProject.name = "momo-native-kits"
4
+ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
5
+
6
+ pluginManagement {
7
+ repositories {
8
+ google {
9
+ mavenContent {
10
+ includeGroupAndSubgroups("androidx")
11
+ includeGroupAndSubgroups("com.android")
12
+ includeGroupAndSubgroups("com.google")
13
+ }
14
+ }
15
+ mavenCentral()
16
+ gradlePluginPortal()
17
+ maven {
18
+ url = uri("https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven")
19
+ credentials {username = "download_packages"; password = "gldt-bjDqLpU_sPcHDuXau2ws" }
20
+ }
21
+ maven {
22
+ url = uri("https://artifacts.mservice.com.vn/repository/maven-momo-app/")
23
+ credentials {
24
+ username = "viewer"
25
+ password = "viewer"
26
+ }
27
+ isAllowInsecureProtocol = true
28
+ }
29
+ }
30
+ }
31
+
32
+ dependencyResolutionManagement {
33
+ repositories {
34
+ google {
35
+ mavenContent {
36
+ includeGroupAndSubgroups("androidx")
37
+ includeGroupAndSubgroups("com.android")
38
+ includeGroupAndSubgroups("com.google")
39
+ }
40
+ }
41
+ mavenCentral()
42
+ maven { url = uri("https://maven.pkg.jetbrains.space/public/p/compose/dev") }
43
+ maven {
44
+ url = uri("https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven")
45
+ credentials {
46
+ username = "download_packages";
47
+ password = "gldt-bjDqLpU_sPcHDuXau2ws"
48
+ }
49
+ }
50
+ maven {
51
+ url = uri("https://artifacts.mservice.com.vn/repository/maven-momo-app/")
52
+ credentials {
53
+ username = "viewer"
54
+ password = "viewer"
55
+ }
56
+ isAllowInsecureProtocol = true
57
+ }
58
+ }
59
+ }
60
+
61
+ include(":compose")
62
+
63
+ include(":sample:androidApp")
64
+ include(":sample:shared")