@momo-kits/native-kits 0.162.6-debug → 0.163.1-beta.1-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 (123) hide show
  1. package/CLAUDE.md +78 -0
  2. package/compose/build.gradle.kts +8 -11
  3. package/compose/build.gradle.kts.backup +7 -10
  4. package/compose/compose.podspec +1 -1
  5. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +7 -2
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +5 -12
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +24 -6
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +19 -4
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +10 -1
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +2 -2
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +1 -1
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +1 -1
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +16 -5
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +1 -1
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +101 -6
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +15 -4
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +33 -8
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +1 -1
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +25 -22
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +29 -27
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +26 -3
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +30 -27
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +13 -3
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +5 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +11 -3
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +18 -3
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +11 -11
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +11 -3
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +5 -1
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +59 -84
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +71 -13
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +51 -10
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +1 -6
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +21 -4
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +1 -1
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +75 -16
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +26 -5
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +1 -1
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +11 -3
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +36 -15
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +9 -3
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +28 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +13 -2
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +17 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +10 -4
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +28 -3
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +47 -8
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +25 -4
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +11 -2
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +17 -1
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +6 -1
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +111 -50
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +5 -1
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +8 -7
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +12 -1
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +96 -4
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +12 -2
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +21 -9
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +2 -2
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +14 -9
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +11 -8
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +1 -1
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +40 -24
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +1 -1
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +5 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +2 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +4 -94
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +2 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +5 -1
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +15 -5
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +14 -65
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +33 -48
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +55 -56
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +9 -3
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +31 -13
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +1 -1
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +24 -6
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +6 -11
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +1 -2
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +3 -6
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +1 -1
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +13 -3
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +2 -3
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +40 -1
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +2 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +8 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +17 -2
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +1 -1
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +3 -3
  91. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +3 -2
  92. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +2 -0
  93. package/example/ios/Example.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  94. package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  95. package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
  96. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +58 -0
  97. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/Pods-Example.xcscheme +58 -0
  98. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImage.xcscheme +58 -0
  99. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +58 -0
  100. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SkeletonUI.xcscheme +58 -0
  101. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +46 -0
  102. package/gradle.properties +1 -1
  103. package/ios/Application/ApplicationEnvironment.swift +0 -1
  104. package/ios/Application/Components.swift +0 -1
  105. package/ios/Application/FloatingButton.swift +0 -1
  106. package/ios/Badge/Badge.swift +0 -1
  107. package/ios/Badge/BadgeRibbon.swift +0 -2
  108. package/ios/Button/Button.swift +1 -1
  109. package/ios/Checkbox/Checkbox.swift +0 -1
  110. package/ios/Input/Input.swift +0 -1
  111. package/ios/Input/InputPhoneNumber.swift +0 -1
  112. package/ios/Input/InputSearch.swift +0 -3
  113. package/ios/Input/InputTextArea.swift +0 -1
  114. package/ios/OTPKeyboard/KeyboardButton.swift +1 -1
  115. package/ios/Popup/PopupDisplay.swift +0 -6
  116. package/ios/Popup/PopupInput.swift +0 -2
  117. package/ios/Template/TrustBanner/TrustBanner.swift +0 -2
  118. package/ios/Typography/Text.swift +7 -13
  119. package/ios/Typography/Typography.swift +8 -22
  120. package/local.properties +8 -0
  121. package/package.json +1 -1
  122. package/ios/Application/FontScaleStore.swift +0 -59
  123. package/ios/Information/Information.swift +0 -151
@@ -2,7 +2,17 @@ package vn.momo.kits.components
2
2
 
3
3
  import androidx.compose.foundation.Canvas
4
4
  import androidx.compose.foundation.background
5
- import androidx.compose.foundation.layout.*
5
+ import androidx.compose.foundation.border
6
+ import androidx.compose.foundation.layout.Box
7
+ import androidx.compose.foundation.layout.WindowInsets
8
+ import androidx.compose.foundation.layout.asPaddingValues
9
+ import androidx.compose.foundation.layout.fillMaxHeight
10
+ import androidx.compose.foundation.layout.fillMaxSize
11
+ import androidx.compose.foundation.layout.fillMaxWidth
12
+ import androidx.compose.foundation.layout.height
13
+ import androidx.compose.foundation.layout.navigationBars
14
+ import androidx.compose.foundation.layout.padding
15
+ import androidx.compose.foundation.layout.width
6
16
  import androidx.compose.runtime.Composable
7
17
  import androidx.compose.ui.Alignment
8
18
  import androidx.compose.ui.Modifier
