@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,12 +2,34 @@ 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.*
6
- import androidx.compose.foundation.layout.*
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
7
20
  import androidx.compose.foundation.pager.HorizontalPager
8
21
  import androidx.compose.foundation.pager.rememberPagerState
22
+ import androidx.compose.foundation.rememberScrollState
9
23
  import androidx.compose.foundation.shape.RoundedCornerShape
10
- import androidx.compose.runtime.*
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
11
33
  import androidx.compose.ui.Alignment
12
34
  import androidx.compose.ui.Modifier
13
35
  import androidx.compose.ui.graphics.Color
@@ -19,10 +41,18 @@ import androidx.compose.ui.unit.Dp
19
41
  import androidx.compose.ui.unit.dp
20
42
  import kotlinx.coroutines.launch
21
43
  import vn.momo.kits.application.IsShowBaseLineDebug
22
- import vn.momo.kits.const.*
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
23
49
  import vn.momo.kits.modifier.activeOpacityClickable
24
50
  import vn.momo.kits.modifier.conditional
25
51
 
52
+ // ---------------------------------------------------------------------------
53
+ // Data model
54
+ // ---------------------------------------------------------------------------
55
+
26
56
  data class TabViewItem(
27
57
  val title: String,
28
58
  val icon: String? = null,
@@ -38,6 +68,10 @@ enum class TabViewType { DEFAULT, CARD }
38
68
 
39
69
  enum class TabViewDirection { ROW, COLUMN }
40
70
 
71
+ // ---------------------------------------------------------------------------
72
+ // Public composable
73
+ // ---------------------------------------------------------------------------
74
+
41
75
  @Composable
42
76
  fun TabView(
43
77
  modifier: Modifier = Modifier,
@@ -152,6 +186,10 @@ fun TabView(
152
186
  }
153
187
  }
154
188
 
189
+ // ---------------------------------------------------------------------------
190
+ // Default fixed-width tab bar
191
+ // ---------------------------------------------------------------------------
192
+
155
193
  @Composable
156
194
  private fun DefaultTabBar(
157
195
  tabs: List<TabViewItem>,
@@ -202,10 +240,24 @@ private fun DefaultTabBar(
202
240
  }
203
241
 
204
242
  // Animated underline indicator
205
- TabUnderlineIndicator(offsetX = indicatorOffsetX, width = indicatorWidth, color = selectedColor)
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
+ )
206
254
  }
207
255
  }
208
256
 
257
+ // ---------------------------------------------------------------------------
258
+ // Scrollable tab bar
259
+ // ---------------------------------------------------------------------------
260
+
209
261
  @Composable
210
262
  private fun ScrollableTabBar(
211
263
  tabs: List<TabViewItem>,
@@ -286,14 +338,24 @@ private fun ScrollableTabBar(
286
338
  }
287
339
 
288
340
  // Animated underline indicator aligned to bottom of the bar
289
- TabUnderlineIndicator(
290
- offsetX = animatedX - scrollOffsetDp + Spacing.XS,
291
- width = (animatedWidth - Spacing.XS * 2).coerceAtLeast(0.dp),
292
- color = selectedColor,
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
+ ),
293
351
  )
294
352
  }
295
353
  }
296
354
 
355
+ // ---------------------------------------------------------------------------
356
+ // Card tab bar
357
+ // ---------------------------------------------------------------------------
358
+
297
359
  @Composable
298
360
  private fun CardTabBar(
299
361
  tabs: List<TabViewItem>,
@@ -332,7 +394,17 @@ private fun CardTabBar(
332
394
  contentAlignment = Alignment.Center,
333
395
  ) {
334
396
  Row(verticalAlignment = Alignment.CenterVertically) {
335
- TabLeadingIcon(tab = tab, active = isActive, color = iconColor)
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
+ }
336
408
  Text(
337
409
  text = tab.title,
338
410
  style = if (isActive) Typography.headerSSemibold else Typography.bodyDefaultRegular,
@@ -341,13 +413,23 @@ private fun CardTabBar(
341
413
  overflow = TextOverflow.Ellipsis,
342
414
  modifier = Modifier.weight(1f, fill = false),
343
415
  )
344
- TabTrailingBadge(tab)
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
+ }
345
423
  }
346
424
  }
