@momo-kits/native-kits 0.167.1-duo.8-debug → 0.167.1-duo.9

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 (254) hide show
  1. package/CLAUDE.md +4 -1
  2. package/ios/Application/ApplicationEnvironment.swift +11 -0
  3. package/ios/Application/ComposeApi.swift +2 -1
  4. package/ios/Application/{Components.swift → LegacyHeader.swift} +6 -62
  5. package/ios/Application/Screen.swift +3 -2
  6. package/ios/Avatar/Avatar.swift +4 -3
  7. package/ios/Badge/Badge.swift +6 -4
  8. package/ios/Badge/BadgeDot.swift +1 -1
  9. package/ios/Badge/BadgeRibbon.swift +0 -1
  10. package/ios/Button/Button.swift +15 -12
  11. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +12 -20
  12. package/ios/Carousel/Carousel.swift +29 -12
  13. package/ios/Checkbox/Checkbox.swift +7 -3
  14. package/ios/Chip/Chip.swift +5 -4
  15. package/ios/Collapse/Collapse.swift +70 -19
  16. package/ios/Colors+Radius+Spacing/Colors.swift +9 -0
  17. package/ios/DateTimePicker/DateTimePicker.swift +54 -20
  18. package/ios/DateTimePicker/WheelPicker.swift +103 -105
  19. package/ios/Divider/Divider.swift +37 -4
  20. package/ios/Extensions/Color++.swift +18 -0
  21. package/ios/Icon/Icon.swift +7 -1
  22. package/ios/IconButton/IconButton.swift +15 -7
  23. package/ios/Image/Image.swift +7 -34
  24. package/ios/Information/Information.swift +27 -9
  25. package/ios/Input/ErrorView.swift +2 -2
  26. package/ios/Input/Input.swift +160 -147
  27. package/ios/Input/InputPhoneNumber.swift +12 -9
  28. package/ios/Input/InputSearch.swift +102 -75
  29. package/ios/Input/InputTextArea.swift +128 -145
  30. package/ios/InputDropDown/InputDropDown.swift +10 -7
  31. package/ios/InputMoney/InputMoney.swift +33 -11
  32. package/ios/InputOTP/InputOTP.swift +22 -12
  33. package/ios/Layout/Card.swift +50 -0
  34. package/ios/Layout/GridContext.swift +123 -3
  35. package/ios/Layout/Item.swift +5 -4
  36. package/ios/Layout/Section.swift +4 -100
  37. package/ios/Loader/Loader.swift +5 -9
  38. package/ios/Lottie/LottieView.swift +10 -0
  39. package/ios/{Application/Navigation/Overplay → Navigation}/BottomSheet.swift +61 -9
  40. package/ios/{Application/Navigation → Navigation}/BottomTab/BottomTab.swift +60 -34
  41. package/ios/{Application/Navigation → Navigation}/BottomTab/BottomTabBar.swift +11 -6
  42. package/ios/{Application → Navigation/Component}/FloatingButton.swift +14 -3
  43. package/ios/Navigation/Component/Header.swift +493 -0
  44. package/ios/Navigation/Component/HeaderBackground.swift +134 -0
  45. package/ios/Navigation/Component/HeaderJourney.swift +73 -0
  46. package/ios/Navigation/Component/HeaderLocation.swift +48 -0
  47. package/ios/Navigation/Component/HeaderRight.swift +386 -0
  48. package/ios/Navigation/Component/HeaderTitle.swift +36 -0
  49. package/ios/{Application/Navigation → Navigation/Component}/HeaderUser.swift +20 -23
  50. package/ios/{Application/Navigation/component → Navigation/Component}/SideBar.swift +49 -28
  51. package/ios/{Application/Navigation/Overplay → Navigation/Component}/SnackBar.swift +5 -5
  52. package/ios/Navigation/HostBackGestureBridge.swift +57 -0
  53. package/ios/Navigation/Navigation.swift +190 -0
  54. package/ios/{Application/Navigation → Navigation}/NavigationContainer.swift +46 -41
  55. package/ios/{Application/Navigation → Navigation}/Navigator.swift +65 -9
  56. package/ios/{Application → Navigation}/StackScreen.swift +236 -103
  57. package/ios/{Application/Navigation → Navigation}/Tracking/ScreenTracker.swift +12 -5
  58. package/ios/OTPKeyboard/OTPKeyboard.swift +8 -11
  59. package/ios/Pagination/PaginationScroll.swift +2 -2
  60. package/ios/Popup/PopupDisplay.swift +79 -159
  61. package/ios/Popup/PopupInput.swift +10 -13
  62. package/ios/Popup/PopupLayout.swift +97 -2
  63. package/ios/Popup/PopupNotify.swift +27 -55
  64. package/ios/Popup/PopupPromotion.swift +22 -50
  65. package/ios/PopupView/FullscreenPopup.swift +13 -19
  66. package/ios/PopupView/PopupView.swift +1 -1
  67. package/ios/PopupView/Utils++.swift +0 -8
  68. package/ios/ProgressInfo/ProgressInfo.swift +4 -2
  69. package/ios/Radio/Radio.swift +2 -1
  70. package/ios/Rating/Rating.swift +9 -1
  71. package/ios/ScrollIndicator/ScrollIndicator.swift +11 -10
  72. package/ios/Skeleton/Skeleton.swift +22 -27
  73. package/ios/Slider/Slider.swift +16 -18
  74. package/ios/Stepper/Stepper.swift +6 -1
  75. package/ios/Steps/Steps.swift +8 -6
  76. package/ios/SuggestAction/SuggestAction.swift +5 -0
  77. package/ios/Swipeable/SwipeCell.swift +10 -6
  78. package/ios/Switch/Switch.swift +22 -20
  79. package/ios/TabView/TabView.swift +102 -21
  80. package/ios/Tag/Tag.swift +15 -4
  81. package/ios/Template/Logo/Logo.swift +2 -1
  82. package/ios/Template/TrustBanner/TrustBanner.swift +41 -27
  83. package/ios/Title/Title.swift +6 -17
  84. package/ios/Tooltip/Tooltip.swift +29 -14
  85. package/ios/Typography/Text.swift +61 -19
  86. package/ios/Uploader/Uploader.swift +3 -1
  87. package/ios/native-kits.podspec +1 -0
  88. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +1 -1
  89. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +77 -1
  90. package/package.json +1 -1
  91. package/build.gradle.kts +0 -11
  92. package/compose/build.gradle.kts +0 -204
  93. package/compose/build.gradle.kts.backup +0 -204
  94. package/compose/compose.podspec +0 -47
  95. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
  96. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
  97. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
  98. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
  99. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -153
  100. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +0 -6
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -124
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -831
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -82
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -356
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -113
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -49
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
  132. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -189
  133. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -475
  134. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
  135. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -266
  136. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -240
  137. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -223
  138. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -264
  139. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -185
  140. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
  141. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
  142. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  143. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  144. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
  145. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  146. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -361
  147. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -108
  148. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -310
  149. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
  150. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  151. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
  152. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
  153. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -323
  154. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -220
  155. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
  156. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
  157. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -199
  158. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
  159. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -552
  160. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -88
  161. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -125
  162. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -207
  163. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -498
  164. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -176
  165. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
  166. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
  167. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  168. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -234
  169. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -188
  170. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
  171. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -16
  172. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +0 -18
  173. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
  174. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  175. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  176. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
  177. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -297
  178. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -54
  179. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -50
  180. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +0 -232
  181. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -41
  182. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
  183. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
  184. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  185. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
  186. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
  187. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  188. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -338
  189. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +0 -58
  190. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -137
  191. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -106
  192. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -205
  193. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -393
  194. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  195. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -708
  196. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -148
  197. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -35
  198. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -203
  199. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -232
  200. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  201. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +0 -98
  202. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +0 -312
  203. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
  204. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -408
  205. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -92
  206. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +0 -105
  207. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +0 -74
  208. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -366
  209. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -37
  210. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -363
  211. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +0 -185
  212. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
  213. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
  214. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -12
  215. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
  216. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
  217. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -74
  218. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +0 -13
  219. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  220. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
  221. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  222. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -118
  223. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -40
  224. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -45
  225. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
  226. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -38
  227. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
  228. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -217
  229. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +0 -86
  230. package/gradle/libs.versions.toml +0 -69
  231. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  232. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  233. package/gradle.properties +0 -26
  234. package/gradlew +0 -252
  235. package/gradlew.bat +0 -94
  236. package/ios/Application/HeaderRight.swift +0 -324
  237. package/ios/Application/Navigation/HeaderBackProps.swift +0 -66
  238. package/ios/Application/Navigation/HeaderTitle.swift +0 -57
  239. package/ios/Application/Navigation/NavigationOptions.swift +0 -109
  240. package/ios/Application/Navigation/NavigatorManager.swift +0 -29
  241. package/ios/Application/Navigation/component/DuoScrollGradient.swift +0 -54
  242. package/ios/Application/Navigation/component/Header.swift +0 -183
  243. package/ios/Application/Navigation/component/HeaderBackground.swift +0 -84
  244. package/ios/Application/Navigation/component/HeaderColor.swift +0 -65
  245. package/ios/Application/Navigation/component/HeaderRightWidthKey.swift +0 -11
  246. package/ios/Application/Navigation/component/NavigationFooter.swift +0 -90
  247. package/ios/Application/Navigation/component/NavigationHeaderRight.swift +0 -280
  248. package/ios-demo/README.md +0 -120
  249. package/settings.gradle.kts +0 -64
  250. /package/ios/{Application/Layout → Layout}/ScreenLayout.swift +0 -0
  251. /package/ios/{Application/Navigation → Navigation}/BottomTab/CurvedContainer.swift +0 -0
  252. /package/ios/{Application/Navigation → Navigation}/BottomTab/DuoBarCompression.swift +0 -0
  253. /package/ios/{Application/Navigation → Navigation}/BottomTab/DuoTabBar.swift +0 -0
  254. /package/ios/{Application/Navigation/Overplay → Navigation}/ModalScreen.swift +0 -0
