@momo-kits/native-kits 0.163.1-beta.8-debug → 0.163.1-beta.9-debug

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/CLAUDE.md +1 -1
  2. package/compose/build.gradle.kts +1 -1
  3. package/compose/compose.podspec +1 -1
  4. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
  5. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +30 -3
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +5 -0
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +1 -1
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +3 -0
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +56 -0
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +4 -0
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +22 -0
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +8 -2
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +63 -0
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +32 -19
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +49 -0
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +1 -1
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +1 -1
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +3 -1
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +93 -75
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +26 -7
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +3 -1
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +23 -2
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +11 -0
  25. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
  26. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +26 -3
  27. package/gradle.properties +1 -1
  28. package/ios/Application/ApplicationEnvironment.swift +15 -2
  29. package/ios/Application/Components.swift +50 -44
  30. package/ios/Application/FloatingButton.swift +10 -9
  31. package/ios/Application/HeaderRight.swift +79 -45
  32. package/ios/Application/Localize.swift +277 -0
  33. package/ios/Application/MaxApi.swift +18 -0
  34. package/ios/Application/Navigation/BottomTab/BottomTab.swift +104 -0
  35. package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +215 -0
  36. package/ios/Application/Navigation/BottomTab/CurvedContainer.swift +65 -0
  37. package/ios/Application/Navigation/HeaderBackProps.swift +66 -0
  38. package/ios/Application/Navigation/HeaderTitle.swift +57 -0
  39. package/ios/Application/Navigation/HeaderUser.swift +209 -0
  40. package/ios/Application/Navigation/NavigationContainer.swift +200 -0
  41. package/ios/Application/Navigation/NavigationOptions.swift +109 -0
  42. package/ios/Application/Navigation/Navigator.swift +385 -0
  43. package/ios/Application/Navigation/Overplay/BottomSheet.swift +256 -0
  44. package/ios/Application/Navigation/Overplay/ModalScreen.swift +74 -0
  45. package/ios/Application/Navigation/Overplay/SnackBar.swift +144 -0
  46. package/ios/Application/Navigation/Tracking/ScreenTracker.swift +117 -0
  47. package/ios/Application/Navigation/component/Header.swift +178 -0
  48. package/ios/Application/Navigation/component/HeaderBackground.swift +83 -0
  49. package/ios/Application/Navigation/component/HeaderColor.swift +65 -0
  50. package/ios/Application/Screen.swift +2 -1
  51. package/ios/Application/StackScreen.swift +501 -0
  52. package/ios/Avatar/Avatar.swift +193 -0
  53. package/ios/Badge/Badge.swift +11 -14
  54. package/ios/Badge/BadgeRibbon.swift +92 -21
  55. package/ios/BaselineView/BaselineView.swift +163 -0
  56. package/ios/Button/Button.swift +124 -29
  57. package/ios/Carousel/Carousel.swift +196 -0
  58. package/ios/Checkbox/Checkbox.swift +23 -28
  59. package/ios/Chip/Chip.swift +56 -33
  60. package/ios/Collapse/Collapse.swift +192 -0
  61. package/ios/Colors+Radius+Spacing/Colors.swift +20 -17
  62. package/ios/Colors+Radius+Spacing/Spacing.swift +3 -1
  63. package/ios/Colors+Radius+Spacing/Theme.swift +295 -0
  64. package/ios/DateTimePicker/DateTimePicker.swift +212 -0
  65. package/ios/DateTimePicker/DateTimePickerTypes.swift +55 -0
  66. package/ios/DateTimePicker/DateTimePickerUtils.swift +167 -0
  67. package/ios/DateTimePicker/WheelPicker.swift +165 -0
  68. package/ios/Divider/Divider.swift +16 -0
  69. package/ios/Extensions/ActiveOpacityButtonStyle.swift +14 -0
  70. package/ios/Extensions/Color++.swift +32 -0
  71. package/ios/Icon/Icon.swift +10 -1
  72. package/ios/IconButton/IconButton.swift +140 -0
  73. package/ios/Image/Image.swift +16 -3
  74. package/ios/Information/Information.swift +3 -1
  75. package/ios/Input/ErrorView.swift +3 -1
  76. package/ios/Input/Input.swift +72 -33
  77. package/ios/Input/InputPhoneNumber.swift +33 -21
  78. package/ios/Input/InputSearch.swift +107 -48
  79. package/ios/Input/InputTextArea.swift +134 -64
  80. package/ios/InputDropDown/InputDropDown.swift +201 -0
  81. package/ios/InputMoney/InputMoney.swift +347 -0
  82. package/ios/InputOTP/InputOTP.swift +210 -0
  83. package/ios/Loader/Loader.swift +113 -0
  84. package/ios/MoMoUIKits.podspec +5 -0
  85. package/ios/Pagination/PaginationDot.swift +61 -0
  86. package/ios/Pagination/PaginationNumber.swift +35 -0
  87. package/ios/Pagination/PaginationScroll.swift +101 -0
  88. package/ios/Pagination/PaginationWhiteDot.swift +37 -0
  89. package/ios/Popup/PopupDisplay.swift +11 -20
  90. package/ios/Popup/PopupInput.swift +2 -8
  91. package/ios/Popup/PopupNotify.swift +218 -0
  92. package/ios/Popup/PopupPromotion.swift +16 -8
  93. package/ios/ProgressInfo/ProgressInfo.swift +296 -0
  94. package/ios/Radio/Radio.swift +69 -0
  95. package/ios/Rating/Rating.swift +82 -0
  96. package/ios/Resources/MoMoUIKitsColors.xcassets/AccentColor.colorset/Contents.json +11 -0
  97. package/ios/Resources/MoMoUIKitsColors.xcassets/Background.colorset/Contents.json +38 -0
  98. package/ios/Resources/MoMoUIKitsColors.xcassets/Border.colorset/Contents.json +38 -0
  99. package/ios/Resources/MoMoUIKitsColors.xcassets/Card.colorset/Contents.json +38 -0
  100. package/ios/Resources/MoMoUIKitsColors.xcassets/Contents.json +6 -0
  101. package/ios/Resources/MoMoUIKitsColors.xcassets/Error.colorset/Contents.json +38 -0
  102. package/ios/Resources/MoMoUIKitsColors.xcassets/Primary.colorset/Contents.json +38 -0
  103. package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryDark.colorset/Contents.json +38 -0
  104. package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryLight.colorset/Contents.json +38 -0
  105. package/ios/Resources/MoMoUIKitsColors.xcassets/Secondary.colorset/Contents.json +38 -0
  106. package/ios/Resources/MoMoUIKitsColors.xcassets/Success.colorset/Contents.json +38 -0
  107. package/ios/Resources/MoMoUIKitsColors.xcassets/Text.colorset/Contents.json +38 -0
  108. package/ios/Resources/MoMoUIKitsColors.xcassets/TextSecondary.colorset/Contents.json +38 -0
  109. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/Contents.json +9 -0
  110. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-default.colorset/Contents.json +38 -0
  111. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-disable.colorset/Contents.json +38 -0
  112. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-pressed.colorset/Contents.json +38 -0
  113. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-selected.colorset/Contents.json +38 -0
  114. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-surface.colorset/Contents.json +38 -0
  115. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-tonal.colorset/Contents.json +38 -0
  116. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-default.colorset/Contents.json +38 -0
  117. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-disable.colorset/Contents.json +38 -0
  118. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/gradient.colorset/Contents.json +38 -0
  119. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/primary.colorset/Contents.json +38 -0
  120. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/secondary.colorset/Contents.json +38 -0
  121. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-container.colorset/Contents.json +38 -0
  122. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-primary.colorset/Contents.json +38 -0
  123. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-secondary.colorset/Contents.json +38 -0
  124. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-default.colorset/Contents.json +38 -0
  125. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-disable.colorset/Contents.json +38 -0
  126. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-hint.colorset/Contents.json +38 -0
  127. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-secondary.colorset/Contents.json +38 -0
  128. package/ios/Resources/MoMoUIKitsColors.xcassets/Warning.colorset/Contents.json +38 -0
  129. package/ios/Skeleton/Skeleton.swift +99 -0
  130. package/ios/Slider/Slider.swift +237 -0
  131. package/ios/Stepper/Stepper.swift +220 -0
  132. package/ios/Steps/Steps.swift +467 -0
  133. package/ios/SuggestAction/SuggestAction.swift +99 -0
  134. package/ios/Swipeable/SwipeCell.swift +187 -0
  135. package/ios/Swipeable/SwipeCellModel.swift +21 -0
  136. package/ios/Switch/Switch.swift +53 -28
  137. package/ios/TabView/TabView.swift +534 -0
  138. package/ios/Tag/Tag.swift +98 -0
  139. package/ios/Template/TrustBanner/TrustBanner.swift +6 -7
  140. package/ios/Title/Title.swift +269 -0
  141. package/ios/Tooltip/Tooltip.swift +485 -0
  142. package/ios/Typography/FontScaleStore.swift +19 -0
  143. package/ios/Typography/Text.swift +79 -5
  144. package/ios/Typography/Typography.swift +3 -0
  145. package/ios/Uploader/Uploader.swift +174 -0
  146. package/ios/native-kits.podspec +61 -8
  147. package/ios-demo/MoMoUIKitsDemo.podspec +20 -0
  148. package/ios-demo/README.md +120 -0
  149. package/ios-demo/Resources/dot_loading.json +558 -0
  150. package/ios-demo/Resources/icon.json +4052 -0
  151. package/ios-demo/Resources/lottie_circle_loader.json +1 -0
  152. package/ios-demo/Sources/MoMoUIKitsDemo/DemoScaffold.swift +48 -0
  153. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsBadgeDemoView.swift +25 -0
  154. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsButtonDemoView.swift +26 -0
  155. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsCheckboxDemoView.swift +19 -0
  156. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsChipDemoView.swift +33 -0
  157. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsInputDemoView.swift +48 -0
  158. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsPopupDemoView.swift +21 -0
  159. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsRadioDemoView.swift +17 -0
  160. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsTypographyDemoView.swift +28 -0
  161. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoContext.swift +31 -0
  162. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoFactory.swift +24 -0
  163. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AnimatedHeaderDemo.swift +110 -0
  164. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +93 -0
  165. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +269 -0
  166. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BaselineView.swift +117 -0
  167. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BottomTabDemo.swift +89 -0
  168. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +100 -0
  169. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +126 -0
  170. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +63 -0
  171. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +20 -0
  172. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +93 -0
  173. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +107 -0
  174. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +124 -0
  175. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +14 -0
  176. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/HeaderUserDemo.swift +49 -0
  177. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +279 -0
  178. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +58 -0
  179. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +78 -0
  180. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +138 -0
  181. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +111 -0
  182. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +136 -0
  183. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +107 -0
  184. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +73 -0
  185. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +100 -0
  186. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +32 -0
  187. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +57 -0
  188. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +70 -0
  189. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LocalizeDemo.swift +188 -0
  190. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +229 -0
  191. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +72 -0
  192. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +175 -0
  193. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +121 -0
  194. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +76 -0
  195. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +89 -0
  196. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +32 -0
  197. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +56 -0
  198. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +32 -0
  199. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +150 -0
  200. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +138 -0
  201. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +103 -0
  202. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +94 -0
  203. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +79 -0
  204. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +152 -0
  205. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +33 -0
  206. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +190 -0
  207. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +34 -0
  208. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +182 -0
  209. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +109 -0
  210. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +187 -0
  211. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +87 -0
  212. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +131 -0
  213. package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +51 -0
  214. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
  215. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
  216. package/local.properties +2 -2
  217. package/package.json +1 -1
  218. package/publish.sh +53 -0
  219. package/scripts/gen-ios-color.mjs +136 -0
  220. package/.claude/settings.local.json +0 -62
