@momo-kits/native-kits 0.163.1-beta.2-debug → 0.163.1-beta.20-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 (245) hide show
  1. package/.claude/settings.local.json +112 -0
  2. package/CLAUDE.md +1 -1
  3. package/compose/build.gradle.kts +2 -1
  4. package/compose/build.gradle.kts.backup +1 -0
  5. package/compose/compose.podspec +1 -1
  6. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
  7. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +30 -3
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +8 -10
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +2 -3
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +3 -0
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +56 -0
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +11 -9
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -1
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +40 -55
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +69 -26
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +5 -5
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +3 -1
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +21 -0
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +3 -6
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +19 -0
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +22 -0
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +28 -21
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +50 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +25 -22
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +37 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +68 -22
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +1 -1
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +7 -1
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +112 -115
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +15 -3
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +33 -9
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +6 -5
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +3 -1
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +2 -1
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -1
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +23 -2
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +11 -0
  39. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
  40. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +26 -3
  41. package/gradle/libs.versions.toml +2 -0
  42. package/gradle.properties +1 -1
  43. package/ios/Application/ApplicationEnvironment.swift +15 -3
  44. package/ios/Application/Components.swift +36 -30
  45. package/ios/Application/FloatingButton.swift +10 -9
  46. package/ios/Application/Localize.swift +309 -0
  47. package/ios/Application/MaxApi.swift +18 -0
  48. package/ios/Application/Navigation/BottomTab/BottomTab.swift +104 -0
  49. package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +215 -0
  50. package/ios/Application/Navigation/BottomTab/CurvedContainer.swift +65 -0
  51. package/ios/Application/Navigation/HeaderBackProps.swift +66 -0
  52. package/ios/Application/Navigation/HeaderTitle.swift +57 -0
  53. package/ios/Application/Navigation/HeaderUser.swift +209 -0
  54. package/ios/Application/Navigation/NavigationContainer.swift +203 -0
  55. package/ios/Application/Navigation/NavigationOptions.swift +109 -0
  56. package/ios/Application/Navigation/Navigator.swift +385 -0
  57. package/ios/Application/Navigation/Overplay/BottomSheet.swift +256 -0
  58. package/ios/Application/Navigation/Overplay/ModalScreen.swift +74 -0
  59. package/ios/Application/Navigation/Overplay/SnackBar.swift +144 -0
  60. package/ios/Application/Navigation/Tracking/ScreenTracker.swift +117 -0
  61. package/ios/Application/Navigation/component/Header.swift +178 -0
  62. package/ios/Application/Navigation/component/HeaderBackground.swift +83 -0
  63. package/ios/Application/Navigation/component/HeaderColor.swift +65 -0
  64. package/ios/Application/Navigation/component/HeaderRightWidthKey.swift +11 -0
  65. package/ios/Application/Navigation/component/NavigationHeaderRight.swift +196 -0
  66. package/ios/Application/Screen.swift +2 -1
  67. package/ios/Application/StackScreen.swift +501 -0
  68. package/ios/Avatar/Avatar.swift +193 -0
  69. package/ios/Badge/Badge.swift +11 -14
  70. package/ios/Badge/BadgeRibbon.swift +91 -17
  71. package/ios/BaselineView/BaselineView.swift +163 -0
  72. package/ios/Button/Button.swift +137 -28
  73. package/ios/Carousel/Carousel.swift +196 -0
  74. package/ios/Checkbox/Checkbox.swift +23 -28
  75. package/ios/Chip/Chip.swift +56 -33
  76. package/ios/Collapse/Collapse.swift +192 -0
  77. package/ios/Colors+Radius+Spacing/Colors.swift +20 -17
  78. package/ios/Colors+Radius+Spacing/Spacing.swift +3 -1
  79. package/ios/Colors+Radius+Spacing/Theme.swift +295 -0
  80. package/ios/DateTimePicker/DateTimePicker.swift +212 -0
  81. package/ios/DateTimePicker/DateTimePickerTypes.swift +55 -0
  82. package/ios/DateTimePicker/DateTimePickerUtils.swift +167 -0
  83. package/ios/DateTimePicker/WheelPicker.swift +165 -0
  84. package/ios/Divider/Divider.swift +16 -0
  85. package/ios/Extensions/ActiveOpacityButtonStyle.swift +14 -0
  86. package/ios/Extensions/Color++.swift +32 -0
  87. package/ios/Icon/Icon.swift +10 -1
  88. package/ios/IconButton/IconButton.swift +140 -0
  89. package/ios/Image/Image.swift +16 -3
  90. package/ios/Information/Information.swift +3 -1
  91. package/ios/Input/ErrorView.swift +3 -1
  92. package/ios/Input/Input.swift +72 -33
  93. package/ios/Input/InputPhoneNumber.swift +33 -21
  94. package/ios/Input/InputSearch.swift +107 -48
  95. package/ios/Input/InputTextArea.swift +134 -64
  96. package/ios/InputDropDown/InputDropDown.swift +201 -0
  97. package/ios/InputMoney/InputMoney.swift +347 -0
  98. package/ios/InputOTP/InputOTP.swift +210 -0
  99. package/ios/Loader/Loader.swift +113 -0
  100. package/ios/MoMoUIKits.podspec +5 -0
  101. package/ios/Pagination/PaginationDot.swift +61 -0
  102. package/ios/Pagination/PaginationNumber.swift +35 -0
  103. package/ios/Pagination/PaginationScroll.swift +101 -0
  104. package/ios/Pagination/PaginationWhiteDot.swift +37 -0
  105. package/ios/Popup/PopupDisplay.swift +11 -20
  106. package/ios/Popup/PopupInput.swift +2 -8
  107. package/ios/Popup/PopupNotify.swift +218 -0
  108. package/ios/Popup/PopupPromotion.swift +5 -3
  109. package/ios/ProgressInfo/ProgressInfo.swift +296 -0
  110. package/ios/Radio/Radio.swift +69 -0
  111. package/ios/Rating/Rating.swift +82 -0
  112. package/ios/Resources/MoMoUIKitsColors.xcassets/AccentColor.colorset/Contents.json +11 -0
  113. package/ios/Resources/MoMoUIKitsColors.xcassets/Background.colorset/Contents.json +38 -0
  114. package/ios/Resources/MoMoUIKitsColors.xcassets/Border.colorset/Contents.json +38 -0
  115. package/ios/Resources/MoMoUIKitsColors.xcassets/Card.colorset/Contents.json +38 -0
  116. package/ios/Resources/MoMoUIKitsColors.xcassets/Contents.json +6 -0
  117. package/ios/Resources/MoMoUIKitsColors.xcassets/Error.colorset/Contents.json +38 -0
  118. package/ios/Resources/MoMoUIKitsColors.xcassets/Primary.colorset/Contents.json +38 -0
  119. package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryDark.colorset/Contents.json +38 -0
  120. package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryLight.colorset/Contents.json +38 -0
  121. package/ios/Resources/MoMoUIKitsColors.xcassets/Secondary.colorset/Contents.json +38 -0
  122. package/ios/Resources/MoMoUIKitsColors.xcassets/Success.colorset/Contents.json +38 -0
  123. package/ios/Resources/MoMoUIKitsColors.xcassets/Text.colorset/Contents.json +38 -0
  124. package/ios/Resources/MoMoUIKitsColors.xcassets/TextSecondary.colorset/Contents.json +38 -0
  125. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/Contents.json +9 -0
  126. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-default.colorset/Contents.json +38 -0
  127. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-disable.colorset/Contents.json +38 -0
  128. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-pressed.colorset/Contents.json +38 -0
  129. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-selected.colorset/Contents.json +38 -0
  130. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-surface.colorset/Contents.json +38 -0
  131. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-tonal.colorset/Contents.json +38 -0
  132. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-default.colorset/Contents.json +38 -0
  133. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-disable.colorset/Contents.json +38 -0
  134. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/gradient.colorset/Contents.json +38 -0
  135. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/primary.colorset/Contents.json +38 -0
  136. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/secondary.colorset/Contents.json +38 -0
  137. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-container.colorset/Contents.json +38 -0
  138. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-primary.colorset/Contents.json +38 -0
  139. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-secondary.colorset/Contents.json +38 -0
  140. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-default.colorset/Contents.json +38 -0
  141. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-disable.colorset/Contents.json +38 -0
  142. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-hint.colorset/Contents.json +38 -0
  143. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-secondary.colorset/Contents.json +38 -0
  144. package/ios/Resources/MoMoUIKitsColors.xcassets/Warning.colorset/Contents.json +38 -0
  145. package/ios/Skeleton/Skeleton.swift +99 -0
  146. package/ios/Slider/Slider.swift +237 -0
  147. package/ios/Stepper/Stepper.swift +220 -0
  148. package/ios/Steps/Steps.swift +467 -0
  149. package/ios/SuggestAction/SuggestAction.swift +99 -0
  150. package/ios/Swipeable/SwipeCell.swift +187 -0
  151. package/ios/Swipeable/SwipeCellModel.swift +21 -0
  152. package/ios/Switch/Switch.swift +53 -28
  153. package/ios/TabView/TabView.swift +534 -0
  154. package/ios/Tag/Tag.swift +98 -0
  155. package/ios/Template/TrustBanner/TrustBanner.swift +7 -8
  156. package/ios/Title/Title.swift +269 -0
  157. package/ios/Tooltip/Tooltip.swift +485 -0
  158. package/ios/Typography/FontScaleStore.swift +19 -0
  159. package/ios/Typography/Text.swift +86 -17
  160. package/ios/Typography/Typography.swift +12 -14
  161. package/ios/Uploader/Uploader.swift +174 -0
  162. package/ios/native-kits.podspec +61 -8
  163. package/ios-demo/MoMoUIKitsDemo.podspec +20 -0
  164. package/ios-demo/README.md +120 -0
  165. package/ios-demo/Resources/dot_loading.json +558 -0
  166. package/ios-demo/Resources/icon.json +4052 -0
  167. package/ios-demo/Resources/lottie_circle_loader.json +1 -0
  168. package/ios-demo/Sources/MoMoUIKitsDemo/DemoScaffold.swift +48 -0
  169. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsBadgeDemoView.swift +25 -0
  170. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsButtonDemoView.swift +26 -0
  171. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsCheckboxDemoView.swift +19 -0
  172. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsChipDemoView.swift +33 -0
  173. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsInputDemoView.swift +48 -0
  174. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsPopupDemoView.swift +21 -0
  175. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsRadioDemoView.swift +17 -0
  176. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsTypographyDemoView.swift +28 -0
  177. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoContext.swift +31 -0
  178. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoFactory.swift +24 -0
  179. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AnimatedHeaderDemo.swift +110 -0
  180. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +93 -0
  181. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +269 -0
  182. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BaselineView.swift +117 -0
  183. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BottomTabDemo.swift +89 -0
  184. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +100 -0
  185. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +126 -0
  186. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +64 -0
  187. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +20 -0
  188. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +93 -0
  189. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +107 -0
  190. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +124 -0
  191. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +14 -0
  192. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/HeaderUserDemo.swift +49 -0
  193. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +279 -0
  194. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +58 -0
  195. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +78 -0
  196. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +138 -0
  197. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +111 -0
  198. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +136 -0
  199. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +107 -0
  200. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +73 -0
  201. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +100 -0
  202. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +32 -0
  203. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +57 -0
  204. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +70 -0
  205. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LocalizeDemo.swift +188 -0
  206. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +229 -0
  207. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +72 -0
  208. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +175 -0
  209. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +121 -0
  210. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +76 -0
  211. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +89 -0
  212. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +32 -0
  213. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +56 -0
  214. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +32 -0
  215. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +150 -0
  216. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +138 -0
  217. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +103 -0
  218. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +94 -0
  219. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +79 -0
  220. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +152 -0
  221. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +33 -0
  222. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +190 -0
  223. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +34 -0
  224. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +182 -0
  225. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +109 -0
  226. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +187 -0
  227. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +87 -0
  228. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +131 -0
  229. package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +51 -0
  230. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
  231. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
  232. package/local.properties +2 -2
  233. package/package.json +1 -1
  234. package/publish.sh +53 -0
  235. package/scripts/gen-ios-color.mjs +136 -0
  236. package/example/ios/Example.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  237. package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  238. package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -5
  239. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
  240. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
  241. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImage.xcscheme +0 -58
  242. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +0 -58
  243. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SkeletonUI.xcscheme +0 -58
  244. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -46
  245. package/ios/Application/FontScaleStore.swift +0 -59
