@momo-kits/native-kits 0.152.4-beta.11 → 0.152.4-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.
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |spec|
2
2
  spec.name = 'MoMoComposeKits'
3
- spec.version = '0.152.4'
3
+ spec.version = '0.0.1'
4
4
  spec.homepage = 'MoMoComposeKits'
5
5
  spec.source = { :http=> ''}
6
6
  spec.authors = 'M_SERVICE'
@@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.width
14
14
  import androidx.compose.foundation.shape.CircleShape
15
15
  import androidx.compose.foundation.shape.RoundedCornerShape
16
16
  import androidx.compose.runtime.Composable
17
+ import androidx.compose.runtime.Stable
17
18
  import androidx.compose.runtime.getValue
18
19
  import androidx.compose.runtime.mutableStateOf
19
20
  import androidx.compose.runtime.remember
@@ -32,6 +33,7 @@ import vn.momo.kits.components.Icon
32
33
  import vn.momo.kits.const.AppTheme
33
34
  import vn.momo.kits.const.Colors
34
35
 
36
+ @Stable
35
37
  data class HeaderRightData(
36
38
  val useShortcut: Boolean = false,
37
39
  val useMore: Boolean = false,
@@ -85,7 +85,6 @@ import vn.momo.kits.modifier.shadow
85
85
  import vn.momo.kits.utils.getAppStatusBarHeight
86
86
  import kotlin.math.max
87
87
 
88
- @Deprecated("Use NavigationContainer(StackScreen) instead", ReplaceWith("NavigationContainer(StackScreen)"))
89
88
  @Composable
90
89
  fun LiteScreen(
91
90
  scrollable: Boolean = true,
@@ -352,7 +351,8 @@ private class LiteScreenHeaderPolicy(
352
351
  val realConstraints = constraints.copy(
353
352
  minWidth = 0,
354
353
  minHeight = 0,
355
- maxWidth = constraints.maxWidth - spacing12 * 2,
354
+ maxWidth = (constraints.maxWidth - spacing12 * 2)
355
+ .coerceAtLeast(0),
356
356
  )
357
357
  val backIconPlaceable =
358
358
  measurables.find { it.layoutId == HeaderId.BACK_ID }?.measure(realConstraints)
@@ -13,6 +13,8 @@ import androidx.compose.ui.semantics.semantics
13
13
  import androidx.compose.ui.unit.Dp
14
14
  import androidx.compose.ui.unit.dp
15
15
  import coil3.compose.AsyncImage
16
+ import coil3.compose.LocalPlatformContext
17
+ import coil3.request.ImageRequest
16
18
  import vn.momo.kits.const.AppTheme
17
19
  import vn.momo.kits.utils.Icons
18
20
  import vn.momo.kits.utils.noThemeIcons
@@ -24,6 +26,9 @@ fun Icon(
24
26
  color: Color? = AppTheme.current.colors.text.default,
25
27
  modifier: Modifier = Modifier,
26
28
  ) {
29
+ // decode image without downscaling it
30
+ val context = LocalPlatformContext.current
31
+
27
32
  val iconUrl = remember(source) {
28
33
  if (source.contains("https")) {
29
34
  source
@@ -49,7 +54,13 @@ fun Icon(
49
54
  ) {
50
55
  AsyncImage(
51
56
  modifier = Modifier.matchParentSize(),
52
- model = iconUrl,
57
+ model = ImageRequest.Builder(context)
58
+ .data(iconUrl)
59
+ .size(
60
+ coil3.size.Dimension.Undefined,
61
+ coil3.size.Dimension.Undefined
62
+ )
63
+ .build(),
53
64
  contentDescription = null,
54
65
  contentScale = ContentScale.Fit,
55
66
  colorFilter = colorFilter,
@@ -6,7 +6,6 @@ import androidx.compose.foundation.ScrollState
6
6
  import androidx.compose.foundation.background
7
7
  import androidx.compose.foundation.gestures.ScrollableState
8
8
  import androidx.compose.foundation.layout.Box
9
- import androidx.compose.foundation.layout.BoxScope
10
9
  import androidx.compose.foundation.layout.Column
11
10
  import androidx.compose.foundation.layout.ColumnScope
12
11
  import androidx.compose.foundation.layout.Spacer
@@ -5,7 +5,6 @@ import androidx.compose.animation.core.tween
5
5
  import androidx.compose.foundation.layout.Box
6
6
  import androidx.compose.foundation.layout.fillMaxWidth
7
7
  import androidx.compose.foundation.layout.offset
8
- import androidx.compose.foundation.layout.padding
9
8
  import androidx.compose.runtime.Composable
10
9
  import androidx.compose.runtime.DisposableEffect
11
10
  import androidx.compose.runtime.LaunchedEffect
@@ -0,0 +1,85 @@
1
+ import SwiftUI
2
+
3
+ public struct Badge: View {
4
+ let label: String
5
+ let backgroundColor: Color?
6
+
7
+ private var primaryColors: [Color] {
8
+ [
9
+ Colors.black03,
10
+ Colors.pink03,
11
+ Colors.violet03,
12
+ Colors.indigo03,
13
+ Colors.blue03,
14
+ Colors.mint03,
15
+ Colors.green03,
16
+ Colors.lime03,
17
+ Colors.yellow03,
18
+ Colors.gold03,
19
+ Colors.orange03,
20
+ Colors.red03
21
+ ]
22
+ }
23
+
24
+ public init(label: String = "Label", backgroundColor: Color? = nil) {
25
+ self.label = label
26
+ self.backgroundColor = backgroundColor
27
+ }
28
+
29
+ private func isNumber(_ text: String) -> Bool {
30
+ return text.range(of: "^\\d+$", options: .regularExpression) != nil
31
+ }
32
+
33
+ private func formatTitle(_ text: String) -> String {
34
+ if isNumber(text), let number = Int(text), number > 99 {
35
+ return "99+"
36
+ }
37
+ return text
38
+ }
39
+
40
+ private var badgeColor: Color {
41
+ // If a custom background color is provided, use it
42
+ if let bgColor = backgroundColor {
43
+ return bgColor
44
+ }
45
+
46
+ // Otherwise, use default colors based on label type
47
+ if isNumber(label) {
48
+ return Colors.red03 // error.primary
49
+ } else {
50
+ return Colors.orange03 // warning.primary
51
+ }
52
+ }
53
+
54
+ public var body: some View {
55
+ Text(formatTitle(label))
56
+ .font(.system(size: scaleSize(10), weight: .bold))
57
+ .foregroundColor(Colors.black01)
58
+ .padding(.horizontal, Spacing.XS)
59
+ .frame(minWidth: scaleSize(16), minHeight: scaleSize(16))
60
+ .background(badgeColor)
61
+ .cornerRadius(Radius.M)
62
+ .overlay(
63
+ RoundedRectangle(cornerRadius: Radius.M)
64
+ .stroke(Colors.black01, lineWidth: 1)
65
+ )
66
+ }
67
+ }
68
+
69
+ // MARK: - Preview
70
+ #if DEBUG
71
+ struct Badge_Previews: PreviewProvider {
72
+ static var previews: some View {
73
+ VStack(spacing: 20) {
74
+ Badge(label: "5")
75
+ Badge(label: "99")
76
+ Badge(label: "100")
77
+ Badge(label: "New")
78
+ Badge(label: "Hot", backgroundColor: Colors.pink03)
79
+ }
80
+ .padding()
81
+ .previewLayout(.sizeThatFits)
82
+ }
83
+ }
84
+ #endif
85
+
@@ -0,0 +1,174 @@
1
+ import SwiftUI
2
+
3
+ public enum RibbonPosition {
4
+ case topLeft
5
+ case topRight
6
+ case bottomLeft
7
+ case bottomRight
8
+ }
9
+
10
+ public struct BadgeRibbon: View {
11
+ let position: RibbonPosition
12
+ let label: String
13
+ let isRound: Bool
14
+ let backgroundColor: Color
15
+
16
+ public init(
17
+ position: RibbonPosition = .topRight,
18
+ label: String = "Label",
19
+ isRound: Bool = false,
20
+ backgroundColor: Color? = nil
21
+ ) {
22
+ self.position = position
23
+ self.label = label
24
+ self.isRound = isRound
25
+ self.backgroundColor = backgroundColor ?? Colors.orange03
26
+ }
27
+
28
+ private var rotation: Angle {
29
+ switch position {
30
+ case .topRight, .bottomRight:
31
+ return .degrees(180)
32
+ case .topLeft, .bottomLeft:
33
+ return .zero
34
+ }
35
+ }
36
+
37
+ private var useUpTail: Bool {
38
+ position == .bottomLeft || position == .topRight
39
+ }
40
+
41
+ private var verticalAlignment: VerticalAlignment {
42
+ switch position {
43
+ case .topLeft, .bottomRight:
44
+ return .top
45
+ case .bottomLeft, .topRight:
46
+ return .bottom
47
+ }
48
+ }
49
+
50
+ public var body: some View {
51
+ HStack(alignment: verticalAlignment, spacing: 0) {
52
+ if useUpTail {
53
+ upTail
54
+ } else {
55
+ downTail
56
+ }
57
+
58
+ if isRound {
59
+ roundContent
60
+ } else {
61
+ skewContent
62
+ }
63
+ }
64
+ .frame(height: RibbonConstants.ribbonHeight)
65
+ .rotationEffect(rotation)
66
+ }
67
+
68
+ private var roundContent: some View {
69
+ HStack(spacing: 0) {
70
+ Text(label)
71
+ .font(.system(size: 12, weight: .medium))
72
+ .foregroundColor(Colors.black01)
73
+ .lineLimit(1)
74
+ .rotationEffect(rotation)
75
+ }
76
+ .frame(height: RibbonConstants.roundHeight)
77
+ .padding(.trailing, RibbonConstants.roundPaddingEnd)
78
+ .background(
79
+ RoundedRectangle(cornerRadius: Radius.M)
80
+ .fill(backgroundColor)
81
+ .mask(
82
+ HStack(spacing: 0) {
83
+ Rectangle()
84
+ RoundedRectangle(cornerRadius: Radius.M)
85
+ }
86
+ )
87
+ )
88
+ }
89
+
90
+ private var skewContent: some View {
91
+ HStack(spacing: 0) {
92
+ Text(label)
93
+ .font(.system(size: 12, weight: .medium))
94
+ .foregroundColor(Colors.black01)
95
+ .lineLimit(1)
96
+ .rotationEffect(rotation)
97
+ .frame(height: RibbonConstants.skewBodyHeight)
98
+ .padding(.horizontal, 8)
99
+ .background(backgroundColor)
100
+
101
+ rightTail
102
+ }
103
+ }
104
+
105
+ private var upTail: some View {
106
+ ImageView(
107
+ "https://static.momocdn.net/app/img/kits/utils/Head_down_4x.png",
108
+ placeholder: AnyView(Color.clear)
109
+ )
110
+ .frame(width: RibbonConstants.headTailWidth, height: RibbonConstants.headTailHeight)
111
+ .rotationEffect(.degrees(180))
112
+ .offset(x: 1)
113
+ .clipped()
114
+ }
115
+
116
+ private var downTail: some View {
117
+ ImageView(
118
+ "https://static.momocdn.net/app/img/kits/utils/Head_4x.png",
119
+ placeholder: AnyView(Color.clear)
120
+ )
121
+ .frame(width: RibbonConstants.headTailWidth, height: RibbonConstants.headTailHeight)
122
+ .offset(x: 1)
123
+ .clipped()
124
+ }
125
+
126
+ private var rightTail: some View {
127
+ ImageView(
128
+ "https://static.momocdn.net/app/img/kits/utils/Tail_4x.png",
129
+ placeholder: AnyView(Color.clear)
130
+ )
131
+ .frame(width: RibbonConstants.skewTailWidth, height: RibbonConstants.skewTailHeight)
132
+ .offset(x: -2)
133
+ .clipped()
134
+ }
135
+ }
136
+
137
+ // MARK: - Constants
138
+ private struct RibbonConstants {
139
+ static let ribbonHeight: CGFloat = 20
140
+ static let roundHeight: CGFloat = 16
141
+ static let skewBodyHeight: CGFloat = 16
142
+ static let roundRightRadius: CGFloat = 12
143
+ static let roundPaddingEnd: CGFloat = 6
144
+ static let skewTailWidth: CGFloat = 8
145
+ static let skewTailHeight: CGFloat = 16
146
+ static let headTailWidth: CGFloat = 5
147
+ static let headTailHeight: CGFloat = 20
148
+ }
149
+
150
+ // MARK: - String Extension for Text Size
151
+ extension String {
152
+ func size(withAttributes attributes: [NSAttributedString.Key: Any]?) -> CGSize {
153
+ let size = (self as NSString).size(withAttributes: attributes)
154
+ return size
155
+ }
156
+ }
157
+
158
+ // MARK: - Preview
159
+ #if DEBUG
160
+ struct BadgeRibbon_Previews: PreviewProvider {
161
+ static var previews: some View {
162
+ VStack(spacing: 30) {
163
+ // Basic ribbon examples
164
+ BadgeRibbon(position: .topRight, label: "New")
165
+ BadgeRibbon(position: .topLeft, label: "Hot", isRound: true)
166
+ BadgeRibbon(position: .bottomLeft, label: "Sale")
167
+ BadgeRibbon(position: .bottomRight, label: "50% OFF", isRound: true)
168
+ }
169
+ .padding()
170
+ .previewLayout(.sizeThatFits)
171
+ }
172
+ }
173
+ #endif
174
+
@@ -1,6 +1,6 @@
1
1
  import Foundation
2
- import SwiftUI
3
2
  import Lottie
3
+ import SwiftUI
4
4
 
5
5
  // MARK: - ButtonType
6
6
 
@@ -33,7 +33,7 @@ public extension ButtonType {
33
33
  func backgroundColor(loading: Bool) -> Color {
34
34
  switch self {
35
35
  case .disabled: return Colors.black05.opacity(loading ? 0.75 : 1)
36
- case .primary: return Colors.primary.opacity(loading ? 0.75 : 1)
36
+ case .primary: return Colors.primary.opacity(loading ? 0.75 : 1)
37
37
  case .secondary: return Colors.card.opacity(loading ? 0.75 : 1)
38
38
  case .outline: return Colors.card.opacity(loading ? 0.75 : 1)
39
39
  case .tonal: return Colors.primaryLight.opacity(loading ? 0.75 : 1)
@@ -116,13 +116,13 @@ extension ButtonSize {
116
116
  }
117
117
 
118
118
  public struct Button: View {
119
-
120
119
  var title: String
121
120
  var action: () -> Void
122
121
  var type: ButtonType
123
122
  var size: ButtonSize
124
123
  var iconLeft: AnyView?
125
124
  var iconRight: AnyView?
125
+ var isFull: Bool
126
126
  var loading: Bool
127
127
 
128
128
  public init(
@@ -132,6 +132,7 @@ public struct Button: View {
132
132
  size: ButtonSize = .large,
133
133
  iconLeft: AnyView? = nil,
134
134
  iconRight: AnyView? = nil,
135
+ isFull: Bool = true,
135
136
  loading: Bool = false
136
137
  ) {
137
138
  self.title = title
@@ -140,6 +141,7 @@ public struct Button: View {
140
141
  self.size = size
141
142
  self.iconLeft = iconLeft
142
143
  self.iconRight = iconRight
144
+ self.isFull = isFull
143
145
  self.loading = loading
144
146
  }
145
147
 
@@ -156,7 +158,6 @@ public struct Button: View {
156
158
  }
157
159
 
158
160
  public var body: some View {
159
-
160
161
  let loadingOnLeft = shouldLoadingOnLeft(iconLeft, iconRight)
161
162
 
162
163
  let bg = type.backgroundColor(loading: loading)
@@ -165,12 +166,11 @@ public struct Button: View {
165
166
  let borderWidth = type.borderWidth
166
167
 
167
168
  SwiftUI.Button(action: {
168
- if !loading && type != .disabled {
169
+ if !loading, type != .disabled {
169
170
  action()
170
171
  }
171
172
  }) {
172
173
  HStack(spacing: size.iconSpacing) {
173
-
174
174
  if loading && loadingOnLeft {
175
175
  LottieView(name: "lottie_circle_loader", loopMode: .loop)
176
176
  .frame(width: size.iconSize, height: size.iconSize)
@@ -195,7 +195,7 @@ public struct Button: View {
195
195
  iconRight.frame(width: size.iconSize, height: size.iconSize)
196
196
  }
197
197
  }
198
- .frame(maxWidth: .infinity)
198
+ .frame(maxWidth: isFull ? .infinity : nil)
199
199
  .padding(.horizontal, size.padding)
200
200
  .frame(height: size.height)
201
201
  .background(bg)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.152.4-beta.11",
3
+ "version": "0.152.4-beta.13",
4
4
  "private": false,
5
5
  "dependencies": {
6
6
  "@momo-platform/native-max-api": "1.0.18"