package/CLAUDE.md CHANGED
@@ -40,7 +40,7 @@ Publishing is automated (`publish.sh` + GitLab CI on `[ci build]` / `main`). Do
40
40
  ## Architecture essentials
41
41
 
42
42
  - **Entry point:** wrap content in `NavigationContainer(...)` from `navigation/`. It builds the `Navigator`, takes a host-supplied `Localize` (falls back to an empty one), and provides the CompositionLocals below. **Do not use** `ApplicationContainer` (`application/NavigationContainer.kt`) — deprecated and does **not** wire `LocalLocalize` / `LocalNavigator` / `LocalMaxApi`.
43
- - **Configuration flows via CompositionLocals**, not params. Public ones: `AppTheme`, `AppStatusBar`, `AppNavigationBar` (`const/Theme.kt`); `ApplicationContext`, `AppConfig`, `AppLanguage`, `LocalLocalize`, `ScaleSizeMaxRate` (`application/`); `LocalNavigator`, `LocalMaxApi` (`navigation/`). Read with `X.current`.
43
+ - **Configuration flows via CompositionLocals**, not params. Public ones: `AppTheme`, `AppStatusBar`, `AppNavigationBar` (`const/Theme.kt`); `ApplicationContext`, `AppConfig`, `AppLanguage`, `LocalLocalize` (`application/`); `LocalNavigator`, `LocalMaxApi` (`navigation/`). Read with `X.current`.
44
44
  - **Platform code** goes through `expect`/`actual` in `platform/` — never reference Android/iOS APIs from `commonMain` directly.