@@ -1,7 +1,9 @@
1
1
  package vn.momo.kits.components
2
2
 
3
3
  import androidx.compose.foundation.border
4
+ import androidx.compose.foundation.layout.Box
4
5
  import androidx.compose.foundation.layout.BoxWithConstraints
6
+ import androidx.compose.foundation.layout.fillMaxSize
5
7
  import androidx.compose.runtime.Composable
6
8
  import androidx.compose.runtime.getValue
7
9
  import androidx.compose.runtime.mutableStateOf
@@ -17,10 +19,12 @@ import androidx.compose.ui.semantics.contentDescription
17
19
  import androidx.compose.ui.semantics.semantics
18
20
  import androidx.compose.ui.platform.LocalDensity
19
21
  import androidx.compose.ui.unit.dp
20
- import coil3.compose.AsyncImage
22
+ import coil3.compose.AsyncImage as CoilAsyncImage
21
23
  import vn.momo.kits.application.IsShowBaseLineDebug
22
24
  import vn.momo.kits.const.AppTheme
23
25
  import vn.momo.kits.const.Colors
26
+ import vn.momo.kits.gifimage.GifImage
27
+ import vn.momo.kits.gifimage.GifImageState
24
28
  import vn.momo.kits.modifier.conditional
25
29
 
