@momo-kits/native-kits 0.162.3-debug → 0.162.3-fontscale.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 (130) hide show
  1. package/.codegraph/.gitignore +5 -0
  2. package/CLAUDE.md +78 -0
  3. package/compose/build.gradle.kts +12 -8
  4. package/compose/build.gradle.kts.backup +11 -7
  5. package/compose/compose.podspec +1 -1
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +2 -7
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +3 -11
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +6 -24
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +4 -19
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +1 -10
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +2 -2
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +1 -1
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +1 -1
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +6 -17
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +1 -1
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +6 -101
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +5 -19
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +8 -33
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +1 -1
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +1 -6
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +27 -29
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +3 -26
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +27 -26
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +3 -13
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -5
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +3 -11
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +3 -18
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +11 -11
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +3 -11
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +69 -26
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +1 -5
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +84 -59
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +13 -71
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +10 -51
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +6 -1
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +4 -21
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +1 -1
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +16 -75
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +5 -26
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +1 -1
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +3 -11
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +16 -40
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +3 -9
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -28
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +2 -13
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +4 -10
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +3 -28
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +8 -47
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +4 -25
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +2 -11
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +1 -17
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +1 -6
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +50 -111
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +1 -5
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +1 -5
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +1 -12
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +4 -96
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +5 -7
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +2 -12
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +9 -21
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +2 -2
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +9 -14
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +8 -11
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +1 -1
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +3 -18
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +1 -1
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -5
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -2
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +94 -4
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -2
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +2 -2
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +3 -7
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +5 -15
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +42 -24
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +48 -33
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +58 -57
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +28 -25
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +13 -31
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +1 -1
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +6 -24
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +11 -6
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +2 -1
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +9 -6
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +1 -1
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +3 -13
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +3 -2
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +1 -40
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -2
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -8
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +2 -17
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +1 -1
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +3 -3
  94. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +2 -3
  95. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -2
  96. package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Example.xcscheme +32 -0
  97. package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  98. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  99. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/WorkspaceSettings.xcsettings +16 -0
  100. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +6 -0
  101. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
  102. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +58 -0
  103. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Pods-Example.xcscheme +58 -0
  104. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImage.xcscheme +58 -0
  105. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +58 -0
  106. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SkeletonUI.xcscheme +58 -0
  107. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios-LottiePrivacyInfo.xcscheme +58 -0
  108. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios.xcscheme +58 -0
  109. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +60 -0
  110. package/gradle/libs.versions.toml +2 -0
  111. package/gradle.properties +1 -1
  112. package/ios/Application/Components.swift +1 -0
  113. package/ios/Application/FloatingButton.swift +1 -0
  114. package/ios/Badge/Badge.swift +1 -0
  115. package/ios/Badge/BadgeRibbon.swift +2 -0
  116. package/ios/Button/Button.swift +1 -1
  117. package/ios/Checkbox/Checkbox.swift +1 -0
  118. package/ios/Information/Information.swift +151 -0
  119. package/ios/Input/Input.swift +1 -0
  120. package/ios/Input/InputPhoneNumber.swift +1 -0
  121. package/ios/Input/InputSearch.swift +3 -0
  122. package/ios/Input/InputTextArea.swift +1 -0
  123. package/ios/OTPKeyboard/KeyboardButton.swift +1 -1
  124. package/ios/Popup/PopupDisplay.swift +6 -0
  125. package/ios/Popup/PopupInput.swift +2 -0
  126. package/ios/Template/TrustBanner/TrustBanner.swift +2 -0
  127. package/ios/Typography/Text.swift +1 -0
  128. package/ios/Typography/Typography.swift +14 -5
  129. package/local.properties +8 -0
  130. package/package.json +1 -1
@@ -3,11 +3,7 @@ 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.Box
7
- import androidx.compose.foundation.layout.height
8
- import androidx.compose.foundation.layout.padding
9
- import androidx.compose.foundation.layout.size
10
- import androidx.compose.foundation.layout.width
6
+ import androidx.compose.foundation.layout.*
11
7
  import androidx.compose.foundation.shape.RoundedCornerShape
12
8
  import androidx.compose.runtime.Composable
13
9
  import androidx.compose.runtime.remember
@@ -22,7 +18,6 @@ import vn.momo.kits.const.Spacing
22
18
  import vn.momo.kits.modifier.conditional
