@momo-kits/native-kits 0.168.1-beta.1 → 0.168.1-beta.10-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 (161) hide show
  1. package/CLAUDE.md +7 -5
  2. package/build.gradle.kts +11 -0
  3. package/compose/build.gradle.kts +198 -0
  4. package/compose/build.gradle.kts.backup +198 -0
  5. package/compose/compose.podspec +47 -0
  6. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +20 -0
  7. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +6 -0
  8. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +12 -0
  9. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
  10. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +153 -0
  11. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +6 -0
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +110 -0
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/application/DesignSystemKits.kt +62 -0
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +1071 -0
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +56 -0
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +81 -0
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +338 -0
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +175 -0
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +357 -0
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +115 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +89 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +128 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +209 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +542 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +49 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +86 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +125 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +231 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +189 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +478 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +114 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +265 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +235 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +223 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +265 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +185 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +343 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +84 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +361 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +108 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +308 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +59 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +21 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +90 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +330 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +220 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +473 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +122 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +207 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +92 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +560 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +125 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +207 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +501 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +176 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +182 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +193 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +236 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +180 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +325 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +17 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +16 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +194 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +287 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +54 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +50 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +306 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +41 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +52 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +66 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +104 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +48 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +338 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +58 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +137 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +116 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +205 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +399 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +8 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +732 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +148 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +35 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +228 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +217 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +97 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +377 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +169 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +455 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +105 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +106 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +74 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +399 -0
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +39 -0
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +363 -0
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +192 -0
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +133 -0
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +127 -0
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +12 -0
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +91 -0
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +74 -0
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +20 -0
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +55 -0
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +15 -0
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +118 -0
  121. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +42 -0
  122. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +45 -0
  123. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +32 -0
  124. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +38 -0
  125. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
  126. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +217 -0
  127. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +138 -0
  128. package/gradle/libs.versions.toml +69 -0
  129. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  130. package/gradle/wrapper/gradle-wrapper.properties +8 -0
  131. package/gradle.properties +26 -0
  132. package/gradlew +252 -0
  133. package/gradlew.bat +94 -0
  134. package/ios/Application/ApplicationEnvironment.swift +7 -6
  135. package/ios/Application/DesignSystemKits.swift +100 -0
  136. package/ios/Application/DesignSystemKitsPayload.swift +68 -0
  137. package/ios/Badge/BadgeRibbon.swift +8 -1
  138. package/ios/Extensions/Color++.swift +2 -4
  139. package/ios/Input/Input.swift +13 -3
  140. package/ios/Input/InputPhoneNumber.swift +1 -3
  141. package/ios/Input/InputSearch.swift +1 -2
  142. package/ios/Input/InputTextArea.swift +5 -3
  143. package/ios/InputMoney/InputMoney.swift +6 -7
  144. package/ios/Layout/ScreenLayout.swift +46 -11
  145. package/ios/Navigation/BottomTab/DuoBarCompression.swift +2 -3
  146. package/ios/Navigation/BottomTab/DuoTabBar.swift +94 -69
  147. package/ios/Navigation/Component/HeaderBackground.swift +22 -1
  148. package/ios/Navigation/StackScreen.swift +3 -7
  149. package/ios/Popup/PopupLayout.swift +0 -2
  150. package/ios/Stepper/Stepper.swift +1 -2
  151. package/ios/Template/TrustBanner/TrustBanner.swift +4 -2
  152. package/ios/Typography/FontScale.swift +14 -11
  153. package/ios/Typography/Text.swift +86 -12
  154. package/ios/Typography/Typography.swift +2 -2
  155. package/ios/native-kits.podspec +1 -1
  156. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  157. package/ios-demo/README.md +120 -0
  158. package/package.json +1 -1
  159. package/settings.gradle.kts +64 -0
  160. package/ios/Typography/FontScaleStore.swift +0 -58
  161. package/ios/Typography/KitDesignSystem.swift +0 -17
@@ -3,7 +3,7 @@
3
3
  // MoMoUIKits
4
4
  //
5
5
  // iPhone Duo tab bar, port of RN `BottomTab/DuoTabBar.tsx` (Figma Fold-Design-System MT1/MT2):
6
- // a glass rail in the side bar, or a floating glass bar when unfolded portrait.
6
+ // a rail in the side bar, or a floating bar when unfolded portrait.
7
7
  //
8
8
 
9
9
  import SwiftUI
@@ -16,12 +16,15 @@ private let railGap = Spacing.XXS
16
16
  // selection bubble overflows the 48 rail cell by 5 above and below (Figma MT2)
17
17
  private let railBubbleWidth: CGFloat = 44
18
18
  private let railBubbleHeight: CGFloat = 58
19
- let duoFloatingTabBarHeight: CGFloat = 62
19
+ private let floatingHeight = DuoMetrics.floatingTabBarHeight
20
20
  private let floatingPadding = Spacing.XS
