@momo-kits/native-kits 0.155.1-hello.8 → 0.155.1-hello.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 (115) hide show
  1. package/build.gradle.kts +11 -0
  2. package/compose/build.gradle.kts +180 -0
  3. package/compose/compose.podspec +54 -0
  4. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +113 -0
  5. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  6. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  7. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  8. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  9. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  10. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  11. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  12. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  13. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  14. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +57 -0
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +95 -0
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +201 -0
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +222 -0
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +48 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +305 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +715 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +121 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +405 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +85 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +35 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +343 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +353 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +98 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +138 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +78 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +151 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +190 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +119 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +407 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +175 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +244 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +233 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +233 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +257 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +240 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +364 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +59 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +44 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +95 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +43 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +351 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +106 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +72 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +17 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +99 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +99 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +95 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +132 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +217 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +180 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +208 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +239 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +191 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +13 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +189 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +285 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +59 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +68 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +15 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +50 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +241 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +122 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +94 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +163 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +302 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +495 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +169 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +233 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +190 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +258 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +80 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +306 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +31 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +370 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +135 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +42 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +62 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +88 -0
  105. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +152 -0
  106. package/gradle/libs.versions.toml +57 -0
  107. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  108. package/gradle/wrapper/gradle-wrapper.properties +8 -0
  109. package/gradle.properties +26 -0
  110. package/gradlew +252 -0
  111. package/gradlew.bat +94 -0
  112. package/local.properties +8 -0
  113. package/package.json +1 -1
  114. package/publish_release.sh +105 -0
  115. package/settings.gradle.kts +52 -0
