@momo-kits/native-kits 0.152.4-beta.5 → 0.152.4-beta.7

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 (156) hide show
  1. package/CODE_OF_CONDUCT.md +133 -0
  2. package/CONTRIBUTING.md +114 -0
  3. package/LICENSE +20 -0
  4. package/README.md +7 -0
  5. package/build.gradle.kts +32 -0
  6. package/compose/MoMoComposeKits.podspec +54 -0
  7. package/compose/build.gradle.kts +149 -0
  8. package/compose/src/androidMain/AndroidManifest.xml +2 -0
  9. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +105 -0
  10. package/compose/src/commonMain/composeResources/files/lottie_circle_loader.json +1 -0
  11. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  12. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  13. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  14. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  19. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  20. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  21. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  22. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  23. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  24. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +57 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +201 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +222 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +48 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +306 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +715 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +214 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +392 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +77 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +27 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +334 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +345 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +90 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +131 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +58 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +143 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +179 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +111 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +384 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +160 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +234 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +223 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +232 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +236 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +228 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +364 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +50 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +34 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +85 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +33 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +338 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +95 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +64 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +89 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +91 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +84 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +208 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +172 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +199 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +237 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +191 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +13 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +191 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +258 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +59 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +68 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +49 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +232 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +111 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +94 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +159 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +302 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScaleSizeScope.kt +17 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +484 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +169 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +216 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +180 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +251 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +80 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +306 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +31 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +385 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +123 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +38 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +62 -0
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +88 -0
  109. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +144 -0
  110. package/gradle.properties +19 -0
  111. package/gradlew +240 -0
  112. package/gradlew.bat +91 -0
  113. package/ios/Application/ApplicationEnvironment.swift +50 -0
  114. package/ios/Application/Components.swift +263 -0
  115. package/ios/Application/ComposeApi.swift +22 -0
  116. package/ios/Application/FloatingButton.swift +172 -0
  117. package/ios/Application/HeaderRight.swift +271 -0
  118. package/ios/Application/Screen.swift +249 -0
  119. package/ios/Badge/BadgeDot.swift +31 -0
  120. package/ios/Button/Button.swift +211 -0
  121. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
  122. package/ios/Checkbox/Checkbox.swift +81 -0
  123. package/ios/Chip/Chip.swift +96 -0
  124. package/ios/Colors+Radius+Spacing/Colors.swift +172 -0
  125. package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
  126. package/ios/Colors+Radius+Spacing/Spacing.swift +12 -0
  127. package/ios/Extensions/Color++.swift +25 -0
  128. package/ios/Icon/Icon.swift +51 -0
  129. package/ios/Image/Image.swift +70 -0
  130. package/ios/Input/Input.swift +207 -0
  131. package/ios/Input/InputPhoneNumber.swift +176 -0
  132. package/ios/Input/InputSearch.swift +238 -0
  133. package/ios/Input/InputTextArea.swift +242 -0
  134. package/ios/Lottie/LottieView.swift +86 -0
  135. package/ios/OTPKeyboard/KeyboardButton.swift +41 -0
  136. package/ios/OTPKeyboard/OTPKeyboard.swift +145 -0
  137. package/ios/Popup/PopupDisplay.swift +284 -0
  138. package/ios/Popup/PopupInput.swift +96 -0
  139. package/ios/Popup/PopupPromotion.swift +73 -0
  140. package/ios/PopupView/FullscreenPopup.swift +251 -0
  141. package/ios/PopupView/Modifiers.swift +158 -0
  142. package/ios/PopupView/PopupView.swift +289 -0
  143. package/ios/PopupView/Utils++.swift +281 -0
  144. package/ios/ScrollIndicator/ScrollIndicator.swift +110 -0
  145. package/ios/Swipeable/SwipeCell.swift +278 -0
  146. package/ios/Swipeable/SwipeCellModel.swift +86 -0
  147. package/ios/Switch/Switch.swift +44 -0
  148. package/ios/Template/Logo/Logo.swift +75 -0
  149. package/ios/Template/TrustBanner/TrustBanner.swift +120 -0
  150. package/ios/Theme.md +18 -0
  151. package/ios/Typography/Text.swift +140 -0
  152. package/ios/Typography/Typography.swift +95 -0
  153. package/ios/native-kits.podspec +18 -0
  154. package/package.json +6 -7
  155. package/settings.gradle.kts +25 -0
  156. package/shared/build.gradle.kts +0 -74