23
19
  import vn.momo.kits.modifier.setAutomationId
24
20
 
25
- // Pre-computed shapes to avoid repeated creation
26
21
  private val switchShape = RoundedCornerShape(20.dp)
27
22
  private val circleShape = RoundedCornerShape(percent = 100)
28
23
 
@@ -2,34 +2,12 @@ package vn.momo.kits.components
2
2
 
3
3
  import androidx.compose.animation.core.animateDpAsState
4
4
  import androidx.compose.animation.core.tween
5
- import androidx.compose.foundation.ScrollState
6
- import androidx.compose.foundation.background
7
- import androidx.compose.foundation.border
8
- import androidx.compose.foundation.horizontalScroll
9
- import androidx.compose.foundation.layout.Arrangement
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.height
16
- import androidx.compose.foundation.layout.offset
17
- import androidx.compose.foundation.layout.padding
18
- import androidx.compose.foundation.layout.width
19
- import androidx.compose.foundation.layout.wrapContentWidth
5
+ import androidx.compose.foundation.*
6
+ import androidx.compose.foundation.layout.*
20
7
  import androidx.compose.foundation.pager.HorizontalPager
21
8
  import androidx.compose.foundation.pager.rememberPagerState
22
- import androidx.compose.foundation.rememberScrollState
23
9
  import androidx.compose.foundation.shape.RoundedCornerShape
24
- import androidx.compose.runtime.Composable
25
- import androidx.compose.runtime.LaunchedEffect
26
- import androidx.compose.runtime.getValue
27
- import androidx.compose.runtime.mutableStateListOf
28
- import androidx.compose.runtime.mutableStateOf
29
- import androidx.compose.runtime.remember
30
- import androidx.compose.runtime.rememberCoroutineScope
31
- import androidx.compose.runtime.setValue
32
- import androidx.compose.runtime.snapshotFlow
10
+ import androidx.compose.runtime.*
33
11
  import androidx.compose.ui.Alignment
34
12
  import androidx.compose.ui.Modifier
35
13
  import androidx.compose.ui.graphics.Color
@@ -41,18 +19,10 @@ import androidx.compose.ui.unit.Dp
41
19
  import androidx.compose.ui.unit.dp
42
20
  import kotlinx.coroutines.launch
43
21
  import vn.momo.kits.application.IsShowBaseLineDebug
44
- import vn.momo.kits.const.AppTheme
45
- import vn.momo.kits.const.Colors
46
- import vn.momo.kits.const.Radius
47
- import vn.momo.kits.const.Spacing
48
- import vn.momo.kits.const.Typography
22
+ import vn.momo.kits.const.*
49
23
  import vn.momo.kits.modifier.activeOpacityClickable
50
24
  import vn.momo.kits.modifier.conditional
51
25
 
52
- // ---------------------------------------------------------------------------
53
- // Data model
54
- // ---------------------------------------------------------------------------
55
-
56
26
  data class TabViewItem(
57
27
  val title: String,
58
28
  val icon: String? = null,
@@ -68,10 +38,6 @@ enum class TabViewType { DEFAULT, CARD }
68
38
 
69
39
  enum class TabViewDirection { ROW, COLUMN }
70
40
 
71
- // ---------------------------------------------------------------------------
72
- // Public composable
73
- // ---------------------------------------------------------------------------
74
-
75
41
  @Composable
76
42
  fun TabView(
77
43
  modifier: Modifier = Modifier,
@@ -186,10 +152,6 @@ fun TabView(
186
152
  }
187
153
  }
188
154
 
189
- // ---------------------------------------------------------------------------
190
- // Default fixed-width tab bar
191
- // ---------------------------------------------------------------------------
192
-
193
155
  @Composable
194
156
  private fun DefaultTabBar(
195
157
  tabs: List<TabViewItem>,
@@ -240,24 +202,10 @@ private fun DefaultTabBar(
240
202
  }
241
203
 
242
204
  // Animated underline indicator
243
- Box(
244
- modifier = Modifier
245
- .align(Alignment.BottomStart)
246
- .offset(x = indicatorOffsetX)
247
- .width(indicatorWidth)
248
- .height(2.dp)
249
- .background(
250
- color = selectedColor,
251
- shape = RoundedCornerShape(topStart = Radius.XXS, topEnd = Radius.XXS),
252
- ),
253
- )
205
+ TabUnderlineIndicator(offsetX = indicatorOffsetX, width = indicatorWidth, color = selectedColor)
254
206
  }
255
207
  }
