@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
@@ -54,6 +54,8 @@ extension View {
54
54
  // MARK: - PopupDisplay
55
55
 
56
56
  public struct PopupDisplay: View {
57
+ @EnvironmentObject private var localize: Localize
58
+
57
59
  // MARK: Lifecycle
58
60
 
59
61
  public init(isPresented: Binding<Bool>, title: String = "", description: String = "", url: String = "", buttonDirection: PopupButtonDirection = .column, buttonType: PopupButtonType = .button, actionButtonTitle: String = "", closeButtonTitle: String = "", onPressAction: @escaping () -> Void = {}, onPressCloseButton: @escaping () -> Void = {}, onClose: @escaping () -> Void = {}, errorCode: String = "", isShowCloseIcon: Bool = true) {
@@ -91,9 +93,6 @@ public struct PopupDisplay: View {
91
93
  @State private var isScrollable = false
92
94
 
93
95
  public var body: some View {
94
- let language = UserDefaults.standard.string(forKey: "language")?.replacingOccurrences(of: "\"", with: "") ?? "vi"
95
- let errorCodeLabels: [String: String] = ["vi": "Mã lỗi: ", "en": "Error code: "]
96
-
97
96
  var shouldUseColumn: Bool {
98
97
  buttonDirection == .column || (buttonDirection == .auto && (closeButtonTitle.count > 12 || actionButtonTitle.count > 12))
99
98
  }
@@ -170,7 +169,7 @@ public struct PopupDisplay: View {
170
169
  .padding(.bottom, 8)
171
170
 
172
171
  if(!errorCode.isEmpty) {
173
- MomoText((errorCodeLabels[language] ?? "Mã lỗi: ") + errorCode, typography: .descriptionXsRegular, color: Colors.black12)
172
+ MomoText(localize.translate("errorCode") + errorCode, typography: .descriptionXsRegular, color: Colors.black12)
174
173
  .lineLimit(1)
175
174
  .padding(.bottom, 8)
176
175
  }
@@ -38,15 +38,14 @@ public struct PopupNotifyProps {
38
38
  }
39
39
 
40
40
  public struct PopupNotify: View {
41
+ @EnvironmentObject private var localize: Localize
42
+
41
43
  public let props: PopupNotifyProps
42
44
 
43
45
  @State private var descriptionHeight: CGFloat = 0
44
46
 
45
47
  private var errorCodePrefix: String {
46
- let language = UserDefaults.standard
47
- .string(forKey: "language")?
48
- .replacingOccurrences(of: "\"", with: "") ?? "vi"
49
- return language == "en" ? "Error code: " : "Mã lỗi: "
48
+ localize.translate("errorCode")
50
49
  }
51
50
 
52
51
  private var maxDescriptionHeight: CGFloat {
@@ -2,6 +2,8 @@ import SwiftUI
2
2
  import SDWebImageSwiftUI
3
3
 
4
4
  public struct PopupPromotion: View {
5
+ @Environment(\.appTheme) private var theme
6
+
5
7
  var imageUrl: String
6
8
  var onIconClose: (() -> Void)?
7
9
  var onAction: (() -> Void)?
@@ -18,21 +20,26 @@ public struct PopupPromotion: View {
18
20
  }
19
21
 
20
22
  public var body: some View {
23
+ // Mirrors Kotlin's `Modifier.fillMaxWidth().aspectRatio(0.72f)` box with
24
+ // `ContentScale.FillBounds` inside it: a fixed-ratio frame the image stretches
25
+ // to exactly fill (no `.aspectRatio` modifier on the image itself, unlike the
26
+ // previous `.fit`, which letterboxed instead of stretching).
27
+ let boxWidth = UIScreen.main.bounds.width - Spacing.XL * 2
28
+ let boxHeight = boxWidth / 0.72
29
+
21
30
  VStack(spacing: 8) {
22
31
  if(imageUrl.isEmpty) {
23
- Icon(source: "media_fail", size: UIScreen.main.bounds.width - Spacing.XL * 2)
32
+ Icon(source: "media_fail", size: boxWidth)
24
33
  }
25
34
  else {
26
35
  WebImage(url: URL(string: imageUrl)!)
27
36
  .resizable()
28
37
  .placeholder {
29
38
  Color.gray
30
- .aspectRatio(0.72, contentMode: .fit)
31
- .frame(maxWidth: UIScreen.main.bounds.width - Spacing.XL * 2)
39
+ .frame(width: boxWidth, height: boxHeight)
32
40
  .clipped()
33
41
  }
34
- .aspectRatio(0.72, contentMode: .fit)
35
- .frame(maxWidth: UIScreen.main.bounds.width - Spacing.XL * 2, alignment: .center)
42
+ .frame(width: boxWidth, height: boxHeight, alignment: .center)
36
43
  .clipped()
37
44
  .onTapGesture {
38
45
  onAction?()
@@ -53,16 +60,17 @@ public struct PopupPromotion: View {
53
60
  }) {
54
61
  ZStack {
55
62
  Circle()
56
- .strokeBorder(Colors.black01, lineWidth: 2)
57
- .background(Circle().fill(Colors.black17))
63
+ .strokeBorder(theme.colors.background.surface, lineWidth: 2)
64
+ .background(Circle().fill(theme.colors.text.default))
58
65
  .frame(width: 22, height: 22)
59
66
 
60
- Icon(source: "navigation_close", size: 16, color: Colors.black01)
67
+ Icon(source: "navigation_close", size: 16, color: theme.colors.background.surface)
61
68
  }
62
69
  .frame(width: 40, height: 40)
63
70
  .padding(8)
64
71
  .zIndex(1)
65
72
  }
73
+ .buttonStyle(.plain)
66
74
  }
67
75
  }
68
76
 
@@ -97,7 +97,7 @@ public struct ProgressInfo: View {
97
97
  // MARK: - Tokens
98
98
 
99
99
  private let progressInfoLineColor = Colors.pink08
100
- private let progressInfoAccentColor = Color(hex: "a50064") // pink_MoMo_Branding
100
+ private let progressInfoAccentColor = Colors.pinkMoMoBranding
101
101
 
102
102
  // MARK: - Horizontal variant
103
103
 
@@ -196,6 +196,8 @@ private struct ProgressInfoHorizontal: View {
196
196
  // MARK: - Vertical variant
197
197
 
198
198
  private struct ProgressInfoVertical: View {
199
+ @Environment(\.appTheme) private var theme
200
+
199
201
  let steps: [ProgressInfoItem]
200
202
  let size: ProgressInfoSize
201
203
  let useNumber: Bool
@@ -218,7 +220,7 @@ private struct ProgressInfoVertical: View {
218
220
  )
219
221
  if !isLast {
220
222
  Rectangle()
221
- .fill(Colors.primary.opacity(0.2))
223
+ .fill(theme.colors.primary.opacity(0.2))
222
224
  .frame(width: 2)
223
225
  .frame(maxHeight: .infinity)
224
226
  }
@@ -34,22 +34,21 @@ public struct Radio: View {
34
34
  }
35
35
 
36
36
  public var body: some View {
37
- HStack(spacing: 0) {
38
- RoundedRectangle(cornerRadius: Radius.M)
39
- .stroke(borderColor, lineWidth: borderWidth)
40
- .frame(width: 20, height: 20)
41
- .padding(.trailing, label.isEmpty ? 0 : Spacing.XS)
37
+ SwiftUI.Button(action: onTap) {
38
+ HStack(spacing: 0) {
39
+ RoundedRectangle(cornerRadius: Radius.M)
40
+ .stroke(borderColor, lineWidth: borderWidth)
41
+ .frame(width: 20, height: 20)
42
+ .padding(.trailing, label.isEmpty ? 0 : Spacing.XS)
42
43
 
43
- if !label.isEmpty {
44
- MomoText(label, typography: .descriptionDefaultRegular)
45
- }
46
- }
47
- .contentShape(Rectangle())
48
- .onTapGesture {
49
- if !disabled {
50
- onTap()
44
+ if !label.isEmpty {
45
+ MomoText(label, typography: .descriptionDefaultRegular)
46
+ }
51
47
  }
48
+ .contentShape(Rectangle())
52
49
  }
50
+ .buttonStyle(ActiveOpacityButtonStyle())
51
+ .disabled(disabled)
53
52
  }
54
53
 
55
54
  private var borderWidth: CGFloat {
@@ -52,7 +52,7 @@ public struct Rating: View {
52
52
  SwiftUI.Button(action: { onRatingChange(index + 1) }) {
53
53
  icon
54
54
  }
55
- .buttonStyle(.plain)
55
+ .buttonStyle(ActiveOpacityButtonStyle())
56
56
  } else {
57
57
  icon
58
58
  }
@@ -70,14 +70,14 @@ private struct StepperButton: View {
70
70
  let iconColor: Color = disabled ? theme.colors.text.disable : theme.colors.primary
71
71
  let iconName = sign == "-" ? "24_navigation_minus_circle" : "24_navigation_plus_circle"
72
72
 
73
- SwiftUI.Button(action: { if !disabled { onPress() } }) {
73
+ SwiftUI.Button(action: onPress) {
74
74
  ZStack {
75
75
  Circle().fill(theme.colors.background.disable)
76
76
  Icon(source: iconName, size: specs.iconSize, color: iconColor)
77
77
  }
78
78
  .frame(width: specs.buttonSize, height: specs.buttonSize)
79
79
  }
80
- .buttonStyle(.plain)
80
+ .buttonStyle(ActiveOpacityButtonStyle())
81
81
  .disabled(disabled)
82
82
  }
83
83
  }
@@ -201,7 +201,7 @@ private struct StepsHorizontal: View {
201
201
 
202
202
  let clickable = status == .completed && onPress != nil && !disabled
203
203
 
204
- VStack(alignment: colAlignment, spacing: 0) {
204
+ let columnBody = VStack(alignment: colAlignment, spacing: 0) {
205
205
  if let time = item.time, !time.isEmpty {
206
206
  MomoText(time, typography: .descriptionXsRegular, color: subColor)
207
207
  .multilineTextAlignment(textAlignment)
@@ -250,8 +250,16 @@ private struct StepsHorizontal: View {
250
250
  }
251
251
  }
252
252
  .contentShape(Rectangle())
253
- .onTapGesture {
254
- if clickable { onPress?(item, index) }
253
+
254
+ if clickable {
255
+ // Mirrors Compose's `activeOpacityClickable` press feedback; non-clickable
256
+ // steps render with no press interaction at all.
257
+ SwiftUI.Button(action: { onPress?(item, index) }) {
258
+ columnBody
259
+ }
260
+ .buttonStyle(ActiveOpacityButtonStyle())
261
+ } else {
262
+ columnBody
255
263
  }
256
264
  }
257
265
 
@@ -338,7 +346,7 @@ private struct StepsVertical: View {
338
346
 
339
347
  let clickable = status == .completed && onPress != nil && !disabled
340
348
 
341
- HStack(alignment: .top, spacing: 0) {
349
+ let rowBody = HStack(alignment: .top, spacing: 0) {
342
350
  VStack(spacing: 0) {
343
351
  StepBubble(
344
352
  index: index,
@@ -380,8 +388,16 @@ private struct StepsVertical: View {
380
388
  }
381
389
  .frame(maxWidth: .infinity)
382
390
  .contentShape(Rectangle())
383
- .onTapGesture {
384
- if clickable { onPress?(item, index) }
391
+
392
+ if clickable {
393
+ // Mirrors Compose's `activeOpacityClickable` press feedback; non-clickable
394
+ // steps render with no press interaction at all.
395
+ SwiftUI.Button(action: { onPress?(item, index) }) {
396
+ rowBody
397
+ }
398
+ .buttonStyle(ActiveOpacityButtonStyle())
399
+ } else {
400
+ rowBody
385
401
  }
386
402
  }
387
403
  }
@@ -77,9 +77,11 @@ public struct SuggestAction: View {
77
77
 
78
78
  Spacer().frame(width: Spacing.S)
79
79
 
80
- Icon(source: "navigation_close", size: 24, color: theme.colors.text.default)
81
- .contentShape(Rectangle())
82
- .onTapGesture { onClose() }
80
+ SwiftUI.Button(action: onClose) {
81
+ Icon(source: "navigation_close", size: 24, color: theme.colors.text.default)
82
+ .contentShape(Rectangle())
83
+ }
84
+ .buttonStyle(ActiveOpacityButtonStyle())
83
85
  }
84
86
  .padding(Spacing.M)
85
87
  .frame(maxWidth: .infinity)
@@ -6,6 +6,8 @@ private let swipeActionWidth: CGFloat = 56
6
6
  // MARK: - Swipe
7
7
 
8
8
  public struct Swipe<Content: View>: View {
9
+ @Environment(\.appTheme) private var theme
10
+
9
11
  private let leftActions: [SwipeAction]
10
12
  private let rightActions: [SwipeAction]
11
13
  private let height: CGFloat
@@ -54,7 +56,7 @@ public struct Swipe<Content: View>: View {
54
56
  action: action,
55
57
  height: height,
56
58
  itemRadius: itemRadius,
57
- defaultBackgroundColor: Colors.primary
59
+ defaultBackgroundColor: theme.colors.primary
58
60
  )
59
61
  }
60
62
  Spacer(minLength: 0)
@@ -69,14 +71,14 @@ public struct Swipe<Content: View>: View {
69
71
  action: action,
70
72
  height: height,
71
73
  itemRadius: itemRadius,
72
- defaultBackgroundColor: Colors.error
74
+ defaultBackgroundColor: theme.colors.error.primary
73
75
  )
74
76
  }
75
77
  }
76
78
  }
77
79
 
78
80
  ZStack {
79
- Colors.card
81
+ theme.colors.background.surface
80
82
  content()
81
83
  }
82
84
  .frame(maxWidth: .infinity)
@@ -1,44 +1,69 @@
1
1
  import Foundation
2
2
  import SwiftUI
3
3
 
4
- public struct Switch: View{
4
+ public struct Switch: View {
5
5
  @Binding var value: Bool
6
6
  var disabled: Bool
7
- var onChange: ((Bool)->Void)?
8
-
9
- public init(_ value: Binding<Bool>,disabled: Bool = false, onChange: ((Bool)->Void)? = nil){
7
+ var onChange: ((Bool) -> Void)?
8
+ var title: String?
9
+ var accessibilityId: String?
10
+
11
+ public init(
12
+ _ value: Binding<Bool>,
13
+ disabled: Bool = false,
14
+ onChange: ((Bool) -> Void)? = nil,
15
+ title: String? = "",
16
+ accessibilityId: String? = ""
17
+ ) {
10
18
  self._value = value
11
19
  self.disabled = disabled
12
20
  self.onChange = onChange
21
+ self.title = title
22
+ self.accessibilityId = accessibilityId
23
+ }
24
+
25
+ // Mirrors Kotlin's `backgroundColor`: shared by the track AND the inner dot.
26
+ private var backgroundColor: Color {
27
+ switch (disabled, value) {
28
+ case (true, true): return Colors.green09
29
+ case (true, false): return Colors.black05
30
+ case (false, true): return Colors.green03
31
+ case (false, false): return Colors.black07
32
+ }
33
+ }
34
+
35
+ // Mirrors Kotlin's `circleBackgroundColor` (the outer 14pt thumb circle).
36
+ private var circleColor: Color {
37
+ value ? Colors.black01 : Colors.black03
13
38
  }
14
-
15
-
39
+
40
+ private var automationId: String {
41
+ accessibilityId?.isEmpty == false ? accessibilityId! : "toggle_\(title?.isEmpty == false ? title! : "unknown")_\(value)"
42
+ }
43
+
16
44
  public var body: some View {
17
45
  SwiftUI.Button(action: {
18
- withAnimation{
46
+ withAnimation {
19
47
  value.toggle()
20
48
  onChange?(value)
21
49
  }
22
- }){
23
- HStack{
24
- HStack {
25
- }
26
- .frame(width: 6, height: 6)
27
- .background(value ? Colors.pink03 : Colors.black07)
28
- .clipShape(Circle())
29
- .opacity(disabled ? 0.4 : 1)
30
- }
31
- .frame(width: 14, height: 14)
32
- .background(Colors.black01)
33
- .clipShape(Circle())
34
- .padding(.leading,5)
35
- .padding(.trailing,5)
36
-
37
- }
38
- .disabled(disabled)
39
- .frame(width: 40, height: 24, alignment: value == true ? .trailing : .leading)
40
- .background(value ? Colors.pink03 : Colors.black07)
41
- .clipShape(Capsule())
42
- .opacity(disabled ? 0.4 : 1)
50
+ }) {
51
+ HStack {
52
+ HStack {}
53
+ .frame(width: 6, height: 6)
54
+ .background(backgroundColor)
55
+ .clipShape(Circle())
56
+ }
57
+ .frame(width: 14, height: 14)
58
+ .background(circleColor)
59
+ .clipShape(Circle())
60
+ .padding(.leading, Spacing.XS)
61
+ .padding(.trailing, Spacing.XS)
62
+ }
63
+ .disabled(disabled)
64
+ .frame(width: 38, height: 20, alignment: value ? .trailing : .leading)
65
+ .background(backgroundColor)
66
+ .clipShape(Capsule())
67
+ .accessibilityIdentifier(automationId)
43
68
  }
44
69
  }
@@ -363,13 +363,15 @@ private struct CardTabBar: View {
363
363
  let isActive = selectedIndex == index
364
364
  let iconColor = isActive ? selectedColor : unselectedColor
365
365
 
366
- cardItem(tab: tab, isActive: isActive, iconColor: iconColor)
367
- .frame(maxWidth: .infinity)
368
- .frame(height: isActive ? 44 : 40)
369
- .background(isActive ? theme.colors.background.surface : theme.colors.background.tonal)
370
- .clipShape(UnstyledRoundedRectangle(topLeft: Radius.M, topRight: Radius.M))
371
- .contentShape(Rectangle())
372
- .onTapGesture { onPress(index) }
366
+ SwiftUI.Button(action: { onPress(index) }) {
367
+ cardItem(tab: tab, isActive: isActive, iconColor: iconColor)
368
+ .frame(maxWidth: .infinity)
369
+ .frame(height: isActive ? 44 : 40)
370
+ .background(isActive ? theme.colors.background.surface : theme.colors.background.tonal)
371
+ .clipShape(UnstyledRoundedRectangle(topLeft: Radius.M, topRight: Radius.M))
372
+ .contentShape(Rectangle())
373
+ }
374
+ .buttonStyle(ActiveOpacityButtonStyle())
373
375
  }
374
376
  }
375
377
  .frame(maxWidth: .infinity)
@@ -416,15 +418,17 @@ private struct TabItemView: View {
416
418
  private var textStyle: TypographyStyle { active ? .headerSSemibold : .bodyDefaultRegular }
417
419
 
418
420
  var body: some View {
419
- Group {
420
- if direction == .column {
421
- columnBody
422
- } else {
423
- rowBody
421
+ SwiftUI.Button(action: onPress) {
422
+ Group {
423
+ if direction == .column {
424
+ columnBody
425
+ } else {
426
+ rowBody
427
+ }
424
428
  }
429
+ .contentShape(Rectangle())
425
430
  }
426
- .contentShape(Rectangle())
427
- .onTapGesture { onPress() }
431
+ .buttonStyle(ActiveOpacityButtonStyle())
428
432
  }
429
433
 
430
434
  @ViewBuilder
@@ -52,15 +52,14 @@ let defaultBanner = TrustBannerData(
52
52
 
53
53
  public struct TrustBanner: View {
54
54
  @EnvironmentObject var applicationEnvironment: ApplicationEnvironment
55
-
55
+ @EnvironmentObject private var localize: Localize
56
+
56
57
  var onPress: ((String)->Void)?
57
-
58
+
58
59
  public init(onPress: ((String)->Void)?) {
59
60
  self.onPress = onPress
60
61
  }
61
-
62
- var language: String? = "vi"
63
-
62
+
64
63
  func onPressSecurity() {
65
64
  if (onPress != nil) {
66
65
  onPress!(applicationEnvironment.config?.trustBanner?.urlConfig ?? defaultBanner.urlConfig)
@@ -75,7 +74,7 @@ public struct TrustBanner: View {
75
74
  .scaledToFit()
76
75
  .frame(width: 64, height: 64)
77
76
  VStack(alignment: .leading){
78
- Text(applicationEnvironment.config?.trustBanner?.content[language ?? "vi"] as? String ?? defaultBanner.content[language ?? "vi"])
77
+ Text(applicationEnvironment.config?.trustBanner?.content[localize.currentLanguage] ?? defaultBanner.content[localize.currentLanguage])
79
78
  .foregroundColor(Color(hex: "484848"))
80
79
  .lineLimit(2)
81
80
  .font(.system(size: 13, weight: Font.Weight.regular))
@@ -84,7 +83,7 @@ public struct TrustBanner: View {
84
83
  .padding(.bottom, 8)
85
84
  HStack {
86
85
  HStack(spacing: 0) {
87
- Text(applicationEnvironment.config?.trustBanner?.subContent[language ?? "vi"] as? String ?? defaultBanner.subContent[language ?? "vi"])
86
+ Text(applicationEnvironment.config?.trustBanner?.subContent[localize.currentLanguage] ?? defaultBanner.subContent[localize.currentLanguage])
88
87
  .foregroundColor(Colors.pink03)
89
88
  .font(.system(size: 13, weight: .bold))
90
89
  .ignoreBoldTextSetting()
@@ -462,6 +462,9 @@ private struct TooltipSecondaryButton: View {
462
462
  .padding(.vertical, Spacing.S)
463
463
  }
464
464
  .buttonStyle(.plain)
465
+ // Mirrors Compose's `Modifier.weight(1f, fill = false)` on the secondary button:
466
+ // it yields space to the primary button first under width pressure.
467
+ .layoutPriority(-1)
465
468
  }
466
469
  }
467
470
 
@@ -0,0 +1,19 @@
1
+ import CoreGraphics
2
+
3
+ /// App-wide font-scale preference for the SwiftUI kit. An exported holder the host writes once at
4
+ /// app startup (from the cache-backed `FontScaleProvider`); `scaleSize`/`appFont` read the snapshot.
5
+ /// No realtime: the SwiftUI kit has no navigation container to scope reactive updates, so a startup
6
+ /// snapshot is enough. When `useOSScaleRate` is false the kit applies `userScaleRate` instead of the
7
+ /// OS Dynamic Type factor.
8
+ public final class FontScaleStore {
9
+ public static let shared = FontScaleStore()
10
+ private init() {}
11
+
12
+ public private(set) var userScaleRate: CGFloat = 1
13
+ public private(set) var useOSScaleRate: Bool = true
14
+
15
+ public func update(userScaleRate: CGFloat, useOSScaleRate: Bool) {
16
+ self.userScaleRate = userScaleRate
17
+ self.useOSScaleRate = useOSScaleRate
18
+ }
19
+ }
@@ -1,6 +1,9 @@
1
1
  import SwiftUI
2
2
 
3
3
  public func scaleSize(_ size: CGFloat, _ scaleRate: CGFloat? = nil) -> CGFloat {
4
+ if !FontScaleStore.shared.useOSScaleRate {
5
+ return size * FontScaleStore.shared.userScaleRate
6
+ }
4
7
  let defaultScreenSize: CGFloat = 375
5
8
  let maxFontScale: CGFloat = scaleRate ?? 1.5
6
9
  let maxDeviceScale: CGFloat = 5
@@ -11,13 +11,16 @@ public extension View {
11
11
 
12
12
  public extension Font {
13
13
  static func appFont(size: CGFloat) -> Font {
14
+ if !FontScaleStore.shared.useOSScaleRate {
15
+ return Font.system(size: size * FontScaleStore.shared.userScaleRate)
16
+ }
14
17
  let defaultScreenSize: CGFloat = 375
15
18
  let maxFontScale: CGFloat = 1.5
16
19
  let maxDeviceScale: CGFloat = 5
17
-
20
+
18
21
  let deviceWidth = UIScreen.main.bounds.width
19
22
  let deviceScale = deviceWidth / defaultScreenSize
20
-
23
+
21
24
  let defaultFont = UIFont.systemFont(ofSize: UIFont.labelFontSize)
22
25
  let scaledFont = UIFontMetrics.default.scaledFont(for: defaultFont)
23
26
  let fontScale = scaledFont.pointSize / defaultFont.pointSize
@@ -34,7 +37,7 @@ public extension Font {
34
37
 
35
38
  return Font.system(size: fontSize)
36
39
  }
37
-
40
+
38
41
  // New supported typography styles
39
42
  static let headline_default_bold = appFont(size: 24).weight(.bold)
40
43
  static let header_m_bold = appFont(size: 18).weight(.bold)
@@ -52,7 +55,7 @@ public extension Font {
52
55
  static let action_s_bold = appFont(size: 14).weight(.bold)
53
56
  static let action_xs_bold = appFont(size: 12).weight(.bold)
54
57
  static let action_xxs_bold = appFont(size: 10).weight(.bold)
55
-
58
+
56
59
  // Legacy styles
57
60
  static let headline_default = appFont(size: 28).weight(.semibold)
58
61
  static let headline_s = appFont(size: 24).weight(.semibold)
@@ -77,7 +80,7 @@ public extension Font {
77
80
  static let action_xxs = appFont(size: 10).weight(.bold)
78
81
  static let action_xs = appFont(size: 12).weight(.bold)
79
82
  static let action_s = appFont(size: 15).weight(.bold)
80
-
83
+
81
84
  // deprecated
82
85
  static let h1 = appFont(size: 36).weight(.semibold) //headline_xl
83
86
  static let h2 = appFont(size: 32).weight(.semibold)
@@ -172,12 +172,3 @@ private struct UploaderImageItem: View {
172
172
  .buttonStyle(ActiveOpacityButtonStyle())
173
173
  }
174
174
  }
175
-
176
- // MARK: - Active opacity button style
177
-
178
- private struct ActiveOpacityButtonStyle: ButtonStyle {
179
- func makeBody(configuration: Configuration) -> some View {
180
- configuration.label
181
- .opacity(configuration.isPressed ? 0.5 : 1)
182
- }
183
- }
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'MoMoUIKits'
3
- s.version = '0.162.2-sp.7'
3
+ s.version = '0.162.2-sp.8'
4
4
  s.summary = 'MoMoUIKits for iOS'
5
5
  s.homepage = 'https://momo.vn'
6
6
  s.license = { :type => 'MIT' }
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'MoMoUIKitsDemo'
3
- s.version = '0.162.2-sp.7'
3
+ s.version = '0.162.2-sp.8'
4
4
  s.summary = 'Demo browser for MoMoUIKits SwiftUI components'
5
5
  s.homepage = 'https://momo.vn'
6
6
  s.license = { :type => 'MIT' }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.162.2-sp.7-debug",
3
+ "version": "0.162.2-sp.8-debug",
4
4
  "private": false,
5
5
  "dependencies": {},
6
6
  "devDependencies": {},
@@ -1,2 +0,0 @@
1
- // Resource bundle lookup lives in Extensions/Color++.swift so existing Pods
2
- // projects that already include the color extension can resolve Color.momoAsset.