45
45
  - **Native bridge:** `IMaxApi` (`vn.momo.maxapi`, exposed as `LocalMaxApi`) is the host-app bridge (dismiss, tracking, device info, language).
46
46
  - Navigation uses a runtime `DynamicScreenRegistry`; overlays (modal/bottom-sheet/snackbar) go through `Navigator` + `OverplayComponentRegistry`.
@@ -40,7 +40,7 @@ kotlin {
40
40
  }
41
41
 
42
42
  cocoapods {
43
- version = "0.163.1-beta.8-debug"
43
+ version = "0.163.1-beta.9-debug"
44
44
  summary = "IOS Shared module"
45
45
  homepage = "https://momo.vn"
46
46
  ios.deploymentTarget = "15.0"
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |spec|
2
2
  spec.name = 'compose'
3
- spec.version = '0.162.2-beta.19'
3
+ spec.version = '0.163.1-beta.9-debug'
4
4
  spec.homepage = 'https://momo.vn'
5
5
  spec.source = { :http=> ''}
6
6
  spec.authors = ''
@@ -0,0 +1,7 @@
1
+ package vn.momo.kits.platform
2
+
3
+ import androidx.compose.runtime.Composable
4
+
5
+ // Android's LocalDensity.fontScale already tracks Configuration.fontScale live.
6
+ @Composable
7
+ actual fun ProvideOsFontScale(content: @Composable () -> Unit) = content()
@@ -8,7 +8,10 @@ import android.graphics.PorterDuffColorFilter
8
8
  import android.os.Build
9
9
  import androidx.compose.foundation.layout.Box
10
10
  import androidx.compose.runtime.Composable
11
+ import androidx.compose.runtime.LaunchedEffect
11
12
  import androidx.compose.runtime.getValue
13
+ import androidx.compose.runtime.rememberUpdatedState
14
+ import androidx.compose.runtime.snapshotFlow
12
15
  import androidx.compose.ui.Modifier
13
16
  import androidx.compose.ui.graphics.Color
14
17
  import androidx.compose.ui.graphics.NativePaint
@@ -21,7 +24,7 @@ import androidx.compose.ui.unit.dp
21
24
  import com.airbnb.lottie.LottieProperty
22
25
  import com.airbnb.lottie.compose.LottieAnimation
23
26
  import com.airbnb.lottie.compose.LottieCompositionSpec
24
- import com.airbnb.lottie.compose.LottieConstants
27
+ import com.airbnb.lottie.compose.animateLottieCompositionAsState
25
28
  import com.airbnb.lottie.compose.rememberLottieComposition
26
29
  import com.airbnb.lottie.compose.rememberLottieDynamicProperties
27
30
  import com.airbnb.lottie.compose.rememberLottieDynamicProperty
@@ -78,11 +81,14 @@ actual fun LottieAnimation(
78
81
  tintColor: Color?,
79
82
  bgColor: Color?,
80
83
  placedAsOverlay: Boolean,
84
+ iterations: Int,
85
+ isPlaying: Boolean,
86
+ onEvent: ((String) -> Unit)?,
81
87
  modifier: Modifier,
82
88
  useCompose: Boolean
83
89
  ) {
84
90
  if (useCompose) {
85
- ComposeLottieAnimation(path, tintColor, bgColor, modifier)
91
+ ComposeLottieAnimation(path, tintColor, bgColor, iterations, isPlaying, onEvent, modifier)
86
92
  return
87
93
  }
88
94
 
@@ -110,9 +116,30 @@ actual fun LottieAnimation(
110
116
  )
111
117
  )
112
118
 
119
+ val lottieState = animateLottieCompositionAsState(
120
+ composition = composition,
121
+ iterations = iterations,
122
+ isPlaying = isPlaying,
123
+ restartOnPlay = false,
124
+ )
125
+
126
+ val currentOnEvent by rememberUpdatedState(onEvent)
127
+
128
+ LaunchedEffect(isPlaying) {
129
+ currentOnEvent?.invoke(if (isPlaying) LottieEvent.Start else LottieEvent.Pause)
130
+ }
131
+
132
+ LaunchedEffect(lottieState) {
133
+ var armed = false
134
+ snapshotFlow { lottieState.isAtEnd }.collect { atEnd ->
135
+ if (!atEnd) armed = true
136
+ else if (armed) { armed = false; currentOnEvent?.invoke(LottieEvent.Finish) }
137
+ }
138
+ }
139
+
113
140
  LottieAnimation(
114
141
  composition = composition,
115
- iterations = LottieConstants.IterateForever,
142
+ progress = { lottieState.progress },
116
143
  dynamicProperties = if (tintColor != null) dynamicProperties else null,
117
144
  modifier = modifier
118
145
  )
@@ -29,6 +29,8 @@ data class MiniAppContext(
29
29
  val permissions: List<Map<String, Any>>? = emptyList(),
30
30
  val features: FeatureFlags? = null,
31
31
  val scaleSizeMaxRate: Float? = null,
32
+ val userScaleRate: Float? = null,
33
+ val useOSScaleRate: Boolean? = null,
32
34
  ) {
33
35
  companion object {
34
36
 
@@ -61,6 +63,8 @@ data class MiniAppContext(
61
63
  permissions = if (!parent.permissions.isNullOrEmpty()) parent.permissions else child.permissions,
62
64
  features = mergeFeatureFlags(parent.features, child.features),
63
65
  scaleSizeMaxRate = parent.scaleSizeMaxRate ?: child.scaleSizeMaxRate,
66
+ userScaleRate = parent.userScaleRate ?: child.userScaleRate,
67
+ useOSScaleRate = parent.useOSScaleRate ?: child.useOSScaleRate,
64
68
  )
65
69
  }
66
70
 
@@ -98,4 +102,5 @@ val LocalComponentInformation = staticCompositionLocalOf<ComponentInformation?>
98
102
  null
99
103
  }
100
104
 
105
+ @Deprecated("Max font scale is fixed at MAX_FONT_SCALE (1.5); this CompositionLocal is no longer read.")
101
106
  val ScaleSizeMaxRate = staticCompositionLocalOf<Float?> { null }
@@ -139,7 +139,7 @@ private fun ToolkitHeaderRight(
139
139
  }
140
140
 
141
141
  fun onPressClose() {
142
- api?.request("dismissAll", "")
142
+ api?.request("dismissAll", "", { _ -> })
143
143
  }
144
144
 
145
145
  fun onPressMore() {
@@ -7,6 +7,7 @@ import androidx.compose.ui.Modifier
7
7
  import androidx.compose.ui.unit.Dp
8
8
  import vn.momo.kits.const.*
9
9
  import vn.momo.kits.modifier.DeprecatedModifier
10
+ import vn.momo.kits.platform.ProvideOsFontScale
10
11
  import vn.momo.kits.platform.getStatusBarHeight
11
12
 
12
13
  @Deprecated("Use IMaxApi instead", ReplaceWith("IMaxApi"))
@@ -93,6 +94,7 @@ fun ApplicationContainer(
93
94
 
94
95
  val appStatusBarHeight = statusBarHeight ?: getStatusBarHeight()
95
96
 
97
+ ProvideOsFontScale {
96
98
  CompositionLocalProvider(
97
99
  AppTheme provides appTheme,
98
100
  PlatformApi provides composeApi,
@@ -103,5 +105,6 @@ fun ApplicationContainer(
103
105
  content()
104
106
  }
105
107
  }
108
+ }
106
109
 
107
110
  }
@@ -0,0 +1,56 @@
1
+ package vn.momo.kits.application
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import androidx.compose.runtime.CompositionLocalProvider
5
+ import androidx.compose.runtime.LaunchedEffect
6
+ import androidx.compose.runtime.remember
7
+ import vn.momo.kits.const.AppTheme
8
+ import vn.momo.kits.const.Theme
9
+ import vn.momo.kits.navigation.LocalMaxApi
10
+ import vn.momo.kits.platform.ProvideOsFontScale
11
+ import vn.momo.maxapi.IMaxApi
12
+
13
+
14
+ @Composable
15
+ fun WidgetContainer(
16
+ theme: Theme? = null,
17
+ miniAppContext: MiniAppContext? = null,
18
+ maxApi: IMaxApi? = null,
19
+ localize: Localize? = null,
20
+ content: @Composable () -> Unit,
21
+ ) {
22
+ val parentContext = LocalContext.current
23
+ val mergedContext = remember(parentContext, miniAppContext) {
24
+ MiniAppContext.merge(parentContext, miniAppContext)
25
+ }
26
+ val resolvedTheme = theme ?: AppTheme.current
27
+ val resolvedLocalize = localize ?: LocalLocalize.current
28
+ val resolvedMaxApi = maxApi ?: LocalMaxApi.current
29
+
30
+ LaunchedEffect(resolvedMaxApi, localize) {
31
+ val api = resolvedMaxApi ?: return@LaunchedEffect
32
+ val target = localize ?: return@LaunchedEffect
33
+ runCatching {
34
+ api.getLanguage(callback = { data ->
35
+ if (parseLanguage(data) == Localize.EN) target.changeLanguage(Localize.EN)
36
+ })
37
+ }
38
+ }
39
+
40
+ ProvideOsFontScale {
41
+ CompositionLocalProvider(
42
+ AppTheme provides resolvedTheme,
43
+ LocalContext provides mergedContext,
44
+ LocalLocalize provides resolvedLocalize,
45
+ LocalMaxApi provides resolvedMaxApi,
46
+ ) {
47
+ content()
48
+ }
49
+ }
50
+ }
51
+
52
+ private fun parseLanguage(raw: Map<String, Any?>?): String? {
53
+ val code = (raw?.get("response") as? String)?.trim()?.lowercase()
54
+ if (code.isNullOrEmpty()) return null
55
+ return if (code.startsWith(Localize.EN)) Localize.EN else Localize.VI
56
+ }
@@ -4,6 +4,10 @@ import androidx.compose.runtime.Composable
4
4
  import androidx.compose.runtime.CompositionLocalProvider
5
5
  import vn.momo.kits.application.ScaleSizeMaxRate
6
6
 
7
+ @Deprecated(
8
+ "Max font scale is fixed at MAX_FONT_SCALE (1.5); this override is no longer applied. Remove the wrapper.",
9
+ ReplaceWith("content()"),
10
+ )
7
11
  @Composable
8
12
  fun ScaleSizeScope(
9
13
  scaleSizeMaxRate: Float? = null,
@@ -0,0 +1,22 @@
1
+ package vn.momo.kits.const
2
+
3
+ import androidx.compose.runtime.getValue
4
+ import androidx.compose.runtime.mutableStateOf
5
+ import androidx.compose.runtime.setValue
6
+
7
+ // App-wide font-scale holder. The kit is sandboxed and can't read the host cache directly, so the
8
+ // host (which sees both core and this kit) seeds this once at startup and pushes runtime updates into
9
+ // it. scaleSize() reads it as the fallback, so every screen — including direct NavigationContainer
10
+ // screens with no host-pushed MiniAppContext — scales with no per-render prop and no async flicker.
11
+ // Backed by snapshot state: writes recompose text automatically.
12
+ object KitFontScale {
13
+ var userScaleRate by mutableStateOf(1f)
14
+ private set
15
+ var useOSScaleRate by mutableStateOf(true)
16
+ private set
17
+
18
+ fun update(userScaleRate: Float, useOSScaleRate: Boolean) {
19
+ this.userScaleRate = userScaleRate
20
+ this.useOSScaleRate = useOSScaleRate
21
+ }
22
+ }
@@ -11,7 +11,7 @@ import androidx.compose.ui.unit.*
11
11
  import org.jetbrains.compose.resources.Font
12
12
  import org.jetbrains.compose.resources.FontResource
13
13
  import org.jetbrains.compose.resources.InternalResourceApi
14
- import vn.momo.kits.application.ScaleSizeMaxRate
14
+ import vn.momo.kits.application.LocalContext
15
15
  import vn.momo.kits.platform.getScreenDimensions
16
16
  import vn.momo.uikits.resources.*
17
17
  import kotlin.math.max
@@ -23,7 +23,13 @@ const val MAX_DEVICE_SCALE = 5
23
23
 
24
24
  @Composable
25
25
  fun scaleSize(size: Float): Float {
26
- val scaleSizeMaxRate: Float = ScaleSizeMaxRate.current ?: MAX_FONT_SCALE
26
+ val context = LocalContext.current
27
+ // Host-pushed context wins; otherwise fall back to the app-wide KitFontScale holder.
28
+ val useOsScale = context?.useOSScaleRate ?: KitFontScale.useOSScaleRate
29
+ if (!useOsScale) {
30
+ return size * (context?.userScaleRate ?: KitFontScale.userScaleRate)
31
+ }
32
+ val scaleSizeMaxRate: Float = MAX_FONT_SCALE
27
33
  val deviceWidth = getScreenDimensions().width
28
34
  val deviceScale = deviceWidth / DEFAULT_SCREEN_SIZE
29
35
 
@@ -1,2 +1,65 @@
1
1
  package vn.momo.kits.layout
2
2
 
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.layout.Arrangement
5
+ import androidx.compose.foundation.layout.Box
6
+ import androidx.compose.foundation.layout.BoxWithConstraints
7
+ import androidx.compose.foundation.layout.ExperimentalLayoutApi
8
+ import androidx.compose.foundation.layout.FlowRow
9
+ import androidx.compose.foundation.layout.fillMaxWidth
10
+ import androidx.compose.foundation.layout.padding
11
+ import androidx.compose.foundation.shape.RoundedCornerShape
12
+ import androidx.compose.runtime.Composable
13
+ import androidx.compose.runtime.CompositionLocalProvider
14
+ import androidx.compose.ui.Modifier
15
+ import androidx.compose.ui.draw.clip
16
+ import androidx.compose.ui.draw.shadow
17
+ import androidx.compose.ui.unit.dp
18
+ import vn.momo.kits.components.Image
19
+ import vn.momo.kits.const.AppTheme
20
+ import vn.momo.kits.const.Radius
21
+
22
+ /**
23
+ * A white rounded surface card that lays its [Item]s on a 12-column grid
24
+ * (React kit foundations/Layout/Card). 8dp gutter, 12dp padding, 12dp
25
+ * horizontal margin, Radius.M corners, background = theme surface, optional
26
+ * shadow or [backgroundImage]. Items flow left-to-right and wrap.
27
+ */
28
+ @OptIn(ExperimentalLayoutApi::class)
29
+ @Composable
30
+ fun Card(
31
+ useShadow: Boolean = false,
32
+ backgroundImage: String? = null,
33
+ modifier: Modifier = Modifier,
34
+ content: @Composable () -> Unit,
35
+ ) {
36
+ val columns = 12
37
+ val gutter = 8.dp
38
+ val shape = RoundedCornerShape(Radius.M)
39
+ var surface = modifier.fillMaxWidth().padding(horizontal = 12.dp)
40
+ if (useShadow) surface = surface.shadow(4.dp, shape)
41
+ surface = surface.clip(shape)
42
+ // The React kit drops the surface colour when a backgroundImage is supplied
43
+ // (`!!backgroundImage && { backgroundColor: undefined }`).
44
+ if (backgroundImage == null) surface = surface.background(AppTheme.current.colors.background.surface)
45
+ Box(modifier = surface) {
46
+ // React renders this as an absolutely-filled child BEHIND the content
47
+ // (styles.imageBackground: position absolute, inset 0) — matchParentSize
48
+ // fills the card without contributing to its measured size.
49
+ if (backgroundImage != null) {
50
+ Image(source = backgroundImage, modifier = Modifier.matchParentSize())
51
+ }
52
+ BoxWithConstraints(modifier = Modifier.fillMaxWidth().padding(12.dp)) {
53
+ // `- 1.dp / columns` mirrors the React kit's `- 1 / numberOfColumns`
54
+ // nudge: it keeps a full 12-span Item ~1dp narrower than the content
55
+ // box so sub-pixel rounding can never overflow and wrap the FlowRow.
56
+ val sizePerSpan = (maxWidth - gutter * (columns - 1)) / columns - 1.dp / columns
57
+ CompositionLocalProvider(LocalGridContext provides GridContext(columns, gutter, sizePerSpan)) {
58
+ FlowRow(
59
+ horizontalArrangement = Arrangement.spacedBy(gutter),
60
+ verticalArrangement = Arrangement.spacedBy(gutter),
61
+ ) { content() }
62
+ }
63
+ }
64
+ }
65
+ }
@@ -4,32 +4,45 @@ import androidx.compose.foundation.layout.Box
4
4
  import androidx.compose.foundation.layout.height
5
5
  import androidx.compose.foundation.layout.width
6
6
  import androidx.compose.runtime.Composable
7
+ import androidx.compose.runtime.compositionLocalOf
7
8
  import androidx.compose.ui.Modifier
8
9
  import androidx.compose.ui.unit.Dp
10
+ import androidx.compose.ui.unit.dp
9
11
 
12
+ /**
13
+ * Grid context supplied by [Section] / [Card]: the per-span cell size + gutter,
14
+ * so an [Item] can resolve its pixel width from a 1-12 `widthSpan`. Mirrors the
15
+ * React kit's GridContext (foundations/Layout/GridSystem).
16
+ */
10
17
  data class GridContext(
11
- val numberOfColumns: Number,
12
- val gutterSize: Number,
13
- val sizePerSpan: Number,
14
- val getSizeSpan: (Number) -> Number
15
- )
18
+ val numberOfColumns: Int = 12,
19
+ val gutter: Dp = 12.dp,
20
+ val sizePerSpan: Dp = 0.dp,
21
+ ) {
22
+ /** Width covering `span` columns + the (span-1) gutters between them. */
23
+ fun sizeForSpan(span: Int): Dp = sizePerSpan * span + gutter * (span - 1)
24
+ }
25
+
26
+ /** Provided by Section/Card; null when an Item is rendered outside a grid. */
27
+ val LocalGridContext = compositionLocalOf<GridContext?> { null }
16
28
 
29
+ /**
30
+ * A grid cell. `widthSpan` (1-12) sets the width as a fraction of the parent
31
+ * Section/Card; the parent's flex-wrap flows the cells into rows. Rendered
32
+ * outside a grid it just wraps its content at its natural size.
33
+ */
17
34
  @Composable
18
35
  fun Item(
19
- heightSpan: Number = 1,
20
- widthSpan: Number = 1,
21
- content: @Composable () -> Unit,
36
+ widthSpan: Int = 12,
37
+ heightSpan: Int = 0,
22
38
  modifier: Modifier = Modifier,
23
- grid: GridContext
39
+ content: @Composable () -> Unit,
24
40
  ) {
25
-
26
- val widthItem = grid.getSizeSpan(widthSpan)
27
- val heightItem = grid.getSizeSpan(heightSpan)
28
-
29
- Box(
30
- modifier = modifier.width(width = Dp(widthItem.toFloat()))
31
- .height(height = Dp(heightItem.toFloat()))
32
- ) {
33
- content()
41
+ val grid = LocalGridContext.current
42
+ var m = modifier
43
+ if (grid != null) {
44
+ m = m.width(grid.sizeForSpan(widthSpan))
45
+ if (heightSpan > 0) m = m.height(grid.sizeForSpan(heightSpan))
34
46
  }
35
- }
47
+ Box(modifier = m) { content() }
48
+ }
@@ -1,2 +1,51 @@
1
1
  package vn.momo.kits.layout
2
2
 
3
+ import androidx.compose.foundation.layout.Arrangement
4
+ import androidx.compose.foundation.layout.Box
5
+ import androidx.compose.foundation.layout.BoxWithConstraints
6
+ import androidx.compose.foundation.layout.ExperimentalLayoutApi
7
+ import androidx.compose.foundation.layout.FlowRow
8
+ import androidx.compose.foundation.layout.fillMaxWidth
9
+ import androidx.compose.foundation.layout.padding
10
+ import androidx.compose.runtime.Composable
11
+ import androidx.compose.runtime.CompositionLocalProvider
12
+ import androidx.compose.ui.Modifier
13
+ import androidx.compose.ui.unit.dp
14
+ import vn.momo.kits.components.Image
15
+
16
+ /**
17
+ * A transparent 12-column grid row that wraps its [Item]s (React kit
18
+ * foundations/Layout/Section). 12dp gutter; 12dp horizontal margin when
19
+ * `useMargin`; optional [backgroundImage]. Items flow left-to-right and wrap.
20
+ */
21
+ @OptIn(ExperimentalLayoutApi::class)
22
+ @Composable
23
+ fun Section(
24
+ useMargin: Boolean = true,
25
+ backgroundImage: String? = null,
26
+ modifier: Modifier = Modifier,
27
+ content: @Composable () -> Unit,
28
+ ) {
29
+ val columns = 12
30
+ val gutter = 12.dp
31
+ val margin = if (useMargin) 12.dp else 0.dp
32
+ Box(modifier = modifier.fillMaxWidth().padding(horizontal = margin)) {
33
+ // React renders this as an absolutely-filled child behind the content
34
+ // (styles.imageBackground: position absolute, inset 0).
35
+ if (backgroundImage != null) {
36
+ Image(source = backgroundImage, modifier = Modifier.matchParentSize())
37
+ }
38
+ BoxWithConstraints(modifier = Modifier.fillMaxWidth()) {
39
+ // `- 1.dp / columns` mirrors the React kit's `- 1 / numberOfColumns`
40
+ // nudge — keeps a full 12-span Item ~1dp inside the content box so
41
+ // sub-pixel rounding can never overflow and wrap the FlowRow.
42
+ val sizePerSpan = (maxWidth - gutter * (columns - 1)) / columns - 1.dp / columns
43
+ CompositionLocalProvider(LocalGridContext provides GridContext(columns, gutter, sizePerSpan)) {
44
+ FlowRow(
45
+ horizontalArrangement = Arrangement.spacedBy(gutter),
46
+ verticalArrangement = Arrangement.spacedBy(gutter),
47
+ ) { content() }
48
+ }
49
+ }
50
+ }
51
+ }
@@ -117,7 +117,7 @@ internal fun BottomSheet(
117
117
  easing = CubicBezierEasing(0.3f, 0.0f, 0.8f, 0.15f)
118
118
  )
119
119
  )
120
- navigator.pop()
120
+ OverplayComponentRegistry.hardClearAfterDismiss()
121
121
  }
122
122
  }
123
123
 
@@ -81,7 +81,7 @@ internal fun ModalScreen(
81
81
  targetValue = 0.8f,
82
82
  animationSpec = tween(durationMillis = 200)
83
83
  )
84
- navigator.pop()
84
+ OverplayComponentRegistry.hardClearAfterDismiss()
85
85
  }
86
86
  }
87
87
 
@@ -85,7 +85,9 @@ data class NavigationOptions(
85
85
  val footerComponent: @Composable (() -> Unit)? = null,
86
86
  val floatingButtonProps: FloatingButtonProps? = null,
87
87
  val keyboardOptions: KeyboardOptions = KeyboardOptions()
88
- )
88
+ ) {
89
+ internal fun hasFooter() : Boolean = footerComponent != null
90
+ }
89
91
 
90
92
  data class KeyboardOptions(
91
93
  val keyboardShouldPersistTaps: Boolean = false,