21
- private let floatingQrSize: CGFloat = 44
22
- // floating bar spans 6 of the 8 portrait grid columns, like the content
23
- private let gridColumns: CGFloat = 8
24
- private let gridSpan: CGFloat = 6
21
+ // the system bar sizes its pill to the tabs instead of stretching it across the display
22
+ private let floatingItemWidth: CGFloat = 80
23
+ // while pressed the selection bubble grows into a lens past the pill's edges
24
+ private let lensScaleX: CGFloat = 1.2
25
+ private let lensScaleY: CGFloat = 1.3
26
+ // Figma Home-2026 tab bar "Selection": brand pink at 8%
27
+ private let selectionTintOpacity: Double = 0x14 / 255
25
28
  private let tabSpring = Animation.interpolatingSpring(mass: 0.8, stiffness: 220, damping: 18)
26
29
 
27
30
  /// Room tab screens leave for the Duo tab bar, provided by BottomTab to its tab StackScreens.
@@ -51,47 +54,34 @@ func duoRailHeight(itemCount: Int, hasQr: Bool, compressed: Bool = false) -> CGF
51
54
  }
52
55
 
53
56
  extension ScreenLayout {
57
+ /// Overlaps the home indicator inset like the system tab bar (21pt above the bottom with a 34pt inset).
58
+ var duoFloatingTabBarBottom: CGFloat {
59
+ max(insets.bottom - DuoMetrics.floatingTabBarInsetOverlap, Spacing.S)
60
+ }
61
+
54
62
  func duoTabBarInsets(itemCount: Int, hasFloatingButton: Bool, tabBarCompressed: Bool = false) -> DuoTabBarInsets {
55
63
  guard isIPhoneDuo else { return DuoTabBarInsets() }
56
64
  guard let sideBar else {
57
- return DuoTabBarInsets(overlay: duoFloatingTabBarHeight + Spacing.M)
65
+ // overlay is measured from the bottom safe area, the bar reaches into it
66
+ return DuoTabBarInsets(overlay: floatingHeight + duoFloatingTabBarBottom - insets.bottom)
58
67
  }
59
68
  let rail = duoRailHeight(itemCount: itemCount, hasQr: hasFloatingButton, compressed: tabBarCompressed)
60
69
  return DuoTabBarInsets(sideBarReserve: sideBar.bottom + rail + DuoBarCompression.groupGap)
61
70
  }
62
71
  }
63
72
 
64
- /// Glass on iOS 26, a system blur before it (RN GlassView's fallback).
65
- struct DuoBarMaterial<S: Shape>: ViewModifier {
73
+ /// RN `BarMaterial`: surface with a 1pt border.
74
+ struct DuoBarMaterial<S: InsettableShape>: ViewModifier {
66
75
  let shape: S
67
- var visible: Bool = true
68
-
69
- func body(content: Content) -> some View {
70
- content.background(material.allowsHitTesting(false))
71
- }
72
76
 
73
- @ViewBuilder
74
- private var material: some View {
75
- #if compiler(>=6.2)
76
- if #available(iOS 26.0, *) {
77
- // glass materializes by toggling its effect, it does not fade with opacity
78
- Color.clear
79
- .glassEffect(visible ? .regular : .identity, in: shape)
80
- .shadow(color: Color.black.opacity(visible ? 0.16 : 0), radius: 16, x: 0, y: 6)
81
- .animation(.easeInOut(duration: 0.25), value: visible)
82
- } else {
83
- blur
84
- }
85
- #else
86
- blur
87
- #endif
88
- }
77
+ @Environment(\.appTheme) private var theme
89
78
 
90
- private var blur: some View {
91
- shape.fill(.regularMaterial)
92
- .shadow(color: Color.black.opacity(0.16), radius: 16, x: 0, y: 6)
93
- .opacity(visible ? 1 : 0)
94
- .animation(.easeInOut(duration: 0.25), value: visible)
79
+ func body(content: Content) -> some View {
80
+ content.background(
81
+ shape.fill(theme.colors.background.surface)
82
+ .overlay(shape.strokeBorder(theme.colors.border.default, lineWidth: 1))
83
+ .allowsHitTesting(false)
84
+ )
95
85
  }
96
86
  }
97
87
 
@@ -126,7 +116,7 @@ private struct DuoRailTabBar: View {
126
116
  let onTabSelected: (Int) -> Void
127
117
  let compression: DuoBarCompression
128
118
 
129
- @Environment(\.appTheme) private var theme
119
+ @State private var pressedIndex: Int?
130
120
 
131
121
  private var isRight: Bool { sideBar.edge == .right }
132
122
 
@@ -157,15 +147,15 @@ private struct DuoRailTabBar: View {
157
147
  .ignoresSafeArea()
158
148
  }
159
149
 
160
- /// Glass column of tab items with the sliding selection bubble.
150
+ /// Column of icon-only tab items with the sliding selection bubble.
161
151
  private var rail: some View {
162
152
  ZStack(alignment: .top) {
163
- Capsule()
164
- .fill(theme.colors.background.selected)
153
+ DuoSelectionMaterial(lens: pressedIndex != nil)
165
154
  .frame(width: railBubbleWidth, height: railBubbleHeight)
166
155
  .offset(y: railPadding - (railBubbleHeight - itemSize) / 2
167
- + CGFloat(selectedIndex) * (itemSize + railGap))
156
+ + CGFloat(pressedIndex ?? selectedIndex) * (itemSize + railGap))
168
157
  .animation(tabSpring, value: selectedIndex)
158
+ .animation(tabSpring, value: pressedIndex)
169
159
 
170
160
  VStack(spacing: railGap) {
171
161
  ForEach(items.indices, id: \.self) { index in
@@ -177,19 +167,19 @@ private struct DuoRailTabBar: View {
177
167
  .frame(width: itemSize, height: itemSize)
178
168
  .contentShape(Rectangle())
179
169
  }
180
- .buttonStyle(.plain)
170
+ .buttonStyle(DuoLensPressStyle(index: index, pressedIndex: $pressedIndex))
181
171
  .accessibilityLabel(items[index].label)
182
172
  }
183
173
  }
184
174
  .padding(.vertical, railPadding)
185
175
  }
186
176
  .frame(width: itemSize)
187
- .modifier(DuoBarMaterial(shape: RoundedRectangle(cornerRadius: Radius.XL)))
177
+ .modifier(DuoBarMaterial(shape: Capsule()))
188
178
  .accessibilityIdentifier("bottom_tab_bar")
189
179
  }
190
180
  }