@@ -0,0 +1,353 @@
1
+ package vn.momo.kits.components
2
+
3
+ import androidx.compose.animation.core.animateDpAsState
4
+ import androidx.compose.animation.core.animateFloatAsState
5
+ import androidx.compose.animation.core.tween
6
+ import androidx.compose.foundation.background
7
+ import androidx.compose.foundation.border
8
+ import androidx.compose.foundation.clickable
9
+ import androidx.compose.foundation.interaction.MutableInteractionSource
10
+ import androidx.compose.foundation.interaction.collectIsPressedAsState
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.defaultMinSize
15
+ import androidx.compose.foundation.layout.fillMaxWidth
16
+ import androidx.compose.foundation.layout.height
17
+ import androidx.compose.foundation.layout.padding
18
+ import androidx.compose.foundation.layout.size
19
+ import androidx.compose.foundation.layout.width
20
+ import androidx.compose.foundation.shape.RoundedCornerShape
21
+ import androidx.compose.runtime.Composable
22
+ import androidx.compose.runtime.CompositionLocalProvider
23
+ import androidx.compose.runtime.getValue
24
+ import androidx.compose.runtime.remember
25
+ import androidx.compose.runtime.staticCompositionLocalOf
26
+ import androidx.compose.ui.Alignment
27
+ import androidx.compose.ui.Modifier
28
+ import androidx.compose.ui.draw.alpha
29
+ import androidx.compose.ui.draw.clip
30
+ import androidx.compose.ui.graphics.Color
31
+ import androidx.compose.ui.graphics.graphicsLayer
32
+ import androidx.compose.ui.text.TextStyle
33
+ import androidx.compose.ui.text.style.TextOverflow
34
+ import androidx.compose.ui.unit.Dp
35
+ import androidx.compose.ui.unit.dp
36
+ import vn.momo.kits.application.ApplicationContext
37
+ import vn.momo.kits.application.MiniAppContext.Companion.isShowBaselineDebug
38
+ import vn.momo.kits.const.AppTheme
39
+ import vn.momo.kits.const.Colors
40
+ import vn.momo.kits.const.Radius
41
+ import vn.momo.kits.const.Spacing
42
+ import vn.momo.kits.const.Typography
43
+ import vn.momo.kits.modifier.conditional
44
+ import vn.momo.kits.platform.LottieAnimation
45
+
46
+ enum class ButtonType {
47
+ PRIMARY,
48
+ SECONDARY,
49
+ TONAL,
50
+ OUTLINE,
51
+ DANGER,
52
+ TEXT,
53
+ DISABLED
54
+ }
55
+
56
+ data class ButtonSpecs(
57
+ val height: Dp,
58
+ val radius: Dp,
59
+ val padding: Dp,
60
+ val width: Dp,
61
+ )
62
+
63
+ enum class Size(val value: ButtonSpecs) {
64
+ LARGE(
65
+ ButtonSpecs(
66
+ height = 48.dp,
67
+ radius = Radius.S,
68
+ padding = Spacing.L,
69
+ width = 128.dp
70
+ )
71
+ ),
72
+ MEDIUM(
73
+ ButtonSpecs(
74
+ height = 36.dp,
75
+ radius = Radius.S,
76
+ padding = Spacing.M,
77
+ width = 80.dp
78
+ )
79
+ ),
80
+ SMALL(
81
+ ButtonSpecs(
82
+ height = 28.dp,
83
+ radius = Radius.S,
84
+ padding = Spacing.S,
85
+ width = 60.dp
86
+ )
87
+ )
88
+ }
89
+
90
+ private val styleCache = mapOf(
91
+ Size.LARGE to Typography.actionDefaultBold,
92
+ Size.MEDIUM to Typography.actionSBold,
93
+ Size.SMALL to Typography.actionXsBold
94
+ )
95
+
96
+ private val iconSizeCache = mapOf(
97
+ Size.LARGE to 24.dp,
98
+ Size.MEDIUM to 16.dp,
99
+ Size.SMALL to 16.dp
100
+ )
101
+
102
+ private val iconSpaceCache = mapOf(
103
+ Size.SMALL to Spacing.XS,
104
+ Size.MEDIUM to Spacing.S,
105
+ Size.LARGE to Spacing.S
106
+ )
107
+
108
+ fun getStyle(size: Size): TextStyle {
109
+ return styleCache[size] ?: Typography.actionDefaultBold
110
+ }
111
+
112
+ fun getIconSize(size: Size): Dp = iconSizeCache[size] ?: 24.dp
113
+ fun getIconSpace(size: Size): Dp = iconSpaceCache[size] ?: Spacing.S
114
+
115
+ @Composable
116
+ fun getTextColor(loading: Boolean, type: ButtonType): Color {
117
+ val theme = AppTheme.current
118
+
119
+ return remember(type, theme, loading) {
120
+ when (type) {
121
+ ButtonType.DISABLED -> theme.colors.text.disable
122
+ ButtonType.PRIMARY -> Colors.black_01
123
+ ButtonType.SECONDARY -> theme.colors.text.default
124
+ ButtonType.OUTLINE -> theme.colors.primary
125
+ ButtonType.TONAL -> theme.colors.primary
126
+ ButtonType.DANGER -> Colors.black_01
127
+ ButtonType.TEXT -> theme.colors.primary
128
+ }.withLoading(loading)
129
+ }
130
+ }
131
+
132
+ @Composable
133
+ fun RenderTitle(size: Size, title: String = "", type: ButtonType) {
134
+ val style = remember(size) { getStyle(size) }
135
+ val color = TextColor.current
136
+ Text(
137
+ style = style,
138
+ text = title,
139
+ color = color,
140
+ overflow = TextOverflow.Ellipsis,
141
+ maxLines = 1
142
+ )
143
+ }
144
+
145
+ @Composable
146
+ fun RenderIcon(
147
+ size: Size,
148
+ isIconLeft: Boolean,
149
+ useTintColor: Boolean = true,
150
+ icon: String = "",
151
+ forceLoading: Boolean = false
152
+ ) {
153
+ val bgColor = BackgroundColor.current
154
+ val iconSize = remember(size) { getIconSize(size) }
155
+ val margin = remember(size) { getIconSpace(size) }
156
+ val color = if (useTintColor) TextColor.current else Color.Unspecified
157
+
158
+ val showLoading = forceLoading
159
+
160
+ val modifier = Modifier.padding(
161
+ start = if (isIconLeft) 0.dp else margin,
162
+ end = if (isIconLeft) margin else 0.dp
163
+ )
164
+
165
+ if (showLoading) {
166
+ Box(modifier) {
167
+ LottieAnimation(
168
+ modifier = Modifier.size(iconSize),
169
+ bgColor = bgColor,
170
+ tintColor = color,
171
+ path = "files/lottie_circle_loader"
172
+ )
173
+ }
174
+ } else if (icon.isNotEmpty()) {
175
+ Icon(
176
+ source = icon,
177
+ color = color,
178
+ size = iconSize,
179
+ modifier = modifier
180
+ )
181
+ }
182
+ }
183
+
184
+ private fun shouldLoadingOnLeft(iconLeft: String, iconRight: String): Boolean {
185
+ val hasLeft = iconLeft.isNotEmpty()
186
+ val hasRight = iconRight.isNotEmpty()
187
+ return when {
188
+ !hasLeft && !hasRight -> true
189
+ hasLeft && !hasRight -> true
190
+ !hasLeft && hasRight -> false
191
+ hasLeft && hasRight -> false
192
+ else -> true
193
+ }
194
+ }
195
+
196
+ @Composable
197
+ fun getTypeStyle(
198
+ type: ButtonType,
199
+ color: Color? = AppTheme.current.colors.primary,
200
+ size: Size,
201
+ ): Modifier {
202
+ val theme = AppTheme.current
203
+ val bgColor = BackgroundColor.current
204
+ val radius = remember(size) { size.value.radius }
205
+ val modifier = Modifier.background(bgColor)
206
+
207
+ return remember(type, color, theme, radius, bgColor) {
208
+ when (type) {
209
+ ButtonType.DISABLED -> modifier
210
+ .border(0.dp, Color.Unspecified, RoundedCornerShape(radius))
211
+
212
+ ButtonType.PRIMARY -> modifier
213
+ .border(0.dp, Color.Unspecified, RoundedCornerShape(radius))
214
+
215
+ ButtonType.SECONDARY -> modifier
216
+ .border(1.dp, theme.colors.border.default, RoundedCornerShape(radius))
217
+
218
+ ButtonType.OUTLINE -> modifier
219
+ .border(1.dp, color ?: theme.colors.primary, RoundedCornerShape(radius))
220
+
221
+ ButtonType.TONAL -> modifier
222
+ .border(0.dp, Color.Unspecified, RoundedCornerShape(radius))
223
+
224
+ ButtonType.DANGER -> modifier
225
+ .border(0.dp, Color.Unspecified, RoundedCornerShape(radius))
226
+
227
+ ButtonType.TEXT -> modifier
228
+ }
229
+ }
230
+ }
231
+
232
+ @Composable
233
+ fun getButtonBackgroundColor(
234
+ loading: Boolean,
235
+ type: ButtonType
236
+ ): Color {
237
+ val theme = AppTheme.current
238
+
239
+ return remember(loading, type, theme) {
240
+ when (type) {
241
+ ButtonType.DISABLED -> theme.colors.background.disable.withLoading(loading)
242
+ ButtonType.PRIMARY -> theme.colors.primary.withLoading(loading)
243
+ ButtonType.SECONDARY -> theme.colors.background.surface.withLoading(loading)
244
+ ButtonType.OUTLINE -> theme.colors.background.surface.withLoading(loading)
245
+ ButtonType.TONAL -> theme.colors.background.tonal.withLoading(loading)
246
+ ButtonType.DANGER -> theme.colors.error.primary.withLoading(loading)
247
+ ButtonType.TEXT -> Color.Unspecified
248
+ }
249
+ }
250
+ }
251
+
252
+ fun Color.withLoading(loading: Boolean): Color =
253
+ this.copy(alpha = if (loading) 0.75f else 1f)
254
+
255
+ @Composable
256
+ fun Button(
257
+ onClick: () -> Unit,
258
+ type: ButtonType = ButtonType.PRIMARY,
259
+ size: Size = Size.LARGE,
260
+ iconRight: String = "",
261
+ iconLeft: String = "",
262
+ title: String = "Button",
263
+ loading: Boolean = false,
264
+ useTintColor: Boolean = true,
265
+ isFull: Boolean = true,
266
+ modifier: Modifier = Modifier,
267
+ ) {
268
+ val radius = remember(size) { size.value.radius }
269
+ val isEnabled = remember(type) { type != ButtonType.DISABLED }
270
+ val loadingOnLeft = remember(iconLeft, iconRight) {
271
+ shouldLoadingOnLeft(iconLeft, iconRight)
272
+ }
273
+
274
+ val sizeSpecs = remember(size) { size.value }
275
+
276
+ val interactionSource = remember { MutableInteractionSource() }
277
+ val isPressed by interactionSource.collectIsPressedAsState()
278
+
279
+ val animatedPadding by animateDpAsState(
280
+ targetValue = if (isPressed && isEnabled && !loading) 2.dp else 0.dp,
281
+ animationSpec = tween(100),
282
+ label = "pressPadding"
283
+ )
284
+
285
+ val targetAlpha = if (isPressed && isEnabled && !loading) 0.5f else 1f
286
+ val alpha by animateFloatAsState(
287
+ targetValue = targetAlpha,
288
+ animationSpec = tween(100),
289
+ label = "buttonPressAlpha"
290
+ )
291
+
292
+ val clickableModifier =
293
+ if (isEnabled && !loading) {
294
+ modifier
295
+ .then(if (isFull) Modifier.fillMaxWidth() else Modifier)
296
+ .clip(RoundedCornerShape(radius))
297
+ .clickable(
298
+ enabled = isEnabled && !loading,
299
+ interactionSource = interactionSource,
300
+ indication = null,
301
+ onClick = onClick
302
+ )
303
+ .alpha(alpha)
304
+ } else {
305
+ modifier
306
+ .then(if (isFull) Modifier.fillMaxWidth() else Modifier)
307
+ .clip(RoundedCornerShape(radius))
308
+ }
309
+
310
+ val application = ApplicationContext.current
311
+
312
+ CompositionLocalProvider(
313
+ IsLoading provides loading,
314
+ BackgroundColor provides getButtonBackgroundColor(loading, type),
315
+ TextColor provides getTextColor(loading, type)
316
+ ) {
317
+ Row(
318
+ modifier = clickableModifier
319
+ .padding(horizontal = animatedPadding)
320
+ .clip(RoundedCornerShape(radius))
321
+ .then(getTypeStyle(type, size = size))
322
+ .conditional(application.isShowBaselineDebug()) {
323
+ border(1.dp, Colors.blue_03)
324
+ }
325
+ .padding(horizontal = sizeSpecs.padding)
326
+ .height(sizeSpecs.height),
327
+ horizontalArrangement = Arrangement.Center,
328
+ verticalAlignment = Alignment.CenterVertically,
329
+ ) {
330
+ RenderIcon(
331
+ size = size,
332
+ isIconLeft = true,
333
+ useTintColor = useTintColor,
334
+ icon = iconLeft,
335
+ forceLoading = loading && loadingOnLeft
336
+ )
337
+ RenderTitle(size, title, type = type)
338
+ RenderIcon(
339
+ size = size,
340
+ isIconLeft = false,
341
+ useTintColor = useTintColor,
342
+ icon = iconRight,
343
+ forceLoading = loading && !loadingOnLeft
344
+ )
345
+ }
346
+ }
347
+ }
348
+
349
+
350
+ private val IsLoading = staticCompositionLocalOf<Boolean> { false }
351
+ private val BackgroundColor = staticCompositionLocalOf<Color> { Color.Transparent }
352
+ private val TextColor = staticCompositionLocalOf<Color> { Color.Transparent }
353
+
@@ -0,0 +1,98 @@
1
+ package vn.momo.kits.components
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.border
5
+ import androidx.compose.foundation.clickable
6
+ import androidx.compose.foundation.layout.Box
7
+ import androidx.compose.foundation.layout.Row
8
+ import androidx.compose.foundation.layout.Spacer
9
+ import androidx.compose.foundation.layout.size
10
+ import androidx.compose.foundation.shape.RoundedCornerShape
11
+ import androidx.compose.runtime.Composable
12
+ import androidx.compose.runtime.remember
13
+ import androidx.compose.ui.Alignment
14
+ import androidx.compose.ui.Modifier
15
+ import androidx.compose.ui.graphics.Color
16
+ import androidx.compose.ui.unit.dp
17
+ import vn.momo.kits.application.ApplicationContext
18
+ import vn.momo.kits.application.MiniAppContext.Companion.isShowBaselineDebug
19
+ import vn.momo.kits.const.AppTheme
20
+ import vn.momo.kits.const.Colors
21
+ import vn.momo.kits.const.Radius
22
+ import vn.momo.kits.const.Spacing
23
+ import vn.momo.kits.const.Typography
24
+ import vn.momo.kits.modifier.activeOpacityClickable
25
+ import vn.momo.kits.modifier.conditional
26
+
27
+ // Pre-computed shape for performance
28
+ private val checkboxShape = RoundedCornerShape(Radius.XS)
29
+
30
+ @Composable
31
+ fun CheckBox(
32
+ disabled: Boolean = false,
33
+ checked: Boolean = false,
34
+ onCheckedChange: (Boolean) -> Unit,
35
+ indeterminate: Boolean = false,
36
+ title: String = "",
37
+ ) {
38
+ // Cache theme access
39
+ val theme = AppTheme.current
40
+
41
+ // Memoize color calculations to avoid repeated conditional logic
42
+ val colors = remember(checked, disabled, theme) {
43
+ when {
44
+ disabled && checked -> Pair(theme.colors.background.tonal, theme.colors.background.tonal)
45
+ disabled -> Pair(theme.colors.border.disable, Color.Transparent)
46
+ checked -> Pair(theme.colors.primary, theme.colors.primary)
47
+ else -> Pair(theme.colors.text.default, Color.Transparent)
48
+ }
49
+ }
50
+
51
+ val (borderColor, backgroundColor) = colors
52
+
53
+ // Memoize icon source to avoid repeated conditional check
54
+ val iconSource = remember(indeterminate) {
55
+ if (indeterminate) "navigation_minus" else "ic_checked"
56
+ }
57
+
58
+ // Memoize click handler to avoid lambda recreation
59
+ val onClickHandler = remember(onCheckedChange, checked) {
60
+ { onCheckedChange(!checked) }
61
+ }
62
+
63
+ val application = ApplicationContext.current
64
+
65
+ Row(verticalAlignment = Alignment.CenterVertically) {
66
+ Box(
67
+ modifier = Modifier
68
+ .size(20.dp)
69
+ .background(backgroundColor, checkboxShape)
70
+ .border(Spacing.XXS, borderColor, checkboxShape)
71
+ .conditional(application.isShowBaselineDebug()) {
72
+ border(1.dp, Colors.blue_03)
73
+ }
74
+ .activeOpacityClickable(
75
+ activeOpacity = 0.8f,
76
+ onClick = onClickHandler,
77
+ enabled = !disabled,
78
+ ),
79
+ ) {
80
+ if (checked) {
81
+ Icon(
82
+ source = iconSource,
83
+ size = 20.dp,
84
+ color = Colors.black_01
85
+ )
86
+ }
87
+ }
88
+
89
+ if (title.isNotEmpty()) {
90
+ Spacer(Modifier.size(Spacing.S))
91
+ Text(
92
+ style = Typography.descriptionDefaultRegular,
93
+ text = title,
94
+ )
95
+ }
96
+ }
97
+
98
+ }
@@ -0,0 +1,138 @@
1
+ package vn.momo.kits.components
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.border
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
10
+ import androidx.compose.foundation.shape.RoundedCornerShape
11
+ import androidx.compose.runtime.Composable
12
+ import androidx.compose.runtime.Immutable
13
+ import androidx.compose.ui.Alignment
14
+ import androidx.compose.ui.Modifier
15
+ import androidx.compose.ui.draw.clip
16
+ import androidx.compose.ui.graphics.Color
17
+ import androidx.compose.ui.text.style.TextAlign
18
+ import androidx.compose.ui.text.style.TextOverflow
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
24
+ import vn.momo.kits.application.ApplicationContext
25
+ import vn.momo.kits.application.MiniAppContext.Companion.isShowBaselineDebug
26
+ import vn.momo.kits.const.scaleSize
27
+ import vn.momo.kits.modifier.activeOpacityClickable
28
+ import vn.momo.kits.modifier.conditional
29
+ import vn.momo.kits.modifier.setAutomationId
30
+
31
+ @Composable
32
+ fun Chip(
33
+ modifier: Modifier = Modifier,
34
+ label: String? = "Label",
35
+ iconLeft: String? = null,
36
+ iconRight: String? = null,
37
+ selected: Boolean = false,
38
+ onClick: () -> Unit = {},
39
+ size: ChipSize = ChipSize.LARGE,
40
+ iconLeftTint: Color? = null,
41
+ iconRightTint: Color? = null,
42
+ backgroundColor: Color? = null,
43
+ accessibilityLabel: String? = null,
44
+ ) {
45
+ val theme = AppTheme.current
46
+ val bg = when {
47
+ selected -> theme.colors.background.selected
48
+ backgroundColor != null -> backgroundColor
49
+ else -> Colors.black_03
50
+ }
51
+
52
+ val textColor = if (selected) theme.colors.primary else theme.colors.text.default
53
+ val leftTint = if (selected) theme.colors.primary else iconLeftTint ?: theme.colors.text.default
54
+ val rightTint = if (selected) theme.colors.primary else iconRightTint ?: theme.colors.text.default
55
+
56
+ val dims = when (size) {
57
+ ChipSize.SMALL -> ChipDefaults.Small
58
+ ChipSize.LARGE -> ChipDefaults.Large
59
+ }
60
+
61
+ val (height, horizontal, iconSize, iconSpacing) =
62
+ listOf(scaleSize(dims.height), scaleSize(dims.horizontal), scaleSize(dims.iconSize), scaleSize(dims.iconSpacing))
63
+
64
+ val radius = scaleSize(Radius.L)
65
+ val application = ApplicationContext.current
66
+
67
+ Row(
68
+ modifier
69
+ .wrapContentWidth()
70
+ .height(height.dp)
71
+ .clip(RoundedCornerShape(radius))
72
+ .background(bg)
73
+ .conditional(selected) {
74
+ Modifier.border(width = 2.dp, color = theme.colors.secondary, shape = RoundedCornerShape(radius))
75
+ }
76
+ .conditional(application.isShowBaselineDebug()) {
77
+ border(1.dp, Colors.blue_03)
78
+ }
79
+ .activeOpacityClickable {
80
+ onClick()
81
+ }
82
+ .padding(horizontal = horizontal.dp)
83
+ .conditional(accessibilityLabel != null) {
84
+ setAutomationId(accessibilityLabel.toString())
85
+ },
86
+ verticalAlignment = Alignment.CenterVertically,
87
+ horizontalArrangement = Arrangement.spacedBy(iconSpacing.dp)
88
+ ) {
89
+ if (iconLeft != null) {
90
+ Icon(source = iconLeft, size = dims.iconSize.dp, color = leftTint)
91
+ }
92
+
93
+ if (!label.isNullOrEmpty()) {
94
+ Text(
95
+ text = label,
96
+ textAlign = TextAlign.Center,
97
+ color = textColor,
98
+ style = when (size) {
99
+ ChipSize.SMALL -> Typography.labelSMedium
100
+ ChipSize.LARGE -> Typography.labelDefaultMedium
101
+ },
102
+ maxLines = 1,
103
+ overflow = TextOverflow.Ellipsis,
104
+ modifier = Modifier.weight(1f, fill = false),
105
+ )
106
+ }
107
+
108
+ if (iconRight != null) {
109
+ Icon(source = iconRight, size = iconSize.dp, color = rightTint)
110
+ }
111
+ }
112
+ }
113
+
114
+ enum class ChipSize { SMALL, LARGE }
115
+
116
+ object ChipDefaults {
117
+ @Immutable
118
+ data class Dimensions(
119
+ val height: Float,
120
+ val horizontal: Float,
121
+ val iconSize: Float,
122
+ val iconSpacing: Float,
123
+ )
124
+
125
+ val Large = Dimensions(
126
+ height = 32f,
127
+ horizontal = 12f,
128
+ iconSize = 20f,
129
+ iconSpacing = 4f,
130
+ )
131
+
132
+ val Small = Dimensions(
133
+ height = 24f,
134
+ horizontal = 10f,
135
+ iconSize = 16f,
136
+ iconSpacing = 4f,
137
+ )
138
+ }