@momo-kits/native-kits 0.162.2-sp.7-debug → 0.162.2-sp.8-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.
Files changed (160) hide show
  1. package/.claude/settings.local.json +15 -1
  2. package/CLAUDE.md +78 -0
  3. package/compose/build.gradle.kts +12 -31
  4. package/compose/build.gradle.kts.backup +11 -30
  5. package/compose/compose.podspec +1 -1
  6. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +2 -7
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +8 -11
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +6 -24
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +4 -19
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +1 -10
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +2 -2
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +1 -1
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +1 -1
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +6 -17
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +1 -1
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +6 -101
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +8 -19
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +8 -33
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +1 -1
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +22 -25
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +27 -29
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +3 -26
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +30 -31
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +3 -13
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -5
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +3 -11
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +3 -18
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +11 -11
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +42 -65
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +69 -26
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +1 -5
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +84 -59
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +13 -71
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +10 -51
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +6 -1
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +4 -21
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +1 -1
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +16 -75
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +5 -26
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +1 -1
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +3 -11
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +16 -40
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +3 -9
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -28
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +2 -13
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +4 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +4 -10
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +3 -28
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +8 -47
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +4 -25
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +2 -11
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +1 -17
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +1 -6
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +50 -111
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +1 -5
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +1 -5
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +1 -12
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +4 -96
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +5 -7
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +2 -12
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +9 -21
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +2 -2
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +9 -14
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +8 -11
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +22 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +1 -1
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +11 -20
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +1 -1
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -5
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -2
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +94 -4
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -2
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +2 -2
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +3 -7
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +9 -15
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +36 -24
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +48 -33
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +67 -61
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +6 -13
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +13 -31
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +1 -1
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +6 -24
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +11 -6
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +2 -1
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +9 -6
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +1 -1
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +3 -13
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +3 -2
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +1 -40
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -2
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -8
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +2 -17
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +1 -1
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +3 -3
  98. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +2 -3
  99. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
  100. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -2
  101. package/gradle/libs.versions.toml +2 -0
  102. package/gradle.properties +1 -1
  103. package/ios/Application/ApplicationEnvironment.swift +4 -2
  104. package/ios/Application/Components.swift +16 -0
  105. package/ios/Application/Localize.swift +277 -0
  106. package/ios/Application/MaxApi.swift +18 -0
  107. package/ios/Application/Navigation/BottomTab/BottomTab.swift +1 -0
  108. package/ios/Application/Navigation/NavigationContainer.swift +27 -3
  109. package/ios/Application/Navigation/Navigator.swift +50 -29
  110. package/ios/Application/Navigation/Overplay/BottomSheet.swift +87 -19
  111. package/ios/Application/Navigation/Overplay/ModalScreen.swift +6 -0
  112. package/ios/Application/Navigation/Tracking/ScreenTracker.swift +117 -0
  113. package/ios/Application/Screen.swift +1 -1
  114. package/ios/Application/StackScreen.swift +49 -1
  115. package/ios/Badge/BadgeRibbon.swift +80 -0
  116. package/ios/Button/Button.swift +68 -12
  117. package/ios/Carousel/Carousel.swift +16 -1
  118. package/ios/Checkbox/Checkbox.swift +14 -20
  119. package/ios/Chip/Chip.swift +35 -26
  120. package/ios/Collapse/Collapse.swift +11 -1
  121. package/ios/Colors+Radius+Spacing/Colors.swift +9 -6
  122. package/ios/Colors+Radius+Spacing/Spacing.swift +3 -1
  123. package/ios/DateTimePicker/DateTimePicker.swift +4 -2
  124. package/ios/DateTimePicker/WheelPicker.swift +7 -3
  125. package/ios/Extensions/ActiveOpacityButtonStyle.swift +14 -0
  126. package/ios/Extensions/Color++.swift +5 -2
  127. package/ios/Icon/Icon.swift +5 -1
  128. package/ios/IconButton/IconButton.swift +35 -7
  129. package/ios/Image/Image.swift +16 -3
  130. package/ios/Information/Information.swift +3 -1
  131. package/ios/Input/ErrorView.swift +3 -1
  132. package/ios/Input/Input.swift +31 -8
  133. package/ios/Input/InputPhoneNumber.swift +14 -3
  134. package/ios/Input/InputSearch.swift +7 -1
  135. package/ios/Input/InputTextArea.swift +78 -34
  136. package/ios/InputDropDown/InputDropDown.swift +4 -1
  137. package/ios/InputMoney/InputMoney.swift +16 -4
  138. package/ios/PARITY_AUDIT.md +641 -0
  139. package/ios/Popup/PopupDisplay.swift +3 -4
  140. package/ios/Popup/PopupNotify.swift +3 -4
  141. package/ios/Popup/PopupPromotion.swift +16 -8
  142. package/ios/ProgressInfo/ProgressInfo.swift +4 -2
  143. package/ios/Radio/Radio.swift +12 -13
  144. package/ios/Rating/Rating.swift +1 -1
  145. package/ios/Stepper/Stepper.swift +2 -2
  146. package/ios/Steps/Steps.swift +22 -6
  147. package/ios/SuggestAction/SuggestAction.swift +5 -3
  148. package/ios/Swipeable/SwipeCell.swift +5 -3
  149. package/ios/Switch/Switch.swift +53 -28
  150. package/ios/TabView/TabView.swift +18 -14
  151. package/ios/Template/TrustBanner/TrustBanner.swift +6 -7
  152. package/ios/Tooltip/Tooltip.swift +3 -0
  153. package/ios/Typography/FontScaleStore.swift +19 -0
  154. package/ios/Typography/Text.swift +3 -0
  155. package/ios/Typography/Typography.swift +8 -5
  156. package/ios/Uploader/Uploader.swift +0 -9
  157. package/ios/native-kits.podspec +1 -1
  158. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  159. package/package.json +1 -1
  160. package/ios/Colors+Radius+Spacing/MoMoUIKitsResources.swift +0 -2
