@momo-kits/native-kits 0.164.1-beta.13-debug → 0.164.1-beta.13

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 (138) hide show
  1. package/package.json +1 -1
  2. package/build.gradle.kts +0 -11
  3. package/compose/build.gradle.kts +0 -190
  4. package/compose/build.gradle.kts.backup +0 -190
  5. package/compose/compose.podspec +0 -47
  6. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
  7. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
  8. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
  9. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
  10. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -150
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -106
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -826
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -82
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -356
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -113
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -23
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -134
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -475
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -214
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -240
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -216
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -259
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -182
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -328
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -97
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -310
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -323
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -217
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -199
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -470
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -88
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -131
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -203
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -498
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -175
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -234
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -188
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -16
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -263
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -52
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -38
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -39
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -299
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -129
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -103
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -191
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -386
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -619
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -157
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -39
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -156
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -225
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -320
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -81
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -309
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -34
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -360
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -15
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -69
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -105
  124. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -40
  125. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -125
  126. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
  127. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -35
  128. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
  129. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -220
  130. package/gradle/libs.versions.toml +0 -69
  131. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  132. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  133. package/gradle.properties +0 -26
  134. package/gradlew +0 -252
  135. package/gradlew.bat +0 -94
  136. package/ios-demo/README.md +0 -120
  137. package/local.properties +0 -8
  138. package/settings.gradle.kts +0 -64
