@momo-kits/native-kits 0.162.2-sp.1 → 0.162.2-sp.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 (239) hide show
  1. package/.claude/settings.local.json +15 -1
  2. package/CLAUDE.md +78 -0
  3. package/build.gradle.kts +11 -0
  4. package/compose/build.gradle.kts +190 -0
  5. package/compose/build.gradle.kts.backup +190 -0
  6. package/compose/compose.podspec +47 -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/OsFontScale.android.kt +7 -0
  9. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +123 -0
  10. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  11. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  12. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  13. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  14. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  19. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  20. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  21. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  22. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  23. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +52 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +106 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +183 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +207 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +39 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +294 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +826 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +110 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +378 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +56 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +82 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +338 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +175 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +356 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +113 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +89 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +128 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +209 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +76 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +125 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +231 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +112 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +477 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +114 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +214 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +240 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +216 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +259 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +182 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +343 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +84 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +328 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +97 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +310 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +59 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +21 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +90 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +323 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +217 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +473 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +122 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +199 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +91 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +470 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +88 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +131 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +203 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +498 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +175 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +182 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +193 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +234 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +188 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +22 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +16 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +188 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +276 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +52 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +66 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +104 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +48 -0
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +253 -0
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +129 -0
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +100 -0
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +172 -0
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +360 -0
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +8 -0
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +581 -0
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +156 -0
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +225 -0
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +169 -0
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +320 -0
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +81 -0
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +309 -0
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +34 -0
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +360 -0
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +132 -0
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +128 -0
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +70 -0
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +58 -0
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +55 -0
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +15 -0
  132. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +105 -0
  133. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +32 -0
  134. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
  135. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +184 -0
  136. package/gradle/libs.versions.toml +69 -0
  137. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  138. package/gradle/wrapper/gradle-wrapper.properties +8 -0
  139. package/gradle.properties +26 -0
  140. package/gradlew +252 -0
  141. package/gradlew.bat +94 -0
  142. package/ios/Application/ApplicationEnvironment.swift +15 -2
  143. package/ios/Application/Components.swift +16 -0
  144. package/ios/Application/HeaderRight.swift +79 -45
  145. package/ios/Application/Localize.swift +277 -0
  146. package/ios/Application/MaxApi.swift +18 -0
  147. package/ios/Application/Navigation/BottomTab/BottomTab.swift +3 -1
  148. package/ios/Application/Navigation/NavigationContainer.swift +53 -4
  149. package/ios/Application/Navigation/Navigator.swift +54 -29
  150. package/ios/Application/Navigation/Overplay/BottomSheet.swift +98 -18
  151. package/ios/Application/Navigation/Overplay/ModalScreen.swift +6 -0
  152. package/ios/Application/Navigation/Tracking/ScreenTracker.swift +117 -0
  153. package/ios/Application/Screen.swift +2 -1
  154. package/ios/Application/StackScreen.swift +55 -3
  155. package/ios/Badge/BadgeRibbon.swift +80 -0
  156. package/ios/Button/Button.swift +67 -11
  157. package/ios/Carousel/Carousel.swift +16 -1
  158. package/ios/Checkbox/Checkbox.swift +14 -20
  159. package/ios/Chip/Chip.swift +35 -26
  160. package/ios/Collapse/Collapse.swift +11 -1
  161. package/ios/Colors+Radius+Spacing/Colors.swift +20 -17
  162. package/ios/Colors+Radius+Spacing/Spacing.swift +3 -1
  163. package/ios/Colors+Radius+Spacing/Theme.swift +15 -15
  164. package/ios/DateTimePicker/DateTimePicker.swift +4 -2
  165. package/ios/DateTimePicker/WheelPicker.swift +7 -3
  166. package/ios/Extensions/ActiveOpacityButtonStyle.swift +14 -0
  167. package/ios/Extensions/Color++.swift +32 -0
  168. package/ios/Icon/Icon.swift +5 -1
  169. package/ios/IconButton/IconButton.swift +35 -7
  170. package/ios/Image/Image.swift +16 -3
  171. package/ios/Information/Information.swift +3 -1
  172. package/ios/Input/ErrorView.swift +3 -1
  173. package/ios/Input/Input.swift +31 -8
  174. package/ios/Input/InputPhoneNumber.swift +14 -3
  175. package/ios/Input/InputSearch.swift +7 -1
  176. package/ios/Input/InputTextArea.swift +78 -34
  177. package/ios/InputDropDown/InputDropDown.swift +4 -1
  178. package/ios/InputMoney/InputMoney.swift +16 -4
  179. package/ios/Popup/PopupDisplay.swift +3 -4
  180. package/ios/Popup/PopupNotify.swift +3 -4
  181. package/ios/ProgressInfo/ProgressInfo.swift +4 -2
  182. package/ios/Radio/Radio.swift +12 -13
  183. package/ios/Rating/Rating.swift +1 -1
  184. package/ios/Resources/MoMoUIKitsColors.xcassets/AccentColor.colorset/Contents.json +11 -0
  185. package/ios/Resources/MoMoUIKitsColors.xcassets/Background.colorset/Contents.json +38 -0
  186. package/ios/Resources/MoMoUIKitsColors.xcassets/Border.colorset/Contents.json +38 -0
  187. package/ios/Resources/MoMoUIKitsColors.xcassets/Card.colorset/Contents.json +38 -0
  188. package/ios/Resources/MoMoUIKitsColors.xcassets/Contents.json +6 -0
  189. package/ios/Resources/MoMoUIKitsColors.xcassets/Error.colorset/Contents.json +38 -0
  190. package/ios/Resources/MoMoUIKitsColors.xcassets/Primary.colorset/Contents.json +38 -0
  191. package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryDark.colorset/Contents.json +38 -0
  192. package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryLight.colorset/Contents.json +38 -0
  193. package/ios/Resources/MoMoUIKitsColors.xcassets/Secondary.colorset/Contents.json +38 -0
  194. package/ios/Resources/MoMoUIKitsColors.xcassets/Success.colorset/Contents.json +38 -0
  195. package/ios/Resources/MoMoUIKitsColors.xcassets/Text.colorset/Contents.json +38 -0
  196. package/ios/Resources/MoMoUIKitsColors.xcassets/TextSecondary.colorset/Contents.json +38 -0
  197. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/Contents.json +9 -0
  198. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-default.colorset/Contents.json +38 -0
  199. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-disable.colorset/Contents.json +38 -0
  200. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-pressed.colorset/Contents.json +38 -0
  201. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-selected.colorset/Contents.json +38 -0
  202. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-surface.colorset/Contents.json +38 -0
  203. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-tonal.colorset/Contents.json +38 -0
  204. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-default.colorset/Contents.json +38 -0
  205. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-disable.colorset/Contents.json +38 -0
  206. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/gradient.colorset/Contents.json +38 -0
  207. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/primary.colorset/Contents.json +38 -0
  208. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/secondary.colorset/Contents.json +38 -0
  209. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-container.colorset/Contents.json +38 -0
  210. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-primary.colorset/Contents.json +38 -0
  211. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-secondary.colorset/Contents.json +38 -0
  212. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-default.colorset/Contents.json +38 -0
  213. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-disable.colorset/Contents.json +38 -0
  214. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-hint.colorset/Contents.json +38 -0
  215. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-secondary.colorset/Contents.json +38 -0
  216. package/ios/Resources/MoMoUIKitsColors.xcassets/Warning.colorset/Contents.json +38 -0
  217. package/ios/Stepper/Stepper.swift +2 -2
  218. package/ios/Steps/Steps.swift +22 -6
  219. package/ios/SuggestAction/SuggestAction.swift +5 -3
  220. package/ios/Swipeable/SwipeCell.swift +5 -3
  221. package/ios/Switch/Switch.swift +53 -28
  222. package/ios/TabView/TabView.swift +18 -14
  223. package/ios/Template/TrustBanner/TrustBanner.swift +6 -7
  224. package/ios/Tooltip/Tooltip.swift +3 -0
  225. package/ios/Typography/FontScaleStore.swift +19 -0
  226. package/ios/Typography/Text.swift +3 -0
  227. package/ios/Typography/Typography.swift +8 -5
  228. package/ios/Uploader/Uploader.swift +0 -9
  229. package/ios/native-kits.podspec +6 -3
  230. package/ios-demo/MoMoUIKitsDemo.podspec +5 -3
  231. package/ios-demo/README.md +120 -0
  232. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoFactory.swift +9 -57
  233. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +21 -3
  234. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LocalizeDemo.swift +188 -0
  235. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +2 -0
  236. package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +5 -4
  237. package/local.properties +8 -0
  238. package/package.json +1 -1
  239. package/settings.gradle.kts +64 -0