26
30
  data class Options(
@@ -73,6 +77,19 @@ private fun getHostFromUrl(url: String): String? {
73
77
  }
74
78
  }
75
79
 
80
+ private fun isGifUrl(url: String): Boolean {
81
+ val path = url.substringBefore('#').substringBefore('?')
82
+ return path.endsWith(".gif", ignoreCase = true)
83
+ }
84
+
85
+ private fun GifImageState.toImageState(): ImageState {
86
+ return when (this) {
87
+ GifImageState.Success -> ImageState.Success
88
+ GifImageState.Error -> ImageState.Error
89
+ GifImageState.Loading -> ImageState.Loading
90
+ }
91
+ }
92
+
76
93
  // Optimized query parameter appending
77
94
  private fun appendSizeQueryParam(url: String, value: String): String {
78
95
  val fragmentIndex = url.indexOf('#')
@@ -95,12 +112,12 @@ fun Image(
95
112
  modifier: Modifier = Modifier,
96
113
  options: Options? = null,
97
114
  loading: Boolean = true,
115
+ onStateChanged: (ImageState) -> Unit = {},
98
116
  ) {
99
117
  val imageOptions = remember(options) {
100
118
  options ?: Options()
101
119
  }
102
120
 
103
- var imageState by remember { mutableStateOf(ImageState.Loading) }
104
121
  val density = LocalDensity.current
105
122
 
106
123
  BoxWithConstraints(
@@ -121,34 +138,46 @@ fun Image(
121
138
  processedUrl
122
139
  }
123
140
  }
124
- else -> source
141
+ else -> source.toString()
125
142
  }
126
143
  }