256
208
 
257
- // ---------------------------------------------------------------------------
258
- // Scrollable tab bar
259
- // ---------------------------------------------------------------------------
260
-
261
209
  @Composable
262
210
  private fun ScrollableTabBar(
263
211
  tabs: List<TabViewItem>,
@@ -338,24 +286,14 @@ private fun ScrollableTabBar(
338
286
  }
339
287
 
340
288
  // Animated underline indicator aligned to bottom of the bar
341
- Box(
342
- modifier = Modifier
343
- .align(Alignment.BottomStart)
344
- .offset(x = animatedX - scrollOffsetDp + Spacing.XS)
345
- .width((animatedWidth - Spacing.XS * 2).coerceAtLeast(0.dp))
346
- .height(2.dp)
347
- .background(
348
- color = selectedColor,
349
- shape = RoundedCornerShape(topStart = Radius.XXS, topEnd = Radius.XXS),
350
- ),
289
+ TabUnderlineIndicator(
290
+ offsetX = animatedX - scrollOffsetDp + Spacing.XS,
291
+ width = (animatedWidth - Spacing.XS * 2).coerceAtLeast(0.dp),
292
+ color = selectedColor,
351
293
  )
352
294
  }
353
295
  }
354
296
 
355
- // ---------------------------------------------------------------------------
356
- // Card tab bar
357
- // ---------------------------------------------------------------------------
358
-
359
297
  @Composable
360
298
  private fun CardTabBar(
361
299
  tabs: List<TabViewItem>,
@@ -394,17 +332,7 @@ private fun CardTabBar(
394
332
  contentAlignment = Alignment.Center,
395
333
  ) {
396
334
  Row(verticalAlignment = Alignment.CenterVertically) {
397
- if (tab.renderIcon != null) {
398
- tab.renderIcon.invoke(isActive)
399
- Spacer(modifier = Modifier.width(Spacing.XS))
400
- } else if (tab.icon != null) {
401
- Icon(
402
- source = tab.icon,
403
- size = 18.dp,
404
- color = iconColor,
405
- )
406
- Spacer(modifier = Modifier.width(Spacing.XS))
407
- }
335
+ TabLeadingIcon(tab = tab, active = isActive, color = iconColor)
408
336
  Text(
409
337
  text = tab.title,
410
338
  style = if (isActive) Typography.headerSSemibold else Typography.bodyDefaultRegular,
@@ -413,23 +341,13 @@ private fun CardTabBar(
413
341
  overflow = TextOverflow.Ellipsis,
414
342
  modifier = Modifier.weight(1f, fill = false),
415
343
  )
416
- if (tab.showDot) {
417
- Spacer(modifier = Modifier.width(Spacing.XS))
418
- BadgeDot(size = tab.dotSize)
419
- } else if (!tab.badgeValue.isNullOrEmpty()) {
420
- Spacer(modifier = Modifier.width(Spacing.XS))
421
- Badge(label = tab.badgeValue, modifier = Modifier)
422
- }
344
+ TabTrailingBadge(tab)
423
345
  }
424
346
  }
425
347
  }
426
348
  }
427
349
  }
428
350
 
429
- // ---------------------------------------------------------------------------
430
- // Shared tab item used by DefaultTabBar and ScrollableTabBar
431
- // ---------------------------------------------------------------------------
432
-
433
351
  @Composable
