@momo-kits/native-kits 0.162.2-beta.22-debug → 0.162.2-beta.23-debug

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,7 +40,7 @@ kotlin {
40
40
  }
41
41
 
42
42
  cocoapods {
43
- version = "0.162.2-beta.22-debug"
43
+ version = "0.162.2-beta.23-debug"
44
44
  summary = "IOS Shared module"
45
45
  homepage = "https://momo.vn"
46
46
  ios.deploymentTarget = "15.0"
@@ -20,8 +20,6 @@ import androidx.compose.ui.Modifier
20
20
  import androidx.compose.ui.draw.alpha
21
21
  import androidx.compose.ui.draw.clip
22
22
  import androidx.compose.ui.graphics.Color
23
- import androidx.compose.ui.semantics.contentDescription
24
- import androidx.compose.ui.semantics.semantics
25
23
  import androidx.compose.ui.text.TextStyle
26
24
  import androidx.compose.ui.text.style.TextOverflow
27
25
  import androidx.compose.ui.unit.Dp
@@ -145,10 +143,9 @@ fun RenderIcon(
145
143
  icon: String = "",
146
144
  forceLoading: Boolean = false,
147
145
  textColor: Color? = null,
148
- iconOnly: Boolean = false,
149
146
  ) {
150
147
  val iconSize = remember(size) { getIconSize(size) }
151
- val margin = remember(size, iconOnly) { if (iconOnly) 0.dp else getIconSpace(size) }
148
+ val margin = remember(size) { getIconSpace(size) }
152
149
  val color = if (useTintColor) textColor else Color.Unspecified
153
150
 
154
151
  val modifier = Modifier.padding(
@@ -249,12 +246,6 @@ fun getButtonBackgroundColor(
249
246
  private fun Color.withLoading(loading: Boolean): Color =
250
247
  this.copy(alpha = if (loading) 0.75f else 1f)
251
248
 
252
- /**
253
- * When [iconOnly] is true the label is hidden and the button collapses to a compact,
254
- * icon-sized box (it ignores [isFull] and always wraps its content). [title] stays
255
- * required and is exposed as the button's accessibility label. Supply the glyph via
256
- * [iconLeft] (preferred) or [iconRight]; while [loading] the spinner replaces the icon.
257
- */
258
249
  @Composable
259
250
  fun Button(
260
251
  onClick: () -> Unit,
@@ -266,7 +257,6 @@ fun Button(
266
257
  loading: Boolean = false,
267
258
  useTintColor: Boolean = true,
268
259
  isFull: Boolean = true,
269
- iconOnly: Boolean = false,
270
260
  modifier: Modifier = Modifier,
271
261
  ) {
272
262
  val radius = remember(size) { size.value.radius }
@@ -274,7 +264,6 @@ fun Button(
274
264
  val loadingOnLeft = remember(iconLeft, iconRight) {
275
265
  shouldLoadingOnLeft(iconLeft, iconRight)
276
266
  }
277
- val iconOnlyIcon = remember(iconLeft, iconRight) { iconLeft.ifEmpty { iconRight } }
278
267
 
279
268
  val sizeSpecs = remember(size) { size.value }
280
269
 
@@ -313,7 +302,7 @@ fun Button(
313
302
  val bgColor = getButtonBackgroundColor(loading, type)
314
303
  val textColor = getTextColor(loading, type)
315
304
 
316
- val rootModifier = if (isFull && !iconOnly) {
305
+ val rootModifier = if (isFull) {
317
306
  Modifier
318
307
  .fillMaxWidth()
319
308
  .wrapContentHeight()
@@ -322,11 +311,7 @@ fun Button(
322
311
  }
323
312
 
324
313
  Box(
325
- modifier = rootModifier
326
- .then(clickableModifier)
327
- .conditional(iconOnly) {
328
- semantics(mergeDescendants = true) { contentDescription = title }
329
- },
314
+ modifier = rootModifier.then(clickableModifier),
330
315
  contentAlignment = Alignment.Center
331
316
  ) {
332
317
  // Visual background (shrinks on press)
@@ -349,35 +334,23 @@ fun Button(
349
334
  horizontalArrangement = Arrangement.Center,
350
335
  verticalAlignment = Alignment.CenterVertically,
351
336
  ) {
352
- if (iconOnly) {
353
- RenderIcon(
354
- size = size,
355
- isIconLeft = true,
356
- useTintColor = useTintColor,
357
- icon = iconOnlyIcon,
358
- forceLoading = loading,
359
- textColor = textColor,
360
- iconOnly = true
361
- )
362
- } else {
363
- RenderIcon(
364
- size = size,
365
- isIconLeft = true,
366
- useTintColor = useTintColor,
367
- icon = iconLeft,
368
- forceLoading = loading && loadingOnLeft,
369
- textColor = textColor
370
- )
371
- RenderTitle(size, title, textColor = textColor)
372
- RenderIcon(
373
- size = size,
374
- isIconLeft = false,
375
- useTintColor = useTintColor,
376
- icon = iconRight,
377
- forceLoading = loading && !loadingOnLeft,
378
- textColor = textColor
379
- )
380
- }
337
+ RenderIcon(
338
+ size = size,
339
+ isIconLeft = true,
340
+ useTintColor = useTintColor,
341
+ icon = iconLeft,
342
+ forceLoading = loading && loadingOnLeft,
343
+ textColor = textColor
344
+ )
345
+ RenderTitle(size, title, textColor = textColor)
346
+ RenderIcon(
347
+ size = size,
348
+ isIconLeft = false,
349
+ useTintColor = useTintColor,
350
+ icon = iconRight,
351
+ forceLoading = loading && !loadingOnLeft,
352
+ textColor = textColor
353
+ )
381
354
  }
382
355
  }
383
356
  }
@@ -12,12 +12,14 @@ import androidx.compose.ui.Alignment
12
12
  import androidx.compose.ui.Modifier
13
13
  import androidx.compose.ui.draw.clip
14
14
  import androidx.compose.ui.graphics.Color
15
+ import androidx.compose.ui.graphics.Shape
15
16
  import androidx.compose.ui.unit.Dp
16
17
  import androidx.compose.ui.unit.dp
17
18
  import vn.momo.kits.application.IsShowBaseLineDebug
18
19
  import vn.momo.kits.const.AppTheme
19
20
  import vn.momo.kits.const.Colors
20
21
  import vn.momo.kits.const.Radius
22
+ import vn.momo.kits.const.Spacing
21
23
  import vn.momo.kits.modifier.conditional
22
24
 
23
25
  data class IconSpecs(
@@ -46,8 +48,29 @@ enum class IconSize(val value: IconSpecs) {
46
48
  )
47
49
  }
48
50
 
49
- // Pre-computed shape to avoid repeated creation
50
- private val iconButtonShape = RoundedCornerShape(Radius.XL)
51
+ enum class IconButtonShape {
52
+ CIRCLE,
53
+ SQUARE,
54
+ RECTANGLE
55
+ }
56
+
57
+ // Resolved footprint + corner radius for a (size, shape) pair.
58
+ data class IconButtonGeometry(
59
+ val width: Dp,
60
+ val height: Dp,
61
+ val radius: Dp
62
+ )
63
+
64
+ // CIRCLE keeps the square footprint fully rounded (legacy default); SQUARE/RECTANGLE use the
65
+ // standard button corner (Radius.S) and RECTANGLE widens the footprint so it reads horizontal.
66
+ internal fun resolveIconButtonGeometry(size: IconSize, shape: IconButtonShape): IconButtonGeometry {
67
+ val base = size.value.height
68
+ return when (shape) {
69
+ IconButtonShape.CIRCLE -> IconButtonGeometry(base, base, size.value.radius)
70
+ IconButtonShape.SQUARE -> IconButtonGeometry(base, base, Radius.S)
71
+ IconButtonShape.RECTANGLE -> IconButtonGeometry(base + Spacing.S, base, Radius.S)
72
+ }
73
+ }
51
74
 
52
75
  // Cache for icon sizes to avoid repeated calculations
53
76
  private val iconSizeMap = mapOf(
@@ -56,34 +79,34 @@ private val iconSizeMap = mapOf(
56
79
  )
57
80
 
58
81
  @Composable
59
- internal fun getIconStyle(type: ButtonType, color: Color? = null): Modifier {
82
+ internal fun getIconStyle(type: ButtonType, shape: Shape, color: Color? = null): Modifier {
60
83
  val theme = AppTheme.current
61
84
 
62
- return remember(type, color, theme) {
85
+ return remember(type, shape, color, theme) {
63
86
  when (type) {
64
87
  ButtonType.DISABLED -> Modifier
65
- .background(theme.colors.background.disable, iconButtonShape)
66
- .border(0.dp, Color.Unspecified, iconButtonShape)
88
+ .background(theme.colors.background.disable, shape)
89
+ .border(0.dp, Color.Unspecified, shape)
67
90
 
68
91
  ButtonType.PRIMARY -> Modifier
69
- .background(theme.colors.primary, iconButtonShape)
70
- .border(0.dp, Color.Unspecified, iconButtonShape)
92
+ .background(theme.colors.primary, shape)
93
+ .border(0.dp, Color.Unspecified, shape)
71
94
 
72
95
  ButtonType.SECONDARY -> Modifier
73
- .background(theme.colors.background.surface, iconButtonShape)
74
- .border(1.dp, theme.colors.border.default, iconButtonShape)
96
+ .background(theme.colors.background.surface, shape)
97
+ .border(1.dp, theme.colors.border.default, shape)
75
98
 
76
99
  ButtonType.OUTLINE -> Modifier
77
- .background(theme.colors.background.surface, iconButtonShape)
78
- .border(1.dp, color ?: theme.colors.primary, iconButtonShape)
100
+ .background(theme.colors.background.surface, shape)
101
+ .border(1.dp, color ?: theme.colors.primary, shape)
79
102
 
80
103
  ButtonType.TONAL -> Modifier
81
- .background(theme.colors.background.tonal, iconButtonShape)
82
- .border(0.dp, Color.Unspecified, iconButtonShape)
104
+ .background(theme.colors.background.tonal, shape)
105
+ .border(0.dp, Color.Unspecified, shape)
83
106
 
84
107
  ButtonType.DANGER -> Modifier
85
- .background(theme.colors.error.primary, iconButtonShape)
86
- .border(0.dp, Color.Unspecified, iconButtonShape)
108
+ .background(theme.colors.error.primary, shape)
109
+ .border(0.dp, Color.Unspecified, shape)
87
110
 
88
111
  ButtonType.TEXT -> Modifier
89
112
  }
@@ -103,6 +126,7 @@ fun IconButton(
103
126
  onClick: () -> Unit,
104
127
  type: ButtonType = ButtonType.PRIMARY,
105
128
  size: IconSize = IconSize.SMALL,
129
+ shape: IconButtonShape = IconButtonShape.CIRCLE,
106
130
  icon: String = "",
107
131
  ) {
108
132
  // Memoize icon size calculation
@@ -115,19 +139,22 @@ fun IconButton(
115
139
  type != ButtonType.DISABLED
116
140
  }
117
141
 
118
- // Memoize radius for clipping
119
- val radius = remember(size) {
120
- size.value.radius
142
+ // Memoize footprint + corner shape for the requested shape
143
+ val geometry = remember(size, shape) {
144
+ resolveIconButtonGeometry(size, shape)
145
+ }
146
+ val cornerShape = remember(geometry.radius) {
147
+ RoundedCornerShape(geometry.radius)
121
148
  }
122
149
 
123
150
  Box(
124
151
  modifier = Modifier
125
- .size(size.value.size)
126
- .then(getIconStyle(type))
152
+ .size(width = geometry.width, height = geometry.height)
153
+ .then(getIconStyle(type, cornerShape))
127
154
  .conditional(IsShowBaseLineDebug) {
128
155
  border(1.dp, Colors.blue_03)
129
156
  }
130
- .clip(RoundedCornerShape(radius))
157
+ .clip(cornerShape)
131
158
  .clickable(enabled = isEnabled, onClick = onClick),
132
159
  contentAlignment = Alignment.Center
133
160
  ) {
package/gradle.properties CHANGED
@@ -18,7 +18,7 @@ kotlin.apple.xcodeCompatibility.nowarn=true
18
18
  name="ComposeKits"
19
19
  group=vn.momo.kits
20
20
  artifact.id=kits
21
- version=0.162.2-beta.22
21
+ version=0.162.2-beta.23
22
22
 
23
23
  repo=GitLab
24
24
  url=https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven
@@ -125,12 +125,7 @@ public struct Button: View {
125
125
  var iconRight: AnyView?
126
126
  var isFull: Bool
127
127
  var loading: Bool
128
- var iconOnly: Bool
129
128
 
130
- /// When `iconOnly` is true the label is hidden and the button collapses to a compact,
131
- /// icon-sized box (it ignores `isFull`). `title` stays required and is exposed as the
132
- /// accessibility label. Supply the glyph via `iconLeft` (preferred) or `iconRight`;
133
- /// while `loading` the spinner replaces the icon.
134
129
  public init(
135
130
  title: String = "",
136
131
  action: @escaping () -> Void,
@@ -139,8 +134,7 @@ public struct Button: View {
139
134
  iconLeft: AnyView? = nil,
140
135
  iconRight: AnyView? = nil,
141
136
  isFull: Bool = true,
142
- loading: Bool = false,
143
- iconOnly: Bool = false
137
+ loading: Bool = false
144
138
  ) {
145
139
  self.title = title
146
140
  self.action = action
@@ -150,7 +144,6 @@ public struct Button: View {
150
144
  self.iconRight = iconRight
151
145
  self.isFull = isFull
152
146
  self.loading = loading
153
- self.iconOnly = iconOnly
154
147
  }
155
148
 
156
149
  private func shouldLoadingOnLeft(_ left: AnyView?, _ right: AnyView?) -> Bool {
@@ -173,46 +166,35 @@ public struct Button: View {
173
166
  let border = type.borderColor
174
167
  let borderWidth = type.borderWidth
175
168
 
176
- let button = SwiftUI.Button(action: {
169
+ SwiftUI.Button(action: {
177
170
  if !loading, type != .disabled {
178
171
  action()
179
172
  }
180
173
  }) {
181
174
  HStack(spacing: size.iconSpacing) {
182
- if iconOnly {
183
- if loading {
184
- LottieView(name: "lottie_circle_loader", loopMode: .loop)
185
- .frame(width: size.iconSize, height: size.iconSize)
186
- .colorMultiply(fg)
187
-
188
- } else if let icon = iconLeft ?? iconRight {
189
- icon.frame(width: size.iconSize, height: size.iconSize)
190
- }
191
- } else {
192
- if loading && loadingOnLeft {
193
- LottieView(name: "lottie_circle_loader", loopMode: .loop)
194
- .frame(width: size.iconSize, height: size.iconSize)
195
- .colorMultiply(fg)
196
-
197
- } else if let iconLeft = iconLeft {
198
- iconLeft.frame(width: size.iconSize, height: size.iconSize)
199
- }
200
-
201
- MomoText(title, typography: size.typographyStyle, color: fg)
202
- .lineLimit(1)
203
- .truncationMode(.tail)
204
-
205
- if loading && !loadingOnLeft {
206
- LottieView(name: "lottie_circle_loader", loopMode: .loop)
207
- .frame(width: size.iconSize, height: size.iconSize)
208
- .colorMultiply(fg)
209
-
210
- } else if let iconRight = iconRight {
211
- iconRight.frame(width: size.iconSize, height: size.iconSize)
212
- }
175
+ if loading && loadingOnLeft {
176
+ LottieView(name: "lottie_circle_loader", loopMode: .loop)
177
+ .frame(width: size.iconSize, height: size.iconSize)
178
+ .colorMultiply(fg)
179
+
180
+ } else if let iconLeft = iconLeft {
181
+ iconLeft.frame(width: size.iconSize, height: size.iconSize)
182
+ }
183
+
184
+ MomoText(title, typography: size.typographyStyle, color: fg)
185
+ .lineLimit(1)
186
+ .truncationMode(.tail)
187
+
188
+ if loading && !loadingOnLeft {
189
+ LottieView(name: "lottie_circle_loader", loopMode: .loop)
190
+ .frame(width: size.iconSize, height: size.iconSize)
191
+ .colorMultiply(fg)
192
+
193
+ } else if let iconRight = iconRight {
194
+ iconRight.frame(width: size.iconSize, height: size.iconSize)
213
195
  }
214
196
  }
215
- .frame(maxWidth: isFull && !iconOnly ? .infinity : nil)
197
+ .frame(maxWidth: isFull ? .infinity : nil)
216
198
  .padding(.horizontal, size.padding)
217
199
  .frame(height: size.height)
218
200
  .background(bg)
@@ -224,11 +206,5 @@ public struct Button: View {
224
206
  .opacity(loading ? 0.75 : 1)
225
207
  }
226
208
  .disabled(type == .disabled || loading)
227
-
228
- if iconOnly {
229
- button.accessibilityLabel(Text(title))
230
- } else {
231
- button
232
- }
233
209
  }
234
210
  }
package/package.json CHANGED
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.162.2-beta.22-debug",
3
+ "version": "0.162.2-beta.23-debug",
4
4
  "private": false,
5
+ "dependencies": {},
6
+ "devDependencies": {},
5
7
  "license": "MoMo"
6
8
  }