347
425
  }
348
426
  }
349
427
  }
350
428
 
429
+ // ---------------------------------------------------------------------------
430
+ // Shared tab item used by DefaultTabBar and ScrollableTabBar
431
+ // ---------------------------------------------------------------------------
432
+
351
433
  @Composable
352
434
  private fun TabItemView(
353
435
  modifier: Modifier = Modifier,
@@ -418,7 +500,17 @@ private fun TabItemView(
418
500
  horizontalArrangement = Arrangement.Center,
419
501
  verticalAlignment = Alignment.CenterVertically,
420
502
  ) {
421
- TabLeadingIcon(tab = tab, active = active, color = textColor)
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
+ }
422
514
  Text(
423
515
  text = tab.title,
424
516
  style = textStyle,
@@ -427,44 +519,13 @@ private fun TabItemView(
427
519
  overflow = TextOverflow.Ellipsis,
428
520
  modifier = if (scrollable) Modifier else Modifier.weight(1f, fill = false),
429
521
  )
430
- TabTrailingBadge(tab)
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
+ }
431
529
  }
432
530
  }
433
531
  }
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,7 +13,11 @@ 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.*
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
17
21
  import vn.momo.kits.modifier.conditional
18
22
 
19
23
  enum class TagSize(val height: Float) {
@@ -15,7 +15,11 @@ 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.*
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
19
23
  import vn.momo.kits.modifier.conditional
20
24
  import vn.momo.kits.modifier.setAutomationId
21
25
 
@@ -36,7 +40,6 @@ fun Text(
36
40
  softWrap: Boolean = true,
37
41
  accessibilityId: String? = null,
38
42
  inlineContent: Map<String, InlineTextContent> = mapOf(),
39
- userScaleRate: Float? = null,
40
43
  ) {
41
44
  Text(
42
45
  text = AnnotatedString(text),
@@ -53,8 +56,7 @@ fun Text(
53
56
  letterSpacing = letterSpacing,
54
57
  softWrap = softWrap,
55
58
  accessibilityId = accessibilityId,
56
- inlineContent = inlineContent,
57
- userScaleRate = userScaleRate
59
+ inlineContent = inlineContent
58
60
  )
59
61
  }
60
62
 
@@ -76,14 +78,13 @@ fun Text(
76
78
  softWrap: Boolean = true,
77
79
  accessibilityId: String? = null,
78
80
  inlineContent: Map<String, InlineTextContent> = mapOf(),
79
- userScaleRate: Float? = null,
80
81
  ) {
81
82
  // Cache theme access to avoid repeated lookups
82
83
  val theme = AppTheme.current
83
84
 
84
85
  // Call @Composable functions directly in composable context
85
- val scaledFontSize = scaleSize(style.fontSize, userScaleRate)
86
- val scaledLineHeight = scaleSize(style.lineHeight, userScaleRate)
86
+ val scaledFontSize = scaleSize(style.fontSize)
87
+ val scaledLineHeight = scaleSize(style.lineHeight)
87
88
  val fontFamilyResult = getFontFamily(fontFamily ?: theme.font, style.fontWeight)
88
89
 
89
90
  // Now memoize the results
@@ -3,7 +3,18 @@ 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.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
7
18
  import androidx.compose.foundation.shape.RoundedCornerShape
8
19
  import androidx.compose.runtime.Composable
9
20
  import androidx.compose.ui.Alignment
@@ -5,9 +5,28 @@ 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.*
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
9
22
  import androidx.compose.foundation.shape.RoundedCornerShape
10
- import androidx.compose.runtime.*
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
11
30
  import androidx.compose.ui.Alignment
12
31
  import androidx.compose.ui.Modifier
13
32
  import androidx.compose.ui.draw.clip
@@ -17,32 +36,63 @@ import androidx.compose.ui.graphics.PathEffect
17
36
  import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
18
37
  import androidx.compose.ui.platform.LocalDensity
19
38
  import androidx.compose.ui.text.style.TextOverflow
20
- import androidx.compose.ui.unit.*
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
21
44
  import androidx.compose.ui.window.Popup
22
45
  import androidx.compose.ui.window.PopupPositionProvider
23
46
  import androidx.compose.ui.window.PopupProperties
24
47
  import vn.momo.kits.application.IsShowBaseLineDebug
25
- import vn.momo.kits.const.*
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
26
53
  import vn.momo.kits.modifier.activeOpacityClickable
27
54
  import vn.momo.kits.modifier.conditional
28
55
 
29
56
 
57
+ // region Types
58
+
59
+ /**
60
+ * Tooltip placement relative to the anchor element.
61
+ */
30
62
  enum class TooltipPlacement {
31
63
  TOP,
32
64
  BOTTOM,
33
65
  LEFT,
34
66
  RIGHT,
35
67
  }
68
+
69
+ /**
70
+ * Cross-axis alignment of the tooltip relative to the anchor.
71
+ */
36
72
  enum class TooltipAlign {
37
73
  START,
38
74
  CENTER,
39
75
  END,
40
76
  }
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
+ */
41
85
  data class TooltipButton(
42
86
  val title: String? = null,
43
87
  val icon: String? = null,
44
88
  val onPress: (() -> Unit)? = null,
45
89
  )
90
+
91
+
92
+ /**
93
+ * State holder for controlling tooltip visibility imperatively.
94
+ * Equivalent to the React Native `useImperativeHandle` ref pattern.
95
+ */
46
96
  @Stable
47
97
  class TooltipState {
48
98
  var isVisible by mutableStateOf(false)
@@ -63,12 +113,30 @@ class TooltipState {
63
113
  isVisible = !isVisible
64
114
  }
65
115
  }
116
+
117
+ /**
118
+ * Creates and remembers a [TooltipState].
119
+ */
66
120
  @Composable
67
121
  fun rememberTooltipState(): TooltipState {
68
122
  return remember { TooltipState() }
69
123
  }
70
124
  private val TOOLTIP_OFFSET = Spacing.S
71
125
  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
+ */
72
140
  private class TooltipPositionProvider(
73
141
  private val placement: TooltipPlacement,
74
142
  private val align: TooltipAlign,
@@ -131,6 +199,27 @@ private class TooltipPositionProvider(
131
199
  }
132
200
  }
133
201
 
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
+ */
134
223
  @Composable
135
224
  fun Tooltip(
136
225
  state: TooltipState,
@@ -436,6 +525,9 @@ private fun TooltipSingleButton(btn: TooltipButton) {
436
525
  )
437
526
  }
438
527
  }
528
+
529
+ private const val MAX_BUTTON_LENGTH = 16
530
+
439
531
  private fun String.limitWithEllipsis(max: Int = 16): String {
440
532
  return if (length > max) take(max) + "…" else this
441
533
  }
@@ -3,7 +3,13 @@ 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.*
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
7
13
  import androidx.compose.foundation.rememberScrollState
8
14
  import androidx.compose.foundation.shape.RoundedCornerShape
9
15
  import androidx.compose.runtime.Composable
@@ -19,7 +25,11 @@ import androidx.compose.ui.graphics.drawscope.Stroke
19
25
  import androidx.compose.ui.unit.Dp
20
26
  import androidx.compose.ui.unit.dp
21
27
  import vn.momo.kits.application.IsShowBaseLineDebug
22
- import vn.momo.kits.const.*
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
23
33
  import vn.momo.kits.modifier.activeOpacityClickable
24
34
  import vn.momo.kits.modifier.conditional
25
35
 
@@ -2,8 +2,20 @@ 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.*
6
- import androidx.compose.runtime.*
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
7
19
  import androidx.compose.ui.Alignment
8
20
  import androidx.compose.ui.Modifier
9
21
  import androidx.compose.ui.unit.dp
@@ -62,7 +74,7 @@ fun DateTimePicker(
62
74
  var currentDate by remember(initialValue) {
63
75
  mutableStateOf(
64
76
  PickerData(
65
- day = initialValue.day,
77
+ day = initialValue.dayOfMonth,
66
78
  month = initialValue.month.number,
67
79
  year = initialValue.year,
68
80
  hour = initialValue.hour,
@@ -83,10 +95,10 @@ fun DateTimePicker(
83
95
  month = when (year) {
84
96
  effectiveMaxDate.year -> month.coerceIn(
85
97
  1,
86
- effectiveMaxDate.month.number
98
+ effectiveMaxDate.monthNumber
87
99
  )
88
100
  effectiveMinDate.year -> month.coerceIn(
89
- effectiveMinDate.month.number,
101
+ effectiveMinDate.monthNumber,
90
102
  12,
91
103
  )
92
104
  else -> month
@@ -100,11 +112,11 @@ fun DateTimePicker(
100
112
  }
101
113
 
102
114
  day = when {
103
- year == effectiveMaxDate.year && month == effectiveMaxDate.month.number ->
104
- day.coerceIn(1, effectiveMaxDate.day)
115
+ year == effectiveMaxDate.year && month == effectiveMaxDate.monthNumber ->
116
+ day.coerceIn(1, effectiveMaxDate.dayOfMonth)
105
117
 
106
- year == effectiveMinDate.year && month == effectiveMinDate.month.number ->
107
- day.coerceIn(effectiveMinDate.day, maxDayOfMonth)
118
+ year == effectiveMinDate.year && month == effectiveMinDate.monthNumber ->
119
+ day.coerceIn(effectiveMinDate.dayOfMonth, maxDayOfMonth)
108
120
 
109
121
  day > maxDayOfMonth -> maxDayOfMonth
110
122
  else -> day
@@ -13,8 +13,8 @@ data class PickerData(
13
13
  fun toLocalDateTime(): LocalDateTime {
14
14
  return LocalDateTime(
15
15
  year = year,
16
- month = month,
17
- day = day,
16
+ monthNumber = month,
17
+ dayOfMonth = day,
18
18
  hour = hour,
19
19
  minute = minute,
20
20
  second = 0,
@@ -2,10 +2,15 @@ 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
7
5
  import kotlin.time.Clock
8
6
  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
9
14
 
10
15
  /**
11
16
  * Format a LocalDateTime object into a string
@@ -14,13 +19,13 @@ fun formatLocalDateTime(dateTime: LocalDateTime, format: String = "yyyy-MM-dd HH
14
19
  return when (format) {
15
20
  "yyyy-MM-dd HH:mm" -> "${dateTime.year}-${paddingNum(dateTime.month.number)}-${
16
21
  paddingNum(
17
- dateTime.day
22
+ dateTime.dayOfMonth
18
23
  )
19
24
  } ${paddingNum(dateTime.hour)}:${paddingNum(dateTime.minute)}"
20
25
 
21
- "dd-MM-yyyy" -> "${paddingNum(dateTime.day)}-${paddingNum(dateTime.month.number)}-${dateTime.year}"
26
+ "dd-MM-yyyy" -> "${paddingNum(dateTime.dayOfMonth)}-${paddingNum(dateTime.month.number)}-${dateTime.year}"
22
27
  "HH:mm" -> "${paddingNum(dateTime.hour)}:${paddingNum(dateTime.minute)}"
23
- else -> "${dateTime.year}-${paddingNum(dateTime.month.number)}-${paddingNum(dateTime.day)} ${
28
+ else -> "${dateTime.year}-${paddingNum(dateTime.month.number)}-${paddingNum(dateTime.dayOfMonth)} ${
24
29
  paddingNum(
25
30
  dateTime.hour
26
31
  )
@@ -55,11 +60,11 @@ fun getDaysInMonth(
55
60
  var endDay = daysInMonth
56
61
 
57
62
  if (year == minDate.year && month == minDate.month.number) {
58
- startDay = minDate.day
63
+ startDay = minDate.dayOfMonth
59
64
  }
60
65
 
61
66
  if (year == maxDate.year && month == maxDate.month.number) {
62
- endDay = maxDate.day
67
+ endDay = maxDate.dayOfMonth
63
68
  }
64
69
 
65
70
  val days = mutableListOf<String>()
@@ -165,8 +170,8 @@ fun createRelativeDate(years: Int): LocalDateTime {
165
170
 
166
171
  return LocalDateTime(
167
172
  adjustedDate.year,
168
- adjustedDate.month.number,
169
- adjustedDate.day,
173
+ adjustedDate.monthNumber,
174
+ adjustedDate.dayOfMonth,
170
175
  currentDateTime.hour,
171
176
  currentDateTime.minute
172
177
  )