@momo-kits/native-kits 0.167.1-duo.2-debug → 0.167.1-duo.3

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 (171) hide show
  1. package/.claude/scheduled_tasks.lock +1 -0
  2. package/.claude/settings.local.json +185 -0
  3. package/CLAUDE.md +8 -3
  4. package/ios/Application/HeaderRight.swift +25 -12
  5. package/ios/Application/Layout/ScreenLayout.swift +196 -0
  6. package/ios/Application/Navigation/BottomTab/BottomTab.swift +30 -9
  7. package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +5 -2
  8. package/ios/Application/Navigation/BottomTab/DuoTabBar.swift +275 -0
  9. package/ios/Application/Navigation/HeaderUser.swift +4 -1
  10. package/ios/Application/Navigation/NavigationContainer.swift +3 -0
  11. package/ios/Application/Navigation/Overplay/BottomSheet.swift +41 -4
  12. package/ios/Application/Navigation/Overplay/ModalScreen.swift +5 -1
  13. package/ios/Application/Navigation/component/DuoScrollGradient.swift +55 -0
  14. package/ios/Application/Navigation/component/Header.swift +9 -3
  15. package/ios/Application/Navigation/component/HeaderBackground.swift +3 -2
  16. package/ios/Application/Navigation/component/NavigationFooter.swift +1 -1
  17. package/ios/Application/Navigation/component/NavigationHeaderRight.swift +61 -9
  18. package/ios/Application/Navigation/component/SideBar.swift +155 -0
  19. package/ios/Application/StackScreen.swift +135 -18
  20. package/ios/Popup/PopupDisplay.swift +84 -68
  21. package/ios/Popup/PopupLayout.swift +45 -0
  22. package/ios/Popup/PopupNotify.swift +43 -32
  23. package/ios/Popup/PopupPromotion.swift +17 -5
  24. package/ios/native-kits.podspec +1 -1
  25. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  26. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DuoTabDemo.swift +76 -0
  27. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +1 -0
  28. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IPhoneDuoDemo.swift +170 -0
  29. package/package.json +1 -1
  30. package/build.gradle.kts +0 -11
  31. package/compose/build.gradle.kts +0 -190
  32. package/compose/build.gradle.kts.backup +0 -190
  33. package/compose/compose.podspec +0 -47
  34. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
  35. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
  36. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
  37. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
  38. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -151
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -124
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -831
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -82
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -356
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -113
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -49
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -189
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -475
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -266
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -240
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -223
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -264
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -185
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -334
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -98
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -310
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -323
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -220
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -199
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -552
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -88
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -125
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -207
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -498
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -176
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -234
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -188
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -16
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +0 -18
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -297
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -54
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -50
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +0 -157
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -41
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -299
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +0 -58
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -129
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -106
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -205
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -393
  132. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  133. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -622
  134. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -148
  135. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -35
  136. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -175
  137. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -232
  138. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  139. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
  140. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -381
  141. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -83
  142. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +0 -105
  143. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +0 -74
  144. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -347
  145. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -37
  146. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -363
  147. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +0 -169
  148. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
  149. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
  150. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -12
  151. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
  152. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
  153. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -71
  154. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  155. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
  156. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  157. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -118
  158. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -40
  159. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -45
  160. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
  161. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -38
  162. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
  163. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -213
  164. package/gradle/libs.versions.toml +0 -69
  165. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  166. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  167. package/gradle.properties +0 -26
  168. package/gradlew +0 -252
  169. package/gradlew.bat +0 -94
  170. package/ios-demo/README.md +0 -120
  171. package/settings.gradle.kts +0 -64