@@ -11,9 +21,22 @@ import androidx.compose.ui.graphics.Color
11
21
  import androidx.compose.ui.graphics.PathEffect
12
22
  import androidx.compose.ui.graphics.StrokeCap
13
23
  import androidx.compose.ui.unit.dp
24
+ import io.ktor.util.Platform
25
+ import vn.momo.kits.application.IsShowBaseLineDebug
26
+ import vn.momo.kits.const.Colors
27
+ import vn.momo.kits.modifier.conditional
14
28
  import vn.momo.kits.platform.getPlatformName
15
29
  import vn.momo.kits.platform.getStatusBarHeight
16
30
 
31
+ /**
32
+ * A debug overlay that draws danger/warning baseline guides on top of the screen.
33
+ *
34
+ * Highlights safe-area boundaries, header regions, and bottom navigation zones
35
+ * using colored solid or dotted lines and semi-transparent red zones.
36
+ *
37
+ * @param enabled When `false` the composable renders nothing. Pass `false` when
38
+ * your QC automation flag is active to suppress the overlay.
39
+ */
17
40
  @Composable
18
41
  fun BaselineView(enabled: Boolean = true) {
19
42
  if (!enabled) return
@@ -146,10 +169,10 @@ fun BaselineView(enabled: Boolean = true) {
146
169
  }
147
170
  }
148
171
 
149
- private enum class BaselineOrientation { Horizontal, Vertical }
172
+ enum class BaselineOrientation { Horizontal, Vertical }
150
173
 
151
174
  @Composable