434
352
  private fun TabItemView(
435
353
  modifier: Modifier = Modifier,
@@ -500,17 +418,7 @@ private fun TabItemView(
500
418
  horizontalArrangement = Arrangement.Center,
501
419
  verticalAlignment = Alignment.CenterVertically,
502
420
  ) {
503
- if (tab.renderIcon != null) {
504
- tab.renderIcon.invoke(active)
505
- Spacer(modifier = Modifier.width(Spacing.XS))
506
- } else if (tab.icon != null) {
507
- Icon(
508
- source = tab.icon,
509
- size = 18.dp,
510
- color = textColor,
511
- )
512
- Spacer(modifier = Modifier.width(Spacing.XS))
513
- }
421
+ TabLeadingIcon(tab = tab, active = active, color = textColor)
514
422
  Text(
515
423
  text = tab.title,
516
424
  style = textStyle,
@@ -519,13 +427,44 @@ private fun TabItemView(
519
427
  overflow = TextOverflow.Ellipsis,
520
428
  modifier = if (scrollable) Modifier else Modifier.weight(1f, fill = false),
521
429
  )
522
- if (tab.showDot) {
523
- Spacer(modifier = Modifier.width(Spacing.XS))
524
- BadgeDot(size = tab.dotSize)
525
- } else if (!tab.badgeValue.isNullOrEmpty()) {
526
- Spacer(modifier = Modifier.width(Spacing.XS))
527
- Badge(label = tab.badgeValue, modifier = Modifier)
528
- }
430
+ TabTrailingBadge(tab)
529
431
  }
530
432
  }
531
433
  }
434
+
435
+ @Composable
436
+ private fun BoxScope.TabUnderlineIndicator(offsetX: Dp, width: Dp, color: Color) {
437
+ Box(
438
+ modifier = Modifier
439
+ .align(Alignment.BottomStart)
440
+ .offset(x = offsetX)
441
+ .width(width)
442
+ .height(2.dp)
443
+ .background(
444
+ color = color,
445
+ shape = RoundedCornerShape(topStart = Radius.XXS, topEnd = Radius.XXS),
446
+ ),
447
+ )
448
+ }
449
+
450
+ @Composable
451
+ private fun TabLeadingIcon(tab: TabViewItem, active: Boolean, color: Color) {
452
+ if (tab.renderIcon != null) {
453
+ tab.renderIcon.invoke(active)
454
+ Spacer(modifier = Modifier.width(Spacing.XS))
455
+ } else if (tab.icon != null) {
456
+ Icon(source = tab.icon, size = 18.dp, color = color)
457
+ Spacer(modifier = Modifier.width(Spacing.XS))
458
+ }
459
+ }
460
+
461
+ @Composable
462
+ private fun TabTrailingBadge(tab: TabViewItem) {
463
+ if (tab.showDot) {
464
+ Spacer(modifier = Modifier.width(Spacing.XS))
465
+ BadgeDot(size = tab.dotSize)
466
+ } else if (!tab.badgeValue.isNullOrEmpty()) {
467
+ Spacer(modifier = Modifier.width(Spacing.XS))
468
+ Badge(label = tab.badgeValue, modifier = Modifier)
469
+ }
470
+ }
@@ -13,11 +13,7 @@ import androidx.compose.ui.Modifier
13
13
  import androidx.compose.ui.graphics.Color
14
14
  import androidx.compose.ui.unit.dp
15
15
  import vn.momo.kits.application.IsShowBaseLineDebug
16
- import vn.momo.kits.const.Colors
17
- import vn.momo.kits.const.Radius
18
- import vn.momo.kits.const.Spacing
19
- import vn.momo.kits.const.Typography
20
- import vn.momo.kits.const.scaleSize
16
+ import vn.momo.kits.const.*
21
17
  import vn.momo.kits.modifier.conditional
22
18
 