@@ -1,473 +0,0 @@
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.*
6
- import androidx.compose.foundation.shape.CircleShape
7
- import androidx.compose.foundation.shape.RoundedCornerShape
8
- import androidx.compose.runtime.Composable
9
- import androidx.compose.runtime.remember
10
- import androidx.compose.ui.Alignment
11
- import androidx.compose.ui.Modifier
12
- import androidx.compose.ui.graphics.Color
13
- import androidx.compose.ui.text.style.TextAlign
14
- import androidx.compose.ui.unit.Dp
15
- import androidx.compose.ui.unit.dp
16
- import vn.momo.kits.application.IsShowBaseLineDebug
17
- import vn.momo.kits.const.*
18
- import vn.momo.kits.modifier.activeOpacityClickable
19
- import vn.momo.kits.modifier.conditional
20
-
21
-
22
- data class StepItem(
23
- val title: String,
24
- val description: String? = null,
25
- val error: Boolean = false,
26
- val time: String? = null,
27
- )
28
-
29
-
30
- enum class StepsSize { SMALL, LARGE }
31
-
32
- enum class StepsAlign { LEFT, RIGHT, CENTER, STRETCH }
33
-
34
-
35
- private enum class StepStatus { INCOMPLETE, CURRENT, COMPLETED, ERROR, DISABLED }
36
-
37
- private fun resolveStatus(
38
- activeIndex: Int,
39
- currentIndex: Int,
40
- error: Boolean,
41
- disabled: Boolean,
42
- ): StepStatus = when {
43
- disabled -> StepStatus.DISABLED
44
- error -> StepStatus.ERROR
45
- activeIndex == currentIndex -> StepStatus.CURRENT
46
- activeIndex > currentIndex -> StepStatus.COMPLETED
47
- else -> StepStatus.INCOMPLETE
48
- }
49
-
50
-
51
- @Composable
52
- private fun resolveIconBgAndBorder(status: StepStatus): Pair<Color, Color> {
53
- val theme = AppTheme.current
54
- return when (status) {
55
- StepStatus.CURRENT, StepStatus.COMPLETED ->
56
- theme.colors.primary to theme.colors.background.tonal
57
- StepStatus.ERROR ->
58
- theme.colors.error.primary to theme.colors.error.container
59
- StepStatus.DISABLED ->
60
- Colors.pink_08 to Colors.pink_10
61
- StepStatus.INCOMPLETE ->
62
- Colors.black_06 to theme.colors.border.default
63
- }
64
- }
65
-
66
- @Composable
67
- private fun resolveTitleColor(status: StepStatus): Color {
68
- val theme = AppTheme.current
69
- return when (status) {
70
- StepStatus.CURRENT -> theme.colors.primary
71
- StepStatus.ERROR -> theme.colors.error.primary
72
- StepStatus.DISABLED -> theme.colors.text.disable
73
- else -> theme.colors.text.default
74
- }
75
- }
76
-
77
- @Composable
78
- private fun StepBubble(
79
- index: Int,
80
- isActive: Boolean,
81
- error: Boolean,
82
- size: StepsSize,
83
- status: StepStatus,
84
- useNumber: Boolean,
85
- customIcon: String?,
86
- modifier: Modifier = Modifier,
87
- ) {
88
- val bubbleSize: Dp = if (size == StepsSize.SMALL) 16.dp else 24.dp
89
- val innerSize: Dp = if (size == StepsSize.SMALL) 12.dp else 16.dp
90
- val dotSize: Dp = if (size == StepsSize.SMALL) 6.dp else 8.dp
91
-
92
- val (bgColor, borderColor) = resolveIconBgAndBorder(status)
93
-
94
- Box(
95
- modifier = modifier
96
- .size(bubbleSize)
97
- .background(color = bgColor, shape = CircleShape)
98
- .border(width = 2.dp, color = borderColor, shape = CircleShape)
99
- .conditional(IsShowBaseLineDebug) { border(1.dp, Colors.blue_03) },
100
- contentAlignment = Alignment.Center,
101
- ) {
102
- when {
103
- useNumber -> {
104
- Text(
105
- text = (index + 1).toString(),
106
- style = Typography.headerXsSemibold,
107
- color = Colors.black_01,
108
- )
109
- }
110
- isActive -> {
111
- if (!customIcon.isNullOrEmpty()) {
112
- Icon(
113
- source = customIcon,
114
- size = innerSize,
115
- color = Colors.black_01,
116
- )
117
- } else {
118
- // current-step dot (white circle matching RN currIcon style)
119
- Box(
120
- modifier = Modifier
121
- .size(dotSize)
122
- .background(color = Colors.black_01, shape = CircleShape),
123
- )
124
- }
125
- }
126
- else -> {
127
- Icon(
128
- source = if (error) "navigation_close" else "notifications_check",
129
- size = innerSize,
130
- color = Colors.black_01,
131
- )
132
- }
133
- }
134
- }
135
- }
136
-
137
-
138
- @Composable
139
- private fun StepsHorizontal(
140
- steps: List<StepItem>,
141
- activeIndex: Int,
142
- size: StepsSize,
143
- useNumber: Boolean,
144
- align: StepsAlign,
145
- customIcon: String?,
146
- disabled: Boolean,
147
- onPress: ((StepItem, Int) -> Unit)?,
148
- ) {
149
- val theme = AppTheme.current
150
- // completed-line colour is primary at 20 % opacity (mirrors RN primary + '33')
151
- val completedLine = remember(theme.colors.primary) { theme.colors.primary.copy(alpha = 0.2f) }
152
- val defaultLine = theme.colors.background.default
153
-
154
- Row(modifier = Modifier.fillMaxWidth()) {
155
- steps.forEachIndexed { index, item ->
156
- val status = resolveStatus(activeIndex, index, item.error, disabled)
157
- val isActiveOrError = status == StepStatus.CURRENT || status == StepStatus.ERROR
158
-
159
- // Horizontal always uses the xs/description typography scale (checkSizeAndStepType=true)
160
- val currentTitleStyle = if (isActiveOrError)
161
- Typography.headerXsSemibold else Typography.descriptionDefaultRegular
162
- val currentDescStyle = if (size == StepsSize.SMALL)
163
- Typography.descriptionXsRegular else Typography.descriptionDefaultRegular
164
-
165
- val titleColor = resolveTitleColor(status)
166
- val subColor = if (disabled) theme.colors.text.disable else theme.colors.text.hint
167
-
168
- val colAlign = when (align) {
169
- StepsAlign.LEFT -> Alignment.Start
170
- StepsAlign.RIGHT -> Alignment.End
171
- StepsAlign.STRETCH -> when (index) {
172
- 0 -> Alignment.Start
173
- steps.size - 1 -> Alignment.End
174
- else -> Alignment.CenterHorizontally
175
- }
176
- StepsAlign.CENTER -> Alignment.CenterHorizontally
177
- }
178
- val textAlign = when (align) {
179
- StepsAlign.LEFT -> TextAlign.Start
180
- StepsAlign.RIGHT -> TextAlign.End
181
- StepsAlign.STRETCH -> when (index) {
182
- 0 -> TextAlign.Start
183
- steps.size - 1 -> TextAlign.End
184
- else -> TextAlign.Center
185
- }
186
- StepsAlign.CENTER -> TextAlign.Center
187
- }
188
-
189
- val hideLineLeft = align == StepsAlign.LEFT ||
190
- (align == StepsAlign.STRETCH && index == 0)
191
- val hideLineRight = align == StepsAlign.RIGHT ||
192
- (align == StepsAlign.STRETCH && index == steps.size - 1)
193
-
194
- val lineLeft = when {
195
- index == 0 -> Color.Transparent
196
- activeIndex >= index -> completedLine
197
- else -> defaultLine
198
- }
199
- val lineRight = when {
200
- index == steps.size - 1 -> Color.Transparent
201
- activeIndex > index -> completedLine
202
- else -> defaultLine
203
- }
204
-
205
- val clickable = status == StepStatus.COMPLETED && onPress != null && !disabled
206
-
207
- Column(
208
- modifier = Modifier
209
- .weight(1f)
210
- .then(
211
- if (clickable) Modifier.activeOpacityClickable { onPress.invoke(item, index) }
212
- else Modifier
213
- ),
214
- horizontalAlignment = colAlign,
215
- ) {
216
- // time label shown above the icon row
217
- if (!item.time.isNullOrEmpty()) {
218
- Text(
219
- text = item.time,
220
- style = Typography.descriptionXsRegular,
221
- color = subColor,
222
- textAlign = textAlign,
223
- )
224
- } else {
225
- Spacer(modifier = Modifier.height(0.dp))
226
- }
227
-
228
- // icon row with horizontal connector lines
229
- Row(
230
- verticalAlignment = Alignment.CenterVertically,
231
- modifier = Modifier.fillMaxWidth(),
232
- ) {
233
- if (!hideLineLeft) {
234
- Box(
235
- modifier = Modifier
236
- .weight(1f)
237
- .height(2.dp)
238
- .background(
239
- color = lineLeft,
240
- shape = RoundedCornerShape(
241
- topEnd = Radius.XS,
242
- bottomEnd = Radius.XS,
243
- ),
244
- ),
245
- )
246
- }
247
- StepBubble(
248
- index = index,
249
- isActive = activeIndex == index,
250
- error = item.error,
251
- size = size,
252
- status = status,
253
- useNumber = useNumber,
254
- customIcon = customIcon,
255
- modifier = Modifier.padding(
256
- start = if (!hideLineLeft) Spacing.XS else 0.dp,
257
- end = if (!hideLineRight) Spacing.XS else 0.dp,
258
- top = Spacing.XS,
259
- bottom = Spacing.XS,
260
- ),
261
- )
262
- if (!hideLineRight) {
263
- Box(
264
- modifier = Modifier
265
- .weight(1f)
266
- .height(2.dp)
267
- .background(
268
- color = lineRight,
269
- shape = RoundedCornerShape(
270
- topStart = Radius.XS,
271
- bottomStart = Radius.XS,
272
- ),
273
- ),
274
- )
275
- }
276
- }
277
-
278
- if (item.title.isNotEmpty()) {
279
- Text(
280
- text = item.title,
281
- style = currentTitleStyle,
282
- color = titleColor,
283
- textAlign = textAlign,
284
- modifier = Modifier.padding(bottom = Spacing.XXS),
285
- )
286
- }
287
-
288
- if (!item.description.isNullOrEmpty()) {
289
- Text(
290
- text = item.description,
291
- style = currentDescStyle,
292
- color = subColor,
293
- textAlign = textAlign,
294
- )
295
- }
296
- }
297
- }
298
- }
299
- }
300
-
301
-
302
- @Composable
303
- private fun StepsVertical(
304
- steps: List<StepItem>,
305
- activeIndex: Int,
306
- size: StepsSize,
307
- useNumber: Boolean,
308
- customIcon: String?,
309
- disabled: Boolean,
310
- onPress: ((StepItem, Int) -> Unit)?,
311
- ) {
312
- val theme = AppTheme.current
313
- val completedLine = remember(theme.colors.primary) { theme.colors.primary.copy(alpha = 0.2f) }
314
- val defaultLine = theme.colors.background.default
315
- val useSmall = size == StepsSize.SMALL
316
- // Fixed connector height; grows proportionally with content in practice
317
- val connectorHeight: Dp = if (useSmall) 24.dp else 32.dp
318
-
319
- Column(modifier = Modifier.fillMaxWidth()) {
320
- steps.forEachIndexed { index, item ->
321
- val status = resolveStatus(activeIndex, index, item.error, disabled)
322
- val isActiveOrError = status == StepStatus.CURRENT || status == StepStatus.ERROR
323
- val isLast = index == steps.size - 1
324
-
325
- // Vertical large: header_s / body; vertical small: header_xs / description
326
- val currentTitleStyle = if (isActiveOrError) {
327
- if (useSmall) Typography.headerXsSemibold else Typography.headerSSemibold
328
- } else {
329
- if (useSmall) Typography.descriptionDefaultRegular else Typography.bodyDefaultRegular
330
- }
331
- val currentDescStyle = if (useSmall)
332
- Typography.descriptionXsRegular else Typography.descriptionDefaultRegular
333
-
334
- val titleColor = resolveTitleColor(status)
335
- val subColor = if (disabled) theme.colors.text.disable else theme.colors.text.hint
336
- val lineColor = if (activeIndex > index) completedLine else defaultLine
337
-
338
- val clickable = status == StepStatus.COMPLETED && onPress != null && !disabled
339
-
340
- Row(
341
- modifier = Modifier
342
- .fillMaxWidth()
343
- .then(
344
- if (clickable) Modifier.activeOpacityClickable { onPress.invoke(item, index) }
345
- else Modifier
346
- ),
347
- ) {
348
- // Left column: bubble + vertical connector line
349
- Column(
350
- horizontalAlignment = Alignment.CenterHorizontally,
351
- modifier = Modifier.padding(end = Spacing.M),
352
- ) {
353
- StepBubble(
354
- index = index,
355
- isActive = activeIndex == index,
356
- error = item.error,
357
- size = size,
358
- status = status,
359
- useNumber = useNumber,
360
- customIcon = customIcon,
361
- )
362
- if (!isLast) {
363
- Box(
364
- modifier = Modifier
365
- .width(2.dp)
366
- .height(connectorHeight)
367
- .padding(vertical = Spacing.XS)
368
- .background(color = lineColor),
369
- )
370
- }
371
- }
372
-
373
- // Right column: title + time on the same row, description below
374
- Column(
375
- modifier = Modifier
376
- .weight(1f)
377
- .padding(bottom = if (isLast) 0.dp else Spacing.S),
378
- ) {
379
- Row(
380
- modifier = Modifier.fillMaxWidth(),
381
- horizontalArrangement = Arrangement.SpaceBetween,
382
- verticalAlignment = Alignment.Top,
383
- ) {
384
- Text(
385
- text = item.title,
386
- style = currentTitleStyle,
387
- color = titleColor,
388
- maxLines = 2,
389
- modifier = Modifier
390
- .weight(1f)
391
- .padding(end = Spacing.S),
392
- )
393
- if (!item.time.isNullOrEmpty()) {
394
- Text(
395
- text = item.time,
396
- style = Typography.descriptionXsRegular,
397
- color = subColor,
398
- )
399
- }
400
- }
401
- if (!item.description.isNullOrEmpty()) {
402
- Spacer(modifier = Modifier.height(Spacing.XXS))
403
- Text(
404
- text = item.description,
405
- style = currentDescStyle,
406
- color = subColor,
407
- )
408
- }
409
- }
410
- }
411
- }
412
- }
413
- }
414
-
415
- // ─── Public API ────────────────────────────────────────────────────────────────
416
-
417
- /**
418
- * Steps — guided progress indicator through a sequence of procedural steps.
419
- *
420
- * Mirrors the React Native `Steps` component from `@momo-kits/step`.
421
- *
422
- * @param steps Ordered list of [StepItem] values to display.
423
- * @param activeIndex Zero-based index of the currently active step.
424
- * @param modifier Modifier applied to the outermost container.
425
- * @param horizontal `true` renders a horizontal layout; defaults to vertical.
426
- * @param size [StepsSize.SMALL] or [StepsSize.LARGE] — affects bubble and typography scale.
427
- * @param useNumber Shows the 1-based step number inside the bubble instead of a check/dot icon.
428
- * @param align Text and icon alignment in horizontal mode: LEFT, RIGHT, CENTER, or STRETCH.
429
- * @param customIcon Icon source name rendered inside the active-step bubble (replaces the dot).
430
- * @param disabled Dims all steps and suppresses all press callbacks.
431
- * @param onPress Invoked with the tapped [StepItem] and its index; only fires for completed steps.
432
- */
433
- @Composable
434
- fun Steps(
435
- steps: List<StepItem>,
436
- activeIndex: Int,
437
- modifier: Modifier = Modifier,
438
- horizontal: Boolean = false,
439
- size: StepsSize = StepsSize.LARGE,
440
- useNumber: Boolean = false,
441
- align: StepsAlign = StepsAlign.CENTER,
442
- customIcon: String? = null,
443
- disabled: Boolean = false,
444
- onPress: ((StepItem, Int) -> Unit)? = null,
445
- ) {
446
- Box(
447
- modifier = modifier
448
- .conditional(IsShowBaseLineDebug) { border(1.dp, Colors.blue_03) },
449
- ) {
450
- if (horizontal) {
451
- StepsHorizontal(
452
- steps = steps,
453
- activeIndex = activeIndex,
454
- size = size,
455
- useNumber = useNumber,
456
- align = align,
457
- customIcon = customIcon,
458
- disabled = disabled,
459
- onPress = onPress,
460
- )
461
- } else {
462
- StepsVertical(
463
- steps = steps,
464
- activeIndex = activeIndex,
465
- size = size,
466
- useNumber = useNumber,
467
- customIcon = customIcon,
468
- disabled = disabled,
469
- onPress = onPress,
470
- )
471
- }
472
- }
473
- }
@@ -1,122 +0,0 @@
1
- package vn.momo.kits.components
2
-
3
- import androidx.compose.animation.AnimatedVisibility
4
- import androidx.compose.animation.fadeIn
5
- import androidx.compose.animation.fadeOut
6
- import androidx.compose.foundation.background
7
- import androidx.compose.foundation.border
8
- import androidx.compose.foundation.layout.*
9
- import androidx.compose.foundation.shape.RoundedCornerShape
10
- import androidx.compose.runtime.Composable
11
- import androidx.compose.runtime.remember
12
- import androidx.compose.ui.Alignment
13
- import androidx.compose.ui.Modifier
14
- import androidx.compose.ui.draw.clip
15
- import androidx.compose.ui.text.SpanStyle
16
- import androidx.compose.ui.text.buildAnnotatedString
17
- import androidx.compose.ui.text.font.FontWeight
18
- import androidx.compose.ui.text.withStyle
19
- import androidx.compose.ui.unit.dp
20
- import vn.momo.kits.application.IsShowBaseLineDebug
21
- import vn.momo.kits.const.*
22
- import vn.momo.kits.modifier.activeOpacityClickable
23
- import vn.momo.kits.modifier.conditional
24
- import vn.momo.kits.modifier.shadow
25
-
26
- @Composable
27
- fun SuggestAction(
28
- message: String,
29
- buttonTitle: String,
30
- boldMessage: String = "",
31
- image: String = "",
32
- visible: Boolean = false,
33
- onClose: () -> Unit = {},
34
- onPressButton: () -> Unit = {},
35
- modifier: Modifier = Modifier,
36
- ) {
37
- val theme = AppTheme.current
38
-
39
- AnimatedVisibility(
40
- visible = visible,
41
- enter = fadeIn(),
42
- exit = fadeOut(),
43
- modifier = modifier,
44
- ) {
45
- Row(
46
- modifier = Modifier
47
- .fillMaxWidth()
48
- .shadow(
49
- color = theme.colors.text.default.copy(alpha = 0.12f),
50
- borderRadius = Radius.S,
51
- blurRadius = 16f,
52
- offsetY = 4.dp,
53
- )
54
- .clip(RoundedCornerShape(Radius.S))
55
- .background(
56
- color = theme.colors.background.surface,
57
- shape = RoundedCornerShape(Radius.S),
58
- )
59
- .conditional(IsShowBaseLineDebug) {
60
- border(1.dp, Colors.blue_03)
61
- }
62
- .padding(Spacing.M),
63
- verticalAlignment = Alignment.CenterVertically,
64
- ) {
65
- if (image.isNotEmpty()) {
66
- Image(
67
- source = image,
68
- modifier = Modifier
69
- .size(32.dp)
70
- .clip(RoundedCornerShape(Radius.XS)),
71
- )
72
- Spacer(modifier = Modifier.width(Spacing.S))
73
- }
74
-
75
- val annotatedMessage = remember(message, boldMessage) {
76
- if (boldMessage.isNotEmpty()) {
77
- val index = message.lowercase().indexOf(boldMessage.lowercase())
78
- if (index != -1) {
79
- buildAnnotatedString {
80
- append(message.substring(0, index))
81
- withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
82
- append(message.substring(index, index + boldMessage.length))
83
- }
84
- append(message.substring(index + boldMessage.length))
85
- }
86
- } else {
87
- buildAnnotatedString { append(message) }
88
- }
89
- } else {
90
- buildAnnotatedString { append(message) }
91
- }
92
- }
93
-
94
- Text(
95
- text = annotatedMessage,
96
- style = Typography.bodyDefaultRegular,
97
- modifier = Modifier
98
- .weight(1f)
99
- .padding(end = Spacing.M),
100
- )
101
-
102
- Button(
103
- title = buttonTitle,
104
- type = ButtonType.TONAL,
105
- size = Size.SMALL,
106
- isFull = false,
107
- onClick = {
108
- onPressButton()
109
- },
110
- )
111
-
112
- Spacer(modifier = Modifier.width(Spacing.S))
113
-
114
- Icon(
115
- source = "navigation_close",
116
- size = 24.dp,
117
- color = theme.colors.text.default,
118
- modifier = Modifier.activeOpacityClickable { onClose() },
119
- )
120
- }
121
- }
122
- }