152
- private fun BaselineDottedLine(
175
+ fun BaselineDottedLine(
153
176
  modifier: Modifier = Modifier,
154
177
  color: Color = Color.Red,
155
178
  orientation: BaselineOrientation = BaselineOrientation.Horizontal,
@@ -1,7 +1,5 @@
1
1
  package vn.momo.kits.components
2
2
 
3
- import vn.momo.kits.modifier.InternalApi
4
-
5
3
  import androidx.compose.animation.core.animateDpAsState
6
4
  import androidx.compose.animation.core.animateFloatAsState
7
5
  import androidx.compose.animation.core.tween
@@ -10,7 +8,14 @@ import androidx.compose.foundation.border
10
8
  import androidx.compose.foundation.clickable
11
9
  import androidx.compose.foundation.interaction.MutableInteractionSource
12
10
  import androidx.compose.foundation.interaction.collectIsPressedAsState
13
- import androidx.compose.foundation.layout.*
11
+ import androidx.compose.foundation.layout.Arrangement
12
+ import androidx.compose.foundation.layout.Box
13
+ import androidx.compose.foundation.layout.Row
14
+ import androidx.compose.foundation.layout.fillMaxWidth
15
+ import androidx.compose.foundation.layout.height
16
+ import androidx.compose.foundation.layout.padding
17
+ import androidx.compose.foundation.layout.size
18
+ import androidx.compose.foundation.layout.wrapContentHeight
14
19
  import androidx.compose.foundation.shape.RoundedCornerShape
15
20
  import androidx.compose.runtime.Composable
16
21
  import androidx.compose.runtime.getValue
@@ -25,7 +30,11 @@ import androidx.compose.ui.text.style.TextOverflow
25
30
  import androidx.compose.ui.unit.Dp
26
31
  import androidx.compose.ui.unit.dp
27
32
  import vn.momo.kits.application.IsShowBaseLineDebug
28
- import vn.momo.kits.const.*
33
+ import vn.momo.kits.const.AppTheme
34
+ import vn.momo.kits.const.Colors
35
+ import vn.momo.kits.const.Radius
36
+ import vn.momo.kits.const.Spacing
37
+ import vn.momo.kits.const.Typography
29
38
  import vn.momo.kits.modifier.conditional
30
39
  import vn.momo.kits.platform.LottieAnimation
31
40
 
@@ -91,37 +100,32 @@ private val iconSpaceCache = mapOf(
91
100
  Size.LARGE to Spacing.S
92
101
  )
93
102
 
94
- private fun getStyle(size: Size): TextStyle {
103
+ fun getStyle(size: Size): TextStyle {
95
104
  return styleCache[size] ?: Typography.actionDefaultBold
96
105
  }
97
106
 
98
- private fun getIconSize(size: Size): Dp = iconSizeCache[size] ?: 24.dp
99
- private fun getIconSpace(size: Size): Dp = iconSpaceCache[size] ?: Spacing.S
107
+ fun getIconSize(size: Size): Dp = iconSizeCache[size] ?: 24.dp
108
+ fun getIconSpace(size: Size): Dp = iconSpaceCache[size] ?: Spacing.S
100
109
 
101
110
  @Composable
102
- internal fun getTextColor(loading: Boolean, type: ButtonType): Color {
111
+ fun getTextColor(loading: Boolean, type: ButtonType): Color {
103
112
  val theme = AppTheme.current
104
113
 
105
114
  return remember(type, theme, loading) {
106
- getButtonColor(type, theme).withLoading(loading)
107
- }
108
- }
109
-
110
- internal fun getButtonColor(type: ButtonType, theme: Theme): Color {
111
- return when (type) {
112
- ButtonType.DISABLED -> theme.colors.text.disable
113
- ButtonType.PRIMARY -> Colors.black_01
114
- ButtonType.SECONDARY -> theme.colors.text.default
115
- ButtonType.OUTLINE -> theme.colors.primary
116
- ButtonType.TONAL -> theme.colors.primary
117
- ButtonType.DANGER -> Colors.black_01
118
- ButtonType.TEXT -> theme.colors.primary
115
+ when (type) {
116
+ ButtonType.DISABLED -> theme.colors.text.disable
117
+ ButtonType.PRIMARY -> Colors.black_01
118
+ ButtonType.SECONDARY -> theme.colors.text.default
119
+ ButtonType.OUTLINE -> theme.colors.primary
120
+ ButtonType.TONAL -> theme.colors.primary
121
+ ButtonType.DANGER -> Colors.black_01
122
+ ButtonType.TEXT -> theme.colors.primary
123
+ }.withLoading(loading)
119
124
  }
120
125
  }
121
126
 
122
-
123
127
  @Composable
124
- internal fun RenderTitle(size: Size, title: String = "", textColor: Color) {
128
+ fun RenderTitle(size: Size, title: String = "", textColor: Color) {
125
129
  val style = remember(size) { getStyle(size) }
126
130
  Text(
127
131
  style = style,
@@ -133,7 +137,6 @@ internal fun RenderTitle(size: Size, title: String = "", textColor: Color) {
133
137
  }
134
138
 
135
139
  @Composable
136
- @InternalApi
137
140
  fun RenderIcon(
138
141
  size: Size,
139
142
  isIconLeft: Boolean,
@@ -184,7 +187,7 @@ private fun shouldLoadingOnLeft(iconLeft: String, iconRight: String): Boolean {
184
187
  }
185
188
 
186
189
  @Composable
187
- internal fun getTypeStyle(
190
+ fun getTypeStyle(
188
191
  type: ButtonType,
189
192
  color: Color? = AppTheme.current.colors.primary,
190
193
  size: Size,
@@ -220,7 +223,7 @@ internal fun getTypeStyle(
220
223
  }
221
224
 
222
225
  @Composable
223
- internal fun getButtonBackgroundColor(
226
+ fun getButtonBackgroundColor(
224
227
  loading: Boolean,
225
228
  type: ButtonType
226
229
  ): Color {
@@ -239,7 +242,7 @@ internal fun getButtonBackgroundColor(
239
242
  }
240
243
  }
241
244
 
242
- private fun Color.withLoading(loading: Boolean): Color =
245
+ fun Color.withLoading(loading: Boolean): Color =
243
246
  this.copy(alpha = if (loading) 0.75f else 1f)
244
247
 
245
248
  @Composable
@@ -8,7 +8,13 @@ import androidx.compose.foundation.layout.PaddingValues
8
8
  import androidx.compose.foundation.layout.fillMaxWidth
9
9
  import androidx.compose.foundation.pager.HorizontalPager
10
10
  import androidx.compose.foundation.pager.rememberPagerState
11
- import androidx.compose.runtime.*
11
+ import androidx.compose.runtime.Composable
12
+ import androidx.compose.runtime.LaunchedEffect
13
+ import androidx.compose.runtime.getValue
14
+ import androidx.compose.runtime.mutableStateOf
15
+ import androidx.compose.runtime.remember
16
+ import androidx.compose.runtime.setValue
17
+ import androidx.compose.runtime.snapshotFlow
12
18
  import androidx.compose.ui.Modifier
13
19
  import androidx.compose.ui.graphics.graphicsLayer
14
20
  import androidx.compose.ui.unit.dp
@@ -18,7 +24,6 @@ import vn.momo.kits.application.IsShowBaseLineDebug
18
24
  import vn.momo.kits.const.Colors
19
25
  import vn.momo.kits.modifier.conditional
20
26
  import kotlin.math.absoluteValue
21
- import kotlin.time.Duration.Companion.milliseconds
22
27
 
23
28
  @Composable
24
29
  fun Carousel(
@@ -27,6 +32,7 @@ fun Carousel(
27
32
  loop: Boolean = false,
28
33
  autoplay: Boolean = false,
29
34
  autoplayInterval: Long = 3000L,
35
+ enableSnap: Boolean = true,
30
36
  scrollEnabled: Boolean = true,
31
37
  inactiveSlideOpacity: Float = 1f,
32
38
  inactiveSlideScale: Float = 1f,
@@ -42,15 +48,18 @@ fun Carousel(
42
48
 
43
49
  val pagerState = rememberPagerState(initialPage = startPage) { virtualPageCount }
44
50
 
51
+ // Map virtual page to real index
45
52
  val realIndex: (Int) -> Int = { page -> page % itemCount }
46
53
 
54
+ // Track user interaction for autoplay pause
47
55
  var isUserScrolling by remember { mutableStateOf(false) }
48
56
 
57
+ // Autoplay
49
58
  if (autoplay && itemCount > 1) {
50
59
  LaunchedEffect(autoplayInterval, isUserScrolling) {
51
60
  if (isUserScrolling) return@LaunchedEffect
52
61
  while (isActive) {
53
- delay(autoplayInterval.milliseconds)
62
+ delay(autoplayInterval)
54
63
  if (!isUserScrolling) {
55
64
  val nextPage = pagerState.currentPage + 1
56
65
  if (nextPage < virtualPageCount) {
@@ -61,6 +70,7 @@ fun Carousel(
61
70
  }
62
71
  }
63
72
 
73
+ // Track scroll state for callbacks
64
74
  LaunchedEffect(pagerState) {
65
75
  snapshotFlow { pagerState.isScrollInProgress }.collect { scrolling ->
66
76
  isUserScrolling = scrolling
@@ -22,6 +22,7 @@ import vn.momo.kits.const.Typography
22
22
  import vn.momo.kits.modifier.activeOpacityClickable
23
23
  import vn.momo.kits.modifier.conditional
24
24
 
25
+ // Pre-computed shape for performance
25
26
  private val checkboxShape = RoundedCornerShape(Radius.XS)
26
27
 
27
28
  @Composable
@@ -32,8 +33,10 @@ fun CheckBox(
32
33
  indeterminate: Boolean = false,
33
34
  title: String = "",
34
35
  ) {
36
+ // Cache theme access
35
37
  val theme = AppTheme.current
36
38
 
39
+ // Memoize color calculations to avoid repeated conditional logic
37
40
  val colors = remember(checked, disabled, theme) {
38
41
  when {
39
42
  disabled && checked -> Pair(theme.colors.background.tonal, theme.colors.background.tonal)
@@ -45,10 +48,12 @@ fun CheckBox(
45
48
 
46
49
  val (borderColor, backgroundColor) = colors
47
50
 
51
+ // Memoize icon source to avoid repeated conditional check
48
52
  val iconSource = remember(indeterminate) {
49
53
  if (indeterminate) "navigation_minus" else "ic_checked"
50
54
  }
51
55
 
56
+ // Memoize click handler to avoid lambda recreation
52
57
  val onClickHandler = remember(onCheckedChange, checked) {
53
58
  { onCheckedChange(!checked) }
54
59
  }
@@ -2,7 +2,11 @@ package vn.momo.kits.components
2
2
 
3
3
  import androidx.compose.foundation.background
4
4
  import androidx.compose.foundation.border
5
- import androidx.compose.foundation.layout.*
5
+ import androidx.compose.foundation.layout.Arrangement
6
+ import androidx.compose.foundation.layout.Row
7
+ import androidx.compose.foundation.layout.height
8
+ import androidx.compose.foundation.layout.padding
9
+ import androidx.compose.foundation.layout.wrapContentWidth
6
10
  import androidx.compose.foundation.shape.RoundedCornerShape
7
11
  import androidx.compose.runtime.Composable
8
12
  import androidx.compose.runtime.Immutable
@@ -13,8 +17,12 @@ import androidx.compose.ui.graphics.Color
13
17
  import androidx.compose.ui.text.style.TextAlign
14
18
  import androidx.compose.ui.text.style.TextOverflow
15
19
  import androidx.compose.ui.unit.dp
20
+ import vn.momo.kits.const.AppTheme
21
+ import vn.momo.kits.const.Colors
22
+ import vn.momo.kits.const.Radius
23
+ import vn.momo.kits.const.Typography
16
24
  import vn.momo.kits.application.IsShowBaseLineDebug
17
- import vn.momo.kits.const.*
25
+ import vn.momo.kits.const.scaleSize
18
26
  import vn.momo.kits.modifier.activeOpacityClickable
19
27
  import vn.momo.kits.modifier.conditional
20
28
  import vn.momo.kits.modifier.setAutomationId
@@ -103,7 +111,7 @@ fun Chip(
103
111
 
104
112
  enum class ChipSize { SMALL, LARGE }
105
113
 
106
- private object ChipDefaults {
114
+ object ChipDefaults {
107
115
  @Immutable
108
116
  data class Dimensions(
109
117
  val height: Float,
@@ -7,9 +7,20 @@ import androidx.compose.animation.expandVertically
7
7
  import androidx.compose.animation.shrinkVertically
8
8
  import androidx.compose.foundation.background
9
9
  import androidx.compose.foundation.border
10
- import androidx.compose.foundation.layout.*
10
+ import androidx.compose.foundation.layout.Box
11
+ import androidx.compose.foundation.layout.Column
12
+ import androidx.compose.foundation.layout.Row
13
+ import androidx.compose.foundation.layout.Spacer
14
+ import androidx.compose.foundation.layout.fillMaxWidth
15
+ import androidx.compose.foundation.layout.padding
16
+ import androidx.compose.foundation.layout.size
17
+ import androidx.compose.foundation.layout.width
11
18
  import androidx.compose.foundation.shape.RoundedCornerShape
12
- import androidx.compose.runtime.*
19
+ import androidx.compose.runtime.Composable
20
+ import androidx.compose.runtime.getValue
21
+ import androidx.compose.runtime.mutableStateOf
22
+ import androidx.compose.runtime.remember
23
+ import androidx.compose.runtime.setValue
13
24
  import androidx.compose.ui.Alignment
14
25
  import androidx.compose.ui.Modifier
15
26
  import androidx.compose.ui.draw.clip
@@ -18,7 +29,11 @@ import androidx.compose.ui.graphics.Color
18
29
  import androidx.compose.ui.text.TextStyle
19
30
  import androidx.compose.ui.unit.dp
20
31
  import vn.momo.kits.application.IsShowBaseLineDebug
21
- import vn.momo.kits.const.*
32
+ import vn.momo.kits.const.AppTheme
33
+ import vn.momo.kits.const.Colors
34
+ import vn.momo.kits.const.Radius
35
+ import vn.momo.kits.const.Spacing
36
+ import vn.momo.kits.const.Typography
22
37
  import vn.momo.kits.modifier.activeOpacityClickable
23
38
  import vn.momo.kits.modifier.conditional
24
39
  import vn.momo.kits.modifier.setAutomationId
@@ -42,8 +42,8 @@ import androidx.compose.ui.unit.toOffset
42
42
  import androidx.compose.ui.unit.toSize
43
43
  import kotlinx.coroutines.CoroutineScope
44
44
  import kotlinx.coroutines.cancel
45
- import kotlinx.coroutines.currentCoroutineContext
46
45
  import kotlinx.coroutines.isActive
46
+ import kotlin.coroutines.coroutineContext
47
47
  import kotlin.math.abs
48
48
  import kotlin.math.sign
49
49
 
@@ -103,7 +103,7 @@ internal class CupertinoOverscrollEffect(
103
103
  * end at the same time, which is not the case:
104
104
  * Spring->Fling->Spring, Fling->Spring, Spring->Fling effects can have different timing per dimension
105
105
  * (see Notes of https://github.com/JetBrains/compose-multiplatform-core/pull/609),
106
- * which is not possible to express without changing API. Hence, this effect will be fixed to latest
106
+ * which is not possible to express without changing API. Hence this effect will be fixed to latest
107
107
  * received delta.
108
108
  */
109
109
  private var direction: CupertinoOverscrollDirection = CupertinoOverscrollDirection.UNKNOWN
@@ -151,7 +151,7 @@ internal class CupertinoOverscrollEffect(
151
151
  override val node: DelegatableNode get() = overscrollNode
152
152
 
153
153
  private fun onDraw() {
154
- // Fix an issue where scrolling was canceled but the overscroll effect was not completed.
154
+ // Fix an issue where scrolling was cancelled but the overscroll effect was not completed.
155
155
  // Reset the overscroll effect when no ongoing animation or interaction is applied.
156
156
  if (!drawCallScheduledByOffsetChange && isInProgress && overscrollNode.pointersDown == 0) {
157
157
  overscrollOffsetState.value = Offset.Zero
@@ -289,7 +289,7 @@ internal class CupertinoOverscrollEffect(
289
289
  }
290
290
 
291
291
  private fun applyPullToRefresh() {
292
- val (isRefresh, refresh, threshHold, _, _) = pullRefreshState ?: return
292
+ val (isRefresh, refresh, threshHold, _, sendHaptic) = pullRefreshState ?: return
293
293
  val overscrollY = overscrollOffset.y
294
294
  if (isRefresh.value || overscrollY < threshHold.value * density) return
295
295
  refresh.invoke()
@@ -398,7 +398,7 @@ internal class CupertinoOverscrollEffect(
398
398
  }
399
399
 
400
400
  springAnimationScope?.cancel()
401
- springAnimationScope = CoroutineScope(currentCoroutineContext())
401
+ springAnimationScope = CoroutineScope(coroutineContext)
402
402
  springAnimationScope?.run {
403
403
  AnimationState(
404
404
  Float.VectorConverter,
@@ -414,7 +414,7 @@ internal class CupertinoOverscrollEffect(
414
414
  } ?: (value * density).toOffset()
415
415
  currentVelocity = velocity * density
416
416
 
417
- // If it was flung from overscroll, cancel animation and return velocity
417
+ // If it was fling from overscroll, cancel animation and return velocity
418
418
  if (reason == CupertinoSpringAnimationReason.FLING_FROM_OVERSCROLL &&
419
419
  initialSign != 0f &&
420
420
  sign(value) != initialSign
@@ -425,7 +425,7 @@ internal class CupertinoOverscrollEffect(
425
425
  springAnimationScope = null
426
426
  }
427
427
 
428
- if (currentCoroutineContext().isActive) {
428
+ if (coroutineContext.isActive) {
429
429
  // The spring is critically damped, so in case spring-fling-spring sequence is slightly
430
430
  // offset and velocity is of the opposite sign, it will end up with no animation
431
431
  overscrollOffset = Offset.Zero
@@ -447,8 +447,8 @@ internal class CupertinoOverscrollEffect(
447
447
  val dpSize = scrollSize / density
448
448
 
449
449
  return Offset(
450
- rubberBandedValue(dpOffset.x, dpSize.width),
451
- rubberBandedValue(dpOffset.y, dpSize.height)
450
+ rubberBandedValue(dpOffset.x, dpSize.width, RUBBER_BAND_COEFFICIENT),
451
+ rubberBandedValue(dpOffset.y, dpSize.height, RUBBER_BAND_COEFFICIENT)
452
452
  ) * density
453
453
  }
454
454
 
@@ -456,8 +456,8 @@ internal class CupertinoOverscrollEffect(
456
456
  * Maps raw delta offset [value] on an axis within scroll container with [dimension]
457
457
  * to actual visible offset
458
458
  */
459
- private fun rubberBandedValue(value: Float, dimension: Float) =
460
- sign(value) * (1f - (1f / (abs(value) * RUBBER_BAND_COEFFICIENT / dimension + 1f))) * dimension
459
+ private fun rubberBandedValue(value: Float, dimension: Float, coefficient: Float) =
460
+ sign(value) * (1f - (1f / (abs(value) * coefficient / dimension + 1f))) * dimension
461
461
 
462
462
  companion object Companion {
463
463
  private const val RUBBER_BAND_COEFFICIENT = 0.55f
@@ -56,7 +56,7 @@ private val iconSizeMap = mapOf(
56
56
  )
57
57
 
58
58
  @Composable
59
- internal fun getIconStyle(type: ButtonType, color: Color? = null): Modifier {
59
+ fun getIconStyle(type: ButtonType, color: Color? = null): Modifier {
60
60
  val theme = AppTheme.current
61
61
 
62
62
  return remember(type, color, theme) {
@@ -91,10 +91,18 @@ internal fun getIconStyle(type: ButtonType, color: Color? = null): Modifier {
91
91
  }
92
92
 
93
93
  @Composable
94
- internal fun getIconColor(type: ButtonType): Color {
94
+ fun getIconColor(type: ButtonType): Color {
95
95
  val theme = AppTheme.current
96
96
  return remember(type, theme) {
97
- getButtonColor(type, theme)
97
+ when (type) {
98
+ ButtonType.DISABLED -> theme.colors.text.disable
99
+ ButtonType.PRIMARY -> Colors.black_01
100
+ ButtonType.SECONDARY -> theme.colors.text.default
101
+ ButtonType.OUTLINE -> theme.colors.primary
102
+ ButtonType.TONAL -> theme.colors.primary
103
+ ButtonType.DANGER -> Colors.black_01
104
+ ButtonType.TEXT -> theme.colors.primary
105
+ }
98
106
  }
99
107
  }
100
108
 
@@ -3,7 +3,11 @@ package vn.momo.kits.components
3
3
  import androidx.compose.foundation.background
4
4
  import androidx.compose.foundation.border
5
5
  import androidx.compose.foundation.clickable
6
- import androidx.compose.foundation.layout.*
6
+ import androidx.compose.foundation.layout.Column
7
+ import androidx.compose.foundation.layout.Row
8
+ import androidx.compose.foundation.layout.height
9
+ import androidx.compose.foundation.layout.padding
10
+ import androidx.compose.foundation.layout.width
7
11
  import androidx.compose.foundation.shape.RoundedCornerShape
8
12
  import androidx.compose.runtime.Composable
9
13
  import androidx.compose.ui.Modifier
@@ -1,17 +1,29 @@
1
1
  package vn.momo.kits.components
2
2
 
3
- import vn.momo.kits.modifier.InternalApi
4
-
5
3
  import androidx.compose.foundation.background
6
4
  import androidx.compose.foundation.border
7
5
  import androidx.compose.foundation.clickable
8
6
  import androidx.compose.foundation.interaction.MutableInteractionSource
9
- import androidx.compose.foundation.layout.*
7
+ import androidx.compose.foundation.layout.Box
8
+ import androidx.compose.foundation.layout.Column
9
+ import androidx.compose.foundation.layout.Row
10
+ import androidx.compose.foundation.layout.Spacer
11
+ import androidx.compose.foundation.layout.fillMaxWidth
12
+ import androidx.compose.foundation.layout.height
13
+ import androidx.compose.foundation.layout.offset
14
+ import androidx.compose.foundation.layout.padding
15
+ import androidx.compose.foundation.layout.size
16
+ import androidx.compose.foundation.layout.wrapContentSize
10
17
  import androidx.compose.foundation.shape.RoundedCornerShape
11
18
  import androidx.compose.foundation.text.BasicTextField
12
19
  import androidx.compose.foundation.text.KeyboardOptions
13
20
  import androidx.compose.material3.CircularProgressIndicator
14
- import androidx.compose.runtime.*
21
+ import androidx.compose.runtime.Composable
22
+ import androidx.compose.runtime.MutableState
23
+ import androidx.compose.runtime.getValue
24
+ import androidx.compose.runtime.mutableStateOf
25
+ import androidx.compose.runtime.remember
26
+ import androidx.compose.runtime.setValue
15
27
  import androidx.compose.ui.Alignment
16
28
  import androidx.compose.ui.Modifier
17
29
  import androidx.compose.ui.focus.onFocusChanged
@@ -32,7 +44,13 @@ import androidx.compose.ui.unit.dp
32
44
  import androidx.compose.ui.unit.sp
33
45
  import androidx.compose.ui.zIndex
34
46
  import vn.momo.kits.application.IsShowBaseLineDebug
35
- import vn.momo.kits.const.*
47
+ import vn.momo.kits.const.AppTheme
48
+ import vn.momo.kits.const.Colors
49
+ import vn.momo.kits.const.Radius
50
+ import vn.momo.kits.const.Spacing
51
+ import vn.momo.kits.const.Typography
52
+ import vn.momo.kits.const.getFont
53
+ import vn.momo.kits.const.scaleSize
36
54
  import vn.momo.kits.modifier.conditional
37
55
  import vn.momo.kits.modifier.setAutomationId
38
56
  import vn.momo.uikits.resources.Res
@@ -70,6 +88,7 @@ enum class InputFontWeight(val value: FontWeight) {
70
88
  )
71
89
  }
72
90
 
91
+ // Consolidated input state for better performance
73
92
  data class InputState(
74
93
  val isFocused: Boolean = false,
75
94
  val passHidden: Boolean = false,
@@ -109,7 +128,6 @@ private class PasswordVisualTransformation(
109
128
  }
110
129
 
111
130
  @Composable
112
- @InternalApi
113
131
  fun getBorderColor(isFocused: Boolean, error: String, disabled: Boolean): Color {
114
132
  val theme = AppTheme.current
115
133
  return remember(isFocused, error, disabled, theme) {
@@ -123,7 +141,6 @@ fun getBorderColor(isFocused: Boolean, error: String, disabled: Boolean): Color
123
141
  }
124
142
 
125
143
  @Composable
126
- @InternalApi
127
144
  fun RenderRightIcon(loading: Boolean, icon: String, color: Color, onClick: () -> Unit, modifier: Modifier = Modifier) {
128
145
  if (loading) {
129
146
  Box {
@@ -150,7 +167,6 @@ fun RenderRightIcon(loading: Boolean, icon: String, color: Color, onClick: () ->
150
167
  }
151
168
 
152
169
  @Composable
153
- @InternalApi
154
170
  fun ErrorView(errorMessage: String, errorSpacing: Boolean, hintText: String) {
155
171
  val theme = AppTheme.current
156
172
  val errorColor = remember(theme) { theme.colors.error.primary }
@@ -310,14 +326,41 @@ fun Input(
310
326
  },
311
327
  decorationBox = { innerTextField ->
312
328
  // Floating label
313
- FloatingLabel(
314
- floatingValue = floatingValue,
315
- floatingIcon = floatingIcon,
316
- titleColor = floatingTitleColor,
317
- iconColor = floatingIconTintColor,
318
- offsetY = -size.values.height / 2,
319
- required = required,
320
- )
329
+ if (floatingValue.isNotEmpty() || floatingIcon.isNotEmpty()) {
330
+ Box(
331
+ modifier = Modifier
332
+ .wrapContentSize()
333
+ .offset(y = (-size.values.height / 2), x = Spacing.S)
334
+ .background(theme.colors.background.surface)
335
+ .zIndex(10f),
336
+ ) {
337
+ Row(
338
+ modifier = Modifier.padding(horizontal = Spacing.S),
339
+ verticalAlignment = Alignment.CenterVertically
340
+ ) {
341
+ Text(
342
+ floatingValue,
343
+ style = Typography.labelSMedium,
344
+ color = floatingTitleColor
345
+ )
346
+ if (required) {
347
+ Text(
348
+ "*",
349
+ style = Typography.labelSMedium,
350
+ color = theme.colors.error.primary,
351
+ )
352
+ }
353
+ if (floatingIcon.isNotEmpty()) {
354
+ Icon(
355
+ source = floatingIcon,
356
+ modifier = Modifier.padding(start = Spacing.XS),
357
+ size = 16.dp,
358
+ color = floatingIconTintColor
359
+ )
360
+ }
361
+ }
362
+ }
363
+ }
321
364
 
322
365
  // Input container
323
366
  Box(
@@ -407,71 +450,3 @@ fun Input(
407
450
  ErrorView(error, errorSpacing, hintText)
408
451
  }
409
452
  }
410
-
411
- internal data class InputColors(
412
- val text: Color,
413
- val placeholder: Color,
414
- val iconTint: Color,
415
- val floatingTitle: Color,
416
- val floatingIcon: Color,
417
- )
418
-
419
- @Composable
420
- internal fun getInputColors(
421
- disabled: Boolean,
422
- iconColor: Color,
423
- floatingValueColor: Color,
424
- floatingIconColor: Color,
425
- ): InputColors {
426
- val theme = AppTheme.current
427
- val disabledColor = theme.colors.text.disable
428
- return InputColors(
429
- text = if (disabled) disabledColor else theme.colors.text.default,
430
- placeholder = if (disabled) disabledColor else theme.colors.text.hint,
431
- iconTint = if (disabled) disabledColor else iconColor,
432
- floatingTitle = if (disabled) disabledColor else floatingValueColor,
433
- floatingIcon = if (disabled) disabledColor else floatingIconColor,
434
- )
435
- }
436
-
437
- @Composable
438
- internal fun FloatingLabel(
439
- floatingValue: String,
440
- floatingIcon: String,
441
- titleColor: Color,
442
- iconColor: Color,
443
- offsetY: Dp,
444
- offsetX: Dp = Spacing.S,
445
- required: Boolean = false,
446
- ) {
447
- if (floatingValue.isEmpty() && floatingIcon.isEmpty()) return
448
- Box(
449
- modifier = Modifier
450
- .wrapContentSize()
451
- .offset(y = offsetY, x = offsetX)
452
- .background(AppTheme.current.colors.background.surface)
453
- .zIndex(10f),
454
- ) {
455
- Row(
456
- modifier = Modifier.padding(horizontal = Spacing.S),
457
- verticalAlignment = Alignment.CenterVertically,
458
- ) {
459
- Text(floatingValue, style = Typography.labelSMedium, color = titleColor)
460
- if (required) {
461
- Text(
462
- "*",
463
- style = Typography.labelSMedium,
464
- color = AppTheme.current.colors.error.primary,
465
- )
466
- }
467
- if (floatingIcon.isNotEmpty()) {
468
- Icon(
469
- source = floatingIcon,
470
- modifier = Modifier.padding(start = Spacing.XS),
471
- size = 16.dp,
472
- color = iconColor,
473
- )
474
- }
475
- }
476
- }
477
- }