@@ -0,0 +1,77 @@
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.Box
6
+ import androidx.compose.foundation.layout.height
7
+ import androidx.compose.foundation.layout.padding
8
+ import androidx.compose.foundation.layout.widthIn
9
+ import androidx.compose.foundation.shape.RoundedCornerShape
10
+ import androidx.compose.runtime.Composable
11
+ import androidx.compose.ui.Alignment
12
+ import androidx.compose.ui.Modifier
13
+ import androidx.compose.ui.graphics.Color
14
+ import androidx.compose.ui.unit.dp
15
+ import vn.momo.kits.const.AppTheme
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
21
+
22
+
23
+ @Composable
24
+ fun Badge(label: String = "Label", backgroundColor: Color? = null) {
25
+ val primaryColors = listOf(
26
+ Color(0xFFF0F0F0),
27
+ Color(0xFFEB2F96),
28
+ Color(0xFF962AF0),
29
+ Color(0xFF4E4BFF),
30
+ Color(0xFF007AFF),
31
+ Color(0xFF13C2C2),
32
+ Color(0xFF34C759),
33
+ Color(0xFFA0D911),
34
+ Color(0xFFFFCC00),
35
+ Color(0xFFFA8C16),
36
+ Color(0xFFFA541C),
37
+ Color(0xFFF5222D)
38
+ )
39
+
40
+ fun isNumber(label: String): Boolean {
41
+ val numberRegex = "^\\d+$".toRegex()
42
+ return numberRegex.matches(label)
43
+ }
44
+
45
+ fun formatTitle(label: String): String {
46
+ if (isNumber(label) && label.toInt() > 99) {
47
+ return "99+"
48
+ }
49
+ return label
50
+ }
51
+
52
+ var badgeColor =
53
+ if (isNumber(label)) {
54
+ AppTheme.current.colors.error.primary
55
+ } else {
56
+ AppTheme.current.colors.warning.primary
57
+ }
58
+
59
+ if (backgroundColor != null && primaryColors.contains(backgroundColor)) {
60
+ badgeColor = backgroundColor
61
+ }
62
+
63
+ Box(
64
+ modifier = Modifier
65
+ .height(scaleSize(16.toFloat()).dp)
66
+ .widthIn(min = scaleSize(16.toFloat()).dp)
67
+ .background(color = badgeColor, shape = RoundedCornerShape(Radius.M))
68
+ .border(width = 1.dp, shape = RoundedCornerShape(Radius.M), color = Colors.black_01)
69
+ .padding(horizontal = Spacing.XS), contentAlignment = Alignment.Center
70
+ ) {
71
+ Text(
72
+ text = formatTitle(label),
73
+ color = Colors.black_01,
74
+ style = Typography.actionXxsBold
75
+ )
76
+ }
77
+ }
@@ -0,0 +1,27 @@
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.Box
6
+ import androidx.compose.foundation.layout.size
7
+ import androidx.compose.foundation.shape.RoundedCornerShape
8
+ import androidx.compose.runtime.Composable
9
+ import androidx.compose.ui.Modifier
10
+ import androidx.compose.ui.unit.dp
11
+ import vn.momo.kits.const.Colors
12
+ import vn.momo.kits.const.Radius
13
+
14
+ enum class DotSize(val size: Int) {
15
+ Small(10),
16
+ Large(16)
17
+ }
18
+
19
+ @Composable
20
+ fun BadgeDot(size: DotSize = DotSize.Large, modifier: Modifier = Modifier) {
21
+ Box(
22
+ modifier = modifier
23
+ .size(size.size.dp)
24
+ .border(width = 1.dp, color = Colors.black_01, shape = RoundedCornerShape(Radius.S))
25
+ .background(color = Colors.red_03, shape = RoundedCornerShape(Radius.S))
26
+ )
27
+ }
@@ -0,0 +1,334 @@
1
+ package vn.momo.kits.components
2
+
3
+ import androidx.compose.foundation.Canvas
4
+ import androidx.compose.foundation.background
5
+ import androidx.compose.foundation.layout.Box
6
+ import androidx.compose.foundation.layout.Row
7
+ import androidx.compose.foundation.layout.height
8
+ import androidx.compose.foundation.layout.padding
9
+ import androidx.compose.foundation.layout.size
10
+ import androidx.compose.foundation.layout.width
11
+ import androidx.compose.foundation.shape.RoundedCornerShape
12
+ import androidx.compose.runtime.Composable
13
+ import androidx.compose.runtime.remember
14
+ import androidx.compose.ui.Alignment
15
+ import androidx.compose.ui.Modifier
16
+ import androidx.compose.ui.geometry.CornerRadius
17
+ import androidx.compose.ui.geometry.Offset
18
+ import androidx.compose.ui.geometry.Rect
19
+ import androidx.compose.ui.geometry.RoundRect
20
+ import androidx.compose.ui.geometry.Size
21
+ import androidx.compose.ui.graphics.Color
22
+ import androidx.compose.ui.graphics.Path
23
+ import androidx.compose.ui.graphics.graphicsLayer
24
+ import androidx.compose.ui.layout.ContentScale
25
+ import androidx.compose.ui.platform.LocalDensity
26
+ import androidx.compose.ui.text.rememberTextMeasurer
27
+ import androidx.compose.ui.text.style.TextAlign
28
+ import androidx.compose.ui.text.style.TextOverflow
29
+ import androidx.compose.ui.unit.Dp
30
+ import androidx.compose.ui.unit.dp
31
+ import androidx.compose.ui.unit.sp
32
+ import vn.momo.kits.const.AppTheme
33
+ import vn.momo.kits.const.Colors
34
+ import vn.momo.kits.const.Typography
35
+ import vn.momo.kits.const.getFontFamily
36
+ import vn.momo.kits.const.scaleSize
37
+
38
+ @Composable
39
+ fun BadgeRibbon(
40
+ position: RibbonPosition = RibbonPosition.TopRight,
41
+ label: String = "Label",
42
+ isRound: Boolean = false,
43
+ modifier: Modifier = Modifier,
44
+ ) {
45
+ val theme = AppTheme.current
46
+
47
+ val rotate = if (position == RibbonPosition.TopRight || position == RibbonPosition.BottomRight) 180f else 0f
48
+ val useUpTail = position == RibbonPosition.BottomLeft || position == RibbonPosition.TopRight
49
+ val verticalAlignment = when(position){
50
+ RibbonPosition.TopLeft, RibbonPosition.BottomRight -> Alignment.Top
51
+ RibbonPosition.BottomLeft, RibbonPosition.TopRight -> Alignment.Bottom
52
+ }
53
+
54
+ Row(
55
+ modifier = modifier
56
+ .height(ribbonHeight)
57
+ .graphicsLayer { rotationZ = rotate },
58
+ verticalAlignment = verticalAlignment
59
+ ) {
60
+ if (useUpTail) {
61
+ UpTail()
62
+ } else {
63
+ DownTail()
64
+ }
65
+
66
+ if (isRound) {
67
+ renderRoundContent(label, rotate, theme.colors.warning.primary)
68
+ } else {
69
+ renderSkewContent(label, rotate, theme.colors.warning.primary)
70
+ }
71
+ }
72
+ }
73
+
74
+ @Composable
75
+ fun renderRoundContent(label: String, rotate: Float, backgroundColor: Color){
76
+ Box(
77
+ modifier = Modifier
78
+ .height(roundHeight)
79
+ .background(
80
+ color = backgroundColor,
81
+ shape = RoundedCornerShape(
82
+ topEnd = roundRightRadius,
83
+ bottomEnd = roundRightRadius,
84
+ )
85
+ )
86
+ .padding(end = roundPaddingEnd),
87
+ contentAlignment = Alignment.Center,
88
+ ) {
89
+ Label(label, rotate)
90
+ }
91
+ }
92
+
93
+ @Composable
94
+ fun renderSkewContent(label: String, rotate: Float, backgroundColor: Color){
95
+ Box(
96
+ modifier = Modifier
97
+ .height(skewBodyHeight)
98
+ .background(backgroundColor),
99
+ contentAlignment = Alignment.Center
100
+ ) {
101
+ Label(label, rotate)
102
+ }
103
+ RightTail()
104
+ }
105
+
106
+ @Composable
107
+ fun Label(label: String, rotate: Float){
108
+ Text(
109
+ text = label,
110
+ color = Colors.black_01,
111
+ maxLines = 1,
112
+ overflow = TextOverflow.Ellipsis,
113
+ style = Typography.labelXsMedium,
114
+ modifier = Modifier.graphicsLayer { rotationZ = rotate }
115
+ )
116
+ }
117
+
118
+ @Composable
119
+ fun UpTail() {
120
+ Image(
121
+ source = "https://static.momocdn.net/app/img/kits/utils/Head_down_4x.png",
122
+ modifier = Modifier
123
+ .graphicsLayer { rotationZ = 180f }
124
+ .width(headTailWidth)
125
+ .height(headTailHeight),
126
+ options = Options(
127
+ contentScale = ContentScale.FillBounds,
128
+ )
129
+ )
130
+ }
131
+
132
+ @Composable
133
+ fun DownTail() {
134
+ Image(
135
+ source = "https://static.momocdn.net/app/img/kits/utils/Head_4x.png",
136
+ modifier = Modifier
137
+ .width(headTailWidth)
138
+ .height(headTailHeight),
139
+ options = Options(
140
+ contentScale = ContentScale.FillBounds,
141
+ )
142
+ )
143
+ }
144
+
145
+ @Composable
146
+ fun RightTail() {
147
+ Image(
148
+ source = "https://static.momocdn.net/app/img/kits/utils/Tail_4x.png",
149
+ modifier = Modifier
150
+ .width(skewTailWidth)
151
+ .height(skewTailHeight),
152
+ options = Options(
153
+ contentScale = ContentScale.FillBounds,
154
+ )
155
+ )
156
+ }
157
+
158
+ @Composable
159
+ fun RoundedBadgeRibbon(
160
+ text: String = "Label",
161
+ position: RibbonPosition = RibbonPosition.TopLeft,
162
+ modifier: Modifier = Modifier
163
+ ) {
164
+ val theme = AppTheme.current
165
+ val density = LocalDensity.current
166
+ val style = Typography.labelXsMedium
167
+ val fontFamily = style.fontFamily
168
+
169
+ val scaledFontSize = scaleSize(style.fontSize.value).sp
170
+ val fontFamilyResult = getFontFamily(fontFamily?.toString() ?: theme.font, style.fontWeight)
171
+
172
+ val fontSize = remember(scaledFontSize) { scaledFontSize }
173
+ val font = remember(fontFamilyResult) { fontFamilyResult }
174
+ val textMeasurer = rememberTextMeasurer()
175
+
176
+ val textLayoutResult = remember(text, fontSize, font) {
177
+ textMeasurer.measure(
178
+ text = text,
179
+ style = style.copy(fontSize = fontSize, fontFamily = font)
180
+ )
181
+ }
182
+
183
+ val textWidth = with(density) { textLayoutResult.size.width.toDp() }
184
+ val textHeight = with(density) { textLayoutResult.size.height.toDp() }
185
+
186
+ val minRibbonHeight = (textHeight * 1.2f).coerceAtLeast(16.dp)
187
+ val paddingBottom = minRibbonHeight / 4f
188
+ val badgeHeight = minRibbonHeight + paddingBottom
189
+ val horizontalPadding = paddingBottom
190
+ val badgeWidth = (textWidth + horizontalPadding * 2).coerceAtLeast(28.dp)
191
+
192
+ val (rotateZ, scaleY, scaleX) = when (position) {
193
+ RibbonPosition.TopLeft -> Triple(0f, 1f, -1f)
194
+ RibbonPosition.TopRight -> Triple(0f, 1f, 1f)
195
+ RibbonPosition.BottomRight -> Triple(0f, -1f, 1f)
196
+ RibbonPosition.BottomLeft -> Triple(0f, -1f, -1f)
197
+ }
198
+
199
+ Box(
200
+ modifier = modifier
201
+ .size(width = badgeWidth, height = badgeHeight)
202
+ .graphicsLayer {
203
+ rotationZ = rotateZ
204
+ this.scaleY = scaleY
205
+ this.scaleX = scaleX
206
+ }
207
+ ) {
208
+ val roundedRect = (badgeHeight - paddingBottom) / 2f
209
+
210
+ Canvas(modifier = Modifier.matchParentSize()) {
211
+ val width = size.width
212
+ val height = size.height
213
+ val ribbonHeight = height - paddingBottom.toPx()
214
+ val cornerRadius = roundedRect.toPx()
215
+
216
+ val mainColor = Color(0xFFFA541C)
217
+ val tailColor = Color(0xFFC41B24)
218
+
219
+ val headWidth = 4.dp.toPx()
220
+ val leftSectionWidth = width * (9f / 28f)
221
+ val middleSectionWidth = width - leftSectionWidth - headWidth
222
+ val rightX = leftSectionWidth + middleSectionWidth
223
+
224
+ // 1. Tail + 2. BG
225
+ val leftMiddlePath = Path().apply {
226
+ addRoundRect(
227
+ RoundRect(
228
+ rect = Rect(
229
+ left = 0f,
230
+ top = 0f,
231
+ right = rightX + 1f,
232
+ bottom = ribbonHeight
233
+ ),
234
+ topLeft = CornerRadius(cornerRadius, cornerRadius),
235
+ topRight = CornerRadius.Zero,
236
+ bottomRight = CornerRadius.Zero,
237
+ bottomLeft = CornerRadius(cornerRadius, cornerRadius)
238
+ )
239
+ )
240
+ }
241
+ drawPath(
242
+ path = leftMiddlePath,
243
+ color = mainColor
244
+ )
245
+
246
+ // 3. Head
247
+ val headPath = Path().apply {
248
+ addRoundRect(
249
+ RoundRect(
250
+ rect = Rect(
251
+ left = rightX,
252
+ top = 0f,
253
+ right = rightX + headWidth,
254
+ bottom = ribbonHeight
255
+ ),
256
+ topLeft = CornerRadius.Zero,
257
+ topRight = CornerRadius(cornerRadius, cornerRadius),
258
+ bottomRight = CornerRadius.Zero,
259
+ bottomLeft = CornerRadius.Zero
260
+ )
261
+ )
262
+ }
263
+ drawPath(
264
+ path = headPath,
265
+ color = mainColor
266
+ )
267
+
268
+ // Draw bottom tail section
269
+ val tailY = ribbonHeight
270
+ val tailHeight = paddingBottom.toPx()
271
+ val halfHeadWidth = headWidth / 2f
272
+ val tailStartX = rightX + headWidth - halfHeadWidth
273
+
274
+ // Background square (main color)
275
+ drawRect(
276
+ color = mainColor,
277
+ topLeft = Offset(tailStartX, tailY),
278
+ size = Size(halfHeadWidth, halfHeadWidth)
279
+ )
280
+
281
+ val tailRoundRadius = tailHeight
282
+ val tailRightPath = Path().apply {
283
+ addRoundRect(
284
+ RoundRect(
285
+ rect = Rect(
286
+ left = tailStartX,
287
+ top = tailY,
288
+ right = tailStartX + halfHeadWidth,
289
+ bottom = tailY + tailHeight
290
+ ),
291
+ topLeft = CornerRadius.Zero,
292
+ topRight = CornerRadius(tailRoundRadius, tailRoundRadius),
293
+ bottomRight = CornerRadius(tailRoundRadius, tailRoundRadius),
294
+ bottomLeft = CornerRadius.Zero
295
+ )
296
+ )
297
+ }
298
+ drawPath(
299
+ path = tailRightPath,
300
+ color = tailColor
301
+ )
302
+ }
303
+
304
+ Text(
305
+ text = text,
306
+ modifier = Modifier
307
+ .padding(bottom = paddingBottom)
308
+ .padding(horizontal = paddingBottom / 2)
309
+ .align(Alignment.Center)
310
+ .graphicsLayer {
311
+ rotationZ = rotateZ
312
+ this.scaleY = scaleY
313
+ this.scaleX = scaleX
314
+ },
315
+ textAlign = TextAlign.Center,
316
+ style = Typography.labelXsMedium,
317
+ maxLines = 1,
318
+ overflow = TextOverflow.Ellipsis,
319
+ color = Colors.black_01
320
+ )
321
+ }
322
+ }
323
+
324
+ val ribbonHeight: Dp = 20.dp
325
+ val roundHeight: Dp = 16.dp
326
+ val skewBodyHeight: Dp = 16.dp
327
+ val roundRightRadius: Dp = 12.dp
328
+ val roundPaddingEnd: Dp = 6.dp
329
+ val skewTailWidth: Dp = 8.dp
330
+ val skewTailHeight: Dp = 16.dp
331
+ val headTailWidth: Dp = 5.dp
332
+ val headTailHeight: Dp = 20.dp
333
+
334
+ enum class RibbonPosition {TopLeft, TopRight, BottomLeft, BottomRight}