@@ -65,21 +65,18 @@ public struct OTPKeyboard: View {
65
65
  HStack {
66
66
  KeyboardButton("", action: self.onPressKey).disabled(true).opacity(0)
67
67
  KeyboardButton("0", action: self.onPressKey)
68
+ // Frame inside the label so the whole key is tappable, not just the glyph.
68
69
  SwiftUI.Button(action: onPressBack) {
69
- HStack {
70
- Image(
71
- systemName: "delete.backward"
72
- ).foregroundColor(Colors.text)
73
- }
74
- }.frame(maxWidth: .infinity, minHeight: 48)
75
- .clipShape(RoundedRectangle(cornerRadius: 8))
70
+ Image(systemName: "delete.backward")
71
+ .foregroundColor(Colors.text)
72
+ .frame(maxWidth: .infinity, minHeight: 48)
73
+ .contentShape(Rectangle())
74
+ }
76
75
  }
77
76
  }
78
77
  .background(Colors.background)
79
78
  .valueChanged(value: value) { otp in
80
- if onChange != nil {
81
- self.onChange!(otp)
82
- }
79
+ onChange?(otp)
83
80
  }
84
81
  }
85
82
 
@@ -128,7 +125,7 @@ private struct ValueView: View {
128
125
 
129
126
  public var body: some View {
130
127
  return HStack {
131
- ForEach(0 ..< valueLength, id: \.self) { i in
128
+ ForEach(0 ..< max(valueLength, 0), id: \.self) { i in
132
129
  if i < value.count {
133
130
  Circle().foregroundColor(Colors.text).frame(width: 8, height: 8)
134
131
  } else {
@@ -14,10 +14,10 @@ import SwiftUI
14
14
  private let INDICATOR_WIDTH: CGFloat = 24
15
15
  private let PROGRESS_WIDTH: CGFloat = 72
16
16
 
17
- /// Memoized offset calculation, mirroring Compose's `calculateOffset`.
17
+ /// Mirrors Compose's `calculateOffset`; clamped because UIKit bounce overshoots the scroll range.
18
18
  private func calculateOffset(currentPosition: CGFloat, maxBound: CGFloat) -> CGFloat {
19
19
  guard maxBound > 0 else { return 0 }
20
- return (PROGRESS_WIDTH - INDICATOR_WIDTH) * (currentPosition / maxBound)
20
+ return (PROGRESS_WIDTH - INDICATOR_WIDTH) * min(max(currentPosition / maxBound, 0), 1)
21
21
  }
22
22
 
23
23
  // MARK: - PaginationScroll
@@ -1,4 +1,3 @@
1
- import SDWebImageSwiftUI
2
1
  import SwiftUI
3
2
 
4
3
  // MARK: - PopupButtonDirection
@@ -16,45 +15,12 @@ public enum PopupButtonType {
16
15
  case button
17
16
  }
18
17
 
19
- extension View {
20
- func measureLineHeights(font: Font,
21
- oneLine: Binding<CGFloat>,
22
- twoLines: Binding<CGFloat>) -> some View {
23
- overlay(
24
- VStack(spacing: 0) {
25
- Text("A")
26
- .font(font)
27
- .ignoreBoldTextSetting()
28
- .lineLimit(1)
29
- .fixedSize()
30
- .background(
31
- GeometryReader { g in
32
- Color.clear.onAppear { oneLine.wrappedValue = g.size.height }
33
- }
34
- )
35
- .hidden()
36
-
37
- Text("A\nA")
38
- .font(font)
39
- .ignoreBoldTextSetting()
40
- .lineLimit(2)
41
- .fixedSize(horizontal: false, vertical: true)
42
- .background(
43
- GeometryReader { g in
44
- Color.clear.onAppear { twoLines.wrappedValue = g.size.height }
45
- }
46
- )
47
- .hidden()
48
- }
49
- .frame(width: 0, height: 0)
50
- )
51
- }
52
- }
53
-
54
18
  // MARK: - PopupDisplay
55
19
 
56
20
  public struct PopupDisplay: View {
21
+ @Environment(\.appTheme) private var theme
57
22
  @Environment(\.localize) private var localize
23
+ @Environment(\.momoFontScale) private var fontScale
58
24
  @Environment(\.screenLayout) private var layout
59
25
 
60
26
  // MARK: Lifecycle
@@ -76,146 +42,100 @@ public struct PopupDisplay: View {
76
42
  }
77
43
 
78
44
  // MARK: Public
79
-
45
+
80
46
  @State private var oneLineH: CGFloat = 0
81
47
  @State private var twoLineH: CGFloat = 0
48
+ @State private var textHeight: CGFloat = .zero
49
+ @State private var actionsHeight: CGFloat = 0
82
50
 
83
- private var fallbackLH: CGFloat { UIFont.preferredFont(forTextStyle: .body).lineHeight }
84
- private var perLine: CGFloat { max(twoLineH - oneLineH, oneLineH > 0 ? oneLineH : fallbackLH) }
85
-
86
- private func heightForLines(lines: CGFloat) -> CGFloat {
87
- guard oneLineH > 0 && twoLineH > 0 else { return ceil(fallbackLH * lines) }
88
- return ceil(oneLineH + max(0, lines - 1) * (twoLineH - oneLineH))
51
+ // ~8.5 lines as laid out; nominal line height until measured
52
+ private var maxHeight8_5: CGFloat {
53
+ popupLinesHeight(8.5, oneLine: oneLineH, twoLines: twoLineH)
54
+ ?? fontScale(TypographyStyle.bodyDefaultRegular.lineHeight) * 8.5
89
55
  }
90
- private var maxHeight8_5: CGFloat { heightForLines(lines: 8.5) }
91
56
 
57
+ private var shouldUseColumn: Bool {
58
+ // UTF-16 length, as PopupNotify counts it
59
+ buttonDirection == .column || (buttonDirection == .auto && (closeButtonTitle.utf16.count > 12 || actionButtonTitle.utf16.count > 12))
60
+ }
92
61
 
93
- @State private var textHeight: CGFloat = .zero
94
- @State private var isScrollable = false
95
- @State private var actionsHeight: CGFloat = 0
96
-
97
62
  public var body: some View {
98
- var shouldUseColumn: Bool {
99
- buttonDirection == .column || (buttonDirection == .auto && (closeButtonTitle.count > 12 || actionButtonTitle.count > 12))
100
- }
63
+ ZStack(alignment: .topTrailing) {
64
+ VStack(spacing: 0) {
65
+ // scrolls when iPhone Duo landscape is too short; actions stay visible
66
+ PopupScrollBody(maxHeight: layout.popupMaxHeight.map { $0 - actionsHeight }) {
67
+ VStack(spacing: 0) {
68
+ if !url.isEmpty {
69
+ PopupHeaderImage(url: url)
70
+ }
71
+ VStack(alignment: .leading, spacing: 0) {
72
+ MomoText(title, typography: .headerDefaultBold, maxLines: 2, accessibilityId: "title_popup_permission")
73
+ .padding(.top, 24)
74
+ .padding(.bottom, 8)
101
75
 
102
- VStack(spacing: 12) {
103
- ZStack(alignment: .topTrailing) {
104
- if(isShowCloseIcon) {
105
- SwiftUI.Button(action: onClose) {
106
- Image(systemName: "xmark.circle.fill")
107
- .resizable()
108
- .frame(width: 22, height: 22)
109
- .overlay(RoundedRectangle(cornerRadius: Radius.L).stroke(Colors.black01, lineWidth: 2))
110
- }.foregroundColor(Colors.black20)
111
- .background(Colors.black01.cornerRadius(15))
112
- .padding(.trailing, -11)
113
- .padding(.top, -11)
114
- .zIndex(1)
115
- .accessibility(identifier: "ic_popup_close")
116
- }
117
-
118
- VStack(spacing: 0) {
119
- // scrolls when iPhone Duo landscape is too short; actions stay visible
120
- PopupScrollBody(maxHeight: layout.popupMaxHeight.map { $0 - actionsHeight }) {
121
- VStack(spacing: 0) {
122
- if(!url.isEmpty) {
123
- WebImage(url: URL(string: url), isAnimating: .constant(true))
124
- .resizable()
125
- .placeholder {
126
- Rectangle()
127
- .fill(Color.gray.opacity(0.3))
128
- .aspectRatio(1.777, contentMode: .fit)
129
- .frame(maxWidth: .infinity, maxHeight: 184)
130
- }
131
- .aspectRatio(1.777, contentMode: .fit)
132
- .frame(maxWidth: .infinity, alignment: .center)
133
- .clipShape(RoundedCorner(radius: 15, corners: [.topLeft, .topRight]))
134
- .clipped()
135
- }
136
- VStack(alignment: .leading, spacing: 0) {
137
- MomoText(title, typography: .headerDefaultBold)
138
- .padding(.top, 24)
139
- .padding(.bottom, 8)
140
- .lineLimit(2)
141
- .accessibility(identifier: "title_popup_permission")
142
-
143
- Group {
144
- if isScrollable {
145
- ScrollView(showsIndicators: false) {
146
- MomoText(description, typography: .bodyDefaultRegular)
147
- .multilineTextAlignment(.leading)
148
- .background(GeometryReader { geo in
149
- Color.clear.onAppear { textHeight = geo.size.height }
150
- })
151
- .measureLineHeights(font: .body_default_regular,
152
- oneLine: $oneLineH,
153
- twoLines: $twoLineH)
154
- .accessibility(identifier: "description_popup_permission")
155
- }
156
- // Cap the visible height to ~8.5 lines
157
- .frame(height: min(maxHeight8_5, textHeight))
158
- } else {
159
- MomoText(description, typography: .bodyDefaultRegular)
160
- .multilineTextAlignment(.leading)
161
- .background(GeometryReader { geo in
162
- Color.clear.onAppear {
163
- textHeight = geo.size.height
164
- // Trigger scroll at ~8.5 lines
165
- isScrollable = textHeight > maxHeight8_5
166
- }
167
- })
168
- .measureLineHeights(font: .body_default_regular,
169
- oneLine: $oneLineH,
170
- twoLines: $twoLineH)
171
- .accessibility(identifier: "description_popup_permission")
172
- }
173
- }
76
+ descriptionContent
174
77
  .padding(.bottom, 8)
175
-
176
- if(!errorCode.isEmpty) {
177
- MomoText(localize.translate("errorCode") + errorCode, typography: .descriptionXsRegular, color: Colors.black12)
178
- .lineLimit(1)
179
- .padding(.bottom, 8)
180
- }
78
+
79
+ if !errorCode.isEmpty {
80
+ MomoText(localize.translate("errorCode") + errorCode, typography: .descriptionXsRegular, color: theme.colors.text.hint, maxLines: 1)
81
+ .padding(.bottom, 8)
181
82
  }
182
- .frame(maxWidth: .infinity, alignment: .leading)
183
- .padding(.horizontal, 24)
184
- .padding(.bottom, 16)
185
83
  }
84
+ .frame(maxWidth: .infinity, alignment: .leading)
85
+ .padding(.horizontal, 24)
86
+ .padding(.bottom, 16)
87
+ .measureLineHeights(typography: .bodyDefaultRegular, oneLine: $oneLineH, twoLines: $twoLineH)
186
88
  }
89
+ }
187
90
 
188
- Group {
189
- if shouldUseColumn {
190
- if buttonType == .text {
191
- ColumnTextButtons
192
- } else {
193
- ColumnButtons
194
- }
91
+ Group {
92
+ if shouldUseColumn {
93
+ if buttonType == .text {
94
+ ColumnTextButtons
195
95
  } else {
196
- if buttonType == .text {
197
- RowTextButtons
198
- } else {
199
- RowButtons
200
- }
96
+ ColumnButtons
201
97
  }
202
- }
203
- .background(
204
- GeometryReader { proxy in
205
- Color.clear
206
- .onAppear { actionsHeight = proxy.size.height }
207
- .onChange(of: proxy.size.height) { actionsHeight = $0 }
98
+ } else {
99
+ if buttonType == .text {
100
+ RowTextButtons
101
+ } else {
102
+ RowButtons
208
103
  }
209
- )
104
+ }
210
105
  }
211
- .fixedSize(horizontal: false, vertical: true)
106
+ .popupReadHeight($actionsHeight)
212
107
  }
108
+ .fixedSize(horizontal: false, vertical: true)
109
+ .background(theme.colors.background.surface)
110
+ .clipShape(RoundedRectangle(cornerRadius: Radius.L))
111
+
112
+ if isShowCloseIcon {
113
+ PopupCloseButton(action: onClose)
114
+ .offset(x: 11, y: -11)
115
+ }
116
+ }
117
+ .frame(maxWidth: layout.popupMaxWidth)
118
+ .padding(.horizontal, 12)
119
+ .accessibilityElement(children: .contain)
120
+ .accessibilityIdentifier("popup_notify")
121
+ }
122
+
123
+ @ViewBuilder
124
+ private var descriptionContent: some View {
125
+ if textHeight > maxHeight8_5 {
126
+ ScrollView(showsIndicators: false) {
127
+ descriptionText
128
+ }
129
+ .frame(height: maxHeight8_5)
130
+ } else {
131
+ descriptionText
213
132
  }
214
- .background(Color.white.cornerRadius(15))
215
- .frame(maxWidth: layout.popupMaxWidth)
216
- .padding(.horizontal, 12)
217
- .accessibilityElement(children: .ignore)
218
- .accessibility(identifier: "popup_notify")
133
+ }
134
+
135
+ private var descriptionText: some View {
136
+ MomoText(description, typography: .bodyDefaultRegular, accessibilityId: "description_popup_permission")
137
+ .frame(maxWidth: .infinity, alignment: .leading)
138
+ .popupReadHeight($textHeight)
219
139
  }
220
140
 
221
141
  // MARK: Internal
@@ -265,7 +185,7 @@ public struct PopupDisplay: View {
265
185
  }
266
186
 
267
187
  var RowButtons: some View {
268
- HStack {
188
+ HStack(spacing: Spacing.S) {
269
189
  if(!closeButtonTitle.isEmpty) {
270
190
  Button(title: closeButtonTitle, action: onPressCloseButton, type: .text, size: .medium).accessibility(identifier: "btn_popup_cancel")
271
191
  }
@@ -278,7 +198,7 @@ public struct PopupDisplay: View {
278
198
  }
279
199
 
280
200
  var ColumnButtons: some View {
281
- VStack(alignment: .trailing) {
201
+ VStack(alignment: .trailing, spacing: Spacing.S) {
282
202
  Button(
283
203
  title: actionButtonTitle,
284
204
  action: onPressAction,
@@ -1,7 +1,9 @@
1
- import SDWebImageSwiftUI
2
1
  import SwiftUI
3
2
 
4
3
  public struct PopupInput: View {
4
+ @Environment(\.appTheme) private var theme
5
+ @Environment(\.screenLayout) private var layout
6
+
5
7
  // MARK: Lifecycle
6
8
 
7
9
  public init(isPresented: Binding<Bool>, title: String = "", description: String = "", numberOfButtons: Int = 1, actionButtonTitle: String = "", closeButtonTitle: String = "", onPressAction: @escaping () -> Void = {}, onPressCloseButton: @escaping () -> Void = {}, onClose: @escaping () -> Void = {}, inputPlaceholder: String = "", inputValue: Binding<String> = Binding.constant(""), onTextChange: ((String) -> Void)? = nil) {
@@ -24,22 +26,13 @@ public struct PopupInput: View {
24
26
  public var body: some View {
25
27
  VStack(spacing: 12) {
26
28
  ZStack(alignment: .topTrailing) {
27
- SwiftUI.Button(action: onPressClose) {
28
- Image(systemName: "xmark.circle.fill")
29
- .resizable()
30
- .frame(width: 16, height: 16)
31
- }.foregroundColor(Colors.black20)
32
- .background(Colors.black01.cornerRadius(8))
33
- .offset(x: 6, y: -6)
34
- .zIndex(1)
35
-
36
29
  VStack {
37
30
  VStack(alignment: .leading) {
38
- MomoText(title, typography: .headerDefaultBold, color: .black)
31
+ MomoText(title, typography: .headerDefaultBold)
39
32
  .padding(.top, 12)
40
33
  .padding(.bottom, 24)
41
34
 
42
- MomoText(description, typography: .bodyDefaultRegular, color: .black)
35
+ MomoText(description, typography: .bodyDefaultRegular)
43
36
  .opacity(0.6)
44
37
  .multilineTextAlignment(.leading)
45
38
  .padding(.bottom, 20)
@@ -61,11 +54,15 @@ public struct PopupInput: View {
61
54
  }
62
55
 
63
56
  }.clipped()
57
+
58
+ PopupCloseButton(action: onPressClose)
59
+ .offset(x: 11, y: -11)
64
60
  }
65
61
  }
66
- .background(Color.white.cornerRadius(8))
62
+ .background(theme.colors.background.surface.cornerRadius(8))
67
63
  .shadow(color: .black.opacity(0.08), radius: 2, x: 0, y: 0)
68
64
  .shadow(color: .black.opacity(0.16), radius: 24, x: 0, y: 0)
65
+ .frame(maxWidth: layout.popupMaxWidth)
69
66
  .padding(.horizontal, 40)
70
67
  }
71
68
 
@@ -1,3 +1,4 @@
1
+ import SDWebImageSwiftUI
1
2
  import SwiftUI
2
3
 
3
4
  // Width of a system alert on the iPhone Duo inner display, in both orientations (RN Popup/utils.ts).
@@ -6,9 +7,9 @@ private let duoPopupMaxWidth: CGFloat = 440
6
7
  extension ScreenLayout {
7
8
  var isDuoDevice: Bool { isIPhoneDuoDevice(windowSize: CGSize(width: width, height: height)) }
8
9
 
9
- /// Card width cap; other devices keep the full window width minus the popup's own padding.
10
+ /// Card width cap (Compose `popupMaxWidth`); unbounded off iPhone Duo, where the popup's own padding sets the width.
10
11
  var popupMaxWidth: CGFloat {
11
- isDuoDevice ? min(width - Spacing.XL * 2, duoPopupMaxWidth) : .infinity
12
+ isDuoDevice ? duoPopupMaxWidth : .infinity
12
13
  }
13
14
 
14
15
  /// Room left for a popup on iPhone Duo, where landscape is too short for it; nil elsewhere.
@@ -43,3 +44,97 @@ struct PopupScrollBody<Content: View>: View {
43
44
  }
44
45
  }
45
46
  }
47
+
48
+ /// Height of `lines` (may be fractional) lines measured by `measureLineHeights`; nil until measured.
49
+ func popupLinesHeight(_ lines: CGFloat, oneLine: CGFloat, twoLines: CGFloat) -> CGFloat? {
50
+ guard oneLine > 0, twoLines > oneLine else { return nil }
51
+ return oneLine + (lines - 1) * (twoLines - oneLine)
52
+ }
53
+
54
+ extension View {
55
+ /// Measures one and two lines of `typography` as MomoText lays them out, its line spacing included.
56
+ func measureLineHeights(typography: TypographyStyle,
57
+ oneLine: Binding<CGFloat>,
58
+ twoLines: Binding<CGFloat>) -> some View {
59
+ overlay(
60
+ VStack(spacing: 0) {
61
+ MomoText("A", typography: typography)
62
+ .fixedSize()
63
+ .popupReadHeight(oneLine)
64
+ MomoText("A\nA", typography: typography)
65
+ .fixedSize()
66
+ .popupReadHeight(twoLines)
67
+ }
68
+ .frame(width: 0, height: 0)
69
+ .hidden()
70
+ .accessibilityHidden(true)
71
+ )
72
+ }
73
+
74
+ func popupReadHeight(_ height: Binding<CGFloat>) -> some View {
75
+ background(
76
+ GeometryReader { proxy in
77
+ Color.clear
78
+ .onAppear { height.wrappedValue = proxy.size.height }
79
+ .onChange(of: proxy.size.height) { height.wrappedValue = $0 }
80
+ }
81
+ )
82
+ }
83
+ }
84
+
85
+ /// 22pt round close button shared by the popups (Compose `PopupNotify` / `PopupPromotion`).
86
+ struct PopupCloseButton: View {
87
+ @Environment(\.appTheme) private var theme
88
+ var tapSize: CGFloat = 22
89
+ let action: () -> Void
90
+
91
+ var body: some View {
92
+ SwiftUI.Button(action: action) {
93
+ Circle()
94
+ .fill(theme.colors.text.default)
95
+ .overlay(Circle().strokeBorder(theme.colors.background.surface, lineWidth: 2))
96
+ .overlay(Icon(source: "navigation_close", size: 16, color: theme.colors.background.surface))
97
+ .frame(width: 22, height: 22)
98
+ .frame(width: tapSize, height: tapSize)
99
+ .contentShape(Rectangle())
100
+ }
101
+ .accessibilityIdentifier("ic_popup_close")
102
+ }
103
+ }
104
+
105
+ /// Compose `Image` states: skeleton while loading, `media_fail` once loading fails.
106
+ struct PopupImagePlaceholder: View {
107
+ @Environment(\.appTheme) private var theme
108
+ let failed: Bool
109
+
110
+ var body: some View {
111
+ if failed {
112
+ Icon(source: "media_fail", color: theme.colors.text.disable)
113
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
114
+ } else {
115
+ Skeleton()
116
+ }
117
+ }
118
+ }
119
+
120
+ /// 16:9 header image, cropped like Compose `Image` (ContentScale.Crop).
121
+ struct PopupHeaderImage: View {
122
+ let url: String
123
+
124
+ @State private var failed = false
125
+
126
+ var body: some View {
127
+ Color.clear
128
+ .aspectRatio(1.777, contentMode: .fit)
129
+ .frame(maxWidth: .infinity)
130
+ .overlay(
131
+ WebImage(url: URL(string: url), isAnimating: .constant(true))
132
+ .onSuccess { _, _, _ in failed = false }
133
+ .onFailure { _ in failed = true }
134
+ .resizable()
135
+ .placeholder { PopupImagePlaceholder(failed: failed || URL(string: url) == nil) }
136
+ .scaledToFill()
137
+ )
138
+ .clipped()
139
+ }
140
+ }
@@ -1,8 +1,17 @@
1
- import SDWebImageSwiftUI
2
1
  import SwiftUI
3
2
 
4
3
  public typealias PopupActionDirection = PopupButtonDirection
5
4
 
5
+ public struct PopupAction {
6
+ public let title: String
7
+ public let onPress: (() -> Void)?
8
+
9
+ public init(title: String, onPress: (() -> Void)? = nil) {
10
+ self.title = title
11
+ self.onPress = onPress
12
+ }
13
+ }
14
+
6
15
  public struct PopupNotifyProps {
7
16
  public var image: String
8
17
  public var title: String
@@ -38,6 +47,7 @@ public struct PopupNotifyProps {
38
47
  }
39
48
 
40
49
  public struct PopupNotify: View {
50
+ @Environment(\.appTheme) private var theme
41
51
  @Environment(\.localize) private var localize
42
52
  @Environment(\.momoFontScale) private var fontScale
43
53
  @Environment(\.screenLayout) private var layout
@@ -46,13 +56,17 @@ public struct PopupNotify: View {
46
56
 
47
57
  @State private var descriptionHeight: CGFloat = 0
48
58
  @State private var actionsHeight: CGFloat = 0
59
+ @State private var oneLineHeight: CGFloat = 0
60
+ @State private var twoLinesHeight: CGFloat = 0
49
61
 
50
62
  private var errorCodePrefix: String {
51
63
  localize.translate("errorCode")
52
64
  }
53
65
 
66
+ // ~8.5 lines as laid out (Compose measures the real lines); nominal line height until measured
54
67
  private var maxDescriptionHeight: CGFloat {
55
- fontScale(TypographyStyle.bodyDefaultRegular.lineHeight) * 8.5
68
+ popupLinesHeight(8.5, oneLine: oneLineHeight, twoLines: twoLinesHeight)
69
+ ?? fontScale(TypographyStyle.bodyDefaultRegular.lineHeight) * 8.5
56
70
  }
57
71
 
58
72
  private var shouldUseColumnButtons: Bool {
@@ -62,7 +76,9 @@ public struct PopupNotify: View {
62
76
  case .row:
63
77
  return false
64
78
  case .auto:
65
- return (props.secondary?.title.count ?? 0) > 12 || (props.primary?.title.count ?? 0) > 12
79
+ // UTF-16 length, as Kotlin and JS count it
80
+ guard let secondary = props.secondary else { return false }
81
+ return secondary.title.utf16.count > 12 || (props.primary?.title.utf16.count ?? 0) > 12
66
82
  }
67
83
  }
68
84
 
@@ -77,7 +93,7 @@ public struct PopupNotify: View {
77
93
  PopupScrollBody(maxHeight: layout.popupMaxHeight.map { $0 - actionsHeight }) {
78
94
  VStack(spacing: 0) {
79
95
  if !props.image.isEmpty {
80
- popupImage
96
+ PopupHeaderImage(url: props.image)
81
97
  }
82
98
  textContent
83
99
  }
@@ -86,25 +102,19 @@ public struct PopupNotify: View {
86
102
  actionButtons
87
103
  .padding(.horizontal, Spacing.XL)
88
104
  .padding(.bottom, Spacing.XL)
89
- .background(
90
- GeometryReader { proxy in
91
- Color.clear
92
- .onAppear { actionsHeight = proxy.size.height }
93
- .onChange(of: proxy.size.height) { actionsHeight = $0 }
94
- }
95
- )
105
+ .popupReadHeight($actionsHeight)
96
106
  }
97
- .background(Colors.black01)
107
+ .background(theme.colors.background.surface)
98
108
  .clipShape(RoundedRectangle(cornerRadius: Radius.L))
99
109
 
100
110
  if props.isShowCloseIcon {
101
- closeButton
111
+ PopupCloseButton(action: props.onIconClose)
102
112
  .offset(x: 11, y: -11)
103
113
  }
104
114
  }
105
115
  .frame(maxWidth: layout.popupMaxWidth)
106
116
  .padding(.horizontal, Spacing.M)
107
- .accessibilityElement(children: .ignore)
117
+ .accessibilityElement(children: .contain)
108
118
  .accessibilityIdentifier("popup_notify")
109
119
  }
110
120
 
@@ -124,7 +134,7 @@ public struct PopupNotify: View {
124
134
  MomoText(
125
135
  errorCodePrefix + props.error,
126
136
  typography: .descriptionXsRegular,
127
- color: Colors.black12,
137
+ color: theme.colors.text.hint,
128
138
  maxLines: 1
129
139
  )
130
140
  .padding(.top, Spacing.S)
@@ -132,20 +142,7 @@ public struct PopupNotify: View {
132
142
  }
133
143
  .frame(maxWidth: .infinity, alignment: .leading)
134
144
  .padding(Spacing.XL)
135
- }
136
-
137
- private var popupImage: some View {
138
- WebImage(url: URL(string: props.image), isAnimating: .constant(true))
139
- .resizable()
140
- .placeholder {
141
- Rectangle()
142
- .fill(Colors.black03)
143
- .aspectRatio(1.777, contentMode: .fit)
144
- .frame(maxWidth: .infinity)
145
- }
146
- .aspectRatio(1.777, contentMode: .fit)
147
- .frame(maxWidth: .infinity)
148
- .clipShape(RoundedCorner(radius: Radius.L, corners: [.topLeft, .topRight]))
145
+ .measureLineHeights(typography: .bodyDefaultRegular, oneLine: $oneLineHeight, twoLines: $twoLinesHeight)
149
146
  }
150
147
 
151
148
  @ViewBuilder
@@ -167,15 +164,7 @@ public struct PopupNotify: View {
167
164
  accessibilityId: "description_popup_permission"
168
165
  )
169
166
  .frame(maxWidth: .infinity, alignment: .leading)
170
- .background(
171
- GeometryReader { proxy in
172
- Color.clear
173
- .onAppear { descriptionHeight = proxy.size.height }
174
- .onChange(of: props.description) { _ in
175
- descriptionHeight = proxy.size.height
176
- }
177
- }
178
- )
167
+ .popupReadHeight($descriptionHeight)
179
168
  }
180
169
 
181
170
  @ViewBuilder
@@ -217,21 +206,4 @@ public struct PopupNotify: View {
217
206
  )
218
207
  .accessibilityIdentifier("btn_popup_cancel")
219
208
  }
220
-
221
- private var closeButton: some View {
222
- SwiftUI.Button(action: props.onIconClose) {
223
- ZStack {
224
- Circle()
225
- .fill(Colors.black17)
226
- .overlay(
227
- Circle()
228
- .stroke(Colors.black01, lineWidth: 2)
229
- )
230
- .frame(width: 22, height: 22)
231
-
232
- Icon(source: "navigation_close", size: 16, color: Colors.black01)
233
- }
234
- }
235
- .accessibilityIdentifier("ic_popup_close")
236
- }
237
209
  }