127
144
 
128
- AsyncImage(
129
- modifier = Modifier.matchParentSize(),
130
- model = urlToLoad,
131
- contentDescription = null,
132
- contentScale = imageOptions.contentScale,
133
- alignment = imageOptions.alignment,
134
- colorFilter = imageOptions.colorFilter,
135
- alpha = imageOptions.alpha,
136
- onLoading = { imageState = ImageState.Loading },
137
- onSuccess = { imageState = ImageState.Success },
138
- onError = { imageState = ImageState.Error },
139
- )
145
+ var imageState by remember(urlToLoad) { mutableStateOf(ImageState.Loading) }
146
+ fun updateImageState(state: ImageState) {
147
+ imageState = state
148
+ onStateChanged(state)
149
+ }
150
+
151
+ if (isGifUrl(urlToLoad)) {
152
+ GifImage(
153
+ modifier = Modifier.matchParentSize(),
154
+ url = urlToLoad,
155
+ contentDescription = null,
156
+ contentScale = imageOptions.contentScale,
157
+ alignment = imageOptions.alignment,
158
+ colorFilter = imageOptions.colorFilter,
159
+ alpha = imageOptions.alpha,
160
+ onStateChanged = { updateImageState(it.toImageState()) },
161
+ )
162
+ } else {
163
+ CoilAsyncImage(
164
+ modifier = Modifier.matchParentSize(),
165
+ model = urlToLoad,
166
+ contentDescription = null,
167
+ contentScale = imageOptions.contentScale,
168
+ alignment = imageOptions.alignment,
169
+ colorFilter = imageOptions.colorFilter,
170
+ alpha = imageOptions.alpha,
171
+ onLoading = { updateImageState(ImageState.Loading) },
172
+ onSuccess = { updateImageState(ImageState.Success) },
173
+ onError = { updateImageState(ImageState.Error) },
174
+ )
175
+ }
140
176
 
141
177
  when (imageState) {
142
- ImageState.Loading -> if (loading) Skeleton()
143
- ImageState.Error -> {
144
- val theme = AppTheme.current
145
- Icon(
146
- source = "media_fail",
147
- color = theme.colors.text.disable,
148
- modifier = Modifier.align(Alignment.Center)
149
- )
150
- }
151
178
  ImageState.Success -> {}
179
+ ImageState.Error -> ImageError()
180
+ ImageState.Loading -> if (loading) Skeleton()
152
181
  }
153
182
  }
154
183
  }