@@ -94,12 +94,27 @@ public struct Carousel<Content: View>: View {
94
94
  // Offset so the current page is centered within the viewport padding.
95
95
  let baseOffset = -CGFloat(currentPage) * step + contentPadding
96
96
 
97
+ // Windows the rendered range around `currentPage` instead of instantiating all
98
+ // `virtualPageCount` slides up front — with `loop=true`, that's `itemCount * 1000`
99
+ // eager views, a real memory/perf regression versus Compose's lazy `HorizontalPager`.
100
+ // Clear spacers of the skipped width keep the HStack's total layout size (and thus
101
+ // the existing `baseOffset` math) unchanged.
102
+ let windowRadius = 3
103
+ let windowStart = max(0, currentPage - windowRadius)
104
+ let windowEnd = min(virtualPageCount - 1, currentPage + windowRadius)
105
+
97
106
  ZStack {
98
107
  HStack(spacing: 0) {
99
- ForEach(0 ..< virtualPageCount, id: \.self) { page in
108
+ if windowStart > 0 {
109
+ Color.clear.frame(width: CGFloat(windowStart) * step)
110
+ }
111
+ ForEach(windowStart...windowEnd, id: \.self) { page in
100
112
  slide(page: page, step: step, viewportWidth: viewportWidth)
101
113
  .frame(width: pageWidth)
102
114
  }
115
+ if windowEnd < virtualPageCount - 1 {
116
+ Color.clear.frame(width: CGFloat(virtualPageCount - 1 - windowEnd) * step)
117
+ }
103
118
  }
104
119
  .offset(x: baseOffset + dragOffset)
105
120
  .animation(isDragging ? nil : .easeInOut(duration: 0.25), value: currentPage)
@@ -28,29 +28,23 @@ public struct Checkbox: View{
28
28
  public var body: some View {
29
29
  HStack(spacing: Spacing.S) {
30
30
  // Checkbox
31
- ZStack {
32
- RoundedRectangle(cornerRadius: Radius.XS)
33
- .fill(backgroundColor)
34
- .frame(width: 20, height: 20)
35
- .overlay(
36
- RoundedRectangle(cornerRadius: Radius.XS)
37
- .stroke(borderColor, lineWidth: Spacing.XXS)
38
- )
31
+ SwiftUI.Button(action: onCheck) {
32
+ ZStack {
33
+ RoundedRectangle(cornerRadius: Radius.XS)
34
+ .fill(backgroundColor)
35
+ .frame(width: 20, height: 20)
36
+ .overlay(
37
+ RoundedRectangle(cornerRadius: Radius.XS)
38
+ .stroke(borderColor, lineWidth: Spacing.XXS)
39
+ )
39
40
 
40
- if checked {
41
- Image(systemName: indeterminate ? "minus" : "checkmark")
42
- .resizable()
43
- .scaledToFit()
44
- .foregroundColor(Colors.black01)
45
- .frame(width: 12, height: 12)
46
- }
47
- }
48
-
49
- .onTapGesture {
50
- if !disabled {
51
- onCheck()
41
+ if checked {
42
+ Icon(source: indeterminate ? "navigation_minus" : "ic_checked", size: 20, color: Colors.black01)
43
+ }
52
44
  }
53
45
  }
46
+ .buttonStyle(ActiveOpacityButtonStyle(activeOpacity: 0.8))
47
+ .disabled(disabled)
54
48
 
55
49
  // Title
56
50
  if !title.isEmpty {
@@ -52,6 +52,13 @@ public struct Chip: View {
52
52
 
53
53
  public var body: some View {
54
54
  let dims = (size == .small) ? Self.Small : Self.Large
55
+ // Mirrors Compose's `scaleSize(...)` on every chip dimension so it responds
56
+ // to Dynamic Type scaling the same way the rest of the kit does.
57
+ let height = scaleSize(dims.height)
58
+ let horizontal = scaleSize(dims.horizontal)
59
+ let iconSize = scaleSize(dims.iconSize)
60
+ let iconSpacing = scaleSize(dims.iconSpacing)
61
+ let radius = scaleSize(Radius.L)
55
62
 
56
63
  let bg: Color = {
57
64
  if selected { return theme.colors.background.selected }
@@ -63,36 +70,38 @@ public struct Chip: View {
63
70
  let leftTint: Color = selected ? theme.colors.primary : iconLeftTint ?? theme.colors.text.default
64
71
  let rightTint: Color = selected ? theme.colors.primary : iconRightTint ?? theme.colors.text.default
65
72
 
66
- HStack(spacing: dims.iconSpacing) {
67
- if let iconLeft {
68
- Icon(source: iconLeft, size: dims.iconSize, color: leftTint)
69
- }
73
+ SwiftUI.Button(action: onClick) {
74
+ HStack(spacing: iconSpacing) {
75
+ if let iconLeft {
76
+ Icon(source: iconLeft, size: iconSize, color: leftTint)
77
+ }
70
78
 
71
- if let text = label, !text.isEmpty {
72
- MomoText(text, typography: (size == .large) ? .labelDefaultMedium : .labelSMedium, color: textColor)
73
- .lineLimit(1)
74
- }
79
+ if let text = label, !text.isEmpty {
80
+ MomoText(text, typography: (size == .large) ? .labelDefaultMedium : .labelSMedium, color: textColor)
81
+ .lineLimit(1)
82
+ }
75
83
 
76
- if let iconRight {
77
- Icon(source: iconRight, size: dims.iconSize, color: rightTint)
78
- }
79
- }
80
- .padding(.horizontal, dims.horizontal)
81
- .frame(height: dims.height)
82
- .background(
83
- RoundedRectangle(cornerRadius: Radius.L, style: .continuous)
84
- .fill(bg)
85
- )
86
- .overlay(
87
- Group {
88
- if selected {
89
- RoundedRectangle(cornerRadius: Radius.L, style: .continuous)
90
- .stroke(theme.colors.secondary, lineWidth: 2)
84
+ if let iconRight {
85
+ Icon(source: iconRight, size: iconSize, color: rightTint)
91
86
  }
92
87
  }
93
- )
94
- .contentShape(RoundedRectangle(cornerRadius: Radius.L, style: .continuous))
95
- .onTapGesture(perform: onClick)
88
+ .padding(.horizontal, horizontal)
89
+ .frame(height: height)
90
+ .background(
91
+ RoundedRectangle(cornerRadius: radius, style: .continuous)
92
+ .fill(bg)
93
+ )
94
+ .overlay(
95
+ Group {
96
+ if selected {
97
+ RoundedRectangle(cornerRadius: radius, style: .continuous)
98
+ .stroke(theme.colors.secondary, lineWidth: 2)
99
+ }
100
+ }
101
+ )
102
+ .contentShape(RoundedRectangle(cornerRadius: radius, style: .continuous))
103
+ }
104
+ .buttonStyle(ActiveOpacityButtonStyle())
96
105
  .modifier(ChipAccessibilityModifier(accessibilityLabel: accessibilityLabel))
97
106
  }
98
107
  }
@@ -30,6 +30,7 @@ public struct Collapse<Content: View>: View {
30
30
  private let useBackgroundCollapseButton: Bool
31
31
  private let backgroundColor: Color?
32
32
  private let titleColor: Color?
33
+ private let accessibilityId: String?
33
34
  private let onPress: ((Bool) -> Void)?
34
35
  private let content: (() -> Content)?
35
36
 
@@ -49,6 +50,7 @@ public struct Collapse<Content: View>: View {
49
50
  useBackgroundCollapseButton: Bool = false,
50
51
  backgroundColor: Color? = nil,
51
52
  titleColor: Color? = nil,
53
+ accessibilityId: String? = nil,
52
54
  onPress: ((Bool) -> Void)? = nil,
53
55
  @ViewBuilder content: @escaping () -> Content
54
56
  ) {
@@ -65,11 +67,17 @@ public struct Collapse<Content: View>: View {
65
67
  self.useBackgroundCollapseButton = useBackgroundCollapseButton
66
68
  self.backgroundColor = backgroundColor
67
69
  self.titleColor = titleColor
70
+ self.accessibilityId = accessibilityId
68
71
  self.onPress = onPress
69
72
  self.content = content
70
73
  _expanded = State(initialValue: expandDefault)
71
74
  }
72
75
 
76
+ // Mirrors Kotlin's `accessibilityId ?: "Collapse/$title"`.
77
+ private var automationId: String {
78
+ accessibilityId ?? "Collapse/\(title)"
79
+ }
80
+
73
81
  private var resolvedBackgroundColor: Color {
74
82
  backgroundColor ?? theme.colors.background.surface
75
83
  }
@@ -97,6 +105,7 @@ public struct Collapse<Content: View>: View {
97
105
  .frame(maxWidth: .infinity)
98
106
  .background(resolvedBackgroundColor)
99
107
  .clipShape(RoundedRectangle(cornerRadius: Radius.S, style: .continuous))
108
+ .accessibilityIdentifier(automationId)
100
109
  .overlay(
101
110
  showBorder
102
111
  ? RoundedRectangle(cornerRadius: Radius.S, style: .continuous)
@@ -159,7 +168,8 @@ public struct Collapse<Content: View>: View {
159
168
  .frame(maxWidth: .infinity)
160
169
  .contentShape(Rectangle())
161
170
  }
162
- .buttonStyle(.plain)
171
+ .buttonStyle(ActiveOpacityButtonStyle())
172
+ .accessibilityIdentifier("\(automationId)|touch")
163
173
  }
164
174
 
165
175
  private var chevron: some View {
@@ -3,18 +3,18 @@ import Foundation
3
3
  import SwiftUI
4
4
 
5
5
  public enum Colors {
6
- public static let primary = Color("Primary")
7
- public static let primaryDark = Color("PrimaryDark")
8
- public static let primaryLight = Color("PrimaryLight")
9
- public static let secondary = Color("Secondary")
10
- public static let background = Color("Background")
11
- public static let border = Color("Border")
12
- public static let text = Color("ThemeColors/text-default")
13
- public static let textSecondary = Color("TextSecondary")
14
- public static let card = Color("Card")
15
- public static let error = Color("Error")
16
- public static let info = Color("Info")
17
- public static let success = Color("Success")
6
+ public static let primary = Color.momoAsset("Primary")
7
+ public static let primaryDark = Color.momoAsset("PrimaryDark")
8
+ public static let primaryLight = Color.momoAsset("PrimaryLight")
9
+ public static let secondary = Color.momoAsset("Secondary")
10
+ public static let background = Color.momoAsset("Background")
11
+ public static let border = Color.momoAsset("Border")
12
+ public static let text = Color.momoAsset("ThemeColors/text-default")
13
+ public static let textSecondary = Color.momoAsset("TextSecondary")
14
+ public static let card = Color.momoAsset("Card")
15
+ public static let error = Color.momoAsset("Error")
16
+ public static let info = blue03
17
+ public static let success = Color.momoAsset("Success")
18
18
 
19
19
  public static let black20 = Color(hex: "000000")
20
20
  public static let black19 = Color(hex: "18191a")
@@ -49,15 +49,18 @@ public enum Colors {
49
49
  public static let pink03 = Color(hex: "eb2f96")
50
50
  public static let pink02 = Color(hex: "d42a87")
51
51
  public static let pink01 = Color(hex: "bc2678")
52
+ public static let pinkMoMoBranding = Color(hex: "a50064")
52
53
 
53
54
 
54
- public static let violet10 = Color(hex: "fcf8fe")
55
- public static let violet09 = Color(hex: "faf4fe")
55
+ public static let violet11 = Color(hex: "fcf8fe")
56
+ public static let violet11Stroke = Color(hex: "dfe1e5")
57
+ public static let violet10 = Color(hex: "faf4fe")
58
+ public static let violet09 = Color(hex: "f4e9fd")
56
59
  public static let violet08 = Color(hex: "ead4fc")
57
60
  public static let violet07 = Color(hex: "d5aaf9")
58
- public static let violet06 = Color(hex: "f4e9fd")
59
- public static let violet05 = Color(hex: "c07ff6")
60
- public static let violet04 = Color(hex: "ab55f3")
61
+ public static let violet06 = Color(hex: "c07ff6")
62
+ public static let violet05 = Color(hex: "ab55f3")
63
+ public static let violet04 = Color(hex: "a03ff1")
61
64
  public static let violet03 = Color(hex: "962af0")
62
65
  public static let violet02 = Color(hex: "8726d8")
63
66
  public static let violet01 = Color(hex: "7822c0")
@@ -8,5 +8,7 @@ public enum Spacing {
8
8
  public static let L: CGFloat = 16
9
9
  public static let XL: CGFloat = 24
10
10
  public static let XXL: CGFloat = 32
11
- public static let XXXL: CGFloat = 48
11
+ public static let Size3XL: CGFloat = 48
12
+ public static let Size4XL: CGFloat = 56
13
+ public static let Size5XL: CGFloat = 64
12
14
  }
@@ -174,26 +174,26 @@ public struct Theme {
174
174
  public let defaultTheme = Theme(
175
175
  dark: false,
176
176
  colors: ColorScheme(
177
- primary: Color("ThemeColors/primary"),
178
- secondary: Color("ThemeColors/secondary"),
179
- gradient: Color("ThemeColors/gradient"),
177
+ primary: Color.momoAsset("ThemeColors/primary"),
178
+ secondary: Color.momoAsset("ThemeColors/secondary"),
179
+ gradient: Color.momoAsset("ThemeColors/gradient"),
180
180
  background: Background(
181
- default: Color("ThemeColors/background-default"),
182
- surface: Color("ThemeColors/background-surface"),
183
- tonal: Color("ThemeColors/background-tonal"),
184
- pressed: Color("ThemeColors/background-pressed"),
185
- selected: Color("ThemeColors/background-selected"),
186
- disable: Color("ThemeColors/background-disable")
181
+ default: Color.momoAsset("ThemeColors/background-default"),
182
+ surface: Color.momoAsset("ThemeColors/background-surface"),
183
+ tonal: Color.momoAsset("ThemeColors/background-tonal"),
184
+ pressed: Color.momoAsset("ThemeColors/background-pressed"),
185
+ selected: Color.momoAsset("ThemeColors/background-selected"),
186
+ disable: Color.momoAsset("ThemeColors/background-disable")
187
187
  ),
188
188
  text: TextColors(
189
- default: Color("ThemeColors/text-default"),
190
- secondary: Color("ThemeColors/text-secondary"),
191
- hint: Color("ThemeColors/text-hint"),
192
- disable: Color("ThemeColors/text-disable")
189
+ default: Color.momoAsset("ThemeColors/text-default"),
190
+ secondary: Color.momoAsset("ThemeColors/text-secondary"),
191
+ hint: Color.momoAsset("ThemeColors/text-hint"),
192
+ disable: Color.momoAsset("ThemeColors/text-disable")
193
193
  ),
194
194
  border: BorderColors(
195
- default: Color("ThemeColors/border-default"),
196
- disable: Color("ThemeColors/border-disable")
195
+ default: Color.momoAsset("ThemeColors/border-default"),
196
+ disable: Color.momoAsset("ThemeColors/border-disable")
197
197
  ),
198
198
  success: ColorSet(
199
199
  primary: Colors.green03,
@@ -14,6 +14,8 @@ private let datePickerWithLabelsHeight: CGFloat = 238
14
14
  /// - `"HH:mm"` shows hour + minute; a lone `"HH"` switches the hour wheel to a
15
15
  /// 12-hour clock with an AM/PM column.
16
16
  public struct DateTimePicker: View {
17
+ @Environment(\.appTheme) private var theme
18
+
17
19
  // MARK: Lifecycle
18
20
 
19
21
  public init(
@@ -84,7 +86,7 @@ public struct DateTimePicker: View {
84
86
 
85
87
  VStack(spacing: 0) {
86
88
  if hasLabel {
87
- MomoText(arrayLabelTime[index], typography: .actionSBold, color: Colors.text)
89
+ MomoText(arrayLabelTime[index], typography: .actionSBold, color: theme.colors.text.default)
88
90
  .padding(.bottom, Spacing.S)
89
91
  }
90
92
 
@@ -100,7 +102,7 @@ public struct DateTimePicker: View {
100
102
  }
101
103
  .frame(maxWidth: .infinity)
102
104
  .frame(height: pickerHeight)
103
- .background(Colors.background)
105
+ .background(theme.colors.background.surface)
104
106
  .padding(.horizontal, Spacing.M)
105
107
  .onAppear { emitIfValid() }
106
108
  }
@@ -14,6 +14,8 @@ private let wheelPickerBorderWidth: CGFloat = 1
14
14
  /// real value can be centered. The currently centered row is reported back via
15
15
  /// `onChange(name, value)`.
16
16
  public struct WheelPicker: View {
17
+ @Environment(\.appTheme) private var theme
18
+
17
19
  // MARK: Lifecycle
18
20
 
19
21
  public init(
@@ -76,9 +78,9 @@ public struct WheelPicker: View {
76
78
  .frame(height: wheelItemHeight * CGFloat(wheelVisibleCount))
77
79
  .overlay(
78
80
  RoundedRectangle(cornerRadius: Radius.S)
79
- .stroke(Colors.border, lineWidth: wheelPickerBorderWidth)
81
+ .stroke(theme.colors.border.default, lineWidth: wheelPickerBorderWidth)
80
82
  )
81
- .background(Colors.background.clipShape(RoundedRectangle(cornerRadius: Radius.S)))
83
+ .background(theme.colors.background.surface.clipShape(RoundedRectangle(cornerRadius: Radius.S)))
82
84
  .overlay(
83
85
  // Centered translucent selection band.
84
86
  Rectangle()
@@ -121,6 +123,8 @@ public struct WheelPicker: View {
121
123
  // MARK: - WheelPickerItem
122
124
 
123
125
  private struct WheelPickerItem: View {
126
+ @Environment(\.appTheme) private var theme
127
+
124
128
  let text: String
125
129
  let isSelected: Bool
126
130
  let index: Int
@@ -142,7 +146,7 @@ private struct WheelPickerItem: View {
142
146
  let scale: CGFloat = isSelected ? 1.0 : 0.87
143
147
 
144
148
  return ZStack {
145
- MomoText(text, typography: .actionSBold, color: Colors.text)
149
+ MomoText(text, typography: .actionSBold, color: theme.colors.text.default)
146
150
  .scaleEffect(scale)
147
151
  }
148
152
  .frame(maxWidth: .infinity)
@@ -0,0 +1,14 @@
1
+ import SwiftUI
2
+
3
+ /// Mirrors Compose's `Modifier.activeOpacityClickable(activeOpacity:)` (modifier/Clickable.kt):
4
+ /// fades the whole tappable subtree to `activeOpacity` while pressed, animated, instead of
5
+ /// relying on a platform-default press indication.
6
+ struct ActiveOpacityButtonStyle: ButtonStyle {
7
+ var activeOpacity: Double = 0.2
8
+
9
+ func makeBody(configuration: Configuration) -> some View {
10
+ configuration.label
11
+ .opacity(configuration.isPressed ? activeOpacity : 1)
12
+ .animation(.default, value: configuration.isPressed)
13
+ }
14
+ }
@@ -1,6 +1,38 @@
1
1
  import SwiftUI
2
+ import Foundation
3
+
4
+ private final class MoMoUIKitsBundleToken {}
5
+
6
+ enum MoMoUIKitsResources {
7
+ static let bundle: Bundle = {
8
+ let bundleName = "MoMoUIKitsResources"
9
+ let tokenBundle = Bundle(for: MoMoUIKitsBundleToken.self)
10
+ let frameworkBundle = Bundle(identifier: "org.cocoapods.MoMoUIKits")
11
+ let candidates = [
12
+ Bundle.main.resourceURL,
13
+ tokenBundle.resourceURL,
14
+ tokenBundle.bundleURL,
15
+ frameworkBundle?.resourceURL,
16
+ frameworkBundle?.bundleURL
17
+ ]
18
+
19
+ for candidate in candidates {
20
+ guard let bundleURL = candidate?.appendingPathComponent("\(bundleName).bundle"),
21
+ let bundle = Bundle(url: bundleURL) else {
22
+ continue
23
+ }
24
+ return bundle
25
+ }
26
+
27
+ return Bundle.main
28
+ }()
29
+ }
2
30
 
3
31
  public extension Color {
32
+ static func momoAsset(_ name: String) -> Color {
33
+ Color(name, bundle: MoMoUIKitsResources.bundle)
34
+ }
35
+
4
36
  init(hex: UInt, alpha: Double = 1) {
5
37
  self.init(
6
38
  .sRGB,
@@ -49,7 +49,11 @@ public struct Icon: View {
49
49
  if let uri = iconSources[source]?.uri {
50
50
  // Mirror Compose: certain icons (e.g. branded glyphs) are never tinted
51
51
  let resolvedColor = noThemeIcons.contains(source) ? nil : color
52
- ImageView(uri, color: resolvedColor).frame(width: size, height: size)
52
+ ImageView(uri, color: resolvedColor)
53
+ .frame(width: size, height: size)
54
+ // Mirrors Compose's auto-generated `contentDescription = "img|$iconUrl"`
55
+ // when no explicit label is provided.
56
+ .accessibilityLabel(accessibilityLabel ?? "img|\(uri)")
53
57
  }
54
58
  }
55
59
  }
@@ -5,13 +5,15 @@ import SwiftUI
5
5
 
6
6
  public enum IconSize {
7
7
  case large
8
+ case medium
8
9
  case small
9
10
 
10
11
  /// Container width/height of the button.
11
12
  var containerSize: CGFloat {
12
13
  switch self {
13
14
  case .large: return 48
14
- case .small: return 40
15
+ case .medium: return 36
16
+ case .small: return 28
15
17
  }
16
18
  }
17
19
 
@@ -19,13 +21,16 @@ public enum IconSize {
19
21
  var iconSize: CGFloat {
20
22
  switch self {
21
23
  case .large: return 24
22
- case .small: return 16
24
+ case .medium, .small: return 16
23
25
  }
24
26
  }
27
+ }
25
28
 
26
- var radius: CGFloat {
27
- Radius.XL
28
- }
29
+ // MARK: - IconShape
30
+
31
+ public enum IconShape {
32
+ case circle
33
+ case square
29
34
  }
30
35
 
31
36
  // MARK: - IconButton
@@ -37,6 +42,7 @@ public struct IconButton: View {
37
42
  var onClick: () -> Void
38
43
  var type: ButtonType
39
44
  var size: IconSize
45
+ var shape: IconShape
40
46
  var color: Color?
41
47
 
42
48
  public init(
@@ -44,12 +50,14 @@ public struct IconButton: View {
44
50
  onClick: @escaping () -> Void,
45
51
  type: ButtonType = .primary,
46
52
  size: IconSize = .small,
53
+ shape: IconShape = .circle,
47
54
  color: Color? = nil
48
55
  ) {
49
56
  self.icon = icon
50
57
  self.onClick = onClick
51
58
  self.type = type
52
59
  self.size = size
60
+ self.shape = shape
53
61
  self.color = color
54
62
  }
55
63
 
@@ -72,9 +80,9 @@ public struct IconButton: View {
72
80
  Icon(source: icon, size: size.iconSize, color: fg)
73
81
  .frame(width: size.containerSize, height: size.containerSize)
74
82
  .background(bg)
75
- .clipShape(RoundedRectangle(cornerRadius: size.radius))
83
+ .clipShape(IconButtonShape(shape))
76
84
  .overlay(
77
- RoundedRectangle(cornerRadius: size.radius)
85
+ IconButtonShape(shape)
78
86
  .stroke(border ?? .clear, lineWidth: border != nil ? borderWidth : 0)
79
87
  )
80
88
  }
@@ -110,3 +118,23 @@ public struct IconButton: View {
110
118
  }
111
119
  }
112
120
  }
121
+
122
+ /// Type-erased shape switch (`Circle` vs a fixed `Radius.S` rounded rect) — mirrors
123
+ /// Compose's `IconShape.toShape()`. `AnyShape` needs iOS 17+, so this hand-rolls the same
124
+ /// erasure at the deployment target's iOS 15 floor.
125
+ private struct IconButtonShape: Shape {
126
+ let shape: IconShape
127
+
128
+ init(_ shape: IconShape) {
129
+ self.shape = shape
130
+ }
131
+
132
+ func path(in rect: CGRect) -> Path {
133
+ switch shape {
134
+ case .circle:
135
+ return Circle().path(in: rect)
136
+ case .square:
137
+ return RoundedRectangle(cornerRadius: Radius.S).path(in: rect)
138
+ }
139
+ }
140
+ }
@@ -5,15 +5,23 @@ import SDWebImageSwiftUI
5
5
  import SkeletonUI
6
6
  import SwiftUI
7
7
 
8
+ public enum ImageState {
9
+ case loading, success, error
10
+ }
11
+
8
12
  public struct ImageView: View {
13
+ @Environment(\.appTheme) private var theme
14
+
9
15
  // MARK: Lifecycle
10
16
 
11
- public init(_ url: String, aspectRatio: CGFloat? = nil, contentMode: ContentMode = ContentMode.fit, placeholder: AnyView? = nil, color: Color? = nil) {
17
+ public init(_ url: String, aspectRatio: CGFloat? = nil, contentMode: ContentMode = ContentMode.fit, placeholder: AnyView? = nil, color: Color? = nil, loading: Bool = true, onStateChanged: ((ImageState) -> Void)? = nil) {
12
18
  self.url = url
13
19
  self.aspectRatio = aspectRatio
14
20
  self.contentMode = contentMode
15
21
  self.placeholder = placeholder
16
22
  self.color = color
23
+ self.loading = loading
24
+ self.onStateChanged = onStateChanged
17
25
  }
18
26
 
19
27
  // MARK: Public
@@ -22,9 +30,11 @@ public struct ImageView: View {
22
30
  return WebImage(url: URL(string: url), isAnimating: .constant(true))
23
31
  .onFailure { _ in
24
32
  error = true
33
+ onStateChanged?(.error)
25
34
  }
26
35
  .onSuccess { _, _, _ in
27
36
  error = false
37
+ onStateChanged?(.success)
28
38
  }
29
39
  .resizable()
30
40
  .renderingMode(color != nil ? .template : .original)
@@ -34,20 +44,21 @@ public struct ImageView: View {
34
44
  Image("media_fail")
35
45
  .resizable()
36
46
  .renderingMode(.template)
37
- .foregroundColor(Colors.black08)
47
+ .foregroundColor(theme.colors.text.disable)
38
48
  .frame(width: 24, height: 24)
39
49
  } else if placeholder != nil {
40
50
  placeholder
41
51
  }
42
52
  })
43
53
  .frame(maxWidth: .infinity, maxHeight: .infinity)
44
- .skeleton(with: !error && placeholder == nil)
54
+ .skeleton(with: loading && !error && placeholder == nil)
45
55
  .shape(type: .rectangle)
46
56
  }
47
57
  .scaledToFit()
48
58
  .transition(.fade)
49
59
  .aspectRatio(aspectRatio, contentMode: contentMode)
50
60
  .foregroundColor(color)
61
+ .onAppear { onStateChanged?(.loading) }
51
62
  }
52
63
 
53
64
  // MARK: Internal
@@ -56,6 +67,8 @@ public struct ImageView: View {
56
67
  var contentMode: ContentMode
57
68
  var placeholder: AnyView?
58
69
  var color: Color?
70
+ var loading: Bool
71
+ var onStateChanged: ((ImageState) -> Void)?
59
72
 
60
73
  @State var error: Bool = false
61
74
  var url: String
@@ -7,6 +7,8 @@ public enum InformationState {
7
7
  }
8
8
 
9
9
  public struct Information: View {
10
+ @Environment(\.appTheme) private var theme
11
+
10
12
  private let title: String?
11
13
  private let description: String
12
14
  private let state: InformationState
@@ -93,7 +95,7 @@ public struct Information: View {
93
95
  .frame(maxWidth: .infinity, alignment: .leading)
94
96
 
95
97
  if let onPressClose, showIconClose {
96
- Icon(source: "navigation_close", size: 16, color: Colors.black17)
98
+ Icon(source: "navigation_close", size: 16, color: theme.colors.text.default)
97
99
  .contentShape(Rectangle())
98
100
  .onTapGesture(perform: onPressClose)
99
101
  }
@@ -8,6 +8,8 @@
8
8
  import SwiftUI
9
9
 
10
10
  public struct ErrorView: View {
11
+ @Environment(\.appTheme) private var theme
12
+
11
13
  public var errorMessage: String
12
14
  public var errorSpacing: Bool
13
15
  public var hintText: String
@@ -43,7 +45,7 @@ public struct ErrorView: View {
43
45
  // MARK: - Helpers
44
46
 
45
47
  private func displayColor() -> Color {
46
- !errorMessage.isEmpty ? Colors.red03 : Colors.black12
48
+ !errorMessage.isEmpty ? theme.colors.error.primary : theme.colors.text.hint
47
49
  }
48
50
 
49
51
  private func displayText() -> String {