23
19
  enum class TagSize(val height: Float) {
@@ -15,11 +15,7 @@ import androidx.compose.ui.text.style.TextOverflow
15
15
  import androidx.compose.ui.unit.TextUnit
16
16
  import androidx.compose.ui.unit.dp
17
17
  import vn.momo.kits.application.IsShowBaseLineDebug
18
- import vn.momo.kits.const.AppTheme
19
- import vn.momo.kits.const.Colors
20
- import vn.momo.kits.const.Typography
21
- import vn.momo.kits.const.getFontFamily
22
- import vn.momo.kits.const.scaleSize
18
+ import vn.momo.kits.const.*
23
19
  import vn.momo.kits.modifier.conditional
24
20
  import vn.momo.kits.modifier.setAutomationId
25
21
 
@@ -3,18 +3,7 @@ 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.Arrangement
7
- import androidx.compose.foundation.layout.Box
8
- import androidx.compose.foundation.layout.Column
9
- import androidx.compose.foundation.layout.IntrinsicSize
10
- import androidx.compose.foundation.layout.Row
11
- import androidx.compose.foundation.layout.Spacer
12
- import androidx.compose.foundation.layout.fillMaxHeight
13
- import androidx.compose.foundation.layout.fillMaxWidth
14
- import androidx.compose.foundation.layout.height
15
- import androidx.compose.foundation.layout.padding
16
- import androidx.compose.foundation.layout.size
17
- import androidx.compose.foundation.layout.width
6
+ import androidx.compose.foundation.layout.*
18
7
  import androidx.compose.foundation.shape.RoundedCornerShape
19
8
  import androidx.compose.runtime.Composable
20
9
  import androidx.compose.ui.Alignment
@@ -5,28 +5,9 @@ import androidx.compose.foundation.background
5
5
  import androidx.compose.foundation.border
6
6
  import androidx.compose.foundation.clickable
7
7
  import androidx.compose.foundation.interaction.MutableInteractionSource
8
- import androidx.compose.foundation.layout.Arrangement
9
- import androidx.compose.foundation.layout.Box
10
- import androidx.compose.foundation.layout.Column
11
- import androidx.compose.foundation.layout.IntrinsicSize
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.height
16
- import androidx.compose.foundation.layout.offset
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.layout.widthIn
21
- import androidx.compose.foundation.layout.wrapContentSize
8
+ import androidx.compose.foundation.layout.*
22
9
  import androidx.compose.foundation.shape.RoundedCornerShape
23
- import androidx.compose.runtime.Composable
24
- import androidx.compose.runtime.LaunchedEffect
25
- import androidx.compose.runtime.Stable
26
- import androidx.compose.runtime.getValue
27
- import androidx.compose.runtime.mutableStateOf
28
- import androidx.compose.runtime.remember
29
- import androidx.compose.runtime.setValue
10
+ import androidx.compose.runtime.*
30
11
  import androidx.compose.ui.Alignment
31
12
  import androidx.compose.ui.Modifier
32
13
  import androidx.compose.ui.draw.clip
@@ -36,63 +17,32 @@ import androidx.compose.ui.graphics.PathEffect
36
17
  import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
37
18
  import androidx.compose.ui.platform.LocalDensity
38
19
  import androidx.compose.ui.text.style.TextOverflow
39
- import androidx.compose.ui.unit.IntOffset
40
- import androidx.compose.ui.unit.IntRect
41
- import androidx.compose.ui.unit.IntSize
42
- import androidx.compose.ui.unit.LayoutDirection
43
- import androidx.compose.ui.unit.dp
20
+ import androidx.compose.ui.unit.*
44
21
  import androidx.compose.ui.window.Popup
45
22
  import androidx.compose.ui.window.PopupPositionProvider
46
23
  import androidx.compose.ui.window.PopupProperties
47
24
  import vn.momo.kits.application.IsShowBaseLineDebug
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.scaleSize
25
+ import vn.momo.kits.const.*
53
26
  import vn.momo.kits.modifier.activeOpacityClickable
54
27
  import vn.momo.kits.modifier.conditional
55
28
 
56
29
 
57
- // region Types
58
-
59
- /**
60
- * Tooltip placement relative to the anchor element.
61
- */
62
30
  enum class TooltipPlacement {
63
31
  TOP,
64
32
  BOTTOM,
65
33
  LEFT,
66
34
  RIGHT,
67
35
  }
68
-
69
- /**
70
- * Cross-axis alignment of the tooltip relative to the anchor.
71
- */
72
36
  enum class TooltipAlign {
73
37
  START,
74
38
  CENTER,
75
39
  END,
76
40
  }
77
-
78
- /**
79
- * Describes a single action button displayed in the tooltip.
80
- *
81
- * @param title Text label for the button (used for text buttons).
82
- * @param icon Icon source for the button (used for icon buttons).
83
- * @param onPress Callback invoked when the button is pressed.
84
- */
85
41
  data class TooltipButton(
86
42
  val title: String? = null,
87
43
  val icon: String? = null,
88
44
  val onPress: (() -> Unit)? = null,
89
45
  )
90
-
91
-
92
- /**
93
- * State holder for controlling tooltip visibility imperatively.
94
- * Equivalent to the React Native `useImperativeHandle` ref pattern.
95
- */
96
46
  @Stable
97
47
  class TooltipState {
98
48
  var isVisible by mutableStateOf(false)
@@ -113,30 +63,12 @@ class TooltipState {
113
63
  isVisible = !isVisible
114
64
  }
115
65
  }
116
-
117
- /**
118
- * Creates and remembers a [TooltipState].
119
- */
120
66
  @Composable
121
67
  fun rememberTooltipState(): TooltipState {
122
68
  return remember { TooltipState() }
123
69
  }
124
70
  private val TOOLTIP_OFFSET = Spacing.S
125
71
  private val ARROW_SIZE = 6.dp
126
- /**
127
- * Custom [PopupPositionProvider] that positions the tooltip relative to the anchor.
128
- *
129
- * Mirrors the React Native `placementStyle` calculation:
130
- * - TOP: tooltip bottom edge sits at `anchorTop - TOOLTIP_OFFSET`
131
- * - BOTTOM: tooltip top edge sits at `anchorBottom + TOOLTIP_OFFSET`
132
- * - LEFT: tooltip right edge sits at `anchorLeft - TOOLTIP_OFFSET`
133
- * - RIGHT: tooltip left edge sits at `anchorRight + TOOLTIP_OFFSET`
134
- *
135
- * Cross-axis alignment:
136
- * - start: tooltip aligns to anchor start edge
137
- * - center: tooltip centers on anchor
138
- * - end: tooltip aligns to anchor end edge
139
- */
140
72
  private class TooltipPositionProvider(
141
73
  private val placement: TooltipPlacement,
142
74
  private val align: TooltipAlign,
@@ -199,27 +131,6 @@ private class TooltipPositionProvider(
199
131
  }
200
132
  }
201
133
 
202
- // endregion
203
-
204
- // region Tooltip Composable
205
-
206
- /**
207
- * A tooltip component that wraps [content] (the anchor) and shows a positioned
208
- * tooltip popup with title, description, close button, and action buttons.
209
- *
210
- * Port of the React Native `Tooltip` component.
211
- *
212
- * @param state Controls visibility (use [rememberTooltipState]).
213
- * @param title Title text displayed in the tooltip header.
214
- * @param description Description text shown under the title.
215
- * @param buttons Action buttons rendered at the bottom.
216
- * @param placement Tooltip position relative to the anchor (default TOP).
217
- * @param align Cross-axis alignment (default CENTER).
218
- * @param onVisibleChange Callback when visibility changes.
219
- * @param onPressClose Callback when the close button (X) is pressed.
220
- * @param modifier Modifier for the anchor wrapper.
221
- * @param content The anchor element that the tooltip is attached to.
222
- */
223
134
  @Composable
224
135
  fun Tooltip(
225
136
  state: TooltipState,
@@ -525,9 +436,6 @@ private fun TooltipSingleButton(btn: TooltipButton) {
525
436
  )
526
437
  }
527
438
  }