@@ -156,7 +185,7 @@ fun Image(
156
185
  // Extracted URL processing logic for better performance
157
186
  private fun processImageUrl(url: String, maxWidth: androidx.compose.ui.unit.Dp, density: androidx.compose.ui.unit.Density): String {
158
187
  val host = getHostFromUrl(url)
159
- return if (host != null && supportedDomains.contains(host)) {
188
+ return if (!isGifUrl(url) && host != null && supportedDomains.contains(host)) {
160
189
  val widthPx = with(density) { maxWidth.roundToPx() }
161
190
  val pixelRatio = density.density
162
191
  val pixelFitForWidth = widthPx * pixelRatio
@@ -167,6 +196,20 @@ private fun processImageUrl(url: String, maxWidth: androidx.compose.ui.unit.Dp,
167
196
  }
168
197
  }
169
198
 
199
+ @Composable
200
+ private fun ImageError() {
201
+ val theme = AppTheme.current
202
+ Box(
203
+ modifier = Modifier.fillMaxSize(),
204
+ contentAlignment = Alignment.Center
205
+ ) {
206
+ Icon(
207
+ source = "media_fail",
208
+ color = theme.colors.text.disable,
209
+ )
210
+ }
211
+ }
212
+
170
213
  @Composable
171
214
  fun Image(
172
215
  source: Painter,
@@ -185,4 +228,4 @@ fun Image(
185
228
  colorFilter = colorFilter,
186
229
  alpha = alpha,
187
230
  )
188
- }
231
+ }
@@ -29,6 +29,7 @@ import androidx.compose.ui.Alignment
29
29
  import androidx.compose.ui.Modifier
30
30
  import androidx.compose.ui.focus.onFocusChanged
31
31
  import androidx.compose.ui.graphics.Color
32
+ import androidx.compose.ui.graphics.takeOrElse
32
33
  import androidx.compose.ui.text.TextStyle
33
34
  import androidx.compose.ui.text.input.KeyboardType
34
35
  import androidx.compose.ui.text.style.TextOverflow
@@ -49,7 +50,7 @@ import vn.momo.kits.utils.ifTrue
49
50
  internal fun RenderRightIconSearch(
50
51
  loading: Boolean,
51
52
  icon: String,
52
- color: Color,
53
+ color: Color?,
53
54
  onClick: () -> Unit,
54
55
  iconModifier: Modifier = Modifier
55
56
  ) {
@@ -57,7 +58,7 @@ internal fun RenderRightIconSearch(
57
58
  Box(Modifier.padding(horizontal = Spacing.S)) {
58
59
  CircularProgressIndicator(
59
60
  modifier = Modifier.size(16.dp),
60
- color = color,
61
+ color = color ?: AppTheme.current.colors.text.default,
61
62
  trackColor = Color.Transparent,
62
63
  strokeWidth = 2.dp
63
64
  )
@@ -90,7 +91,7 @@ data class InputSearchProps(
90
91
  val onPressButtonText: () -> Unit = {},
91
92
  val disabled: Boolean = false,
92
93
  val icon: String = "",
93
- val iconColor: Color = Color(0xff),
94
+ val iconColor: Color? = Color.Unspecified,
94
95
  val onRightIconPressed: () -> Unit = {},
95
96
  val onFocus: () -> Unit = {},
96
97
  val onBlur: () -> Unit = {},
@@ -113,7 +114,6 @@ data class InputSearchProps(
113
114
  fun InputSearch(
114
115
  inputSearchProps: InputSearchProps = InputSearchProps(
115
116
  text = remember { mutableStateOf("") },
116
- iconColor = AppTheme.current.colors.text.default
117
117
  ),
118
118
  ) {
119
119
  var isFocused by remember { mutableStateOf(false) }
@@ -121,7 +121,7 @@ fun InputSearch(
121
121
  val disabledColor = AppTheme.current.colors.text.disable
122
122
  var textColor = AppTheme.current.colors.text.default
123
123
  var placeholderColor = AppTheme.current.colors.text.hint
124
- var iconTintColor = inputSearchProps.iconColor
124
+ var iconTintColor = inputSearchProps.iconColor?.takeOrElse { AppTheme.current.colors.text.default }
125
125
 
126
126
  if (inputSearchProps.disabled) {
127
127
  textColor = disabledColor
@@ -21,9 +21,11 @@ import androidx.compose.ui.unit.sp
21
21
  import androidx.compose.ui.zIndex
22
22
  import vn.momo.kits.application.IsShowBaseLineDebug
23
23
  import vn.momo.kits.const.*
24
+ import vn.momo.kits.modifier.InternalApi
24
25
  import vn.momo.kits.modifier.conditional
25
26
 
26
- internal const val MAX_LENGTH = 300
27
+ @InternalApi
28
+ const val MAX_LENGTH = 300
27
29
  internal val DEFAULT_HEIGHT = 104.dp
28
30
 
29
31
  @Composable
@@ -0,0 +1,21 @@
1
+ package vn.momo.kits.components
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import androidx.compose.runtime.CompositionLocalProvider
5
+ import vn.momo.kits.application.ScaleSizeMaxRate
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
+ )
11
+ @Composable
12
+ fun ScaleSizeScope(
13
+ scaleSizeMaxRate: Float? = null,
14
+ content: @Composable () -> Unit
15
+ ) {
16
+ CompositionLocalProvider(
17
+ ScaleSizeMaxRate provides scaleSizeMaxRate,
18
+ ) {
19
+ content()
20
+ }
21
+ }
@@ -36,7 +36,6 @@ fun Text(
36
36
  softWrap: Boolean = true,
37
37
  accessibilityId: String? = null,
38
38
  inlineContent: Map<String, InlineTextContent> = mapOf(),
39
- userScaleRate: Float? = null,
40
39
  ) {
41
40
  Text(
42
41
  text = AnnotatedString(text),
@@ -53,8 +52,7 @@ fun Text(
53
52
  letterSpacing = letterSpacing,
54
53
  softWrap = softWrap,
55
54
  accessibilityId = accessibilityId,
56
- inlineContent = inlineContent,
57
- userScaleRate = userScaleRate
55
+ inlineContent = inlineContent
58
56
  )
59
57
  }
60
58
 
@@ -76,14 +74,13 @@ fun Text(
76
74
  softWrap: Boolean = true,
77
75
  accessibilityId: String? = null,
78
76
  inlineContent: Map<String, InlineTextContent> = mapOf(),
79
- userScaleRate: Float? = null,
80
77
  ) {
81
78
  // Cache theme access to avoid repeated lookups
82
79
  val theme = AppTheme.current
83
80
 
84
81
  // Call @Composable functions directly in composable context
85
- val scaledFontSize = scaleSize(style.fontSize, userScaleRate)
86
- val scaledLineHeight = scaleSize(style.lineHeight, userScaleRate)
82
+ val scaledFontSize = scaleSize(style.fontSize)
83
+ val scaledLineHeight = scaleSize(style.lineHeight)
87
84
  val fontFamilyResult = getFontFamily(fontFamily ?: theme.font, style.fontWeight)
88
85
 
89
86
  // Now memoize the results
@@ -147,6 +147,17 @@ object Colors {
147
147
  val red_10 = Color(0xFFFEF4F4)
148
148
  val red_11 = Color(0xFFFEF8F8)
149
149
 
150
+ // Translucent overlays, ported from the React kit's Consts (the reference
151
+ // palette). React spells them `#RRGGBBAA`; Compose's Color takes `0xAARRGGBB`.
152
+ val opacity_black_20 = Color(0x33000000)
153
+ val opacity_black_40 = Color(0x66000000)
154
+ val opacity_black_60 = Color(0x99000000)
155
+ val opacity_black_80 = Color(0xCC000000)
156
+ val opacity_white_20 = Color(0x33FFFFFF)
157
+ val opacity_white_40 = Color(0x66FFFFFF)
158
+ val opacity_white_60 = Color(0x99FFFFFF)
159
+ val opacity_white_80 = Color(0xCCFFFFFF)
160
+
150
161
  val colorList: Map<String, Color> = mapOf(
151
162
  "black_01" to black_01,
152
163
  "black_02" to black_02,
@@ -302,5 +313,13 @@ object Colors {
302
313
  "red_09" to red_09,
303
314
  "red_10" to red_10,
304
315
  "red_11" to red_11,
316
+ "opacity_black_20" to opacity_black_20,
317
+ "opacity_black_40" to opacity_black_40,
318
+ "opacity_black_60" to opacity_black_60,
319
+ "opacity_black_80" to opacity_black_80,
320
+ "opacity_white_20" to opacity_white_20,
321
+ "opacity_white_40" to opacity_white_40,
322
+ "opacity_white_60" to opacity_white_60,
323
+ "opacity_white_80" to opacity_white_80,
305
324
  )
306
325
  }
@@ -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.LocalFontScaleConfig
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
@@ -22,58 +22,65 @@ const val MAX_FONT_SCALE = 1.5f
22
22
  const val MAX_DEVICE_SCALE = 5
23
23
 
24
24
  @Composable
25
- fun scaleSize(size: Float, userScaleRate: Float? = null): Float {
26
- val fontScaleConfig = LocalFontScaleConfig.current
27
- val useOSFontScale = fontScaleConfig.useOSFontScale
28
- val customRate = userScaleRate ?: fontScaleConfig.userScaleRate ?: 1f
29
-
30
- val deviceScale = getScreenDimensions().width / DEFAULT_SCREEN_SIZE
31
- val fontScale = fontScaleConfig.osFontScale ?: LocalDensity.current.fontScale
32
-
33
- if (!useOSFontScale) {
34
- return if (customRate > 1f) customRate * size else size
25
+ fun scaleSize(size: Float): Float {
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)
35
31
  }
32
+ val scaleSizeMaxRate: Float = MAX_FONT_SCALE
33
+ val deviceWidth = getScreenDimensions().width
34
+ val deviceScale = deviceWidth / DEFAULT_SCREEN_SIZE
35
+
36
+ val density = LocalDensity.current
37
+ val fontScale = density.fontScale
36
38
 
37
39
  var fontSizeScaleDevice = size
38
40
  var fontSizeScaleOS = size
41
+
39
42
  if (deviceScale > 1) {
40
43
  fontSizeScaleDevice =
41
44
  min(deviceScale * fontSizeScaleDevice, fontSizeScaleDevice + MAX_DEVICE_SCALE)
42
45
  }
43
- if (fontScale > 1f) {
44
- fontSizeScaleOS = min(fontScale * fontSizeScaleOS, fontSizeScaleOS * MAX_FONT_SCALE)
46
+
47
+ if (fontScale > 1) {
48
+ fontSizeScaleOS = min(fontScale * fontSizeScaleOS, fontSizeScaleOS * scaleSizeMaxRate)
45
49
  }
46
50
 
47
- return max(fontSizeScaleDevice, fontSizeScaleOS)
51
+ return max(
52
+ fontSizeScaleDevice,
53
+ fontSizeScaleOS
54
+ )
48
55
  }
49
56
 
50
57
  @Composable
51
- fun scaleSize(size: TextUnit, userScaleRate: Float? = null): TextUnit {
58
+ fun scaleSize(size: TextUnit): TextUnit {
52
59
  if (!size.isSp) return size
53
60
 
54
61
  val density = LocalDensity.current
55
62
 
56
- val scaled = scaleSize(size.value, userScaleRate)
63
+ val scaled = scaleSize(size.value)
57
64
  val spValue = scaled / density.fontScale
58
65
 
59
66
  return TextUnit(value = spValue, type = TextUnitType.Sp)
60
67
  }
61
68
 
62
69
  @Composable
63
- fun scaleSize(size: Dp, userScaleRate: Float? = null): Dp {
64
- return scaleSize(size.value, userScaleRate).dp
70
+ fun scaleSize(size: Dp): Dp {
71
+ return scaleSize(size.value).dp
65
72
  }
66
73
 
67
74
  @Composable
68
- fun scaleSize(textStyle: TextStyle, userScaleRate: Float? = null): TextStyle {
75
+ fun scaleSize(textStyle: TextStyle): TextStyle {
69
76
  return textStyle.copy(
70
77
  fontSize = if (textStyle.fontSize != TextUnit.Unspecified)
71
- scaleSize(textStyle.fontSize, userScaleRate)
78
+ scaleSize(textStyle.fontSize)
72
79
  else
73
80
  TextUnit.Unspecified,
74
81
 
75
82
  lineHeight = if (textStyle.lineHeight != TextUnit.Unspecified)
76
- scaleSize(textStyle.lineHeight, userScaleRate)
83
+ scaleSize(textStyle.lineHeight)
77
84
  else
78
85
  TextUnit.Unspecified,
79
86
  )
@@ -1,2 +1,52 @@
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.FlowRow
8
+ import androidx.compose.foundation.layout.PaddingValues
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
+ import vn.momo.kits.const.Spacing
22
+
23
+ @Composable
24
+ internal fun Card(
25
+ useShadow: Boolean = false,
26
+ backgroundImage: String? = null,
27
+ contentPadding: PaddingValues = PaddingValues(Spacing.M),
28
+ modifier: Modifier = Modifier,
29
+ content: @Composable () -> Unit,
30
+ ) {
31
+ val columns = 12
32
+ val gutter = 8.dp
33
+ val shape = RoundedCornerShape(Radius.M)
34
+ var surface = modifier.fillMaxWidth().padding(horizontal = 12.dp)
35
+ if (useShadow) surface = surface.shadow(4.dp, shape)
36
+ surface = surface.clip(shape)
37
+ if (backgroundImage == null) surface = surface.background(AppTheme.current.colors.background.surface)
38
+ Box(modifier = surface) {
39
+ if (backgroundImage != null) {
40
+ Image(source = backgroundImage, modifier = Modifier.matchParentSize())
41
+ }
42
+ BoxWithConstraints(modifier = Modifier.fillMaxWidth().padding(contentPadding)) {
43
+ val sizePerSpan = (maxWidth - gutter * (columns - 1)) / columns - 1.dp / columns
44
+ CompositionLocalProvider(LocalGridContext provides GridContext(columns, gutter, sizePerSpan)) {
45
+ FlowRow(
46
+ horizontalArrangement = Arrangement.spacedBy(gutter),
47
+ verticalArrangement = Arrangement.spacedBy(gutter),
48
+ ) { content() }
49
+ }
50
+ }
51
+ }
52
+ }
@@ -1,35 +1,38 @@
1
1
  package vn.momo.kits.layout
2
2
 
3
- import androidx.compose.foundation.layout.Box
3
+ import androidx.compose.foundation.layout.Column
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
 
10
- data class GridContext(
11
- val numberOfColumns: Number,
12
- val gutterSize: Number,
13
- val sizePerSpan: Number,
14
- val getSizeSpan: (Number) -> Number
15
- )
12
+ internal data class GridContext(
13
+ val numberOfColumns: Int = 12,
14
+ val gutter: Dp = 12.dp,
15
+ val sizePerSpan: Dp = 0.dp,
16
+ ) {
17
+ fun sizeForSpan(span: Int): Dp = sizePerSpan * span + gutter * (span - 1)
18
+ }
19
+
20
+ internal val LocalGridContext = compositionLocalOf<GridContext?> { null }
16
21
 
17
22
  @Composable
18
- fun Item(
19
- heightSpan: Number = 1,
20
- widthSpan: Number = 1,
21
- content: @Composable () -> Unit,
23
+ internal fun Item(
24
+ widthSpan: Int = 12,
25
+ heightSpan: Int = 0,
22
26
  modifier: Modifier = Modifier,
23
- grid: GridContext
27
+ content: @Composable () -> Unit,
24
28
  ) {
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()
29
+ val grid = LocalGridContext.current
30
+ var m = modifier
31
+ if (grid != null) {
32
+ m = m.width(grid.sizeForSpan(widthSpan))
33
+ if (heightSpan > 0) m = m.height(grid.sizeForSpan(heightSpan))
34
34
  }
35
- }
35
+ // A Column (not a Box) so multiple children flow VERTICALLY instead of stacking
36
+ // on top of each other — matches the React Item's flex-column content.
37
+ Column(modifier = m) { content() }
38
+ }
@@ -1,2 +1,39 @@
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.FlowRow
7
+ import androidx.compose.foundation.layout.fillMaxWidth
8
+ import androidx.compose.foundation.layout.padding
9
+ import androidx.compose.runtime.Composable
10
+ import androidx.compose.runtime.CompositionLocalProvider
11
+ import androidx.compose.ui.Modifier
12
+ import androidx.compose.ui.unit.dp
13
+ import vn.momo.kits.components.Image
14
+
15
+ @Composable
16
+ internal fun Section(
17
+ useMargin: Boolean = true,
18
+ backgroundImage: String? = null,
19
+ modifier: Modifier = Modifier,
20
+ content: @Composable () -> Unit,
21
+ ) {
22
+ val columns = 12
23
+ val gutter = 12.dp
24
+ val margin = if (useMargin) 12.dp else 0.dp
25
+ Box(modifier = modifier.fillMaxWidth().padding(horizontal = margin)) {
26
+ if (backgroundImage != null) {
27
+ Image(source = backgroundImage, modifier = Modifier.matchParentSize())
28
+ }
29
+ BoxWithConstraints(modifier = Modifier.fillMaxWidth()) {
30
+ val sizePerSpan = (maxWidth - gutter * (columns - 1)) / columns - 1.dp / columns
31
+ CompositionLocalProvider(LocalGridContext provides GridContext(columns, gutter, sizePerSpan)) {
32
+ FlowRow(
33
+ horizontalArrangement = Arrangement.spacedBy(gutter),
34
+ verticalArrangement = Arrangement.spacedBy(gutter),
35
+ ) { content() }
36
+ }
37
+ }
38
+ }
39
+ }