191
181
 
192
- /// Floating labelled bar for the unfolded portrait display, QR in the middle cell (Figma MT1-M).
182
+ /// Floating labelled bar for the unfolded portrait display, QR pinned in its own platter beside it.
193
183
  private struct DuoFloatingTabBar: View {
194
184
  let items: [BottomTabItem]
195
185
  let floatingButton: BottomTabFloatingButton?
@@ -198,45 +188,48 @@ private struct DuoFloatingTabBar: View {
198
188
 
199
189
  @Environment(\.screenLayout) private var layout
200
190
  @Environment(\.appTheme) private var theme
191
+ @State private var pressedIndex: Int?
201
192
 
202
193
  private var barWidth: CGFloat {
203
- let columnWidth = (layout.width - 2 * Spacing.M - (gridColumns - 1) * Spacing.M) / gridColumns
204
- return columnWidth * gridSpan + (gridSpan - 1) * Spacing.M
194
+ let margins = layout.insets.leading + layout.insets.trailing + 2 * DuoMetrics.floatingTabBarMargin
195
+ let qr = floatingButton == nil ? 0 : floatingHeight + Spacing.S
196
+ let preferred = CGFloat(items.count) * floatingItemWidth + 2 * floatingPadding
197
+ return max(min(preferred, layout.width - margins - qr), 0)
205
198
  }
206
199
 
207
- private var useQr: Bool { floatingButton != nil && items.count % 2 == 0 }
208
- private var middle: Int { items.count / 2 }
209
- private var cellCount: Int { items.count + (useQr ? 1 : 0) }
210
- private var cellWidth: CGFloat { (barWidth - floatingPadding * 2) / CGFloat(max(cellCount, 1)) }
211
- private var visualIndex: Int { useQr && selectedIndex >= middle ? selectedIndex + 1 : selectedIndex }
200
+ private var cellWidth: CGFloat { (barWidth - floatingPadding * 2) / CGFloat(max(items.count, 1)) }
212
201
 
213
202
  var body: some View {
203
+ HStack(spacing: Spacing.S) {
204
+ bar
205
+ if let floatingButton {
206
+ DuoQrButton(data: floatingButton, size: floatingHeight)
207
+ .shadow(color: Color.black.opacity(0.16), radius: 16, x: 0, y: 6)
208
+ }
209
+ }
210
+ .padding(.bottom, layout.duoFloatingTabBarBottom)
211
+ .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
212
+ .ignoresSafeArea()
213
+ }
214
+
215
+ private var bar: some View {
214
216
  ZStack(alignment: .leading) {
215
- Capsule()
216
- .fill(theme.colors.background.selected)
217
+ DuoSelectionMaterial(lens: pressedIndex != nil)
217
218
  .frame(width: cellWidth)
218
- .offset(x: CGFloat(visualIndex) * cellWidth)
219
- .animation(tabSpring, value: visualIndex)
219
+ .offset(x: CGFloat(pressedIndex ?? selectedIndex) * cellWidth)
220
+ .animation(tabSpring, value: selectedIndex)
221
+ .animation(tabSpring, value: pressedIndex)
220
222
 
221
223
  HStack(spacing: 0) {
222
- ForEach(0..<cellCount, id: \.self) { cell in
223
- if useQr && cell == middle, let floatingButton {
224
- DuoQrButton(data: floatingButton, size: floatingQrSize)
225
- .frame(width: cellWidth)
226
- } else {
227
- let index = useQr && cell > middle ? cell - 1 : cell
228
- tabCell(index)
229
- }
224
+ ForEach(items.indices, id: \.self) { index in
225
+ tabCell(index)
230
226
  }
231
227
  }
232
228
  }
233
229
  .padding(floatingPadding)
234
- .frame(width: barWidth, height: duoFloatingTabBarHeight)
230
+ .frame(width: barWidth, height: floatingHeight)
235
231
  .modifier(DuoBarMaterial(shape: Capsule()))
236
232
  .accessibilityIdentifier("bottom_tab_bar")
237
- .padding(.bottom, layout.insets.bottom + Spacing.M)
238
- .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
239
- .ignoresSafeArea()
240
233
  }
241
234
 
242
235
  private func tabCell(_ index: Int) -> some View {
@@ -247,20 +240,52 @@ private struct DuoFloatingTabBar: View {
247
240
  MomoText(
248
241
  items[index].label,
249
242
  typography: .labelXsMedium,
250
- color: selected ? theme.colors.primary : theme.colors.text.default,
243
+ color: selected ? theme.colors.primary : theme.colors.text.hint,
251
244
  textAlign: .center,
252
245
  maxLines: 1
253
246
  )
247
+ // like the system tab bar the label keeps its design size; a constant snapshot, nothing to observe
248
+ .environment(\.momoFontScale, FontScale(userScaleRate: 1, useOSScaleRate: false))
254
249
  }
255
250
  .frame(width: cellWidth)
256
251
  .frame(maxHeight: .infinity)
257
252
  .contentShape(Rectangle())
258
253
  }
259
- .buttonStyle(.plain)
254
+ .buttonStyle(DuoLensPressStyle(index: index, pressedIndex: $pressedIndex))
260
255
  .accessibilityLabel(items[index].label)
261
256
  }
262
257
  }
263
258
 
259
+ /// Pink tinted capsule under the selected tab; while pressed it grows into a lens (80x54 to about 96x70).
260
+ private struct DuoSelectionMaterial: View {
261
+ let lens: Bool
262
+
263
+ @Environment(\.appTheme) private var theme
264
+
265
+ var body: some View {
266
+ Capsule()
267
+ .fill(theme.colors.primary.opacity(selectionTintOpacity))
268
+ .scaleEffect(x: lens ? lensScaleX : 1, y: lens ? lensScaleY : 1)
269
+ .allowsHitTesting(false)
270
+ }
271
+ }
272
+
273
+ /// Tracks the finger so the selection lens jumps to the pressed tab before it is selected.
274
+ private struct DuoLensPressStyle: ButtonStyle {
275
+ let index: Int
276
+ @Binding var pressedIndex: Int?
277
+
278
+ func makeBody(configuration: Configuration) -> some View {
279
+ configuration.label.onChange(of: configuration.isPressed) { pressed in
280
+ if pressed {
281
+ pressedIndex = index
282
+ } else if pressedIndex == index {
283
+ pressedIndex = nil
284
+ }
285
+ }
286
+ }
287
+ }
288
+
264
289
  private struct DuoTabIcon: View {
265
290
  let item: BottomTabItem
266
291
  let selected: Bool
@@ -274,7 +299,7 @@ private struct DuoTabIcon: View {
274
299
  }
275
300
 
276
301
  var body: some View {
277
- Icon(source: item.icon, size: iconSize, color: selected ? theme.colors.primary : theme.colors.text.default)
302
+ Icon(source: item.icon, size: iconSize, color: selected ? theme.colors.primary : theme.colors.text.hint)
278
303
  .overlay(alignment: .topTrailing) {
279
304
  if let badgeLabel, !badgeLabel.isEmpty {
280
305
  Badge(label: badgeLabel).offset(x: Spacing.S, y: -Spacing.XS)
@@ -90,6 +90,27 @@ private let duoGradientExtra: CGFloat = 52
90
90
  // scroll distance over which the extended gradient collapses to the header
91
91
  private let duoExtendedCollapseDistance: CGFloat = 100
92
92
 
93
+ // scroll distance over which the bar fades in
94
+ private let duoBarFadeDistance: CGFloat = 16
95
+
96
+ /// Port of RN `DuoGlassBackground`: translucent surface with a hairline, shown once the content
97
+ /// scrolls `fadeStart` under the header.
98
+ struct DuoHeaderBar: View {
99
+ let scrollOffset: CGFloat
100
+ var fadeStart: CGFloat = 0
101
+
102
+ @Environment(\.appTheme) private var theme
103
+
104
+ var body: some View {
105
+ theme.colors.background.surface.opacity(0.8)
106
+ .overlay(alignment: .bottom) {
107
+ theme.colors.border.default.frame(height: 0.5)
108
+ }
109
+ .opacity(min(max((scrollOffset - fadeStart) / duoBarFadeDistance, 0), 1))
110
+ .allowsHitTesting(false)
111
+ }
112
+ }
113
+
93
114
  /// Port of RN `DuoScrollGradient`: with the glass header the content scrolls under the bar, so the
94
115
  /// header gradient is drawn under it. Compose draws this inside `HeaderBackground`.
95
116
  struct DuoScrollGradient: View {
@@ -114,7 +135,7 @@ struct DuoScrollGradient: View {
114
135
  let progress = min(scroll / duoExtendedCollapseDistance, 1)
115
136
  gradient
116
137
  .frame(height: headerHeight + (extended ? duoGradientExtra * (1 - progress) : 0))
117
- .opacity(1 - min(scroll / duoGradientExtra, 1))
138
+ .opacity(Double(1 - min(scroll / duoGradientExtra, 1)))
118
139
  }
119
140
  }
120
141
  .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
@@ -403,11 +403,8 @@ public struct StackScreen<Content: View>: View {
403
403
  .background(alignment: .top) {
404
404
  Group {
405
405
  if layout.sideBar != nil {
406
- // glass shows once the banner has scrolled under the header
407
- Color.clear.modifier(DuoBarMaterial(
408
- shape: Rectangle(),
409
- visible: scrollOffset > heroGlassStart(animatedHeader)
410
- ))
406
+ // the bar shows once the banner has scrolled under the header
407
+ DuoHeaderBar(scrollOffset: scrollOffset, fadeStart: heroGlassStart(animatedHeader))
411
408
  } else {
412
409
  HeaderBarBackground(opacity: opacity)
413
410
  }
@@ -457,8 +454,7 @@ public struct StackScreen<Content: View>: View {
457
454
 
458
455
  header
459
456
  .background(
460
- Color.clear
461
- .modifier(DuoBarMaterial(shape: Rectangle(), visible: scrollOffset > 0))
457
+ DuoHeaderBar(scrollOffset: scrollOffset)
462
458
  .edgesIgnoringSafeArea([.top, .horizontal])
463
459
  )
464
460
  .offset(y: -headerHide)
@@ -5,8 +5,6 @@ import SwiftUI
5
5
  private let duoPopupMaxWidth: CGFloat = 440
6
6
 
7
7
  extension ScreenLayout {
8
- var isDuoDevice: Bool { isIPhoneDuoDevice(windowSize: CGSize(width: width, height: height)) }
9
-
10
8
  /// Card width cap (Compose `popupMaxWidth`); unbounded off iPhone Duo, where the popup's own padding sets the width.
11
9
  var popupMaxWidth: CGFloat {
12
10
  isDuoDevice ? duoPopupMaxWidth : .infinity
@@ -84,7 +84,6 @@ private struct StepperButton: View {
84
84
 
85
85
  private struct StepperNumberView: View {
86
86
  @Environment(\.appTheme) private var theme
87
- @Environment(\.momoFontScale) private var fontScale
88
87
 
89
88
  @Binding var text: String
90
89
  var size: StepperSize
@@ -106,7 +105,7 @@ private struct StepperNumberView: View {
106
105
  MomoText(text, typography: .descriptionDefaultRegular, color: textColor)
107
106
  }
108
107
  }
109
- .font(.system(size: fontScale(12)))
108
+ .kitFont(size: 12)
110
109
  .ignoreBoldTextSetting()
111
110
  .foregroundColor(textColor)
112
111
  // Compose's min width includes the horizontal padding.
@@ -11,7 +11,7 @@ import SDWebImageSwiftUI
11
11
 
12
12
  let jsonUrl = "https://static.momocdn.net/app/json/component-kits/design_system.json"
13
13
 
14
- public struct TrustBannerData: Decodable {
14
+ public struct TrustBannerData: Decodable, Equatable {
15
15
  public let content: [String: String]
16
16
  public let subContent: [String: String]
17
17
  public let pciImage: String?
@@ -85,6 +85,7 @@ let defaultBanner = TrustBannerData(
85
85
  public struct TrustBanner: View {
86
86
  @Environment(\.applicationEnvironment) var applicationEnvironment
87
87
  @Environment(\.localize) private var localize
88
+ @Environment(\.designSystemKitsConfigs) private var designSystemKitsConfigs
88
89
 
89
90
  var onPress: ((String)->Void)?
90
91
  private let serviceName: String
@@ -104,7 +105,8 @@ public struct TrustBanner: View {
104
105
  }
105
106
 
106
107
  private var banner: TrustBannerData {
107
- applicationEnvironment.config?.trustBanner ?? defaultBanner
108
+ // Container config wins, else the host-pushed DesignSystemKits config (Compose parity).
109
+ (applicationEnvironment.config ?? designSystemKitsConfigs.designSystemConfig)?.trustBanner ?? defaultBanner
108
110
  }
109
111
 
110
112
  func onPressSecurity() {
@@ -52,7 +52,7 @@ public struct FontScale: Equatable {
52
52
  }
53
53
 
54
54
  /// A host-pushed mini-app context wins per field, matching Compose's
55
- /// `context?.useOSScaleRate ?: KitFontScale.useOSScaleRate`.
55
+ /// `context?.useOSScaleRate ?: DesignSystemKits.getConfigs().useOSScaleRate`.
56
56
  public func overriding(userScaleRate: CGFloat?, useOSScaleRate: Bool?) -> FontScale {
57
57
  guard userScaleRate != nil || useOSScaleRate != nil else { return self }
58
58
  return FontScale(
@@ -66,7 +66,7 @@ public struct FontScale: Equatable {
66
66
  private struct FontScaleKey: EnvironmentKey {
67
67
  /// Computed, never stored: a bare `UIHostingController` root that never got `.momoFontScale()`
68
68
  /// still reads the live store instead of a value frozen at first access.
69
- static var defaultValue: FontScale { FontScaleStore.shared.snapshot }
69
+ static var defaultValue: FontScale { DesignSystemKits.shared.fontScale }
70
70
  }
71
71
 
72
72
  public extension EnvironmentValues {
@@ -77,9 +77,10 @@ public extension EnvironmentValues {
77
77
  }
78
78
 
79
79
  public extension View {
80
- /// Injects a Dynamic-Type-observing font scale and re-renders this subtree on change.
80
+ /// Injects a Dynamic-Type-observing font scale plus `\.designSystemKitsConfigs` (whitelist, remote config)
81
+ /// and re-renders this subtree on change.
81
82
  /// Use at every `UIHostingController` root that is not inside a `NavigationContainer`.
82
- func momoFontScale(_ store: FontScaleStore = .shared, context: MiniAppContext? = nil) -> some View {
83
+ func momoFontScale(_ store: DesignSystemKits = .shared, context: MiniAppContext? = nil) -> some View {
83
84
  modifier(MomoFontScaleModifier(store: store, context: context))
84
85
  }
85
86
  }
@@ -87,17 +88,19 @@ public extension View {
87
88
  /// `@ObservedObject` is load-bearing, same as `MomoLocalizeModifier`: `@Environment(\.momoFontScale)`
88
89
  /// only invalidates when the boxed snapshot changes, which requires *this* body to re-run on publish.
89
90
  private struct MomoFontScaleModifier: ViewModifier {
90
- @ObservedObject var store: FontScaleStore
91
+ @ObservedObject var store: DesignSystemKits
91
92
  let context: MiniAppContext?
92
93
 
93
94
  func body(content: Content) -> some View {
94
- content.environment(
95
- \.momoFontScale,
96
- store.snapshot.overriding(
97
- userScaleRate: context?.userScaleRate,
98
- useOSScaleRate: context?.useOSScaleRate
95
+ content
96
+ .environment(
97
+ \.momoFontScale,
98
+ store.fontScale.overriding(
99
+ userScaleRate: context?.userScaleRate,
100
+ useOSScaleRate: context?.useOSScaleRate
101
+ )
99
102
  )
100
- )
103
+ .environment(\.designSystemKitsConfigs, store.getConfigs())
101
104
  }
102
105
  }
103
106
  // AI-GENERATED END: reactive font-scale snapshot injected through the environment
@@ -4,7 +4,7 @@ import SwiftUI
4
4
  /// free functions). Inside a SwiftUI view prefer `@Environment(\.momoFontScale)` so the view
5
5
  /// re-renders when Dynamic Type or the host preference changes.
6
6
  public func scaleSize(_ size: CGFloat) -> CGFloat {
7
- FontScaleStore.shared.snapshot(size)
7
+ DesignSystemKits.shared.fontScale(size)
8
8
  }
9
9
 
10
10
  @available(*, deprecated, message: "Max font scale is fixed at 1.5; this override is no longer applied. Drop the second argument.")
@@ -105,10 +105,10 @@ private enum MomoFontFace {
105
105
  }
106
106
 
107
107
  /// Port of Compose `getFontFamily`; SF Pro Text is the iOS system font, so the legacy family is `.system`.
108
- private func momoFontFace(family: String, weight: Font.Weight) -> MomoFontFace? {
108
+ private func momoFontFace(family: String, weight: Font.Weight, isWhiteList: Bool) -> MomoFontFace? {
109
109
  let isNewFamily = family == "MomoTrustSans" || family == headerFontFamily
110
110
  // Outside the whitelist the new DS families drop to the legacy font, as before DS-791.
111
- if family == "SFProText" || (isNewFamily && !KitDesignSystem.shared.isWhiteList) { return .system }
111
+ if family == "SFProText" || (isNewFamily && !isWhiteList) { return .system }
112
112
  // single-file families (Compose maps every weight to the same .otf)
113
113
  if family == headerFontFamily || family == "MoMoSignature" { return .named(family) }
114
114
  guard family == "MomoTrustSans" else { return nil }
@@ -127,8 +127,14 @@ private func momoFontFace(family: String, weight: Font.Weight) -> MomoFontFace?
127
127
  /// Header title family (Compose `HEADER_FONT_FAMILY`), whitelist only like the default font.
128
128
  let headerFontFamily = "MoMoTrustDisplay"
129
129
 
130
- private func momoFont(size: CGFloat, weight: Font.Weight, family: String, fallbackFamily: String? = nil) -> Font {
131
- switch momoFontFace(family: family, weight: weight) {
130
+ private func momoFont(
131
+ size: CGFloat,
132
+ weight: Font.Weight,
133
+ family: String,
134
+ fallbackFamily: String? = nil,
135
+ isWhiteList: Bool
136
+ ) -> Font {
137
+ switch momoFontFace(family: family, weight: weight, isWhiteList: isWhiteList) {
132
138
  case .system:
133
139
  return .system(size: size, weight: weight)
134
140
  case .named(let name) where UIFont(name: name, size: size) != nil:
@@ -136,15 +142,15 @@ private func momoFont(size: CGFloat, weight: Font.Weight, family: String, fallba
136
142
  default:
137
143
  // Compose falls back to the default font file when a family is missing
138
144
  if let fallbackFamily, fallbackFamily != family {
139
- return momoFont(size: size, weight: weight, family: fallbackFamily)
145
+ return momoFont(size: size, weight: weight, family: fallbackFamily, isWhiteList: isWhiteList)
140
146
  }
141
147
  return .system(size: size, weight: weight)
142
148
  }
143
149
  }
144
150
 
145
151
  // lineHeight is identical across weights of a family, so the regular face is enough.
146
- private func momoLineHeight(size: CGFloat, family: String, fallbackFamily: String? = nil) -> CGFloat {
147
- switch momoFontFace(family: family, weight: .regular) {
152
+ private func momoLineHeight(size: CGFloat, family: String, fallbackFamily: String? = nil, isWhiteList: Bool) -> CGFloat {
153
+ switch momoFontFace(family: family, weight: .regular, isWhiteList: isWhiteList) {
148
154
  case .system:
149
155
  break
150
156
  case .named(let name):
@@ -152,15 +158,71 @@ private func momoLineHeight(size: CGFloat, family: String, fallbackFamily: Strin
152
158
  fallthrough
153
159
  case nil:
154
160
  if let fallbackFamily, fallbackFamily != family {
155
- return momoLineHeight(size: size, family: fallbackFamily)
161
+ return momoLineHeight(size: size, family: fallbackFamily, isWhiteList: isWhiteList)
156
162
  }
157
163
  }
158
164
  return UIFont.systemFont(ofSize: size).lineHeight
159
165
  }
160
166
 
167
+ /// UIKit counterpart of `momoFont`, for text that is not a `MomoText` (UITextField/UITextView, text measuring).
168
+ func momoUIFont(size: CGFloat, weight: UIFont.Weight, family: String, isWhiteList: Bool) -> UIFont {
169
+ guard case .named(let name) = momoFontFace(family: family, weight: Font.Weight(weight), isWhiteList: isWhiteList),
170
+ let font = UIFont(name: name, size: size) else {
171
+ return .systemFont(ofSize: size, weight: weight)
172
+ }
173
+ return font
174
+ }
175
+
176
+ private extension Font.Weight {
177
+ init(_ weight: UIFont.Weight) {
178
+ switch weight {
179
+ case .ultraLight: self = .ultraLight
180
+ case .thin: self = .thin
181
+ case .light: self = .light
182
+ case .medium: self = .medium
183
+ case .semibold: self = .semibold
184
+ case .bold: self = .bold
185
+ case .heavy: self = .heavy
186
+ case .black: self = .black
187
+ default: self = .regular
188
+ }
189
+ }
190
+ }
191
+
192
+ /// Gives input text the same family as `MomoText` (Compose's `getFontFamily`), e.g. a TextField
193
+ /// next to a `MomoText` placeholder. `size` is unscaled; the environment font scale is applied here.
194
+ private struct KitFontModifier: ViewModifier {
195
+ @Environment(\.appTheme) private var theme
196
+ @Environment(\.momoFontScale) private var fontScale
197
+ @Environment(\.designSystemKitsConfigs) private var designSystemKitsConfigs
198
+ let size: CGFloat
199
+ let weight: Font.Weight
200
+
201
+ func body(content: Content) -> some View {
202
+ content.font(momoFont(
203
+ size: fontScale(size),
204
+ weight: weight,
205
+ family: theme.font,
206
+ isWhiteList: designSystemKitsConfigs.isWhiteList
207
+ ))
208
+ }
209
+ }
210
+
211
+ extension View {
212
+ func kitFont(_ typography: TypographyStyle) -> some View {
213
+ modifier(KitFontModifier(size: typography.fontSize, weight: typography.fontWeight))
214
+ }
215
+
216
+ func kitFont(size: CGFloat, weight: Font.Weight = .regular) -> some View {
217
+ modifier(KitFontModifier(size: size, weight: weight))
218
+ }
219
+ }
220
+
161
221
  public struct MomoText: View {
162
222
  @Environment(\.appTheme) private var theme
163
223
  @Environment(\.momoFontScale) private var fontScale
224
+ // From the environment, not DesignSystemKits.shared, so a whitelist flip re-renders the text.
225
+ @Environment(\.designSystemKitsConfigs) private var designSystemKitsConfigs
164
226
  private let content: String
165
227
  private let typography: TypographyStyle
166
228
  private let color: Color?
@@ -236,7 +298,8 @@ public struct MomoText: View {
236
298
  size: fontScale(fontSize),
237
299
  weight: typography.fontWeight,
238
300
  family: fontFamily ?? theme.font,
239
- fallbackFamily: theme.font
301
+ fallbackFamily: theme.font,
302
+ isWhiteList: designSystemKitsConfigs.isWhiteList
240
303
  )
241
304
  }
242
305
 
@@ -244,7 +307,13 @@ public struct MomoText: View {
244
307
  private var baseText: SwiftUI.Text {
245
308
  let keywords = highlightText.filter { !$0.isEmpty }.sorted { $0.count > $1.count }
246
309
  guard !keywords.isEmpty else { return SwiftUI.Text(content) }
247
- let highlightFont = momoFont(size: fontScale(fontSize), weight: TypographyStyle.headerXsSemibold.fontWeight, family: fontFamily ?? theme.font, fallbackFamily: theme.font)
310
+ let highlightFont = momoFont(
311
+ size: fontScale(fontSize),
312
+ weight: TypographyStyle.headerXsSemibold.fontWeight,
313
+ family: fontFamily ?? theme.font,
314
+ fallbackFamily: theme.font,
315
+ isWhiteList: designSystemKitsConfigs.isWhiteList
316
+ )
248
317
  func isWordChar(_ character: Character?) -> Bool {
249
318
  guard let character else { return false }
250
319
  return character.isLetter || character.isNumber || character == "_"
@@ -282,7 +351,12 @@ public struct MomoText: View {
282
351
 
283
352
  // lineSpacing is added on top of the font's natural line height, not on top of fontSize.
284
353
  let lineSpacing = max(0, fontScale(lineHeight)
285
- - momoLineHeight(size: fontScale(fontSize), family: fontFamily ?? theme.font, fallbackFamily: theme.font))
354
+ - momoLineHeight(
355
+ size: fontScale(fontSize),
356
+ family: fontFamily ?? theme.font,
357
+ fallbackFamily: theme.font,
358
+ isWhiteList: designSystemKitsConfigs.isWhiteList
359
+ ))
286
360
 
287
361
  var text = baseText
288
362
  .font(font)
@@ -10,12 +10,12 @@ public extension View {
10
10
  }
11
11
 
12
12
  public extension Font {
13
- /// Non-reactive: resolves against the current `FontScaleStore` snapshot at each access. The
13
+ /// Non-reactive: resolves against the current `DesignSystemKits` font scale at each access. The
14
14
  /// styles below are computed properties for that reason — as stored `static let`s they would
15
15
  /// freeze the scale at first access and never pick up a Dynamic Type change.
16
16
  /// Inside a view, `@Environment(\.momoFontScale)` + `fontScale.font(size:weight:)` also re-renders.
17
17
  static func appFont(size: CGFloat) -> Font {
18
- FontScaleStore.shared.snapshot.font(size: size)
18
+ DesignSystemKits.shared.fontScale.font(size: size)
19
19
  }
20
20
 
21
21
  // New supported typography styles
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'MoMoUIKits'
3
- s.version = '0.168.1-beta.1'
3
+ s.version = '0.167.1-beta.22'
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.168.1-beta.1'
3
+ s.version = '0.167.1-beta.22'
4
4
  s.summary = 'Demo browser for MoMoUIKits SwiftUI components'
5
5
  s.homepage = 'https://momo.vn'
6
6
  s.license = { :type => 'MIT' }