528
-
529
- private const val MAX_BUTTON_LENGTH = 16
530
-
531
439
  private fun String.limitWithEllipsis(max: Int = 16): String {
532
440
  return if (length > max) take(max) + "…" else this
533
441
  }
@@ -18,8 +18,7 @@ import androidx.compose.ui.draw.clip
18
18
  import androidx.compose.ui.graphics.Color
19
19
  import androidx.compose.ui.layout.ContentScale
20
20
  import androidx.compose.ui.unit.dp
21
- import vn.momo.kits.application.AppConfig
22
- import vn.momo.kits.application.AppLanguage
21
+ import vn.momo.kits.application.LocalLocalize
23
22
  import vn.momo.kits.application.IsShowBaseLineDebug
24
23
  import vn.momo.kits.const.Colors
25
24
  import vn.momo.kits.const.Typography
@@ -68,9 +67,8 @@ fun TrustBanner(
68
67
  onPress: ((Map<String, String>) -> Unit)? = null,
69
68
  trackEvent: ((String, Map<String, String>) -> Unit)? = null
70
69
  ) {
71
- val appConfig = AppConfig.current
72
- val language = AppLanguage.current ?: "vi"
73
- val trustBanner = appConfig?.trustBanner ?: defaultBanner
70
+ val localize = LocalLocalize.current
71
+ val trustBanner = defaultBanner
74
72
  val trackParams = mapOf(
75
73
  "service_name" to serviceName,
76
74
  "screen_name" to screenName,
@@ -124,7 +122,7 @@ fun TrustBanner(
124
122
  .padding(start = 10.dp)
125
123
  ) {
126
124
  Text(
127
- text = trustBanner.content[language] ?: "",
125
+ text = localize.translateData(trustBanner.content),
128
126
  modifier = Modifier.padding(bottom = 8.dp),
129
127
  color = Color(contentColor),
130
128
  style = Typography.descriptionDefaultRegular,
@@ -138,7 +136,7 @@ fun TrustBanner(
138
136
  verticalAlignment = Alignment.CenterVertically,
139
137
  ) {
140
138
  Text(
141
- text = trustBanner.subContent[language] ?: "",
139
+ text = localize.translateData(trustBanner.subContent),
142
140
  color = Color(subContentColor),
143
141
  style = Typography.actionXsBold,
144
142
  maxLines = 2
@@ -3,13 +3,7 @@ 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.horizontalScroll
6
- import androidx.compose.foundation.layout.Arrangement
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.fillMaxSize
11
- import androidx.compose.foundation.layout.padding
12
- import androidx.compose.foundation.layout.size
6
+ import androidx.compose.foundation.layout.*
13
7
  import androidx.compose.foundation.rememberScrollState
14
8
  import androidx.compose.foundation.shape.RoundedCornerShape
15
9
  import androidx.compose.runtime.Composable
@@ -25,11 +19,7 @@ import androidx.compose.ui.graphics.drawscope.Stroke
25
19
  import androidx.compose.ui.unit.Dp
26
20
  import androidx.compose.ui.unit.dp
27
21
  import vn.momo.kits.application.IsShowBaseLineDebug
28
- import vn.momo.kits.const.AppTheme
29
- import vn.momo.kits.const.Colors
30
- import vn.momo.kits.const.Radius
31
- import vn.momo.kits.const.Spacing
32
- import vn.momo.kits.const.Typography
22
+ import vn.momo.kits.const.*
33
23
  import vn.momo.kits.modifier.activeOpacityClickable
34
24
  import vn.momo.kits.modifier.conditional
35
25
 
@@ -2,20 +2,8 @@ package vn.momo.kits.components.datetimepicker
2
2
 
3
3
  import androidx.compose.foundation.background
4
4
  import androidx.compose.foundation.border
5
- import androidx.compose.foundation.layout.Column
6
- import androidx.compose.foundation.layout.Row
7
- import androidx.compose.foundation.layout.Spacer
8
- import androidx.compose.foundation.layout.fillMaxWidth
9
- import androidx.compose.foundation.layout.height
10
- import androidx.compose.foundation.layout.padding
11
- import androidx.compose.foundation.layout.width
12
- import androidx.compose.runtime.Composable
13
- import androidx.compose.runtime.LaunchedEffect
14
- import androidx.compose.runtime.getValue
15
- import androidx.compose.runtime.mutableStateOf
16
- import androidx.compose.runtime.remember
17
- import androidx.compose.runtime.setValue
18
- import androidx.compose.runtime.snapshotFlow
5
+ import androidx.compose.foundation.layout.*
6
+ import androidx.compose.runtime.*
19
7
  import androidx.compose.ui.Alignment
20
8
  import androidx.compose.ui.Modifier
21
9
  import androidx.compose.ui.unit.dp
@@ -74,7 +62,7 @@ fun DateTimePicker(
74
62
  var currentDate by remember(initialValue) {
75
63
  mutableStateOf(
76
64
  PickerData(
77
- day = initialValue.dayOfMonth,
65
+ day = initialValue.day,
78
66
  month = initialValue.month.number,
79
67
  year = initialValue.year,
80
68
  hour = initialValue.hour,
@@ -95,10 +83,10 @@ fun DateTimePicker(
95
83
  month = when (year) {
96
84
  effectiveMaxDate.year -> month.coerceIn(
97
85
  1,
98
- effectiveMaxDate.monthNumber
86
+ effectiveMaxDate.month.number
99
87
  )
100
88
  effectiveMinDate.year -> month.coerceIn(
101
- effectiveMinDate.monthNumber,
89
+ effectiveMinDate.month.number,
102
90
  12,
103
91
  )
104
92
  else -> month
@@ -112,11 +100,11 @@ fun DateTimePicker(
112
100
  }
113
101
 
114
102
  day = when {
115
- year == effectiveMaxDate.year && month == effectiveMaxDate.monthNumber ->
116
- day.coerceIn(1, effectiveMaxDate.dayOfMonth)
103
+ year == effectiveMaxDate.year && month == effectiveMaxDate.month.number ->
104
+ day.coerceIn(1, effectiveMaxDate.day)
117
105
 
118
- year == effectiveMinDate.year && month == effectiveMinDate.monthNumber ->
119
- day.coerceIn(effectiveMinDate.dayOfMonth, maxDayOfMonth)
106
+ year == effectiveMinDate.year && month == effectiveMinDate.month.number ->
107
+ day.coerceIn(effectiveMinDate.day, maxDayOfMonth)
120
108
 
121
109
  day > maxDayOfMonth -> maxDayOfMonth
122
110
  else -> day
@@ -13,8 +13,8 @@ data class PickerData(
13
13
  fun toLocalDateTime(): LocalDateTime {
14
14
  return LocalDateTime(
15
15
  year = year,
16
- monthNumber = month,
17
- dayOfMonth = day,
16
+ month = month,
17
+ day = day,
18
18
  hour = hour,
19
19
  minute = minute,
20
20
  second = 0,
@@ -2,15 +2,10 @@ package vn.momo.kits.components.datetimepicker
2
2
 
3
3
  import androidx.compose.runtime.Composable
4
4
  import androidx.compose.runtime.remember
5
+ import kotlinx.datetime.*
6
+ import kotlinx.datetime.number
5
7
  import kotlin.time.Clock
6
8
  import kotlin.time.ExperimentalTime
7
- import kotlinx.datetime.DatePeriod
8
- import kotlinx.datetime.LocalDateTime
9
- import kotlinx.datetime.TimeZone
10
- import kotlinx.datetime.minus
11
- import kotlinx.datetime.number
12
- import kotlinx.datetime.plus
13
- import kotlinx.datetime.toLocalDateTime
14
9
 
15
10
  /**
16
11
  * Format a LocalDateTime object into a string
@@ -19,13 +14,13 @@ fun formatLocalDateTime(dateTime: LocalDateTime, format: String = "yyyy-MM-dd HH
19
14
  return when (format) {
20
15
  "yyyy-MM-dd HH:mm" -> "${dateTime.year}-${paddingNum(dateTime.month.number)}-${
21
16
  paddingNum(
22
- dateTime.dayOfMonth
17
+ dateTime.day
23
18
  )
24
19
  } ${paddingNum(dateTime.hour)}:${paddingNum(dateTime.minute)}"
25
20
 
26
- "dd-MM-yyyy" -> "${paddingNum(dateTime.dayOfMonth)}-${paddingNum(dateTime.month.number)}-${dateTime.year}"
21
+ "dd-MM-yyyy" -> "${paddingNum(dateTime.day)}-${paddingNum(dateTime.month.number)}-${dateTime.year}"
27
22
  "HH:mm" -> "${paddingNum(dateTime.hour)}:${paddingNum(dateTime.minute)}"
28
- else -> "${dateTime.year}-${paddingNum(dateTime.month.number)}-${paddingNum(dateTime.dayOfMonth)} ${
23
+ else -> "${dateTime.year}-${paddingNum(dateTime.month.number)}-${paddingNum(dateTime.day)} ${
29
24
  paddingNum(
30
25
  dateTime.hour
31
26
  )
@@ -60,11 +55,11 @@ fun getDaysInMonth(
60
55
  var endDay = daysInMonth
61
56
 
62
57
  if (year == minDate.year && month == minDate.month.number) {
63
- startDay = minDate.dayOfMonth
58
+ startDay = minDate.day
64
59
  }
65
60
 
66
61
  if (year == maxDate.year && month == maxDate.month.number) {
67
- endDay = maxDate.dayOfMonth
62
+ endDay = maxDate.day
68
63
  }
69
64
 
70
65
  val days = mutableListOf<String>()
@@ -170,8 +165,8 @@ fun createRelativeDate(years: Int): LocalDateTime {
170
165
 
171
166
  return LocalDateTime(
172
167
  adjustedDate.year,
173
- adjustedDate.monthNumber,
174
- adjustedDate.dayOfMonth,
168
+ adjustedDate.month.number,
169
+ adjustedDate.day,
175
170
  currentDateTime.hour,
176
171
  currentDateTime.minute
177
172
  )