@@ -16,6 +16,7 @@ public struct InputPhoneNumber: View {
16
16
  public var error: String
17
17
  public var errorSpacing: Bool
18
18
  public var loading: Bool
19
+ public var required: Bool
19
20
  public var rightIcon: String
20
21
  public var rightIconColor: Color?
21
22
  public var autofocus: Bool
@@ -24,8 +25,9 @@ public struct InputPhoneNumber: View {
24
25
  public var onBlur: (() -> Void)?
25
26
  public var onRightIconPressed: (() -> Void)?
26
27
  public var accessibilityLabel: String?
27
-
28
+
28
29
  @State private var isFocused: Bool = false
30
+ @FocusState private var isFieldFocused: Bool
29
31
 
30
32
  public init(
31
33
  text: Binding<String>,
@@ -52,6 +54,7 @@ public struct InputPhoneNumber: View {
52
54
  self.error = error
53
55
  self.errorSpacing = errorSpacing
54
56
  self.loading = loading
57
+ self.required = required
55
58
  self.rightIcon = rightIcon
56
59
  self.rightIconColor = rightIconColor
57
60
  self.autofocus = autofocus
@@ -90,9 +93,13 @@ public struct InputPhoneNumber: View {
90
93
  // Text input
91
94
  ZStack(alignment: .leading) {
92
95
  if text.isEmpty {
93
- MomoText(placeholder, typography: size == .small ? .headerSSemibold : .headerMBold, color: theme.colors.text.hint)
96
+ MomoText(
97
+ placeholder + (required ? " *" : ""),
98
+ typography: size == .small ? .headerSSemibold : .headerMBold,
99
+ color: theme.colors.text.hint
100
+ )
94
101
  }
95
-
102
+
96
103
  TextField("", text: textBinding, onEditingChanged: { focused in
97
104
  handleFocusChange(focused)
98
105
  })
@@ -102,6 +109,10 @@ public struct InputPhoneNumber: View {
102
109
  .foregroundColor(theme.colors.text.default)
103
110
  .applyCursorColor(theme.colors.primary)
104
111
  .lineLimit(1)
112
+ .focused($isFieldFocused)
113
+ .onAppear {
114
+ if autofocus { isFieldFocused = true }
115
+ }
105
116
  .accessibility(identifier: accessibilityLabel ?? "")
106
117
  .accessibilityValue(textBinding.wrappedValue.isEmpty ? placeholder : textBinding.wrappedValue)
107
118
  }
@@ -238,7 +238,13 @@ public struct InputSearch: View {
238
238
  }
239
239
 
240
240
  if isFocused && !text.isEmpty {
241
- SwiftButton(action: { text = "" }) {
241
+ SwiftButton(action: {
242
+ text = ""
243
+ // Kotlin's clear icon fires a callback distinct from
244
+ // onChangeText (`onClearPress`, not ported here); route
245
+ // through onChangeText so clearing isn't a silent no-op.
246
+ onChangeText("")
247
+ }) {
242
248
  Image(systemName: "xmark.circle.fill")
243
249
  .foregroundColor(theme.colors.text.hint)
244
250
  .frame(width: 16, height: 16)
@@ -109,6 +109,7 @@ public struct InputTextArea: View {
109
109
 
110
110
  @State private var isFocused = false
111
111
  @State private var isBlurred = false
112
+ @State private var floatingLabelHeight: CGFloat = 16
112
113
 
113
114
  // Make the initializer public
114
115
  public init(
@@ -182,45 +183,88 @@ public struct InputTextArea: View {
182
183
  }
183
184
  }
184
185
  .padding(.horizontal, Spacing.S)
186
+ .background(
187
+ GeometryReader { geo in
188
+ Color.clear.onAppear { floatingLabelHeight = geo.size.height }
189
+ }
190
+ )
185
191
  .background(theme.colors.background.surface)
186
- .offset(x: Spacing.S, y: -height / 10)
192
+ // Kotlin centers the label within the box-height-tall decorationBox
193
+ // by default, then applies `offsetY = -scaleHeight / 2` — net effect:
194
+ // the label ends up centered exactly on the box's top border. Our
195
+ // ZStack anchors top-leading instead, so matching that requires
196
+ // offsetting by half the label's OWN measured height, not half the
197
+ // (104pt-tall) text-area box height.
198
+ .offset(x: Spacing.S, y: -floatingLabelHeight / 2)
187
199
  .zIndex(10)
188
200
  }
189
-
201
+
190
202
  VStack {
191
- ZStack(alignment: .topLeading) {
192
- if text.isEmpty {
193
- Text(placeholder)
194
- .foregroundColor(disabled ? theme.colors.text.disable : theme.colors.text.hint)
195
- .font(.system(size: 16, weight: fontWeight))
196
- .padding(.horizontal, 16)
197
- .padding(.vertical, 12)
203
+ HStack(alignment: .top, spacing: 0) {
204
+ ZStack(alignment: .topLeading) {
205
+ if text.isEmpty {
206
+ Text(placeholder)
207
+ .foregroundColor(disabled ? theme.colors.text.disable : theme.colors.text.hint)
208
+ .font(.system(size: 16, weight: fontWeight))
209
+ .padding(.horizontal, 16)
210
+ .padding(.vertical, 12)
211
+ }
212
+
213
+ UITextViewWrapper(
214
+ text: $text,
215
+ maxLength: maxLength,
216
+ textColor: disabled ? theme.colors.text.disable : theme.colors.text.default,
217
+ cursorColor: theme.colors.primary,
218
+ fontWeight: fontWeight,
219
+ disabled: disabled,
220
+ onChangeText: onChangeText,
221
+ onDone: {
222
+ // Handle done action if needed
223
+ },
224
+ onFocus: {
225
+ isFocused = true
226
+ onFocus()
227
+ }, onBlur: {
228
+ isFocused = false
229
+ isBlurred = true
230
+ onBlur()
231
+ })
232
+ .frame(height: height)
233
+ .padding(.horizontal, 12)
234
+ .padding(.vertical, 8)
235
+ .disabled(disabled)
198
236
  }
199
-
200
- UITextViewWrapper(
201
- text: $text,
202
- maxLength: maxLength,
203
- textColor: disabled ? theme.colors.text.disable : theme.colors.text.default,
204
- cursorColor: theme.colors.primary,
205
- fontWeight: fontWeight,
206
- disabled: disabled,
207
- onChangeText: onChangeText,
208
- onDone: {
209
- // Handle done action if needed
210
- },
211
- onFocus: {
212
- isFocused = true
213
- onFocus()
214
- }, onBlur: {
215
- isFocused = false
216
- isBlurred = true
217
- onBlur()
218
- })
219
- .frame(height: height)
220
- .padding(.horizontal, 12)
221
- .padding(.vertical, 8)
222
- .disabled(disabled) }
223
-
237
+ .frame(maxWidth: .infinity)
238
+
239
+ // Clear button (mirrors Compose: focused + non-empty).
240
+ if isFocused && !text.isEmpty {
241
+ SwiftUI.Button(action: {
242
+ text = ""
243
+ onChangeText("")
244
+ }) {
245
+ Icon(source: "24_navigation_close_circle_full", size: 16, color: theme.colors.text.hint)
246
+ }
247
+ .padding(.leading, Spacing.XS)
248
+ .padding(.top, 12)
249
+ }
250
+
251
+ // Loading indicator and right icon (independent, mirrors
252
+ // Compose's RenderRightIcon: both can render at once).
253
+ if loading {
254
+ ActivityIndicator(isAnimating: .constant(true), style: .medium)
255
+ .frame(width: 16, height: 16)
256
+ .padding(.leading, Spacing.XS)
257
+ .padding(.top, 12)
258
+ }
259
+ if !icon.isEmpty {
260
+ SwiftUI.Button(action: onRightIconPressed) {
261
+ Icon(source: icon, size: 24, color: disabled ? theme.colors.text.disable : (iconColor ?? theme.colors.text.default))
262
+ }
263
+ .padding(.leading, Spacing.XS)
264
+ .padding(.top, 12)
265
+ }
266
+ }
267
+
224
268
  HStack {
225
269
  Spacer()
226
270
  MomoText("\(text.count)/\(maxLength)", typography: .descriptionXsRegular, color: theme.colors.text.hint)
@@ -16,10 +16,13 @@ private struct RenderRightIcon: View {
16
16
  let onPressed: () -> Void
17
17
 
18
18
  var body: some View {
19
+ // Mirrors Compose's two independent `if` blocks: loading spinner and icon
20
+ // can both render at once, not exclusively (not an if/else).
19
21
  if loading {
20
22
  ActivityIndicator(isAnimating: .constant(true), style: .medium)
21
23
  .frame(width: 16, height: 16)
22
- } else if !icon.isEmpty {
24
+ }
25
+ if !icon.isEmpty {
23
26
  SwiftUI.Button(action: onPressed) {
24
27
  Icon(source: icon, size: 24, color: color)
25
28
  }
@@ -75,6 +75,7 @@ public struct InputMoney: View {
75
75
  public var onBlur: (() -> Void)?
76
76
 
77
77
  @State private var isFocused: Bool = false
78
+ @State private var floatingLabelHeight: CGFloat = 16
78
79
 
79
80
  public init(
80
81
  text: Binding<String>,
@@ -141,8 +142,18 @@ public struct InputMoney: View {
141
142
  }
142
143
  }
143
144
  .padding(.horizontal, Spacing.S)
145
+ .background(
146
+ GeometryReader { geo in
147
+ Color.clear.onAppear { floatingLabelHeight = geo.size.height }
148
+ }
149
+ )
144
150
  .background(theme.colors.background.surface)
145
- .offset(x: Spacing.S, y: -8)
151
+ // Kotlin centers the label within the box-height-tall decorationBox by
152
+ // default, then applies `offsetY = -size.values.height / 2` — net effect:
153
+ // the label ends up centered exactly on the box's top border. Our ZStack
154
+ // anchors top-leading instead, so matching that requires offsetting by
155
+ // half the label's OWN measured height, not half the box height.
156
+ .offset(x: Spacing.S, y: -floatingLabelHeight / 2)
146
157
  .zIndex(10)
147
158
  }
148
159
 
@@ -188,13 +199,14 @@ public struct InputMoney: View {
188
199
  }
189
200
  }
190
201
 
191
- // Loading indicator
202
+ // Loading indicator and right icon can both render (mirrors
203
+ // Compose's two independent `if` blocks, not if/else).
192
204
  if loading {
193
205
  ActivityIndicator(isAnimating: .constant(true), style: .medium)
194
206
  .frame(width: 16, height: 16)
195
207
  .padding(.leading, Spacing.S)
196
- } else if !icon.isEmpty {
197
- // Right icon
208
+ }
209
+ if !icon.isEmpty {
198
210
  SwiftUI.Button(action: { onPressIcon?() }) {
199
211
  Icon(source: icon, size: 24, color: iconTintColor)
200
212
  .padding(.leading, Spacing.S)