@@ -1,323 +0,0 @@
1
- package vn.momo.kits.components
2
-
3
- import androidx.compose.animation.core.animateFloatAsState
4
- import androidx.compose.animation.core.spring
5
- import androidx.compose.foundation.background
6
- import androidx.compose.foundation.border
7
- import androidx.compose.foundation.layout.*
8
- import androidx.compose.foundation.shape.RoundedCornerShape
9
- import androidx.compose.runtime.*
10
- import androidx.compose.ui.Alignment
11
- import androidx.compose.ui.Modifier
12
- import androidx.compose.ui.draw.clip
13
- import androidx.compose.ui.input.pointer.pointerInput
14
- import androidx.compose.ui.layout.onGloballyPositioned
15
- import androidx.compose.ui.platform.LocalDensity
16
- import androidx.compose.ui.text.style.TextAlign
17
- import androidx.compose.ui.unit.IntOffset
18
- import androidx.compose.ui.unit.dp
19
- import vn.momo.kits.application.IsShowBaseLineDebug
20
- import vn.momo.kits.const.*
21
- import vn.momo.kits.modifier.conditional
22
- import kotlin.math.abs
23
- import kotlin.math.min
24
- import kotlin.math.roundToInt
25
-
26
- private val THUMB_SIZE = 20.dp
27
- private val THUMB_BORDER = 3.dp
28
- private val TRACK_HEIGHT = 4.dp
29
- private val LABEL_PAD_H = Spacing.XS
30
- private val LABEL_PAD_V = Spacing.XXS
31
- private val LABEL_GAP = Spacing.XS // space between label and thumb top
32
-
33
-
34
- private fun clamp(value: Float, min: Float, max: Float): Float =
35
- min(kotlin.math.max(value, min), max)
36
-
37
- private fun getValueForPosition(
38
- positionInView: Float,
39
- containerWidth: Float,
40
- thumbWidth: Float,
41
- min: Float,
42
- max: Float,
43
- step: Float,
44
- ): Float {
45
- val availableSpace = containerWidth - thumbWidth
46
- if (availableSpace <= 0f) return min
47
- val relStepUnit = step / (max - min)
48
- var relPosition = (positionInView - thumbWidth / 2f) / availableSpace
49
- val relOffset = relPosition % relStepUnit
50
- relPosition -= relOffset
51
- if (relOffset / relStepUnit >= 0.5f) relPosition += relStepUnit
52
- return clamp(min + (relPosition / relStepUnit).roundToInt() * step, min, max)
53
- }
54
-
55
- /** Direct port of RN isLowCloser(). */
56
- private fun isLowCloser(downX: Float, lowPosition: Float, highPosition: Float): Boolean {
57
- if (lowPosition == highPosition) return downX < lowPosition
58
- return abs(downX - lowPosition) < abs(downX - highPosition)
59
- }
60
-
61
- private fun valueToFraction(value: Float, min: Float, max: Float): Float {
62
- if (max == min) return 0f
63
- return clamp((value - min) / (max - min), 0f, 1f)
64
- }
65
-
66
- private fun formatLabel(value: Float): String =
67
- if (value == value.toLong().toFloat()) value.toLong().toString()
68
- else ((value * 10).toLong() / 10.0).toString()
69
-
70
- // ── Component ─────────────────────────────────────────────────────────────────
71
-
72
- /**
73
- * Range slider (or single-thumb when [disableRange] = true), migrated from React Native.
74
- *
75
- * @param min Minimum selectable value.
76
- * @param max Maximum selectable value.
77
- * @param step Snap increment between values.
78
- * @param modifier Modifier applied to the root container.
79
- * @param low Initial lower-thumb value (defaults to [min]).
80
- * @param high Initial upper-thumb value (defaults to [max]).
81
- * @param minRange Minimum required gap between low and high (default 0).
82
- * @param disableRange When true only the low thumb is shown (single-value mode).
83
- * @param floatingLabel When true a value label floats above the active thumb during drag.
84
- * @param disabled Non-interactive; rendered in the disabled colour.
85
- * @param onValueChanged Invoked with (low, high, byUser) on every value change.
86
- * @param onSliderTouchStart Invoked when a drag gesture begins.
87
- * @param onSliderTouchEnd Invoked when a drag gesture ends.
88
- */
89
- @Composable
90
- fun Slider(
91
- min: Float,
92
- max: Float,
93
- step: Float,
94
- modifier: Modifier = Modifier,
95
- low: Float? = null,
96
- high: Float? = null,
97
- minRange: Float = 0f,
98
- disableRange: Boolean = false,
99
- floatingLabel: Boolean = false,
100
- disabled: Boolean = false,
101
- onValueChanged: (low: Float, high: Float, byUser: Boolean) -> Unit = { _, _, _ -> },
102
- onSliderTouchStart: (low: Float, high: Float) -> Unit = { _, _ -> },
103
- onSliderTouchEnd: (low: Float, high: Float) -> Unit = { _, _ -> },
104
- ) {
105
- val theme = AppTheme.current
106
- val density = LocalDensity.current
107
-
108
- // Validated, step-snapped initial values
109
- val initLow = remember(low, min, max, step) {
110
- clamp(low ?: min, min, max)
111
- }
112
- val initHigh = remember(high, min, max, step, disableRange) {
113
- if (disableRange) max else clamp(high ?: max, min, max)
114
- }
115
-
116
- var lowValue by remember { mutableFloatStateOf(initLow) }
117
- var highValue by remember { mutableFloatStateOf(initHigh) }
118
-
119
- // Smoothly animated display fractions
120
- val lowFraction by animateFloatAsState(
121
- targetValue = valueToFraction(lowValue, min, max),
122
- animationSpec = spring(stiffness = 1200f),
123
- label = "lowFraction"
124
- )
125
- val highFraction by animateFloatAsState(
126
- targetValue = valueToFraction(highValue, min, max),
127
- animationSpec = spring(stiffness = 1200f),
128
- label = "highFraction"
129
- )
130
-
131
- var draggingLow by remember { mutableStateOf(true) }
132
- var isDragging by remember { mutableStateOf(false) }
133
-
134
- val thumbColor = if (disabled) theme.colors.text.disable else theme.colors.primary
135
- val trackActiveColor = if (disabled) theme.colors.text.disable else theme.colors.primary
136
- val trackInactiveColor = theme.colors.background.default
137
-
138
- // trackWidthPx is the full pixel width of the BoxWithConstraints (incl. thumb padding)
139
- var trackWidthPx by remember { mutableFloatStateOf(0f) }
140
- val thumbSizePx = with(density) { THUMB_SIZE.toPx() }
141
-
142
- Box(
143
- modifier = modifier
144
- .fillMaxWidth()
145
- .conditional(IsShowBaseLineDebug) { border(1.dp, Colors.blue_03) }
146
- ) {
147
- BoxWithConstraints(
148
- modifier = Modifier
149
- .fillMaxWidth()
150
- .onGloballyPositioned { coords -> trackWidthPx = coords.size.width.toFloat() }
151
- // ── Gesture handling ──────────────────────────────────────────
152
- .pointerInput(disabled, min, max, step, minRange, disableRange) {
153
- if (disabled) return@pointerInput
154
-
155
- awaitPointerEventScope {
156
- while (true) {
157
- // Finger down
158
- val downEvent = awaitPointerEvent()
159
- val downChange = downEvent.changes.firstOrNull() ?: continue
160
- val touchX = downChange.position.x
161
-
162
- // Pick the closer thumb
163
- val lowCenterX = thumbSizePx / 2f +
164
- valueToFraction(lowValue, min, max) * (trackWidthPx - thumbSizePx)
165
- val highCenterX = thumbSizePx / 2f +
166
- valueToFraction(highValue, min, max) * (trackWidthPx - thumbSizePx)
167
-
168
- draggingLow = disableRange || isLowCloser(touchX, lowCenterX, highCenterX)
169
- isDragging = true
170
- onSliderTouchStart(lowValue, highValue)
171
-
172
- // Apply initial press
173
- applyDrag(touchX, trackWidthPx, thumbSizePx,
174
- min, max, step, minRange, draggingLow,
175
- lowValue, highValue) { nl, nh ->
176
- lowValue = nl
177
- highValue = nh
178
- onValueChanged(nl, nh, true)
179
- }
180
-
181
- // Track move / release
182
- while (true) {
183
- val moveEvent = awaitPointerEvent()
184
- val moveChange = moveEvent.changes.firstOrNull() ?: break
185
- moveChange.consume()
186
-
187
- if (!moveChange.pressed) {
188
- isDragging = false
189
- onSliderTouchEnd(lowValue, highValue)
190
- break
191
- }
192
-
193
- applyDrag(moveChange.position.x, trackWidthPx, thumbSizePx,
194
- min, max, step, minRange, draggingLow,
195
- lowValue, highValue) { nl, nh ->
196
- lowValue = nl
197
- highValue = nh
198
- onValueChanged(nl, nh, true)
199
- }
200
- }
201
- }
202
- }
203
- }
204
- ) {
205
- val trackWidth = maxWidth
206
- val availableWidth = trackWidth - THUMB_SIZE
207
-
208
- // ── Floating label ────────────────────────────────────────────────
209
- if (floatingLabel && isDragging) {
210
- val activeFraction = if (draggingLow) lowFraction else highFraction
211
- val activeValue = if (draggingLow) lowValue else highValue
212
- val labelOffsetDp = availableWidth * activeFraction
213
-
214
- Box(
215
- modifier = Modifier
216
- .align(Alignment.TopStart)
217
- .offset { IntOffset(x = with(density) { labelOffsetDp.toPx().roundToInt() }, y = 0) }
218
- ) {
219
- Box(
220
- modifier = Modifier
221
- .background(
222
- color = Colors.black_01,
223
- shape = RoundedCornerShape(Radius.XS)
224
- )
225
- .padding(horizontal = LABEL_PAD_H, vertical = LABEL_PAD_V)
226
- ) {
227
- Text(
228
- text = formatLabel(activeValue),
229
- style = Typography.descriptionXsRegular,
230
- color = theme.colors.text.default,
231
- textAlign = TextAlign.Center
232
- )
233
- }
234
- }
235
- }
236
-
237
- // Top padding pushes track + thumbs below the label when floatingLabel is on
238
- val topPad = if (floatingLabel) THUMB_SIZE + LABEL_GAP else 0.dp
239
-
240
- // ── Inactive track (full width) ───────────────────────────────────
241
- Box(
242
- modifier = Modifier
243
- .align(Alignment.TopStart)
244
- .padding(top = topPad + (THUMB_SIZE - TRACK_HEIGHT) / 2)
245
- .padding(horizontal = THUMB_SIZE / 2)
246
- .fillMaxWidth()
247
- .height(TRACK_HEIGHT)
248
- .clip(RoundedCornerShape(percent = 50))
249
- .background(trackInactiveColor)
250
- )
251
-
252
- // ── Active track (selected range / single value) ──────────────────
253
- val activeStartFraction = if (disableRange) 0f else lowFraction
254
- val activeEndFraction = if (disableRange) lowFraction else highFraction
255
- val activeStartDp = THUMB_SIZE / 2 + availableWidth * activeStartFraction
256
- val activeWidthDp = availableWidth * (activeEndFraction - activeStartFraction)
257
-
258
- if (activeWidthDp > 0.dp) {
259
- Box(
260
- modifier = Modifier
261
- .align(Alignment.TopStart)
262
- .padding(top = topPad + (THUMB_SIZE - TRACK_HEIGHT) / 2)
263
- .offset(x = activeStartDp)
264
- .width(activeWidthDp)
265
- .height(TRACK_HEIGHT)
266
- .clip(RoundedCornerShape(percent = 50))
267
- .background(trackActiveColor)
268
- )
269
- }
270
-
271
- // ── Low thumb ─────────────────────────────────────────────────────
272
- Box(
273
- modifier = Modifier
274
- .align(Alignment.TopStart)
275
- .padding(top = topPad)
276
- .offset(x = availableWidth * lowFraction)
277
- .size(THUMB_SIZE)
278
- .clip(RoundedCornerShape(percent = 100))
279
- .background(thumbColor)
280
- .border(THUMB_BORDER, theme.colors.background.surface, RoundedCornerShape(percent = 100))
281
- )
282
-
283
- // ── High thumb (range mode only) ──────────────────────────────────
284
- if (!disableRange) {
285
- Box(
286
- modifier = Modifier
287
- .align(Alignment.TopStart)
288
- .padding(top = topPad)
289
- .offset(x = availableWidth * highFraction)
290
- .size(THUMB_SIZE)
291
- .clip(RoundedCornerShape(percent = 100))
292
- .background(thumbColor)
293
- .border(THUMB_BORDER, theme.colors.background.surface, RoundedCornerShape(percent = 100))
294
- )
295
- }
296
- }
297
- }
298
- }
299
-
300
- // ── Private drag helper ───────────────────────────────────────────────────────
301
-
302
- private fun applyDrag(
303
- positionX: Float,
304
- trackWidthPx: Float,
305
- thumbSizePx: Float,
306
- min: Float,
307
- max: Float,
308
- step: Float,
309
- minRange: Float,
310
- isLow: Boolean,
311
- currentLow: Float,
312
- currentHigh: Float,
313
- onUpdate: (Float, Float) -> Unit,
314
- ) {
315
- val snapped = getValueForPosition(positionX, trackWidthPx, thumbSizePx, min, max, step)
316
- if (isLow) {
317
- val newLow = clamp(snapped, min, currentHigh - minRange)
318
- if (newLow != currentLow) onUpdate(newLow, currentHigh)
319
- } else {
320
- val newHigh = clamp(snapped, currentLow + minRange, max)
321
- if (newHigh != currentHigh) onUpdate(currentLow, newHigh)
322
- }
323
- }
@@ -1,217 +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.foundation.text.BasicTextField
9
- import androidx.compose.foundation.text.KeyboardOptions
10
- import androidx.compose.runtime.*
11
- import androidx.compose.ui.Alignment
12
- import androidx.compose.ui.Modifier
13
- import androidx.compose.ui.graphics.Color
14
- import androidx.compose.ui.text.TextStyle
15
- import androidx.compose.ui.text.input.KeyboardType
16
- import androidx.compose.ui.text.style.TextAlign
17
- import androidx.compose.ui.unit.Dp
18
- import androidx.compose.ui.unit.dp
19
- import androidx.compose.ui.unit.sp
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
-
25
- enum class StepperSize {
26
- LARGE,
27
- SMALL
28
- }
29
-
30
- private data class StepperSizeSpec(
31
- val buttonSize: Dp,
32
- val iconSize: Dp,
33
- val numberMinWidth: Dp,
34
- val numberHeight: Dp,
35
- )
36
-
37
- private val stepperSizeSpecs: Map<StepperSize, StepperSizeSpec> = mapOf(
38
- StepperSize.LARGE to StepperSizeSpec(
39
- buttonSize = 36.dp,
40
- iconSize = 22.dp,
41
- numberMinWidth = 32.dp,
42
- numberHeight = 28.dp,
43
- ),
44
- StepperSize.SMALL to StepperSizeSpec(
45
- buttonSize = 28.dp,
46
- iconSize = 18.dp,
47
- numberMinWidth = 28.dp,
48
- numberHeight = 24.dp,
49
- ),
50
- )
51
-
52
- @Composable
53
- private fun StepperButton(
54
- sign: String = "+",
55
- size: StepperSize = StepperSize.LARGE,
56
- disabled: Boolean = false,
57
- onPress: () -> Unit = {},
58
- modifier: Modifier = Modifier,
59
- ) {
60
- val theme = AppTheme.current
61
- val specs = remember(size) { stepperSizeSpecs[size] ?: stepperSizeSpecs[StepperSize.LARGE]!! }
62
-
63
- val iconColor: Color = if (disabled) theme.colors.text.disable else theme.colors.primary
64
- val iconName: String =
65
- if (sign == "-") "24_navigation_minus_circle" else "24_navigation_plus_circle"
66
-
67
- val clickableModifier: Modifier = if (!disabled) {
68
- Modifier.activeOpacityClickable(onClick = onPress)
69
- } else {
70
- Modifier
71
- }
72
-
73
- Box(
74
- modifier = modifier
75
- .size(specs.buttonSize)
76
- .background(color = theme.colors.background.disable, shape = CircleShape)
77
- .then(clickableModifier)
78
- .conditional(IsShowBaseLineDebug) { border(1.dp, Colors.blue_03) },
79
- contentAlignment = Alignment.Center,
80
- ) {
81
- Icon(
82
- source = iconName,
83
- size = specs.iconSize,
84
- color = iconColor,
85
- )
86
- }
87
- }
88
-
89
- @Composable
90
- private fun StepperNumberView(
91
- value: Int,
92
- size: StepperSize = StepperSize.LARGE,
93
- disabled: Boolean = false,
94
- editable: Boolean = false,
95
- onValueChange: (String) -> Unit = {},
96
- modifier: Modifier = Modifier,
97
- ) {
98
- val theme = AppTheme.current
99
- val specs = remember(size) { stepperSizeSpecs[size] ?: stepperSizeSpecs[StepperSize.LARGE]!! }
100
-
101
- val textColor: Color = if (disabled) theme.colors.text.disable else theme.colors.text.default
102
- val borderColor: Color =
103
- if (disabled) theme.colors.border.disable else theme.colors.border.default
104
-
105
- val scaledFontSize = scaleSize(12.sp)
106
-
107
- val textStyle = TextStyle(
108
- color = textColor,
109
- fontSize = scaledFontSize,
110
- textAlign = TextAlign.Center,
111
- )
112
-
113
- Box(
114
- modifier = modifier
115
- .defaultMinSize(minWidth = specs.numberMinWidth)
116
- .height(specs.numberHeight)
117
- .border(
118
- width = 1.dp,
119
- color = borderColor,
120
- shape = RoundedCornerShape(Radius.S),
121
- )
122
- .padding(horizontal = Spacing.XS)
123
- .conditional(IsShowBaseLineDebug) { border(1.dp, Colors.blue_03) },
124
- contentAlignment = Alignment.Center,
125
- ) {
126
- BasicTextField(
127
- value = value.toString(),
128
- onValueChange = { if (editable) onValueChange(it) },
129
- enabled = editable && !disabled,
130
- readOnly = !editable,
131
- singleLine = true,
132
- textStyle = textStyle,
133
- keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
134
- decorationBox = { innerTextField -> innerTextField() },
135
- )
136
- }
137
- }
138
-
139
- @Composable
140
- fun Stepper(
141
- defaultValue: Int = 0,
142
- min: Int = 0,
143
- max: Int = 100,
144
- step: Int = 1,
145
- disabled: Any = false,
146
- size: StepperSize = StepperSize.LARGE,
147
- editable: Boolean = false,
148
- onValueChange: (Int) -> Unit = {},
149
- modifier: Modifier = Modifier,
150
- ) {
151
- var value by remember(defaultValue) { mutableStateOf(defaultValue.coerceIn(min, max)) }
152
-
153
- fun applyValue(raw: String) {
154
- var parsed = raw.toIntOrNull() ?: 0
155
- parsed = parsed.coerceIn(min, max)
156
- value = parsed
157
- onValueChange(parsed)
158
- }
159
-
160
- // Resolve per-part disabled state — mirrors RN getViewDisabledStatus()
161
- val disabledMinus: Boolean
162
- val disabledPlus: Boolean
163
- val disabledNumber: Boolean
164
-
165
- when (disabled) {
166
- is BooleanArray if disabled.size >= 2 -> {
167
- disabledMinus = disabled[0]
168
- disabledPlus = disabled[1]
169
- disabledNumber = disabled[0] && disabled[1]
170
- }
171
-
172
- is Boolean if disabled -> {
173
- disabledMinus = true
174
- disabledPlus = true
175
- disabledNumber = true
176
- }
177
-
178
- else -> {
179
- disabledMinus = false
180
- disabledPlus = false
181
- disabledNumber = false
182
- }
183
- }
184
-
185
- // Auto-disable buttons when the value is already at a bound
186
- val effectiveMinusDisabled = disabledMinus || value <= min
187
- val effectivePlusDisabled = disabledPlus || value >= max
188
-
189
- Row(
190
- modifier = modifier
191
- .conditional(IsShowBaseLineDebug) { border(1.dp, Colors.blue_03) },
192
- verticalAlignment = Alignment.CenterVertically,
193
- ) {
194
- StepperButton(
195
- sign = "-",
196
- size = size,
197
- disabled = effectiveMinusDisabled,
198
- onPress = { applyValue((value - step).toString()) },
199
- )
200
-
201
- StepperNumberView(
202
- value = value,
203
- size = size,
204
- disabled = disabledNumber,
205
- editable = editable,
206
- onValueChange = { applyValue(it) },
207
- modifier = Modifier.padding(horizontal = Spacing.S),
208
- )
209
-
210
- StepperButton(
211
- sign = "+",
212
- size = size,
213
- disabled = effectivePlusDisabled,
214
- onPress = { applyValue((value + step).toString()) },
215
- )
216
- }
217
- }